ip stats: A new front-end for RTM_GETSTATS / RTM_SETSTATS
Subsystems (3)
cover ip stats: A new front-end for RTM_GETSTATS / RTM_SETSTATS
A new rtnetlink message, RTM_SETSTATS, has been added recently in kernel commit ca0a53dcec94 ("Merge branch 'net-hw-counters-for-soft-devices'").
At the same time, RTM_GETSTATS has been around for a while. The users of this API are spread in a couple different places: "ip link xstats" reads stats from the IFLA_STATS_LINK_XSTATS and _XSTATS_SLAVE subgroups, "ip link afstats" then reads IFLA_STATS_AF_SPEC.
Finally, to read IFLA_STATS_LINK_OFFLOAD_XSTATS, one would use ifstats. This does not seem to be a good fit for IFLA_OFFLOAD_XSTATS_HW_S_INFO in particular.
The obvious place to expose all these offload stats suites would be under a new link subcommand "ip link offload_xstats", or similar, which would then have syntax for both showing stats and setting them.
However, this looks like a good opportunity to introduce a new top-level command, "ip stats", that would be the go-to place to access anything backed by RTM_GETSTATS and RTM_SETSTATS.
This patchset therefore does the following:
- It adds the new "stats" infrastructure
- It adds specifically the ability to toggle and show the suites that were recently added to Linux, IFLA_OFFLOAD_XSTATS_HW_S_INFO and IFLA_OFFLOAD_XSTATS_L3_STATS.
- It adds support to dump IFLA_OFFLOAD_XSTATS_CPU_HIT, which was not available under "ip" at all.
- Does all this in a way that is easy to extend for new stats suites.
The patchset proceeds as follows:
- Patches #1 and #2 lay some groundwork and tweak existing code.
- Patch #3 adds the shell of the new "ip stats" command.
- Patch #4 adds "ip stats set" and the ability to toggle l3_stats in particular.
- Patch #5 adds "ip stats show", but no actual stats suites.
- Patches #6-#9 add support for showing individual stats suites:
respectively, IFLA_STATS_LINK_64, IFLA_OFFLOAD_XSTATS_CPU_HIT, IFLA_OFFLOAD_XSTATS_HW_S_INFO and IFLA_OFFLOAD_XSTATS_L3_STATS.
- Patch #10 adds support for monitoring stats events to "ip monitor".
- Patch #11 adds man page verbiage for the above.
The plan is to contribute support for afstats and xstats in a follow-up patch set.
Petr Machata (11):
libnetlink: Add filtering to rtnl_statsdump_req_filter()
ip: Publish functions for stats formatting
ip: Add a new family of commands, "stats"
ipstats: Add a "set" command
ipstats: Add a shell of "show" command
ipstats: Add a group "link"
ipstats: Add a group "offload", subgroup "cpu_hit"
ipstats: Add offload subgroup "hw_stats_info"
ipstats: Add offload subgroup "l3_stats"
ipmonitor: Add monitoring support for stats events
man: Add man pages for the "stats" functions
bridge/vlan.c | 6 +- include/libnetlink.h | 11 +- ip/Makefile | 3 +- ip/ip.c | 1 + ip/ip_common.h | 31 + ip/ipaddress.c | 33 +- ip/iplink.c | 3 +- ip/iplink_xstats.c | 3 +- ip/ipmonitor.c | 16 +- ip/ipstats.c | 1241 +++++++++++++++++++++++++++++++++++++++++ lib/libnetlink.c | 19 +- man/man8/ip-monitor.8 | 2 +- man/man8/ip-stats.8 | 160 ++++++ man/man8/ip.8 | 7 +- misc/ifstat.c | 2 +- 15 files changed, 1512 insertions(+), 26 deletions(-) create mode 100644 ip/ipstats.c create mode 100644 man/man8/ip-stats.8
Signature · 1 line
2.31.1
PATCH 1/11 libnetlink: Add filtering to rtnl_statsdump_req_filter()
A number of functions in the rtnl_*_req family accept a caller-provided callback to set up arbitrary filtering. rtnl_statsdump_req_filter() currently only allows setting a field in the IFSM header, not custom attributes. So far these were not necessary, but with introduction of more detailed filtering settings, the callback becomes necessary.
To that end, add a filter_fn and filter_data arguments to the function. Unlike the other filters, this one is typed to expect an IFSM pointer, to permit tweaking the header itself as well.
Pass NULLs in the existing callers.
--- bridge/vlan.c | 6 ++++-- include/libnetlink.h | 11 ++++++++++- ip/iplink.c | 3 ++- ip/iplink_xstats.c | 3 ++- lib/libnetlink.c | 19 ++++++++++++++----- misc/ifstat.c | 2 +- 6 files changed, 33 insertions(+), 11 deletions(-)
bridge/vlan.c +4 -2
@@ -1179,7 +1179,8 @@ static int vlan_show(int argc, char **argv, int subject)__u32 filt_mask; filt_mask =IFLA_STATS_FILTER_BIT (IFLA_STATS_LINK_XSTATS ); -if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask) <0 ) { +if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask, +NULL ,NULL ) <0 ) {perror ("Cannot send dump request" );exit (1 ); }
@@ -1194,7 +1195,8 @@ static int vlan_show(int argc, char **argv, int subject) } filt_mask =IFLA_STATS_FILTER_BIT (IFLA_STATS_LINK_XSTATS_SLAVE ); -if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask) <0 ) { +if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask, +NULL ,NULL ) <0 ) {perror ("Cannot send slave dump request" );exit (1 ); }
include/libnetlink.h +10 -1
@@ -37,6 +37,12 @@ struct nlmsg_chain {struct nlmsg_list *tail; }; +struct ipstats_req { +struct nlmsghdr nlh; +struct if_stats_msg ifsm; +char buf[128 ]; +}; +extern int rcvbuf;int rtnl_open (struct rtnl_handle *rth,unsigned int subscriptions)
@@ -88,7 +94,10 @@ int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,int rtnl_nsiddump_req_filter_fn (struct rtnl_handle *rth,int family,req_filter_fn_t filter_fn) __attribute__((warn_unused_result)); -int rtnl_statsdump_req_filter (struct rtnl_handle *rth,int fam,__u32 filt_mask) +int rtnl_statsdump_req_filter (struct rtnl_handle *rth,int fam,__u32 filt_mask, +int (*filter_fn)(struct ipstats_req *req, +void *data), +void *filter_data) __attribute__((warn_unused_result));int rtnl_dump_request (struct rtnl_handle *rth,int type,void *req,int len)
ip/iplink.c +2 -1
@@ -1644,7 +1644,8 @@ static int iplink_afstats(int argc, char **argv) } } -if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask) <0 ) { +if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask, +NULL ,NULL ) <0 ) {perror ("Cannont send dump request" );return 1 ; }
ip/iplink_xstats.c +2 -1
@@ -65,7 +65,8 @@ int iplink_ifla_xstats(int argc, char **argv)else filt_mask =IFLA_STATS_FILTER_BIT (IFLA_STATS_LINK_XSTATS ); -if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask) <0 ) { +if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , filt_mask, +NULL ,NULL ) <0 ) {perror ("Cannont send dump request" );return -1 ; }
lib/libnetlink.c +14 -5
@@ -619,12 +619,13 @@ int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,return send (rth->fd, &req,sizeof (req),0 ); } -int rtnl_statsdump_req_filter (struct rtnl_handle *rth,int fam,__u32 filt_mask) +int rtnl_statsdump_req_filter (struct rtnl_handle *rth,int fam, +__u32 filt_mask, +int (*filter_fn)(struct ipstats_req *req, +void *data), +void *filter_data) { -struct { -struct nlmsghdr nlh; -struct if_stats_msg ifsm; - } req; +struct ipstats_req req;memset (&req,0 ,sizeof (req)); req.nlh.nlmsg_len =NLMSG_LENGTH (sizeof (struct if_stats_msg ));
@@ -635,6 +636,14 @@ int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask) req.ifsm.family = fam; req.ifsm.filter_mask = filt_mask; +if (filter_fn) { +int err; + + err =filter_fn (&req, filter_data); +if (err) +return err; + } +return send (rth->fd, &req,sizeof (req),0 ); }
misc/ifstat.c +1 -1
@@ -202,7 +202,7 @@ static void load_info(void)ll_init_map (&rth); filter_mask =IFLA_STATS_FILTER_BIT (filter_type);if (rtnl_statsdump_req_filter (&rth,AF_UNSPEC , - filter_mask) <0 ) { + filter_mask,NULL ,NULL ) <0 ) {perror ("Cannot send dump request" );exit (1 ); }
Signature · 1 line
2.31.1
PATCH 2/11 ip: Publish functions for stats formatting
In reply to Petr MachataFormatting struct rtnl_link_stats64 will be useful outside of iplink.c as well. Extract from __print_link_stats() a new function, print_stats64(), make it non-static and publish in the header file.
Additionally, publish the helper size_columns(), which will be useful for formatting the new struct rtnl_hw_stats64.
--- ip/ip_common.h | 3 +++ ip/ipaddress.c | 33 ++++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 11 deletions(-)
ip/ip_common.h +3 -0
@@ -171,4 +171,7 @@ void print_rta_ifidx(FILE *fp, __u32 ifidx, const char *prefix);void __print_rta_gateway (FILE *fp,unsigned char family,const char *gateway);void print_rta_gateway (FILE *fp,unsigned char family,const struct rtattr *rta); +void size_columns (unsigned int cols[],unsigned int n, ...); +void print_stats64 (FILE *fp,struct rtnl_link_stats64 *s, +const struct rtattr *carrier_changes,const char *what);#endif /* _IP_COMMON_H_ */
ip/ipaddress.c +22 -11
@@ -546,7 +546,7 @@ static void print_vfinfo(FILE *fp, struct ifinfomsg *ifi, struct rtattr *vfinfo)print_vf_stats64 (fp, vf[IFLA_VF_STATS ]); } -static void size_columns (unsigned int cols[],unsigned int n, ...) +void size_columns (unsigned int cols[],unsigned int n, ...) {unsigned int i, len;uint64_t val, powi;
@@ -680,10 +680,10 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats) } } -static void __print_link_stats (FILE *fp,struct rtattr *tb[]) +void print_stats64 (FILE *fp,struct rtnl_link_stats64 *s, +const struct rtattr *carrier_changes, +const char *what) { -const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES ]; -struct rtnl_link_stats64 _s, *s = &_s;unsigned int cols[] = {strlen ("*X errors:" ),strlen ("packets" ),
@@ -693,14 +693,10 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[])strlen ("overrun" ), strlen("compressed"), }; -int ret; - - ret =get_rtnl_link_stats_rta (s, tb); -if (ret <0 ) -return ;if (is_json_context ()) { -open_json_object ((ret ==sizeof (*s)) ?"stats64" :"stats" ); +if (what) +open_json_object (what);/* RX stats */ open_json_object ("rx" );
@@ -771,7 +767,8 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[]) }close_json_object (); -close_json_object (); +if (what) +close_json_object (); }else { size_columns(cols, ARRAY_SIZE(cols), s->rx_bytes, s->rx_packets, s->rx_errors,
@@ -870,6 +867,20 @@ static void __print_link_stats(FILE *fp, struct rtattr *tb[]) } } +static void __print_link_stats (FILE *fp,struct rtattr *tb[]) +{ +const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES ]; +struct rtnl_link_stats64 _s, *s = &_s; +int ret; + + ret =get_rtnl_link_stats_rta (s, tb); +if (ret <0 ) +return ; + +print_stats64 (fp, s, carrier_changes, + (ret ==sizeof (*s)) ?"stats64" :"stats" ); +} +static void print_link_stats (FILE *fp,struct nlmsghdr *n) {struct ifinfomsg *ifi =NLMSG_DATA (n);
Signature · 1 line
2.31.1
PATCH 3/11 ip: Add a new family of commands, "stats"
In reply to Petr MachataAdd a core of a new frontend tool for interfacing with the RTM_*STATS family of messages. The following patches will add subcommands for showing and setting individual statistics suites.
Note that in this patch, "ip stats" is made to be an invalid command line. This will be changed in later patches to default to "show" when that is introduced.
--- ip/Makefile | 3 ++- ip/ip.c | 1 + ip/ip_common.h | 1 + ip/ipstats.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 ip/ipstats.c
ip/Makefile +2 -1
@@ -12,7 +12,8 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \ iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \ ipvrf.o iplink_xstats.o ipseg6.o iplink_netdevsim.o iplink_rmnet.o \ ipnexthop.o ipmptcp.o iplink_bareudp.o iplink_wwan.o ipioam6.o \ - iplink_amt.o iplink_batadv.o iplink_gtp.o iplink_virt_wifi.o + iplink_amt.o iplink_batadv.o iplink_gtp.o iplink_virt_wifi.o \ + ipstats.o RTMONOBJ=rtmon.o
ip/ip.c +1 -0
@@ -123,6 +123,7 @@ static const struct cmd { { "mptcp", do_mptcp }, { "ioam", do_ioam6 }, { "help", do_help }, + { "stats", do_ipstats }, { 0 } };
ip/ip_common.h +1 -0
@@ -90,6 +90,7 @@ int do_seg6(int argc, char **argv);int do_ipnh (int argc,char **argv);int do_mptcp (int argc,char **argv);int do_ioam6 (int argc,char **argv); +int do_ipstats (int argc,char **argv);int iplink_get (char *name,__u32 filt_mask);int iplink_ifla_xstats (int argc,char **argv);
ip/ipstats.c new file +31 -0
@@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include "utils.h" +#include "ip_common.h" + +static int do_help (void ) +{ +fprintf (stderr, +"Usage: ip stats help\n" + ); + +return 0 ; +} + +int do_ipstats (int argc,char **argv) +{ +int rc; + +if (argc ==0 ) { +do_help (); + rc =-1 ; + }else if (strcmp (*argv,"help" ) ==0 ) { +do_help (); + rc =0 ; + }else { +fprintf (stderr,"Command \"%s\" is unknown, try \"ip stats help\".\n" , + *argv); + rc =-1 ; + } + +return rc; +}
Signature · 1 line
2.31.1
PATCH 4/11 ipstats: Add a "set" command
In reply to Petr MachataAdd a command to allow toggling HW stats. An example usage:
# ip stats set dev swp1 l3_stats on
--- ip/ipstats.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+)
ip/ipstats.c +78 -0
@@ -1,4 +1,6 @@// SPDX-License-Identifier: GPL-2.0+ +#include <errno.h> +#include "utils.h" #include "ip_common.h"
@@ -6,11 +8,85 @@ static int do_help(void) {fprintf (stderr,"Usage: ip stats help\n" +" ip stats set dev DEV l3_stats { on | off }\n" );return 0 ; } +static int ipstats_set_do (int ifindex,int at,bool enable) +{ +struct ipstats_req req = { + .nlh.nlmsg_len =NLMSG_LENGTH (sizeof (struct if_stats_msg )), + .nlh.nlmsg_flags =NLM_F_REQUEST , + .nlh.nlmsg_type =RTM_SETSTATS , + .ifsm.family =PF_UNSPEC , + .ifsm.ifindex = ifindex, + }; + +addattr8 (&req.nlh,sizeof (req), at, enable); + +if (rtnl_talk (&rth, &req.nlh,NULL ) <0 ) +return -2 ; +return 0 ; +} + +static int ipstats_set (int argc,char **argv) +{ +const char *dev =NULL ; +bool enable = false; +int ifindex; +int at =0 ; + +while (argc >0 ) { +if (strcmp (*argv,"dev" ) ==0 ) { +NEXT_ARG (); +if (dev) +duparg2 ("dev" , *argv); +if (check_ifname (*argv)) +invarg ("\"dev\" not a valid ifname" , *argv); + dev = *argv; + }else if (strcmp (*argv,"l3_stats" ) ==0 ) { +int err; + +NEXT_ARG (); +if (at) { +fprintf (stderr,"A statistics suite to toggle was already given.\n" ); +return -EINVAL ; + } + at =IFLA_STATS_SET_OFFLOAD_XSTATS_L3_STATS ; + enable =parse_on_off ("l3_stats" , *argv, &err); +if (err) +return err; + }else if (strcmp (*argv,"help" ) ==0 ) { +do_help (); +return 0 ; + }else { +fprintf (stderr,"What is \"%s\"?\n" , *argv); +do_help (); +return -EINVAL ; + } + +NEXT_ARG_FWD (); + } + +if (!dev) { +fprintf (stderr,"Not enough information: \"dev\" argument is required.\n" ); +exit (-1 ); + } + +if (!at) { +fprintf (stderr,"Not enough information: stat type to toggle is required.\n" ); +exit (-1 ); + } + + ifindex =ll_name_to_index (dev); +if (!ifindex) +return nodev (dev); + +return ipstats_set_do (ifindex, at, enable); +} +int do_ipstats (int argc,char **argv) {int rc;
@@ -21,6 +97,8 @@ int do_ipstats(int argc, char **argv) }else if (strcmp (*argv,"help" ) ==0 ) {do_help (); rc =0 ; + }else if (strcmp (*argv,"set" ) ==0 ) { + rc =ipstats_set (argc-1 , argv+1 ); }else {fprintf (stderr,"Command \"%s\" is unknown, try \"ip stats help\".\n" , *argv);
Signature · 1 line
2.31.1
PATCH 5/11 ipstats: Add a shell of "show" command
In reply to Petr MachataAdd the scaffolding necessary for adding individual stats suites to show.
Expose some ipstats artifacts in ip_common.h. These will be used to support "xstats" in a follow-up patchset.
--- ip/ip_common.h | 26 +++ ip/ipstats.c | 614 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 638 insertions(+), 2 deletions(-)
ip/ip_common.h +26 -0
@@ -158,6 +158,32 @@ void xdp_dump(FILE *fp, struct rtattr *tb, bool link, bool details);__u32 ipvrf_get_table (const char *name);int name_is_vrf (const char *name); +/* ipstats.c */ +enum ipstats_stat_desc_kind { +IPSTATS_STAT_DESC_KIND_LEAF , +IPSTATS_STAT_DESC_KIND_GROUP , +}; + +struct ipstats_stat_dump_filters ; +struct ipstats_stat_show_attrs ; + +struct ipstats_stat_desc { +const char *name; +enum ipstats_stat_desc_kind kind; +union { +struct { +const struct ipstats_stat_desc **subs; +size_t nsubs; + }; +struct { +void (*pack)(struct ipstats_stat_dump_filters *filters, +const struct ipstats_stat_desc *desc); +int (*show)(struct ipstats_stat_show_attrs *attrs, +const struct ipstats_stat_desc *desc); + }; + }; +}; +#ifndef INFINITY_LIFE_TIME #define INFINITY_LIFE_TIME 0xFFFFFFFFU#endif
ip/ipstats.c +612 -2
642 lines not on this page · raw message
Signature · 1 line
2.31.1
PATCH 6/11 ipstats: Add a group "link"
In reply to Petr MachataAdd the "link" top-level group for showing IFLA_STATS_LINK_64 statistics. For example:
# ip stats show dev swp1 group link
4178: swp1: group link
RX: bytes packets errors dropped missed mcast
47048 354 0 0 0 64
TX: bytes packets errors dropped carrier collsns
47474 355 0 0 0 0 # ip -j stats show dev swp1 group link | jq
[
{
"ifindex": 4178,
"ifname": "swp1",
"group": "link",
"stats64": {
"rx": {
"bytes": 47048,
"packets": 354,
"errors": 0,
"dropped": 0,
"over_errors": 0,
"multicast": 64
},
"tx": {
"bytes": 47474,
"packets": 355,
"errors": 0,
"dropped": 0,
"carrier_errors": 0,
"collisions": 0
}
}
}
]--- ip/ipstats.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+)
ip/ipstats.c +90 -0
@@ -12,6 +12,15 @@ struct ipstats_stat_dump_filters {__u32 mask[IFLA_STATS_MAX +1 ]; }; +static void +ipstats_stat_desc_enable_bit (struct ipstats_stat_dump_filters *filters, +unsigned int group,unsigned int subgroup) +{ + filters->mask[0 ] |=IFLA_STATS_FILTER_BIT (group); +if (subgroup) + filters->mask[group] |=IFLA_STATS_FILTER_BIT (subgroup); +} +struct ipstats_stat_show_attrs {struct if_stats_msg *ifsm;int len;
@@ -89,6 +98,29 @@ ipstats_stat_show_attrs_alloc_tb(struct ipstats_stat_show_attrs *attrs,return err; } +static const struct rtattr * +ipstats_stat_show_get_attr (struct ipstats_stat_show_attrs *attrs, +int group,int subgroup,int *err) +{ +int tmp_err; + +if (err ==NULL ) + err = &tmp_err; + + *err =0 ; +if (subgroup ==0 ) +return attrs->tbs[0 ][group]; + +if (attrs->tbs[0 ][group] ==NULL ) +return NULL ; + + *err =ipstats_stat_show_attrs_alloc_tb (attrs, group); +if (*err !=0 ) +return NULL ; + +return attrs->tbs[group][subgroup]; +} +static void ipstats_stat_show_attrs_free (struct ipstats_stat_show_attrs *attrs) {
@@ -98,7 +130,65 @@ ipstats_stat_show_attrs_free(struct ipstats_stat_show_attrs *attrs)free (attrs->tbs[i]); } +#define IPSTATS_RTA_PAYLOAD (TYPE ,AT ) \ + ({ \ + const struct rtattr *__at = (AT); \ + TYPE *__ret = NULL; \ + \ + if (__at != NULL && \ + __at->rta_len - RTA_LENGTH(0) >= sizeof(TYPE)) \ + __ret = RTA_DATA(__at); \ + __ret; \ + }) + +static int ipstats_show_64 (struct ipstats_stat_show_attrs *attrs, +unsigned int group,unsigned int subgroup) +{ +struct rtnl_link_stats64 *stats; +const struct rtattr *at; +int err; + + at =ipstats_stat_show_get_attr (attrs, group, subgroup, &err); +if (at ==NULL ) +return err; + + stats = IPSTATS_RTA_PAYLOAD(struct rtnl_link_stats64, at); +if (stats ==NULL ) { +fprintf (stderr,"Error: attribute payload too short" ); +return -EINVAL ; + } + +open_json_object ("stats64" ); +print_stats64 (stdout, stats,NULL ,NULL ); +close_json_object (); +return 0 ; +} + +static void +ipstats_stat_desc_pack_link (struct ipstats_stat_dump_filters *filters, +const struct ipstats_stat_desc *desc) +{ +ipstats_stat_desc_enable_bit (filters, +IFLA_STATS_LINK_64 ,0 ); +} + +static int +ipstats_stat_desc_show_link (struct ipstats_stat_show_attrs *attrs, +const struct ipstats_stat_desc *desc) +{ +print_nl (); +return ipstats_show_64 (attrs,IFLA_STATS_LINK_64 ,0 ); +} + +static const struct ipstats_stat_desc ipstats_stat_desc_toplev_link = { + .name ="link" , + .kind =IPSTATS_STAT_DESC_KIND_LEAF , + .pack = &ipstats_stat_desc_pack_link, + .show = &ipstats_stat_desc_show_link, +}; +static const struct ipstats_stat_desc *ipstats_stat_desc_toplev_subs[] = { + &ipstats_stat_desc_toplev_link, };static const struct ipstats_stat_desc ipstats_stat_desc_toplev_group = {
Signature · 1 line
2.31.1
Re: [PATCH iproute2-next 06/11] ipstats: Add a group "link"
Quoted 15 lines · Petr Machata
ip/ipstats.c +15
-0+#define IPSTATS_RTA_PAYLOAD (TYPE ,AT ) \ + ({ \ + const struct rtattr *__at = (AT); \ + TYPE *__ret = NULL; \ + \ + if (__at != NULL && \ + __at->rta_len - RTA_LENGTH(0) >= sizeof(TYPE)) \ + __ret = RTA_DATA(__at); \ + __ret; \ + }) + +static int ipstats_show_64 (struct ipstats_stat_show_attrs *attrs, +unsigned int group,unsigned int subgroup) +{ +struct rtnl_link_stats64 *stats;
ip/ipstats.c ipstats_stat_show_attrs_free(struct ipstats_stat_show_attrs *attrs) · line 157
Quoted 10 lines
ip/ipstats.c +10
-0+const struct rtattr *at; +int err; + + at =ipstats_stat_show_get_attr (attrs, group, subgroup, &err); +if (at ==NULL ) +return err; + + stats = IPSTATS_RTA_PAYLOAD(struct rtnl_link_stats64, at); +if (stats ==NULL ) { +fprintf (stderr,"Error: attribute payload too short" );
When I tested this on 5.15 / 5.16 everything was fine, but now I get:
$ ip stats show dev lo group link 1: lo: group link Error: attribute payload too short
Payload on 5.16:
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=224, nlmsg_type=RTM_NEWSTATS, nlmsg_flags=0, nlmsg_seq=1651407379, nlmsg_pid=330213}, {family=AF_UNSPEC, ifindex=if_nametoindex("lo"), filter_mask=1<<IFLA_STATS_UNSPEC}, [{nla_len=196, nla_type=IFLA_STATS_LINK_64}, {rx_packets=321113, tx_packets=321113, rx_bytes=322735996, tx_bytes=322735996, rx_errors=0, tx_errors=0, rx_dropped=0, tx_dropped=0, multicast=0, collisions=0, rx_length_errors=0, rx_over_errors=0, rx_crc_errors=0, rx_frame_errors=0, rx_fifo_errors=0, rx_missed_errors=0, tx_aborted_errors=0, tx_carrier_errors=0, tx_fifo_errors=0, tx_heartbeat_errors=0, tx_window_errors=0, rx_compressed=0, tx_compressed=0, rx_nohandler=0}]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 224 1: lo: group link
Error: attribute payload too short+++ exited with 22 +++
Payload on net-next:
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=232, nlmsg_type=RTM_NEWSTATS, nlmsg_flags=0, nlmsg_seq=1651407411, nlmsg_pid=198}, {family=AF_UNSPEC, ifindex=if_nametoindex("lo"), filter_mask=1<<IFLA_STATS_UNSPEC}, [{nla_len=204, nla_type=IFLA_STATS_LINK_64}, {rx_packets=0, tx_packets=0, rx_bytes=0, tx_bytes=0, rx_errors=0, tx_errors=0, rx_dropped=0, tx_dropped=0, multicast=0, collisions=0, rx_length_errors=0, rx_over_errors=0, rx_crc_errors=0, rx_frame_errors=0, rx_fifo_errors=0, rx_missed_errors=0, tx_aborted_errors=0, tx_carrier_errors=0, tx_fifo_errors=0, tx_heartbeat_errors=0, tx_window_errors=0, rx_compressed=0, tx_compressed=0, rx_nohandler=0}]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 232 1: lo: group link
RX: bytes packets errors dropped missed mcast
0 0 0 0 0 0
TX: bytes packets errors dropped carrier collsns
0 0 0 0 0 0
+++ exited with 0 +++
Note the difference in size of IFLA_STATS_LINK_64 which carries structrtnl_link_stats64: 196 bytes vs. 204 bytes
The 8 byte difference is most likely from the addition of rx_otherhost_dropped at the end:
I guess it worked for me because I didn't have this member in my copy of the uAPI file, but it's now in iproute2-next:
I was under the impression that such a size increase in a uAPI struct is forbidden, which is why we usually avoid passing structs over netlink.
Quoted 8 lines
ip/ipstats.c +8
-0+return -EINVAL ; + } + +open_json_object ("stats64" ); +print_stats64 (stdout, stats,NULL ,NULL ); +close_json_object (); +return 0 ; +}
Re: [PATCH iproute2-next 06/11] ipstats: Add a group "link"
Quoted 6 lines · Ido Schimmel
When I tested this on 5.15 / 5.16 everything was fine, but now I get:
$ ip stats show dev lo group link 1: lo: group link Error: attribute payload too short
...
Quoted 9 lines
Note the difference in size of
IFLA_STATS_LINK_64which carries structrtnl_link_stats64: 196 bytes vs. 204 bytesThe 8 byte difference is most likely from the addition of
rx_otherhost_droppedat the end:
Quoted 7 lines
I guess it worked for me because I didn't have this member in my copy of the uAPI file, but it's now in iproute2-next:
I was under the impression that such a size increase in a uAPI struct is forbidden, which is why we usually avoid passing structs over netlink.
extending structs at the end is typically allowed. The ABI breakage is when an entry is added in the middle.
Quoted 9 lines
Quoted 9 lines
ip/ipstats.c +8
-0+return -EINVAL ; + } + +open_json_object ("stats64" ); +print_stats64 (stdout, stats,NULL ,NULL ); +close_json_object (); +return 0 ; +}
Re: [PATCH iproute2-next 06/11] ipstats: Add a group "link"
Quoted 22 lines · David Ahern
Quoted 6 lines · Ido Schimmel
When I tested this on 5.15 / 5.16 everything was fine, but now I get:
$ ip stats show dev lo group link 1: lo: group link Error: attribute payload too short...
Quoted 12 lines
Note the difference in size of
IFLA_STATS_LINK_64which carries structrtnl_link_stats64: 196 bytes vs. 204 bytesThe 8 byte difference is most likely from the addition of
rx_otherhost_droppedat the end:I guess it worked for me because I didn't have this member in my copy of the uAPI file, but it's now in iproute2-next:
Quoted 6 lines
Quoted 4 lines
I was under the impression that such a size increase in a uAPI struct is forbidden, which is why we usually avoid passing structs over netlink.
extending structs at the end is typically allowed.
In this case, the iproute2 check needs to be modified as new iproute2 should work with old kernels.
Quoted 1 line
The ABI breakage is when an entry is added in the middle.
Sure, that's well understood.
Thanks!
Quoted 12 lines
Quoted 11 lines
Quoted 11 lines
ip/ipstats.c +8
-0+return -EINVAL ; + } + +open_json_object ("stats64" ); +print_stats64 (stdout, stats,NULL ,NULL ); +close_json_object (); +return 0 ; +}
Re: [PATCH iproute2-next 06/11] ipstats: Add a group "link"
In reply to Ido SchimmelQuoted 28 lines · Ido Schimmel
When I tested this on 5.15 / 5.16 everything was fine, but now I get:
$ ip stats show dev lo group link 1: lo: group link Error: attribute payload too shortPayload on 5.16:
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=224, nlmsg_type=RTM_NEWSTATS, nlmsg_flags=0, nlmsg_seq=1651407379, nlmsg_pid=330213}, {family=AF_UNSPEC, ifindex=if_nametoindex("lo"), filter_mask=1<<IFLA_STATS_UNSPEC}, [{nla_len=196, nla_type=IFLA_STATS_LINK_64}, {rx_packets=321113, tx_packets=321113, rx_bytes=322735996, tx_bytes=322735996, rx_errors=0, tx_errors=0, rx_dropped=0, tx_dropped=0, multicast=0, collisions=0, rx_length_errors=0, rx_over_errors=0, rx_crc_errors=0, rx_frame_errors=0, rx_fifo_errors=0, rx_missed_errors=0, tx_aborted_errors=0, tx_carrier_errors=0, tx_fifo_errors=0, tx_heartbeat_errors=0, tx_window_errors=0, rx_compressed=0, tx_compressed=0, rx_nohandler=0}]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 224 1: lo: group link
Error: attribute payload too short+++ exited with 22 +++Payload on net-next:
recvmsg(3, {msg_name={sa_family=AF_NETLINK, nl_pid=0, nl_groups=00000000}, msg_namelen=12, msg_iov=[{iov_base=[{nlmsg_len=232, nlmsg_type=RTM_NEWSTATS, nlmsg_flags=0, nlmsg_seq=1651407411, nlmsg_pid=198}, {family=AF_UNSPEC, ifindex=if_nametoindex("lo"), filter_mask=1<<IFLA_STATS_UNSPEC}, [{nla_len=204, nla_type=IFLA_STATS_LINK_64}, {rx_packets=0, tx_packets=0, rx_bytes=0, tx_bytes=0, rx_errors=0, tx_errors=0, rx_dropped=0, tx_dropped=0, multicast=0, collisions=0, rx_length_errors=0, rx_over_errors=0, rx_crc_errors=0, rx_frame_errors=0, rx_fifo_errors=0, rx_missed_errors=0, tx_aborted_errors=0, tx_carrier_errors=0, tx_fifo_errors=0, tx_heartbeat_errors=0, tx_window_errors=0, rx_compressed=0, tx_compressed=0, rx_nohandler=0}]], iov_len=32768}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 232 1: lo: group link
RX: bytes packets errors dropped missed mcast
0 0 0 0 0 0
TX: bytes packets errors dropped carrier collsns
0 0 0 0 0 0
+++ exited with 0 +++Note the difference in size of
IFLA_STATS_LINK_64which carries structrtnl_link_stats64: 196 bytes vs. 204 bytesThe 8 byte difference is most likely from the addition of
rx_otherhost_droppedat the end:
Quoted 6 lines
I guess it worked for me because I didn't have this member in my copy of the uAPI file, but it's now in iproute2-next:
Thanks, I'll send a fix.
PATCH 7/11 ipstats: Add a group "offload", subgroup "cpu_hit"
In reply to Petr MachataAdd a new group, "offload", for showing counters from the IFLA_STATS_LINK_OFFLOAD_XSTATS nest, and a subgroup "cpu_hit" for the IFLA_OFFLOAD_XSTATS_CPU_HIT stats suite.
For example:
# ip stats show dev swp1 group offload subgroup cpu_hit
4178: swp1: group offload subgroup cpu_hit
RX: bytes packets errors dropped missed mcast
45522 353 0 0 0 0
TX: bytes packets errors dropped carrier collsns
46054 355 0 0 0 0 # ip -j stats show dev swp1 group offload subgroup cpu_hit | jq
[
{
"ifindex": 4178,
"ifname": "swp1",
"group": "offload",
"subgroup": "cpu_hit",
"stats64": {
"rx": {
"bytes": 45522,
"packets": 353,
"errors": 0,
"dropped": 0,
"over_errors": 0,
"multicast": 0
},
"tx": {
"bytes": 46054,
"packets": 355,
"errors": 0,
"dropped": 0,
"carrier_errors": 0,
"collisions": 0
}
}
}
]--- ip/ipstats.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+)
ip/ipstats.c +37 -0
@@ -164,6 +164,42 @@ static int ipstats_show_64(struct ipstats_stat_show_attrs *attrs,return 0 ; } +static void +ipstats_stat_desc_pack_cpu_hit (struct ipstats_stat_dump_filters *filters, +const struct ipstats_stat_desc *desc) +{ +ipstats_stat_desc_enable_bit (filters, +IFLA_STATS_LINK_OFFLOAD_XSTATS , +IFLA_OFFLOAD_XSTATS_CPU_HIT ); +} + +static int ipstats_stat_desc_show_cpu_hit (struct ipstats_stat_show_attrs *attrs, +const struct ipstats_stat_desc *desc) +{ +print_nl (); +return ipstats_show_64 (attrs, +IFLA_STATS_LINK_OFFLOAD_XSTATS , +IFLA_OFFLOAD_XSTATS_CPU_HIT ); +} + +static const struct ipstats_stat_desc ipstats_stat_desc_offload_cpu_hit = { + .name ="cpu_hit" , + .kind =IPSTATS_STAT_DESC_KIND_LEAF , + .pack = &ipstats_stat_desc_pack_cpu_hit, + .show = &ipstats_stat_desc_show_cpu_hit, +}; + +static const struct ipstats_stat_desc *ipstats_stat_desc_offload_subs[] = { + &ipstats_stat_desc_offload_cpu_hit, +}; + +static const struct ipstats_stat_desc ipstats_stat_desc_offload_group = { + .name ="offload" , + .kind =IPSTATS_STAT_DESC_KIND_GROUP , + .subs = ipstats_stat_desc_offload_subs, + .nsubs =ARRAY_SIZE (ipstats_stat_desc_offload_subs), +}; +static void ipstats_stat_desc_pack_link (struct ipstats_stat_dump_filters *filters,const struct ipstats_stat_desc *desc)
@@ -189,6 +225,7 @@ static const struct ipstats_stat_desc ipstats_stat_desc_toplev_link = {static const struct ipstats_stat_desc *ipstats_stat_desc_toplev_subs[] = { &ipstats_stat_desc_toplev_link, + &ipstats_stat_desc_offload_group, };static const struct ipstats_stat_desc ipstats_stat_desc_toplev_group = {
Signature · 1 line
2.31.1
PATCH 8/11 ipstats: Add offload subgroup "hw_stats_info"
In reply to Petr MachataAdd into the group "offload" a subgroup "hw_stats_info" for showing information about HW statistics counters.
For example:
# ip stats show dev swp1 group offload subgroup hw_stats_info
4178: swp1: group offload subgroup hw_stats_info
l3_stats on used off
# ip -j stats show dev swp1 group offload subgroup hw_stats_info | jq
[
{
"ifindex": 4178,
"ifname": "swp1",
"group": "offload",
"subgroup": "hw_stats_info",
"info": {
"l3_stats": {
"request": true,
"used": false
}
}
}
]--- ip/ipstats.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+)
ip/ipstats.c +217 -0
@@ -164,6 +164,197 @@ static int ipstats_show_64(struct ipstats_stat_show_attrs *attrs,return 0 ; } +enum ipstats_maybe_on_off { +IPSTATS_MOO_OFF =-1 , +IPSTATS_MOO_INVALID , +IPSTATS_MOO_ON , +}; + +static bool ipstats_moo_to_bool (enum ipstats_maybe_on_off moo) +{ +assert (moo !=IPSTATS_MOO_INVALID ); +return moo +1 ; +} + +static int ipstats_print_moo (enum output_type t,const char *key, +const char *fmt,enum ipstats_maybe_on_off moo) +{ +if (!moo) +return 0 ; +return print_on_off (t, key, fmt,ipstats_moo_to_bool (moo)); +} + +struct ipstats_hw_s_info_one { +enum ipstats_maybe_on_off request; +enum ipstats_maybe_on_off used; +}; + +enum ipstats_hw_s_info_idx { +IPSTATS_HW_S_INFO_IDX_L3_STATS , +IPSTATS_HW_S_INFO_IDX_COUNT +}; + +static const char *const ipstats_hw_s_info_name[] = { +"l3_stats" , +}; + +static_assert (ARRAY_SIZE (ipstats_hw_s_info_name) == +IPSTATS_HW_S_INFO_IDX_COUNT , +"mismatch: enum ipstats_hw_s_info_idx x ipstats_hw_s_info_name" ); + +struct ipstats_hw_s_info { +/* Indexed by enum ipstats_hw_s_info_idx. */ +struct ipstats_hw_s_info_one *infos[IPSTATS_HW_S_INFO_IDX_COUNT ]; +}; + +static enum ipstats_maybe_on_off ipstats_dissect_01 (int value,const char *what) +{ +switch (value) { +case 0 : +return IPSTATS_MOO_OFF ; +case 1 : +return IPSTATS_MOO_ON ; +default : +fprintf (stderr,"Invalid value for %s: expected 0 or 1, got %d.\n" , + what, value); +return IPSTATS_MOO_INVALID ; + } +} + +static int ipstats_dissect_hw_s_info_one (const struct rtattr *at, +struct ipstats_hw_s_info_one *p_hwsio, +const char *what) +{ +int attr_id_request =IFLA_OFFLOAD_XSTATS_HW_S_INFO_REQUEST ; +struct rtattr *tb[IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX +1 ]; +int attr_id_used =IFLA_OFFLOAD_XSTATS_HW_S_INFO_USED ; +struct ipstats_hw_s_info_one hwsio = {}; +int err; +int v; + + err =parse_rtattr_nested (tb,IFLA_OFFLOAD_XSTATS_HW_S_INFO_MAX , at); +if (err) +return err; + +if (tb[attr_id_request]) { + v =rta_getattr_u8 (tb[attr_id_request]); + hwsio.request =ipstats_dissect_01 (v,"request" ); + +/* This has to be present & valid. */ +if (!hwsio.request) +return -EINVAL ; + } + +if (tb[attr_id_used]) { + v =rta_getattr_u8 (tb[attr_id_used]); + hwsio.used =ipstats_dissect_01 (v,"used" ); + } + + *p_hwsio = hwsio; +return 0 ; +} + +static int ipstats_dissect_hw_s_info (const struct rtattr *at, +struct ipstats_hw_s_info *hwsi) +{ +struct rtattr *tb[IFLA_OFFLOAD_XSTATS_MAX +1 ]; +int attr_id_l3 =IFLA_OFFLOAD_XSTATS_L3_STATS ; +struct ipstats_hw_s_info_one *hwsio =NULL ; +int err; + + err =parse_rtattr_nested (tb,IFLA_OFFLOAD_XSTATS_MAX , at); +if (err) +return err; + + *hwsi = (struct ipstats_hw_s_info ){}; + +if (tb[attr_id_l3]) { + hwsio =malloc (sizeof (*hwsio)); +if (!hwsio) { + err = -ENOMEM ; + goto out; + } + + err =ipstats_dissect_hw_s_info_one (tb[attr_id_l3], hwsio,"l3" ); +if (err) + goto out; + + hwsi->infos[IPSTATS_HW_S_INFO_IDX_L3_STATS ] = hwsio; + hwsio =NULL ; + } + +return 0 ; + +out: +free (hwsio); +return err; +} + +static void ipstats_fini_hw_s_info (struct ipstats_hw_s_info *hwsi) +{ +int i; + +for (i =0 ; i <IPSTATS_HW_S_INFO_IDX_COUNT ; i++) +free (hwsi->infos[i]); +} + +static void +__ipstats_show_hw_s_info_one (const struct ipstats_hw_s_info_one *hwsio) +{ +if (hwsio ==NULL ) +return ; + +ipstats_print_moo (PRINT_ANY ,"request" ," %s" , hwsio->request); +ipstats_print_moo (PRINT_ANY ,"used" ," used %s" , hwsio->used); +} + +static void +ipstats_show_hw_s_info_one (const struct ipstats_hw_s_info *hwsi, +enum ipstats_hw_s_info_idx idx) +{ +const struct ipstats_hw_s_info_one *hwsio = hwsi->infos[idx]; +const char *name = ipstats_hw_s_info_name[idx]; + +if (hwsio ==NULL ) +return ; + +print_string (PRINT_FP ,NULL ," %s" , name); +open_json_object (name); +__ipstats_show_hw_s_info_one (hwsio); +close_json_object (); +} + +static int __ipstats_show_hw_s_info (const struct rtattr *at) +{ +struct ipstats_hw_s_info hwsi = {}; +int err; + + err =ipstats_dissect_hw_s_info (at, &hwsi); +if (err) +return err; + +open_json_object ("info" ); +ipstats_show_hw_s_info_one (&hwsi,IPSTATS_HW_S_INFO_IDX_L3_STATS ); +close_json_object (); + +ipstats_fini_hw_s_info (&hwsi); +return 0 ; +} + +static int ipstats_show_hw_s_info (struct ipstats_stat_show_attrs *attrs, +unsigned int group,unsigned int subgroup) +{ +const struct rtattr *at; +int err; + + at =ipstats_stat_show_get_attr (attrs, group, subgroup, &err); +if (at ==NULL ) +return err; + +print_nl (); +return __ipstats_show_hw_s_info (at); +} +static void ipstats_stat_desc_pack_cpu_hit (struct ipstats_stat_dump_filters *filters,const struct ipstats_stat_desc *desc)
@@ -189,8 +380,34 @@ static const struct ipstats_stat_desc ipstats_stat_desc_offload_cpu_hit = { .show = &ipstats_stat_desc_show_cpu_hit, }; +static void +ipstats_stat_desc_pack_hw_stats_info (struct ipstats_stat_dump_filters *filters, +const struct ipstats_stat_desc *desc) +{ +ipstats_stat_desc_enable_bit (filters, +IFLA_STATS_LINK_OFFLOAD_XSTATS , +IFLA_OFFLOAD_XSTATS_HW_S_INFO ); +} + +static int +ipstats_stat_desc_show_hw_stats_info (struct ipstats_stat_show_attrs *attrs, +const struct ipstats_stat_desc *desc) +{ +return ipstats_show_hw_s_info (attrs, +IFLA_STATS_LINK_OFFLOAD_XSTATS , +IFLA_OFFLOAD_XSTATS_HW_S_INFO ); +} + +static const struct ipstats_stat_desc ipstats_stat_desc_offload_hw_s_info = { + .name ="hw_stats_info" , + .kind =IPSTATS_STAT_DESC_KIND_LEAF , + .pack = &ipstats_stat_desc_pack_hw_stats_info, + .show = &ipstats_stat_desc_show_hw_stats_info, +}; +static const struct ipstats_stat_desc *ipstats_stat_desc_offload_subs[] = { &ipstats_stat_desc_offload_cpu_hit, + &ipstats_stat_desc_offload_hw_s_info, };static const struct ipstats_stat_desc ipstats_stat_desc_offload_group = {
Signature · 1 line
2.31.1
PATCH 9/11 ipstats: Add offload subgroup "l3_stats"
In reply to Petr MachataAdd into the group "offload" a subgroup "l3_stats" for showing L3 statistics.
For example:
# ip stats show dev swp2.200 group offload subgroup l3_stats
4212: swp2.200: group offload subgroup l3_stats on used on
RX: bytes packets errors dropped mcast
1920 21 1 0 0
TX: bytes packets errors dropped
756 9 0 0 # ip -j stats show dev swp2.200 group offload subgroup l3_stats | jq
[
{
"ifindex": 4212,
"ifname": "swp2.200",
"group": "offload",
"subgroup": "l3_stats",
"info": {
"request": true,
"used": true
},
"stats64": {
"rx": {
"bytes": 1920,
"packets": 21,
"errors": 1,
"dropped": 0,
"multicast": 0
},
"tx": {
"bytes": 756,
"packets": 9,
"errors": 0,
"dropped": 0
}
}
}
]--- ip/ipstats.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+)
ip/ipstats.c +158 -0
@@ -164,6 +164,82 @@ static int ipstats_show_64(struct ipstats_stat_show_attrs *attrs,return 0 ; } +static void print_hw_stats64 (FILE *fp,struct rtnl_hw_stats64 *s) +{ +unsigned int cols[] = { +strlen ("*X: bytes" ), +strlen ("packets" ), +strlen ("errors" ), +strlen ("dropped" ), +strlen ("overrun" ), + }; + +if (is_json_context ()) { +/* RX stats */ +open_json_object ("rx" ); +print_u64 (PRINT_JSON ,"bytes" ,NULL , s->rx_bytes); +print_u64 (PRINT_JSON ,"packets" ,NULL , s->rx_packets); +print_u64 (PRINT_JSON ,"errors" ,NULL , s->rx_errors); +print_u64 (PRINT_JSON ,"dropped" ,NULL , s->rx_dropped); +print_u64 (PRINT_JSON ,"multicast" ,NULL , s->multicast); +close_json_object (); + +/* TX stats */ +open_json_object ("tx" ); +print_u64 (PRINT_JSON ,"bytes" ,NULL , s->tx_bytes); +print_u64 (PRINT_JSON ,"packets" ,NULL , s->tx_packets); +print_u64 (PRINT_JSON ,"errors" ,NULL , s->tx_errors); +print_u64 (PRINT_JSON ,"dropped" ,NULL , s->tx_dropped); +close_json_object (); + }else { +size_columns (cols,ARRAY_SIZE (cols), + s->rx_bytes, s->rx_packets, s->rx_errors, + s->rx_dropped, s->multicast); +size_columns (cols,ARRAY_SIZE (cols), + s->tx_bytes, s->tx_packets, s->tx_errors, + s->tx_dropped,0 ); + +/* RX stats */ +fprintf (fp," RX: %*s %*s %*s %*s %*s%s" , + cols[0 ] -4 ,"bytes" , cols[1 ],"packets" , + cols[2 ],"errors" , cols[3 ],"dropped" , + cols[4 ],"mcast" , _SL_); + +fprintf (fp," " ); +print_num (fp, cols[0 ], s->rx_bytes); +print_num (fp, cols[1 ], s->rx_packets); +print_num (fp, cols[2 ], s->rx_errors); +print_num (fp, cols[3 ], s->rx_dropped); +print_num (fp, cols[4 ], s->multicast); +fprintf (fp,"%s" , _SL_); + +/* TX stats */ +fprintf (fp," TX: %*s %*s %*s %*s%s" , + cols[0 ] -4 ,"bytes" , cols[1 ],"packets" , + cols[2 ],"errors" , cols[3 ],"dropped" , _SL_); + +fprintf (fp," " ); +print_num (fp, cols[0 ], s->tx_bytes); +print_num (fp, cols[1 ], s->tx_packets); +print_num (fp, cols[2 ], s->tx_errors); +print_num (fp, cols[3 ], s->tx_dropped); + } +} + +static int ipstats_show_hw64 (const struct rtattr *at) +{ +struct rtnl_hw_stats64 *stats; + + stats = IPSTATS_RTA_PAYLOAD(struct rtnl_hw_stats64, at); +if (stats ==NULL ) { +fprintf (stderr,"Error: attribute payload too short" ); +return -EINVAL ; + } + +print_hw_stats64 (stdout, stats); +return 0 ; +} +enum ipstats_maybe_on_off {IPSTATS_MOO_OFF =-1 ,IPSTATS_MOO_INVALID ,
@@ -355,6 +431,57 @@ static int ipstats_show_hw_s_info(struct ipstats_stat_show_attrs *attrs,return __ipstats_show_hw_s_info (at); } +static int __ipstats_show_hw_stats (const struct rtattr *at_hwsi, +const struct rtattr *at_stats, +enum ipstats_hw_s_info_idx idx) +{ +int err =0 ; + +if (at_hwsi !=NULL ) { +struct ipstats_hw_s_info hwsi = {}; + + err =ipstats_dissect_hw_s_info (at_hwsi, &hwsi); +if (err) +return err; + +open_json_object ("info" ); +__ipstats_show_hw_s_info_one (hwsi.infos[idx]); +close_json_object (); + +ipstats_fini_hw_s_info (&hwsi); + } + +if (at_stats !=NULL ) { +print_nl (); +open_json_object ("stats64" ); + err =ipstats_show_hw64 (at_stats); +close_json_object (); + } + +return err; +} + +static int ipstats_show_hw_stats (struct ipstats_stat_show_attrs *attrs, +unsigned int group, +unsigned int hw_s_info, +unsigned int hw_stats, +enum ipstats_hw_s_info_idx idx) +{ +const struct rtattr *at_stats; +const struct rtattr *at_hwsi; +int err =0 ; + + at_hwsi =ipstats_stat_show_get_attr (attrs, group, hw_s_info, &err); +if (at_hwsi ==NULL ) +return err; + + at_stats =ipstats_stat_show_get_attr (attrs, group, hw_stats, &err); +if (at_stats ==NULL && err !=0 ) +return err; + +return __ipstats_show_hw_stats (at_hwsi, at_stats, idx); +} +static void ipstats_stat_desc_pack_cpu_hit (struct ipstats_stat_dump_filters *filters,const struct ipstats_stat_desc *desc)
@@ -405,9 +532,40 @@ static const struct ipstats_stat_desc ipstats_stat_desc_offload_hw_s_info = { .show = &ipstats_stat_desc_show_hw_stats_info, }; +static void +ipstats_stat_desc_pack_l3_stats (struct ipstats_stat_dump_filters *filters, +const struct ipstats_stat_desc *desc) +{ +ipstats_stat_desc_enable_bit (filters, +IFLA_STATS_LINK_OFFLOAD_XSTATS , +IFLA_OFFLOAD_XSTATS_L3_STATS ); +ipstats_stat_desc_enable_bit (filters, +IFLA_STATS_LINK_OFFLOAD_XSTATS , +IFLA_OFFLOAD_XSTATS_HW_S_INFO ); +} + +static int +ipstats_stat_desc_show_l3_stats (struct ipstats_stat_show_attrs *attrs, +const struct ipstats_stat_desc *desc) +{ +return ipstats_show_hw_stats (attrs, +IFLA_STATS_LINK_OFFLOAD_XSTATS , +IFLA_OFFLOAD_XSTATS_HW_S_INFO , +IFLA_OFFLOAD_XSTATS_L3_STATS , +IPSTATS_HW_S_INFO_IDX_L3_STATS ); +} + +static const struct ipstats_stat_desc ipstats_stat_desc_offload_l3_stats = { + .name ="l3_stats" , + .kind =IPSTATS_STAT_DESC_KIND_LEAF , + .pack = &ipstats_stat_desc_pack_l3_stats, + .show = &ipstats_stat_desc_show_l3_stats, +}; +static const struct ipstats_stat_desc *ipstats_stat_desc_offload_subs[] = { &ipstats_stat_desc_offload_cpu_hit, &ipstats_stat_desc_offload_hw_s_info, + &ipstats_stat_desc_offload_l3_stats, };static const struct ipstats_stat_desc ipstats_stat_desc_offload_group = {
Signature · 1 line
2.31.1
PATCH 10/11 ipmonitor: Add monitoring support for stats events
In reply to Petr MachataToggles and offloads of HW statistics cause emission of and RTM_NEWSTATS event. Add support to "ip monitor" for these events.
--- ip/ip_common.h | 1 + ip/ipmonitor.c | 16 +++++++++++++++- ip/ipstats.c | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-)
ip/ip_common.h +1 -0
@@ -57,6 +57,7 @@ int print_nexthop_bucket(struct nlmsghdr *n, void *arg);void netns_map_init (void );void netns_nsid_socket_init (void );int print_nsid (struct nlmsghdr *n,void *arg); +int ipstats_print (struct nlmsghdr *n,void *arg);char *get_name_from_nsid (int nsid);int get_netnsid_from_name (const char *name);int set_netnsid_from_name (const char *name,int nsid);
ip/ipmonitor.c +15 -1
@@ -34,7 +34,7 @@ static void usage(void)"Usage: ip monitor [ all | OBJECTS ] [ FILE ] [ label ] [ all-nsid ]\n" " [ dev DEVICE ]\n" "OBJECTS := address | link | mroute | neigh | netconf |\n" -" nexthop | nsid | prefix | route | rule\n" +" nexthop | nsid | prefix | route | rule | stats\n" "FILE := file FILENAME\n");exit (-1 ); }
@@ -158,6 +158,11 @@ static int accept_msg(struct rtnl_ctrl_data *ctrl,print_nsid (n, arg);return 0 ; +case RTM_NEWSTATS : +print_headers (fp,"[STATS]" , ctrl); +ipstats_print (n, arg); +return 0 ; +case NLMSG_ERROR :case NLMSG_NOOP :case NLMSG_DONE :
@@ -185,6 +190,7 @@ int do_ipmonitor(int argc, char **argv)int lprefix =0 ;int lneigh =0 ;int lnetconf =0 ; +int lstats =0 ;int lrule =0 ;int lnsid =0 ;int ifindex =0 ;
@@ -253,6 +259,9 @@ int do_ipmonitor(int argc, char **argv) }else if (matches (*argv,"nexthop" ) ==0 ) { lnexthop =1 ; groups =0 ; + }else if (strcmp (*argv,"stats" ) ==0 ) { + lstats =1 ; + groups =0 ; }else if (strcmp (*argv,"all" ) ==0 ) { prefix_banner =1 ; }else if (matches (*argv,"all-nsid" ) ==0 ) {
@@ -349,6 +358,11 @@ int do_ipmonitor(int argc, char **argv)exit (1 ); } +if (lstats &&rtnl_add_nl_group (&rth,RTNLGRP_STATS ) <0 ) { +fprintf (stderr,"Failed to add stats group to list\n" ); +exit (1 ); + } +if (listen_all_nsid &&rtnl_listen_all_nsid (&rth) <0 )exit (1 );
ip/ipstats.c +20 -0
@@ -1219,3 +1219,23 @@ int do_ipstats(int argc, char **argv)return rc; } + +int ipstats_print (struct nlmsghdr *n,void *arg) +{ +struct ipstats_stat_enabled_one one = { + .desc = &ipstats_stat_desc_offload_hw_s_info, + }; +struct ipstats_stat_enabled enabled = { + .enabled = &one, + .nenabled =1 , + }; +FILE *fp = arg; +int rc; + + rc =ipstats_process_ifsm (n, &enabled); +if (rc) +return rc; + +fflush (fp); +return 0 ; +}
Signature · 1 line
2.31.1
PATCH 11/11 man: Add man pages for the "stats" functions
In reply to Petr MachataAdd a man page for the new "stats" command. Also mention the new "stats" group in ip-monitor.
--- man/man8/ip-monitor.8 | 2 +- man/man8/ip-stats.8 | 160 ++++++++++++++++++++++++++++++++++++++++++ man/man8/ip.8 | 7 +- 3 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 man/man8/ip-stats.8
man/man8/ip-monitor.8 +1 -1
@@ -55,7 +55,7 @@ command is the first in the command line and then the object list follows: is the list of object types that we want to monitor. It may contain .BR link ", " address ", " route ", " mroute ", " prefix ", " -.BR neigh ", " netconf ", " rule ", " nsid " and " nexthop "." +.BR neigh ", " netconf ", " rule ", " stats ", " nsid " and " nexthop "." If no .B file argument is given,
man/man8/ip-stats.8 new file +160 -0
160 lines not on this page · raw message
man/man8/ip.8 +6 -1
@@ -22,7 +22,7 @@ ip \- show / manipulate routing, network devices, interfaces and tunnels .BR link " | " address " | " addrlabel " | " route " | " rule " | " neigh " | "\ ntable " | " tunnel " | " tuntap " | " maddress " | " mroute " | " mrule " | "\ monitor " | " xfrm " | " netns " | " l2tp " | " tcp_metrics " | " token " | "\ - macsec " | " vrf " | " mptcp " | " ioam " }" + macsec " | " vrf " | " mptcp " | " ioam " | " stats " }" .sp .ti -8
@@ -302,6 +302,10 @@ readability. .B rule - rule in routing policy database. +.TP +.B stats +- manage and show interface statistics. + .TP .B tcp_metrics/tcpmetrics - manage TCP Metrics
@@ -419,6 +423,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2. .BR ip-ntable (8), .BR ip-route (8), .BR ip-rule (8), +.BR ip-stats (8) .BR ip-tcp_metrics (8), .BR ip-token (8), .BR ip-tunnel (8),
Signature · 1 line
2.31.1
This series was applied to iproute2/iproute2-next.git (main) by David Ahern <[email protected]>:
Hello:
This series was applied to iproute2/iproute2-next.git (main) by David Ahern <[email protected]>:
Quoted 9 lines · On Fri, 22 Apr 2022 10:30:49 +0200 you wrote:
A new rtnetlink message,
RTM_SETSTATS, has been added recently in kernel commitca0a53dcec94("Merge branch 'net-hw-counters-for-soft-devices'").At the same time,
RTM_GETSTATShas been around for a while. The users of this API are spread in a couple different places: "ip link xstats" reads stats from theIFLA_STATS_LINK_XSTATSand_XSTATS_SLAVEsubgroups, "ip link afstats" then readsIFLA_STATS_AF_SPEC.[...]
Here is the summary with links:
- [iproute2-next,01/11] libnetlink: Add filtering to rtnl_statsdump_req_filter()
https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=a463d6b19107 - [iproute2-next,02/11] ip: Publish functions for stats formatting https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=5520cf1603ba - [iproute2-next,03/11] ip: Add a new family of commands, "stats" https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=54d82b0699a0 - [iproute2-next,04/11] ipstats: Add a "set" command https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=82f6444f83c7 - [iproute2-next,05/11] ipstats: Add a shell of "show" command (no matching commit) - [iproute2-next,06/11] ipstats: Add a group "link" https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=0517a2fd66ae - [iproute2-next,07/11] ipstats: Add a group "offload", subgroup "cpu_hit" https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=af5e7955273e - [iproute2-next,08/11] ipstats: Add offload subgroup "hw_stats_info" https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=179030fa6bc7 - [iproute2-next,09/11] ipstats: Add offload subgroup "l3_stats" https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=0f1fd40cc9e8 - [iproute2-next,10/11] ipmonitor: Add monitoring support for stats events https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=a05a27c07cbf - [iproute2-next,11/11] man: Add man pages for the "stats" functions https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=b28eb051b321
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html