@@ -27,6 +27,7 @@ enum {
SEG6_LOCAL_OIF,
SEG6_LOCAL_BPF,
SEG6_LOCAL_VRFTABLE,
+ SEG6_LOCAL_COUNTERS,
__SEG6_LOCAL_MAX,
};
#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
@@ -78,4 +79,33 @@ enum {
#define SEG6_LOCAL_BPF_PROG_MAX (__SEG6_LOCAL_BPF_PROG_MAX - 1)
+/* SRv6 Behavior counters are encoded as netlink attributes guaranteeing the
+ * correct alignment.
+ * Each counter is identified by a different attribute type (i.e.
+ * SEG6_LOCAL_CNT_PACKETS).
+ *
+ * - SEG6_LOCAL_CNT_PACKETS: identifies a counter that counts the number of
+ * packets that have been CORRECTLY processed by an SRv6 Behavior instance
+ * (i.e., packets that generate errors or are dropped are NOT counted).
+ *
+ * - SEG6_LOCAL_CNT_BYTES: identifies a counter that counts the total amount
+ * of traffic in bytes of all packets that have been CORRECTLY processed by
+ * an SRv6 Behavior instance (i.e., packets that generate errors or are
+ * dropped are NOT counted).
+ *
+ * - SEG6_LOCAL_CNT_ERRORS: identifies a counter that counts the number of
+ * packets that have NOT been properly processed by an SRv6 Behavior instance
+ * (i.e., packets that generate errors or are dropped).
+ */
+enum {
+ SEG6_LOCAL_CNT_UNSPEC,
+ SEG6_LOCAL_CNT_PAD, /* pad for 64 bits values */
+ SEG6_LOCAL_CNT_PACKETS,
+ SEG6_LOCAL_CNT_BYTES,
+ SEG6_LOCAL_CNT_ERRORS,
+ __SEG6_LOCAL_CNT_MAX,
+};
+
+#define SEG6_LOCAL_CNT_MAX (__SEG6_LOCAL_CNT_MAX - 1)
+
#endif
@@ -102,9 +102,16 @@ static void usage(void)
"BOOL := [1|0]\n"
"FEATURES := ecn\n"
"ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl ]\n"
- "ENCAPHDR := [ MPLSLABEL | SEG6HDR ]\n"
+ "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL ]\n"
"SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n"
"SEGMODE := [ encap | inline ]\n"
+ "SEG6LOCAL := action ACTION [ OPTIONS ] [ count ]\n"
+ "ACTION := { End | End.X | End.T | End.DX2 | End.DX6 | End.DX4 |\n"
+ " End.DT6 | End.DT4 | End.B6 | End.B6.Encaps | End.BM |\n"
+ " End.S | End.AS | End.AM | End.BPF }\n"
+ "OPTIONS := OPTION [ OPTIONS ]\n"
+ "OPTION := { srh SEG6HDR | nh4 ADDR | nh6 ADDR | iif DEV | oif DEV |\n"
+ " table TABLEID | vrftable TABLEID | endpoint PROGNAME }\n"
"ROUTE_GET_FLAGS := [ fibmatch ]\n");
exit(-1);
}
@@ -266,6 +266,42 @@ static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
}
}
+static void print_seg6_local_counters(FILE *fp, struct rtattr *encap)
+{
+ struct rtattr *tb[SEG6_LOCAL_CNT_MAX + 1];
+ __u64 packets = 0, bytes = 0, errors = 0;
+
+ parse_rtattr_nested(tb, SEG6_LOCAL_CNT_MAX, encap);
+
+ if (tb[SEG6_LOCAL_CNT_PACKETS])
+ packets = rta_getattr_u64(tb[SEG6_LOCAL_CNT_PACKETS]);
+
+ if (tb[SEG6_LOCAL_CNT_BYTES])
+ bytes = rta_getattr_u64(tb[SEG6_LOCAL_CNT_BYTES]);
+
+ if (tb[SEG6_LOCAL_CNT_ERRORS])
+ errors = rta_getattr_u64(tb[SEG6_LOCAL_CNT_ERRORS]);
+
+ if (is_json_context()) {
+ open_json_object("stats64");
+
+ print_u64(PRINT_JSON, "packets", NULL, packets);
+ print_u64(PRINT_JSON, "bytes", NULL, bytes);
+ print_u64(PRINT_JSON, "errors", NULL, errors);
+
+ close_json_object();
+ } else {
+ print_string(PRINT_FP, NULL, "%s ", "packets");
+ print_num(fp, 1, packets);
+
+ print_string(PRINT_FP, NULL, "%s ", "bytes");
+ print_num(fp, 1, bytes);
+
+ print_string(PRINT_FP, NULL, "%s ", "errors");
+ print_num(fp, 1, errors);
+ }
+}
+
static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[SEG6_LOCAL_MAX + 1];
@@ -325,6 +361,9 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
if (tb[SEG6_LOCAL_BPF])
print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint");
+
+ if (tb[SEG6_LOCAL_COUNTERS] && show_stats)
+ print_seg6_local_counters(fp, tb[SEG6_LOCAL_COUNTERS]);
}
static void print_encap_mpls(FILE *fp, struct rtattr *encap)
@@ -862,13 +901,39 @@ static int lwt_parse_bpf(struct rtattr *rta, size_t len,
return 0;
}
+/* for the moment, counters are always initialized to zero by the kernel; so we
+ * do not expect to parse any argument here.
+ */
+static int seg6local_fill_counters(struct rtattr *rta, size_t len, int attr)
+{
+ struct rtattr *nest;
+ int ret;
+
+ nest = rta_nest(rta, len, attr);
+
+ ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_PACKETS, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_BYTES, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = rta_addattr64(rta, len, SEG6_LOCAL_CNT_ERRORS, 0);
+ if (ret < 0)
+ return ret;
+
+ rta_nest_end(rta, nest);
+ return 0;
+}
+
static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
char ***argvp)
{
int segs_ok = 0, hmac_ok = 0, table_ok = 0, vrftable_ok = 0;
+ int action_ok = 0, srh_ok = 0, bpf_ok = 0, counters_ok = 0;
int nh4_ok = 0, nh6_ok = 0, iif_ok = 0, oif_ok = 0;
__u32 action = 0, table, vrftable, iif, oif;
- int action_ok = 0, srh_ok = 0, bpf_ok = 0;
struct ipv6_sr_hdr *srh;
char **argv = *argvp;
int argc = *argcp;
@@ -932,6 +997,11 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
if (!oif)
exit(nodev(*argv));
ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
+ } else if (strcmp(*argv, "count") == 0) {
+ if (counters_ok++)
+ duparg2("count", *argv);
+ ret = seg6local_fill_counters(rta, len,
+ SEG6_LOCAL_COUNTERS);
} else if (strcmp(*argv, "srh") == 0) {
NEXT_ARG();
if (srh_ok++)
@@ -240,7 +240,8 @@ throw " | " unreachable " | " prohibit " | " blackhole " | " nat " ]"
.B seg6local
.BR action
.IR SEG6_ACTION " [ "
-.IR SEG6_ACTION_PARAM " ] "
+.IR SEG6_ACTION_PARAM " ] [ "
+.BR count " ] "
.ti -8
.IR ROUTE_GET_FLAGS " := "
@@ -801,8 +802,14 @@ is a set of encapsulation attributes specific to the
.B seg6local
.in +2
.IR SEG6_ACTION " [ "
-.IR SEG6_ACTION_PARAM " ] "
-- Operation to perform on matching packets.
+.IR SEG6_ACTION_PARAM " ] [ "
+.BR count " ] "
+- Operation to perform on matching packets. The optional \fBcount\fR
+attribute is used to collect statistics on the processing of actions.
+Three counters are implemented: 1) packets correctly processed;
+2) bytes correctly processed; 3) packets that cause a processing error
+(i.e., missing SID List, wrong SID List, etc). To retrieve the counters
+related to an action use the \fB-s\fR flag in the \fBshow\fR command.
The following actions are currently supported (\fBLinux 4.14+ only\fR).
.in +2