From 3d8048dcc326b5ae62a7be7b034b7e262a9c92fb Mon Sep 17 00:00:00 2001 From: Nogah Frankel Date: Thu, 26 Jan 2017 14:44:38 +0200 Subject: [PATCH 1/7] ifstat: Includes reorder Reorder the includes in misc/ifstat.c to match convention. Signed-off-by: Nogah Frankel Reviewed-by: Jiri Pirko --- misc/ifstat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/misc/ifstat.c b/misc/ifstat.c index 92d67b0c..5bcbcc8e 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -28,12 +28,12 @@ #include #include -#include -#include #include #include -#include +#include "libnetlink.h" +#include "json_writer.h" +#include "SNAPSHOT.h" int dump_zeros; int reset_history; From 5a52102b7c8fb5ccf6dbdacb486f153faba4bac6 Mon Sep 17 00:00:00 2001 From: Nogah Frankel Date: Thu, 26 Jan 2017 14:44:39 +0200 Subject: [PATCH 2/7] ifstat: Add extended statistics to ifstat Extended stats are part of the RTM_GETSTATS method. This patch adds them to ifstat. While extended stats can come in many forms, we support only the rtnl_link_stats64 struct for them (which is the 64 bits version of struct rtnl_link_stats). We support stats in the main nesting level, or one lower. The extension can be called by its name or any shorten of it. If there is more than one matched, the first one will be picked. To get the extended stats the flag -x is used. Signed-off-by: Nogah Frankel Reviewed-by: Jiri Pirko --- misc/ifstat.c | 160 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 15 deletions(-) diff --git a/misc/ifstat.c b/misc/ifstat.c index 5bcbcc8e..94671191 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -34,6 +34,7 @@ #include "libnetlink.h" #include "json_writer.h" #include "SNAPSHOT.h" +#include "utils.h" int dump_zeros; int reset_history; @@ -48,17 +49,21 @@ int pretty; double W; char **patterns; int npatterns; +bool is_extended; +int filter_type; +int sub_type; char info_source[128]; int source_mismatch; #define MAXS (sizeof(struct rtnl_link_stats)/sizeof(__u32)) +#define NO_SUB_TYPE 0xffff struct ifstat_ent { struct ifstat_ent *next; char *name; int ifindex; - unsigned long long val[MAXS]; + __u64 val[MAXS]; double rate[MAXS]; __u32 ival[MAXS]; }; @@ -106,6 +111,48 @@ static int match(const char *id) return 0; } +static int get_nlmsg_extended(const struct sockaddr_nl *who, + struct nlmsghdr *m, void *arg) +{ + struct if_stats_msg *ifsm = NLMSG_DATA(m); + struct rtattr *tb[IFLA_STATS_MAX+1]; + int len = m->nlmsg_len; + struct ifstat_ent *n; + + if (m->nlmsg_type != RTM_NEWSTATS) + return 0; + + len -= NLMSG_LENGTH(sizeof(*ifsm)); + if (len < 0) + return -1; + + parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len); + if (tb[filter_type] == NULL) + return 0; + + n = malloc(sizeof(*n)); + if (!n) + abort(); + + n->ifindex = ifsm->ifindex; + n->name = strdup(ll_index_to_name(ifsm->ifindex)); + + if (sub_type == NO_SUB_TYPE) { + memcpy(&n->val, RTA_DATA(tb[filter_type]), sizeof(n->val)); + } else { + struct rtattr *attr; + + attr = parse_rtattr_one_nested(sub_type, tb[filter_type]); + if (attr == NULL) + return 0; + memcpy(&n->val, RTA_DATA(attr), sizeof(n->val)); + } + memset(&n->rate, 0, sizeof(n->rate)); + n->next = kern_db; + kern_db = n; + return 0; +} + static int get_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *m, void *arg) { @@ -147,18 +194,34 @@ static void load_info(void) { struct ifstat_ent *db, *n; struct rtnl_handle rth; + __u32 filter_mask; if (rtnl_open(&rth, 0) < 0) exit(1); - if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETLINK) < 0) { - perror("Cannot send dump request"); - exit(1); - } + if (is_extended) { + ll_init_map(&rth); + filter_mask = IFLA_STATS_FILTER_BIT(filter_type); + if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC, RTM_GETSTATS, + filter_mask) < 0) { + perror("Cannot send dump request"); + exit(1); + } - if (rtnl_dump_filter(&rth, get_nlmsg, NULL) < 0) { - fprintf(stderr, "Dump terminated\n"); - exit(1); + if (rtnl_dump_filter(&rth, get_nlmsg_extended, NULL) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } + } else { + if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETLINK) < 0) { + perror("Cannot send dump request"); + exit(1); + } + + if (rtnl_dump_filter(&rth, get_nlmsg, NULL) < 0) { + fprintf(stderr, "Dump terminated\n"); + exit(1); + } } rtnl_close(&rth); @@ -553,10 +616,17 @@ static void update_db(int interval) } for (i = 0; i < MAXS; i++) { double sample; - unsigned long incr = h1->ival[i] - n->ival[i]; + __u64 incr; + + if (is_extended) { + incr = h1->val[i] - n->val[i]; + n->val[i] = h1->val[i]; + } else { + incr = (__u32) (h1->ival[i] - n->ival[i]); + n->val[i] += incr; + n->ival[i] = h1->ival[i]; + } - n->val[i] += incr; - n->ival[i] = h1->ival[i]; sample = (double)(incr*1000)/interval; if (interval >= scan_interval) { n->rate[i] += W*(sample-n->rate[i]); @@ -656,6 +726,47 @@ static int verify_forging(int fd) return -1; } +static void xstat_usage(void) +{ + fprintf(stderr, +"Usage: ifstat supported xstats:\n"); +} + +struct extended_stats_options_t { + char *name; + int id; + int sub_type; +}; + +/* Note: if one xstat name is subset of another, it should be before it in this + * list. + * Name length must be under 64 chars. + */ +static const struct extended_stats_options_t extended_stats_options[] = { +}; + +static const char *get_filter_type(const char *name) +{ + int name_len; + int i; + + name_len = strlen(name); + for (i = 0; i < ARRAY_SIZE(extended_stats_options); i++) { + const struct extended_stats_options_t *xstat; + + xstat = &extended_stats_options[i]; + if (strncmp(name, xstat->name, name_len) == 0) { + filter_type = xstat->id; + sub_type = xstat->sub_type; + return xstat->name; + } + } + + fprintf(stderr, "invalid ifstat extension %s\n", name); + xstat_usage(); + return NULL; +} + static void usage(void) __attribute__((noreturn)); static void usage(void) @@ -673,7 +784,8 @@ static void usage(void) " -s, --noupdate don't update history\n" " -t, --interval=SECS report average over the last SECS\n" " -V, --version output version information\n" -" -z, --zeros show entries with zero activity\n"); +" -z, --zeros show entries with zero activity\n" +" -x, --extended=TYPE show extended stats of TYPE\n"); exit(-1); } @@ -691,6 +803,7 @@ static const struct option longopts[] = { { "interval", 1, 0, 't' }, { "version", 0, 0, 'V' }, { "zeros", 0, 0, 'z' }, + { "extended", 1, 0, 'x'}, { 0 } }; @@ -699,10 +812,12 @@ int main(int argc, char *argv[]) char hist_name[128]; struct sockaddr_un sun; FILE *hist_fp = NULL; + const char *stats_type = NULL; int ch; int fd; - while ((ch = getopt_long(argc, argv, "hjpvVzrnasd:t:e", + is_extended = false; + while ((ch = getopt_long(argc, argv, "hjpvVzrnasd:t:ex:", longopts, NULL)) != EOF) { switch (ch) { case 'z': @@ -743,6 +858,10 @@ int main(int argc, char *argv[]) exit(-1); } break; + case 'x': + stats_type = optarg; + is_extended = true; + break; case 'v': case 'V': printf("ifstat utility, iproute2-ss%s\n", SNAPSHOT); @@ -757,6 +876,12 @@ int main(int argc, char *argv[]) argc -= optind; argv += optind; + if (stats_type) { + stats_type = get_filter_type(stats_type); + if (!stats_type) + exit(-1); + } + sun.sun_family = AF_UNIX; sun.sun_path[0] = 0; sprintf(sun.sun_path+1, "ifstat%d", getuid()); @@ -795,8 +920,13 @@ int main(int argc, char *argv[]) snprintf(hist_name, sizeof(hist_name), "%s", getenv("IFSTAT_HISTORY")); else - snprintf(hist_name, sizeof(hist_name), - "%s/.ifstat.u%d", P_tmpdir, getuid()); + if (!stats_type) + snprintf(hist_name, sizeof(hist_name), + "%s/.ifstat.u%d", P_tmpdir, getuid()); + else + snprintf(hist_name, sizeof(hist_name), + "%s/.%s_ifstat.u%d", P_tmpdir, stats_type, + getuid()); if (reset_history) unlink(hist_name); From 1c2df6134462307bd8934f5de249c6a0da5f7900 Mon Sep 17 00:00:00 2001 From: Nogah Frankel Date: Thu, 26 Jan 2017 14:44:40 +0200 Subject: [PATCH 3/7] ifstat: Add "sw only" extended statistics to ifstat Add support for extended statistics of SW only type, for counting only the packets that went via the cpu. (useful for systems with forward offloading). It reads it from filter type IFLA_STATS_LINK_OFFLOAD_XSTATS and sub type IFLA_OFFLOAD_XSTATS_CPU_HIT. It is under the name 'cpu_hits' (or any shorten of it as 'cpu' or simply 'c') For example: ifstat -x c Signed-off-by: Nogah Frankel Reviewed-by: Jiri Pirko --- misc/ifstat.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/misc/ifstat.c b/misc/ifstat.c index 94671191..a853ee6d 100644 --- a/misc/ifstat.c +++ b/misc/ifstat.c @@ -729,7 +729,8 @@ static int verify_forging(int fd) static void xstat_usage(void) { fprintf(stderr, -"Usage: ifstat supported xstats:\n"); +"Usage: ifstat supported xstats:\n" +" cpu_hits Counts only packets that went via the CPU.\n"); } struct extended_stats_options_t { @@ -743,6 +744,7 @@ struct extended_stats_options_t { * Name length must be under 64 chars. */ static const struct extended_stats_options_t extended_stats_options[] = { + {"cpu_hits", IFLA_STATS_LINK_OFFLOAD_XSTATS, IFLA_OFFLOAD_XSTATS_CPU_HIT}, }; static const char *get_filter_type(const char *name) From aaacdfd5704de644638063c0be2885303a1e1e21 Mon Sep 17 00:00:00 2001 From: Nogah Frankel Date: Thu, 26 Jan 2017 14:44:41 +0200 Subject: [PATCH 4/7] ifstat: Add xstat to ifstat man page Add documentation about the extended statistics to the ifstat man page. Add ifstat man age to the man8 Makefile Signed-off-by: Nogah Frankel Reviewed-by: Jiri Pirko --- man/man8/Makefile | 3 ++- man/man8/ifstat.8 | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/man/man8/Makefile b/man/man8/Makefile index 77d347ca..bc2fc813 100644 --- a/man/man8/Makefile +++ b/man/man8/Makefile @@ -18,7 +18,8 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 rtpr.8 ss. tc-connmark.8 tc-csum.8 tc-mirred.8 tc-nat.8 tc-pedit.8 tc-police.8 \ tc-simple.8 tc-skbedit.8 tc-vlan.8 tc-xt.8 tc-ife.8 \ tc-tunnel_key.8 \ - devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 + devlink.8 devlink-dev.8 devlink-monitor.8 devlink-port.8 devlink-sb.8 \ + ifstat.8 all: $(TARGETS) diff --git a/man/man8/ifstat.8 b/man/man8/ifstat.8 index e49d8680..3ba0088d 100644 --- a/man/man8/ifstat.8 +++ b/man/man8/ifstat.8 @@ -14,7 +14,8 @@ ifstat \- handy utility to read network interface statistics The utility keeps records of the previous data displayed in history files and by default only shows difference between the last and the current call. Location of the history files defaults to /tmp/.ifstat.u$UID but may be -overridden with the IFSTAT_HISTORY environment variable. +overridden with the IFSTAT_HISTORY environment variable. Similarly, the default +location for xstat (extended stats) is /tmp/._ifstat.u$UID. .SH OPTIONS .TP .B \-h, \-\-help @@ -46,6 +47,15 @@ Report average over the last SECS seconds. .TP .B \-z, \-\-zeros Show entries with zero activity. +.TP +.B \-x, \-\-extended=TYPE +Show extended stats of TYPE. Supported types are: + +.in +8 +.B cpu_hits +- Counts only packets that went via the CPU. +.in -8 + .SH ENVIRONMENT .TP .B IFSTAT_HISTORY From e7867c34e804786c0f0b528821cc4c2eabb15f88 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 6 Feb 2017 21:47:35 +0100 Subject: [PATCH 5/7] ip: HSR: Fix cut and paste error Fixes: 5c0aec93a516 ("ip: Add HSR support") Signed-off-by: Ralf Baechle --- ip/iplink_hsr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iplink_hsr.c b/ip/iplink_hsr.c index cb744ebf..696b2c91 100644 --- a/ip/iplink_hsr.c +++ b/ip/iplink_hsr.c @@ -144,7 +144,7 @@ static void hsr_print_help(struct link_util *lu, int argc, char **argv, struct link_util hsr_link_util = { .id = "hsr", - .maxattr = IFLA_VLAN_MAX, + .maxattr = IFLA_HSR_MAX, .parse_opt = hsr_parse_opt, .print_opt = hsr_print_opt, .print_help = hsr_print_help, From 38e6dbc4b34a39e0337c8855a7c3ca4c5e80490e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 2 Feb 2017 05:47:27 -0800 Subject: [PATCH 6/7] ss: print tcpi_rcv_mss and tcpi_advmss tcpi_rcv_mss and tcpi_advmss tcp info fields were not yet reported by ss. While adding GRO support to packetdrill, I found this was useful. Signed-off-by: Eric Dumazet --- misc/ss.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/misc/ss.c b/misc/ss.c index 4454bd16..7f79eeaa 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -707,6 +707,8 @@ struct tcpstat { int snd_wscale; int rcv_wscale; int mss; + int rcv_mss; + int advmss; unsigned int cwnd; unsigned int lastsnd; unsigned int lastrcv; @@ -1872,6 +1874,10 @@ static void tcp_stats_print(struct tcpstat *s) if (s->mss) printf(" mss:%d", s->mss); + if (s->rcv_mss) + printf(" rcvmss:%d", s->rcv_mss); + if (s->advmss) + printf(" advmss:%d", s->advmss); if (s->cwnd) printf(" cwnd:%u", s->cwnd); if (s->ssthresh) @@ -2189,6 +2195,8 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r, s.rttvar = (double)info->tcpi_rttvar / 1000; s.ato = (double)info->tcpi_ato / 1000; s.mss = info->tcpi_snd_mss; + s.rcv_mss = info->tcpi_rcv_mss; + s.advmss = info->tcpi_advmss; s.rcv_space = info->tcpi_rcv_space; s.rcv_rtt = (double)info->tcpi_rcv_rtt / 1000; s.lastsnd = info->tcpi_last_data_sent; From 72dfff6e11d3992b5581eae2e8cf7b9855e84477 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 2 Feb 2017 16:22:56 +0100 Subject: [PATCH 7/7] man: ip-route.8: Fix 'expires' indenting Descriptions of each route sub-command's arguments are enclosed in .RS/.RE pairs. For 'replace' sub-command, '.RE' was incorrectly put before the last argument ('expires'). Fixes: 3fbe7ca847367 ("iproute2: ip-route.8.in: Add expires option for ip route") Signed-off-by: Phil Sutter --- man/man8/ip-route.8.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/man8/ip-route.8.in b/man/man8/ip-route.8.in index 85191531..d6e06649 100644 --- a/man/man8/ip-route.8.in +++ b/man/man8/ip-route.8.in @@ -704,13 +704,13 @@ is a set of encapsulation attributes specific to the .sp .in -8 -.RE .TP .BI expires " TIME " "(4.4+ only)" the route will be deleted after the expires time. .B Only support IPv6 at present. +.RE .TP ip route delete