Assume all statistics in ip(8) represented either by IFLA_STATS64 or IFLA_STATS is 64 bit. It is clean that we can store __u32 counters of @struct rtnl_link_stats in __u64 counters in @struct rtnl_link_stats64.
New get_rtnl_link_stats_rta() follows __print_link_stats() behaviour on handling of stats attribute: copy no more than size of data structure and no less than attribute length zeroing rest. Drop print_link_stats32() as it's functionality can be handled by 64bit variant. Move code from __print_link_stats() to print_link_stats64() and finally rename print_link_stats64() to __print_link_stats(). More users of introduced function will come in future. Signed-off-by: Serhey Popovych <serhe.popov...@gmail.com> --- include/utils.h | 3 + ip/ipaddress.c | 171 +++---------------------------------------------------- lib/utils.c | 45 +++++++++++++++ 3 files changed, 56 insertions(+), 163 deletions(-) diff --git a/include/utils.h b/include/utils.h index 0394268..ffb2a2c 100644 --- a/include/utils.h +++ b/include/utils.h @@ -294,6 +294,9 @@ int make_path(const char *path, mode_t mode); char *find_cgroup2_mount(void); int get_command_name(const char *pid, char *comm, size_t len); +int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64, + struct rtattr *tb[]); + #ifdef NEED_STRLCPY size_t strlcpy(char *dst, const char *src, size_t size); size_t strlcat(char *dst, const char *src, size_t size); diff --git a/ip/ipaddress.c b/ip/ipaddress.c index ae419f0..078c6cf 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -594,152 +594,18 @@ static void print_vf_stats64(FILE *fp, struct rtattr *vfstats) } } -static void print_link_stats64(FILE *fp, const struct rtnl_link_stats64 *s, - const struct rtattr *carrier_changes) +static void __print_link_stats(FILE *fp, struct rtattr *tb[]) { - if (is_json_context()) { - open_json_object("stats64"); - - /* RX stats */ - open_json_object("rx"); - print_uint(PRINT_JSON, "bytes", NULL, s->rx_bytes); - print_uint(PRINT_JSON, "packets", NULL, s->rx_packets); - print_uint(PRINT_JSON, "errors", NULL, s->rx_errors); - print_uint(PRINT_JSON, "dropped", NULL, s->rx_dropped); - print_uint(PRINT_JSON, "over_errors", NULL, s->rx_over_errors); - print_uint(PRINT_JSON, "multicast", NULL, s->multicast); - if (s->rx_compressed) - print_uint(PRINT_JSON, - "compressed", NULL, s->rx_compressed); - - /* RX error stats */ - if (show_stats > 1) { - print_uint(PRINT_JSON, - "length_errors", - NULL, s->rx_length_errors); - print_uint(PRINT_JSON, - "crc_errors", - NULL, s->rx_crc_errors); - print_uint(PRINT_JSON, - "frame_errors", - NULL, s->rx_frame_errors); - print_uint(PRINT_JSON, - "fifo_errors", - NULL, s->rx_fifo_errors); - print_uint(PRINT_JSON, - "missed_errors", - NULL, s->rx_missed_errors); - if (s->rx_nohandler) - print_uint(PRINT_JSON, - "nohandler", NULL, s->rx_nohandler); - } - close_json_object(); - - /* TX stats */ - open_json_object("tx"); - print_uint(PRINT_JSON, "bytes", NULL, s->tx_bytes); - print_uint(PRINT_JSON, "packets", NULL, s->tx_packets); - print_uint(PRINT_JSON, "errors", NULL, s->tx_errors); - print_uint(PRINT_JSON, "dropped", NULL, s->tx_dropped); - print_uint(PRINT_JSON, - "carrier_errors", - NULL, s->tx_carrier_errors); - print_uint(PRINT_JSON, "collisions", NULL, s->collisions); - if (s->tx_compressed) - print_uint(PRINT_JSON, - "compressed", NULL, s->tx_compressed); - - /* TX error stats */ - if (show_stats > 1) { - print_uint(PRINT_JSON, - "aborted_errors", - NULL, s->tx_aborted_errors); - print_uint(PRINT_JSON, - "fifo_errors", - NULL, s->tx_fifo_errors); - print_uint(PRINT_JSON, - "window_errors", - NULL, s->tx_window_errors); - print_uint(PRINT_JSON, - "heartbeat_errors", - NULL, s->tx_heartbeat_errors); - if (carrier_changes) - print_uint(PRINT_JSON, "carrier_changes", NULL, - rta_getattr_u32(carrier_changes)); - } - - close_json_object(); - close_json_object(); - } else { - /* RX stats */ - fprintf(fp, " RX: bytes packets errors dropped overrun mcast %s%s", - s->rx_compressed ? "compressed" : "", _SL_); - - fprintf(fp, " "); - print_num(fp, 10, s->rx_bytes); - print_num(fp, 8, s->rx_packets); - print_num(fp, 7, s->rx_errors); - print_num(fp, 7, s->rx_dropped); - print_num(fp, 7, s->rx_over_errors); - print_num(fp, 7, s->multicast); - if (s->rx_compressed) - print_num(fp, 7, s->rx_compressed); - - /* RX error stats */ - if (show_stats > 1) { - fprintf(fp, "%s", _SL_); - fprintf(fp, " RX errors: length crc frame fifo missed%s%s", - s->rx_nohandler ? " nohandler" : "", _SL_); - fprintf(fp, " "); - print_num(fp, 8, s->rx_length_errors); - print_num(fp, 7, s->rx_crc_errors); - print_num(fp, 7, s->rx_frame_errors); - print_num(fp, 7, s->rx_fifo_errors); - print_num(fp, 7, s->rx_missed_errors); - if (s->rx_nohandler) - print_num(fp, 7, s->rx_nohandler); - } - fprintf(fp, "%s", _SL_); - - /* TX stats */ - fprintf(fp, " TX: bytes packets errors dropped carrier collsns %s%s", - s->tx_compressed ? "compressed" : "", _SL_); - - fprintf(fp, " "); - print_num(fp, 10, s->tx_bytes); - print_num(fp, 8, s->tx_packets); - print_num(fp, 7, s->tx_errors); - print_num(fp, 7, s->tx_dropped); - print_num(fp, 7, s->tx_carrier_errors); - print_num(fp, 7, s->collisions); - if (s->tx_compressed) - print_num(fp, 7, s->tx_compressed); - - /* TX error stats */ - if (show_stats > 1) { - fprintf(fp, "%s", _SL_); - fprintf(fp, " TX errors: aborted fifo window heartbeat"); - if (carrier_changes) - fprintf(fp, " transns"); - fprintf(fp, "%s", _SL_); + const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES]; + struct rtnl_link_stats64 _s, *s = &_s; + int ret; - fprintf(fp, " "); - print_num(fp, 8, s->tx_aborted_errors); - print_num(fp, 7, s->tx_fifo_errors); - print_num(fp, 7, s->tx_window_errors); - print_num(fp, 7, s->tx_heartbeat_errors); - if (carrier_changes) - print_num(fp, 7, - rta_getattr_u32(carrier_changes)); - } - } -} + ret = get_rtnl_link_stats_rta(s, tb); + if (ret < 0) + return; -static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s, - const struct rtattr *carrier_changes) -{ if (is_json_context()) { - open_json_object("stats"); + open_json_object((ret == sizeof(*s)) ? "stats64" : "stats"); /* RX stats */ open_json_object("rx"); @@ -876,27 +742,6 @@ static void print_link_stats32(FILE *fp, const struct rtnl_link_stats *s, } } -static void __print_link_stats(FILE *fp, struct rtattr **tb) -{ - const struct rtattr *carrier_changes = tb[IFLA_CARRIER_CHANGES]; - - if (tb[IFLA_STATS64]) { - struct rtnl_link_stats64 stats = { 0 }; - - memcpy(&stats, RTA_DATA(tb[IFLA_STATS64]), - MIN(RTA_PAYLOAD(tb[IFLA_STATS64]), sizeof(stats))); - - print_link_stats64(fp, &stats, carrier_changes); - } else if (tb[IFLA_STATS]) { - struct rtnl_link_stats stats = { 0 }; - - memcpy(&stats, RTA_DATA(tb[IFLA_STATS]), - MIN(RTA_PAYLOAD(tb[IFLA_STATS]), sizeof(stats))); - - print_link_stats32(fp, &stats, carrier_changes); - } -} - static void print_link_stats(FILE *fp, struct nlmsghdr *n) { struct ifinfomsg *ifi = NLMSG_DATA(n); diff --git a/lib/utils.c b/lib/utils.c index 8e15625..d86c2ee 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -1431,6 +1431,51 @@ int get_real_family(int rtm_type, int rtm_family) return rtm_family; } +/* Based on copy_rtnl_link_stats() from kernel at net/core/rtnetlink.c */ +static void copy_rtnl_link_stats64(struct rtnl_link_stats64 *stats64, + const struct rtnl_link_stats *stats) +{ + __u64 *a = (__u64 *)stats64; + const __u32 *b = (const __u32 *)stats; + const __u32 *e = b + sizeof(*stats) / sizeof(*b); + + while (b < e) + *a++ = *b++; +} + +int get_rtnl_link_stats_rta(struct rtnl_link_stats64 *stats64, + struct rtattr *tb[]) +{ + struct rtnl_link_stats stats; + void *s; + struct rtattr *rta; + int size, len; + + if (tb[IFLA_STATS64]) { + rta = tb[IFLA_STATS64]; + size = sizeof(struct rtnl_link_stats64); + s = stats64; + } else if (tb[IFLA_STATS]) { + rta = tb[IFLA_STATS]; + size = sizeof(struct rtnl_link_stats); + s = &stats; + } else { + return -1; + } + + len = RTA_PAYLOAD(rta); + if (len < size) + memset(s + len, 0, size - len); + else + len = size; + + memcpy(s, RTA_DATA(rta), len); + + if (s != stats64) + copy_rtnl_link_stats64(stats64, s); + return size; +} + #ifdef NEED_STRLCPY size_t strlcpy(char *dst, const char *src, size_t size) { -- 1.7.10.4