From 7fbef77a30dc415e41b9803b5443ce4675149b19 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Mon, 7 Jun 2010 19:20:28 -0700 Subject: [PATCH] netdev-linux: Add capability to get stats from vport layer. The vport layer has the ability to track stats using 64-bit counters, even if the kernel is only 32-bit. This first attempts to collect stats from these counters if they are available and otherwise falls back to the normal Linux interfaces. --- lib/netdev-linux.c | 59 ++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 2fa05b66..31d01780 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -48,6 +48,7 @@ #include "dynamic-string.h" #include "fatal-signal.h" #include "netdev-provider.h" +#include "netdev-vport.h" #include "netlink.h" #include "ofpbuf.h" #include "openflow/openflow.h" @@ -76,14 +77,15 @@ static struct rtnetlink_notifier netdev_linux_cache_notifier; static int cache_notifier_refcount; enum { - VALID_IFINDEX = 1 << 0, - VALID_ETHERADDR = 1 << 1, - VALID_IN4 = 1 << 2, - VALID_IN6 = 1 << 3, - VALID_MTU = 1 << 4, - VALID_CARRIER = 1 << 5, - VALID_IS_PSEUDO = 1 << 6, /* Represents is_internal and is_tap. */ - VALID_POLICING = 1 << 7 + VALID_IFINDEX = 1 << 0, + VALID_ETHERADDR = 1 << 1, + VALID_IN4 = 1 << 2, + VALID_IN6 = 1 << 3, + VALID_MTU = 1 << 4, + VALID_CARRIER = 1 << 5, + VALID_IS_PSEUDO = 1 << 6, /* Represents is_internal and is_tap. */ + VALID_POLICING = 1 << 7, + VALID_HAVE_VPORT_STATS = 1 << 8 }; struct tap_state { @@ -109,6 +111,7 @@ struct netdev_dev_linux { bool is_tap; /* Is this a tuntap device? */ uint32_t kbits_rate; /* Policing data. */ uint32_t kbits_burst; + bool have_vport_stats; union { struct tap_state tap; @@ -795,10 +798,7 @@ swap_uint64(uint64_t *a, uint64_t *b) *a ^= *b; } -/* Retrieves current device stats for 'netdev'. - * - * XXX All of the members of struct netdev_stats are 64 bits wide, but on - * 32-bit architectures the Linux network stats are only 32 bits. */ +/* Retrieves current device stats for 'netdev'. */ static int netdev_linux_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) @@ -810,26 +810,39 @@ netdev_linux_get_stats(const struct netdev *netdev_, COVERAGE_INC(netdev_get_stats); - if (use_netlink_stats < 0) { - use_netlink_stats = check_for_working_netlink_stats(); + if (netdev_dev->have_vport_stats || + !(netdev_dev->cache_valid & VALID_HAVE_VPORT_STATS)) { + + error = netdev_vport_get_stats(netdev_, stats); + netdev_dev->have_vport_stats = !error; + netdev_dev->cache_valid |= VALID_HAVE_VPORT_STATS; } - if (use_netlink_stats) { - int ifindex; - error = get_ifindex(netdev_, &ifindex); - if (!error) { - error = get_stats_via_netlink(ifindex, stats); + if (!netdev_dev->have_vport_stats) { + if (use_netlink_stats < 0) { + use_netlink_stats = check_for_working_netlink_stats(); + } + if (use_netlink_stats) { + int ifindex; + + error = get_ifindex(netdev_, &ifindex); + if (!error) { + error = get_stats_via_netlink(ifindex, stats); + } + } else { + error = get_stats_via_proc(netdev_get_name(netdev_), stats); } - } else { - error = get_stats_via_proc(netdev_get_name(netdev_), stats); } /* If this port is an internal port then the transmit and receive stats * will appear to be swapped relative to the other ports since we are the * one sending the data, not a remote computer. For consistency, we swap - * them back here. */ + * them back here. This does not apply if we are getting stats from the + * vport layer because it always tracks stats from the perspective of the + * switch. */ netdev_linux_update_is_pseudo(netdev_dev); - if (!error && (netdev_dev->is_internal || netdev_dev->is_tap)) { + if (!error && !netdev_dev->have_vport_stats && + (netdev_dev->is_internal || netdev_dev->is_tap)) { swap_uint64(&stats->rx_packets, &stats->tx_packets); swap_uint64(&stats->rx_bytes, &stats->tx_bytes); swap_uint64(&stats->rx_errors, &stats->tx_errors); -- 2.30.2