diff --git a/ip/iproute.c b/ip/iproute.c index 5853f026..c6d87e58 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -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); } diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 566fc7ea..ebc688e2 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -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++) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index 34763cc3..2978bc0e 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -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