From 337c9b992772763b499c5868ba60cbeb17c6ef28 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 29 Oct 2014 08:55:30 -0700 Subject: [PATCH] netdev-linux: Add support for 64-bit network device stats. Reported-by: Andrey Korolyov Tested-by: Andrey Korolyov Signed-off-by: Ben Pfaff --- AUTHORS | 1 + configure.ac | 2 ++ lib/netdev-linux.c | 77 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3af0fd584a1..1503c3b3050 100644 --- a/AUTHORS +++ b/AUTHORS @@ -178,6 +178,7 @@ Amre Shakimov ashakimov@vmware.com André Ruß andre.russ@hybris.com Andreas Beckmann debian@abeckmann.de Andrei Andone andrei.andone@softvision.ro +Andrey Korolyov andrey@xdel.ru Anshuman Manral anshuman.manral@outlook.com Anton Matsiuk anton.matsiuk@gmail.com Anup Khadka khadka.py@gmail.com diff --git a/configure.ac b/configure.ac index 62224b9867d..a8a530a08c5 100644 --- a/configure.ac +++ b/configure.ac @@ -67,6 +67,8 @@ AC_CHECK_DECLS([sys_siglist], [], [], [[#include ]]) AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec], [], [], [[#include ]]) AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include ]]) +AC_CHECK_TYPES([struct rtnl_link_stats64], [], [], + [[#include ]]) AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r]) AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h stdatomic.h]) AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index ab5ef7dd2b6..ff7c2748383 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -138,6 +138,39 @@ struct tpacket_auxdata { uint16_t tp_vlan_tpid; }; +/* Linux 2.6.35 introduced IFLA_STATS64 and rtnl_link_stats64. */ +#ifndef HAVE_STRUCT_RTNL_LINK_STATS64 +#define IFLA_STATS64 23 +struct rtnl_link_stats64 { + uint64_t rx_packets; + uint64_t tx_packets; + uint64_t rx_bytes; + uint64_t tx_bytes; + uint64_t rx_errors; + uint64_t tx_errors; + uint64_t rx_dropped; + uint64_t tx_dropped; + uint64_t multicast; + uint64_t collisions; + + uint64_t rx_length_errors; + uint64_t rx_over_errors; + uint64_t rx_crc_errors; + uint64_t rx_frame_errors; + uint64_t rx_fifo_errors; + uint64_t rx_missed_errors; + + uint64_t tx_aborted_errors; + uint64_t tx_carrier_errors; + uint64_t tx_fifo_errors; + uint64_t tx_heartbeat_errors; + uint64_t tx_window_errors; + + uint64_t rx_compressed; + uint64_t tx_compressed; +}; +#endif /* !HAVE_STRUCT_RTNL_LINK_STATS64 */ + enum { VALID_IFINDEX = 1 << 0, VALID_ETHERADDR = 1 << 1, @@ -4575,6 +4608,34 @@ netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst, dst->tx_window_errors = src->tx_window_errors; } +/* Copies 'src' into 'dst', performing format conversion in the process. */ +static void +netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst, + const struct rtnl_link_stats64 *src) +{ + dst->rx_packets = src->rx_packets; + dst->tx_packets = src->tx_packets; + dst->rx_bytes = src->rx_bytes; + dst->tx_bytes = src->tx_bytes; + dst->rx_errors = src->rx_errors; + dst->tx_errors = src->tx_errors; + dst->rx_dropped = src->rx_dropped; + dst->tx_dropped = src->tx_dropped; + dst->multicast = src->multicast; + dst->collisions = src->collisions; + dst->rx_length_errors = src->rx_length_errors; + dst->rx_over_errors = src->rx_over_errors; + dst->rx_crc_errors = src->rx_crc_errors; + dst->rx_frame_errors = src->rx_frame_errors; + dst->rx_fifo_errors = src->rx_fifo_errors; + dst->rx_missed_errors = src->rx_missed_errors; + dst->tx_aborted_errors = src->tx_aborted_errors; + dst->tx_carrier_errors = src->tx_carrier_errors; + dst->tx_fifo_errors = src->tx_fifo_errors; + dst->tx_heartbeat_errors = src->tx_heartbeat_errors; + dst->tx_window_errors = src->tx_window_errors; +} + static int get_stats_via_netlink(const struct netdev *netdev_, struct netdev_stats *stats) { @@ -4595,13 +4656,19 @@ get_stats_via_netlink(const struct netdev *netdev_, struct netdev_stats *stats) } if (ofpbuf_try_pull(reply, NLMSG_HDRLEN + sizeof(struct ifinfomsg))) { - const struct nlattr *a = nl_attr_find(reply, 0, IFLA_STATS); - if (a && nl_attr_get_size(a) >= sizeof(struct rtnl_link_stats)) { - netdev_stats_from_rtnl_link_stats(stats, nl_attr_get(a)); + const struct nlattr *a = nl_attr_find(reply, 0, IFLA_STATS64); + if (a && nl_attr_get_size(a) >= sizeof(struct rtnl_link_stats64)) { + netdev_stats_from_rtnl_link_stats64(stats, nl_attr_get(a)); error = 0; } else { - VLOG_WARN_RL(&rl, "RTM_GETLINK reply lacks stats"); - error = EPROTO; + const struct nlattr *a = nl_attr_find(reply, 0, IFLA_STATS); + if (a && nl_attr_get_size(a) >= sizeof(struct rtnl_link_stats)) { + netdev_stats_from_rtnl_link_stats(stats, nl_attr_get(a)); + error = 0; + } else { + VLOG_WARN_RL(&rl, "RTM_GETLINK reply lacks stats"); + error = EPROTO; + } } } else { VLOG_WARN_RL(&rl, "short RTM_GETLINK reply");