From f613a0d72c521ca3a4eeb2c29ac523f6fdf72667 Mon Sep 17 00:00:00 2001 From: Pravin Shelar Date: Thu, 15 Sep 2011 19:36:17 -0700 Subject: [PATCH] datapath: Always use generic stats for devices (vports) Currently ovs is using device stats for Linux devices and count them itself in other situations. This leads to overlap with hardware stats, inconsistencies, etc. It's much better to just always count the packets flowing through the switch and let userspace do any merging that it wants. Following patch removes vport->get_stats() interface. vport-stat is changed to use new `struct ovs_vport_stat` rather than rtnl_link_stats64. Definitions of rtnl_link_stats64 is removed from OVS. dipf_port->stat is also removed as aggregate stats are only available at netdev layer. Signed-off-by: Pravin B Shelar Acked-by: Jesse Gross --- acinclude.m4 | 2 - configure.ac | 1 - datapath/datapath.c | 17 +- .../linux/compat/include/linux/netdevice.h | 13 - datapath/linux/compat/netdevice.c | 48 ---- datapath/vport-capwap.c | 2 +- datapath/vport-gre.c | 2 +- datapath/vport-internal_dev.c | 9 +- datapath/vport-netdev.c | 24 +- datapath/vport-netdev.h | 1 - datapath/vport-patch.c | 1 - datapath/vport.c | 153 ++++-------- datapath/vport.h | 22 +- include/automake.mk | 1 - include/linux/automake.mk | 2 - include/linux/if_link.h | 56 ----- include/openvswitch/datapath-protocol.h | 16 +- lib/dpif-linux.c | 15 +- lib/dpif-linux.h | 2 +- lib/dpif.c | 1 - lib/dpif.h | 1 - lib/netdev-linux.c | 230 +++++++++++------- lib/netdev-linux.h | 9 +- lib/netdev-vport.c | 45 +++- m4/openvswitch.m4 | 19 -- utilities/ovs-dpctl.c | 47 ++-- 26 files changed, 303 insertions(+), 436 deletions(-) delete mode 100644 include/linux/automake.mk delete mode 100644 include/linux/if_link.h diff --git a/acinclude.m4 b/acinclude.m4 index b3794893..648132a2 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -254,8 +254,6 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_get_be16]) OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_find_nested]) - OVS_GREP_IFELSE([$KSRC/include/linux/if_link.h], [rtnl_link_stats64]) - OVS_GREP_IFELSE([$KSRC/include/linux/if_vlan.h], [ADD_ALL_VLANS_CMD], [OVS_DEFINE([HAVE_VLAN_BUG_WORKAROUND])]) diff --git a/configure.ac b/configure.ac index e03946aa..7387d826 100644 --- a/configure.ac +++ b/configure.ac @@ -47,7 +47,6 @@ OVS_CHECK_NDEBUG OVS_CHECK_NETLINK OVS_CHECK_OPENSSL OVS_CHECK_LOGDIR -OVS_CHECK_RTNL_LINK_STATS64 OVS_CHECK_PYTHON OVS_CHECK_PYUIC4 OVS_CHECK_OVSDBMONITOR diff --git a/datapath/datapath.c b/datapath/datapath.c index 0238c5f3..98c2bafd 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -1504,10 +1504,10 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = { [OVS_VPORT_ATTR_NAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, [OVS_VPORT_ATTR_PORT_NO] = { .type = NLA_U32 }, [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 }, - [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct rtnl_link_stats64) }, + [OVS_VPORT_ATTR_STATS] = { .len = sizeof(struct ovs_vport_stats) }, [OVS_VPORT_ATTR_ADDRESS] = { .len = ETH_ALEN }, #else - [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct rtnl_link_stats64) }, + [OVS_VPORT_ATTR_STATS] = { .minlen = sizeof(struct ovs_vport_stats) }, [OVS_VPORT_ATTR_ADDRESS] = { .minlen = ETH_ALEN }, #endif [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED }, @@ -1545,11 +1545,11 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, NLA_PUT_U32(skb, OVS_VPORT_ATTR_TYPE, vport_get_type(vport)); NLA_PUT_STRING(skb, OVS_VPORT_ATTR_NAME, vport_get_name(vport)); - nla = nla_reserve(skb, OVS_VPORT_ATTR_STATS, sizeof(struct rtnl_link_stats64)); + nla = nla_reserve(skb, OVS_VPORT_ATTR_STATS, sizeof(struct ovs_vport_stats)); if (!nla) goto nla_put_failure; - if (vport_get_stats(vport, nla_data(nla))) - __skb_trim(skb, skb->len - nla->nla_len); + + vport_get_stats(vport, nla_data(nla)); NLA_PUT(skb, OVS_VPORT_ATTR_ADDRESS, ETH_ALEN, vport_get_addr(vport)); @@ -1628,10 +1628,13 @@ static struct vport *lookup_vport(struct ovs_header *ovs_header, static int change_vport(struct vport *vport, struct nlattr *a[OVS_VPORT_ATTR_MAX + 1]) { int err = 0; + if (a[OVS_VPORT_ATTR_STATS]) - err = vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS])); - if (!err && a[OVS_VPORT_ATTR_ADDRESS]) + vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS])); + + if (a[OVS_VPORT_ATTR_ADDRESS]) err = vport_set_addr(vport, nla_data(a[OVS_VPORT_ATTR_ADDRESS])); + return err; } diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h index 1ac38312..8d24cd96 100644 --- a/datapath/linux/compat/include/linux/netdevice.h +++ b/datapath/linux/compat/include/linux/netdevice.h @@ -77,19 +77,6 @@ extern void unregister_netdevice_many(struct list_head *head); extern void dev_disable_lro(struct net_device *dev); #endif -/* Linux 2.6.28 introduced dev_get_stats(): - * const struct net_device_stats *dev_get_stats(struct net_device *dev); - * - * Linux 2.6.36 changed dev_get_stats() to: - * struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, - * struct rtnl_link_stats64 *storage); - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) -#define dev_get_stats(dev, storage) rpl_dev_get_stats(dev, storage) -struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, - struct rtnl_link_stats64 *storage); -#endif - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #define skb_checksum_help(skb) skb_checksum_help((skb), 0) #endif diff --git a/datapath/linux/compat/netdevice.c b/datapath/linux/compat/netdevice.c index 91855c47..9e92eeb8 100644 --- a/datapath/linux/compat/netdevice.c +++ b/datapath/linux/compat/netdevice.c @@ -1,54 +1,6 @@ -#include #include #include -/* Linux 2.6.28 introduced dev_get_stats(): - * const struct net_device_stats *dev_get_stats(struct net_device *dev); - * - * Linux 2.6.36 changed dev_get_stats() to: - * struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, - * struct rtnl_link_stats64 *storage); - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) -struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, - struct rtnl_link_stats64 *storage) -{ - const struct net_device_stats *stats; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - stats = dev->get_stats(dev); -#else /* 2.6.28 < kernel version < 2.6.36 */ - stats = (dev_get_stats)(dev); -#endif /* 2.6.28 < kernel version < 2.6.36 */ - - storage->rx_packets = stats->rx_packets; - storage->tx_packets = stats->tx_packets; - storage->rx_bytes = stats->rx_bytes; - storage->tx_bytes = stats->tx_bytes; - storage->rx_errors = stats->rx_errors; - storage->tx_errors = stats->tx_errors; - storage->rx_dropped = stats->rx_dropped; - storage->tx_dropped = stats->tx_dropped; - storage->multicast = stats->multicast; - storage->collisions = stats->collisions; - storage->rx_length_errors = stats->rx_length_errors; - storage->rx_over_errors = stats->rx_over_errors; - storage->rx_crc_errors = stats->rx_crc_errors; - storage->rx_frame_errors = stats->rx_frame_errors; - storage->rx_fifo_errors = stats->rx_fifo_errors; - storage->rx_missed_errors = stats->rx_missed_errors; - storage->tx_aborted_errors = stats->tx_aborted_errors; - storage->tx_carrier_errors = stats->tx_carrier_errors; - storage->tx_fifo_errors = stats->tx_fifo_errors; - storage->tx_heartbeat_errors = stats->tx_heartbeat_errors; - storage->tx_window_errors = stats->tx_window_errors; - storage->rx_compressed = stats->rx_compressed; - storage->tx_compressed = stats->tx_compressed; - - return storage; -} -#endif /* kernel version < 2.6.36 */ - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) static bool can_checksum_protocol(unsigned long features, __be16 protocol) { diff --git a/datapath/vport-capwap.c b/datapath/vport-capwap.c index 68a168b6..76db8a73 100644 --- a/datapath/vport-capwap.c +++ b/datapath/vport-capwap.c @@ -788,7 +788,7 @@ static void capwap_frag_expire(unsigned long ifq) const struct vport_ops capwap_vport_ops = { .type = OVS_VPORT_TYPE_CAPWAP, - .flags = VPORT_F_GEN_STATS | VPORT_F_TUN_ID, + .flags = VPORT_F_TUN_ID, .init = capwap_init, .exit = capwap_exit, .create = capwap_create, diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c index 24c53f89..5beae42e 100644 --- a/datapath/vport-gre.c +++ b/datapath/vport-gre.c @@ -389,7 +389,7 @@ static void gre_exit(void) const struct vport_ops gre_vport_ops = { .type = OVS_VPORT_TYPE_GRE, - .flags = VPORT_F_GEN_STATS | VPORT_F_TUN_ID, + .flags = VPORT_F_TUN_ID, .init = gre_init, .exit = gre_exit, .create = gre_create, diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c index 04f51eb3..ecfb3793 100644 --- a/datapath/vport-internal_dev.c +++ b/datapath/vport-internal_dev.c @@ -32,16 +32,14 @@ static inline struct internal_dev *internal_dev_priv(struct net_device *netdev) return netdev_priv(netdev); } -/* This function is only called by the kernel network layer. It is not a vport - * get_stats() function. If a vport get_stats() function is defined that - * results in this being called it will cause infinite recursion. */ +/* This function is only called by the kernel network layer.*/ static struct net_device_stats *internal_dev_sys_stats(struct net_device *netdev) { struct vport *vport = internal_dev_get_vport(netdev); struct net_device_stats *stats = &internal_dev_priv(netdev)->stats; if (vport) { - struct rtnl_link_stats64 vport_stats; + struct ovs_vport_stats vport_stats; vport_get_stats(vport, &vport_stats); @@ -55,7 +53,6 @@ static struct net_device_stats *internal_dev_sys_stats(struct net_device *netdev stats->tx_errors = vport_stats.rx_errors; stats->rx_dropped = vport_stats.tx_dropped; stats->tx_dropped = vport_stats.rx_dropped; - stats->collisions = vport_stats.collisions; } return stats; @@ -266,7 +263,7 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb) const struct vport_ops internal_vport_ops = { .type = OVS_VPORT_TYPE_INTERNAL, - .flags = VPORT_F_REQUIRED | VPORT_F_GEN_STATS | VPORT_F_FLOW, + .flags = VPORT_F_REQUIRED | VPORT_F_FLOW, .create = internal_dev_create, .destroy = internal_dev_destroy, .set_addr = netdev_set_addr, diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c index 7cd6c6b3..4c7f1cb4 100644 --- a/datapath/vport-netdev.c +++ b/datapath/vport-netdev.c @@ -35,9 +35,6 @@ MODULE_PARM_DESC(vlan_tso, "Enable TSO for VLAN packets"); #define vlan_tso true #endif -/* If the native device stats aren't 64 bit use the vport stats tracking instead. */ -#define USE_VPORT_STATS (sizeof(((struct net_device_stats *)0)->rx_bytes) < sizeof(u64)) - static void netdev_port_receive(struct vport *vport, struct sk_buff *skb); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) @@ -144,16 +141,6 @@ static struct vport *netdev_create(const struct vport_parms *parms) goto error_put; } - /* If we are using the vport stats layer initialize it to the current - * values so we are roughly consistent with the device stats. */ - if (USE_VPORT_STATS) { - struct rtnl_link_stats64 stats; - - err = netdev_get_stats(vport, &stats); - if (!err) - vport_set_stats(vport, &stats); - } - err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport); if (err) @@ -218,13 +205,6 @@ struct kobject *netdev_get_kobj(const struct vport *vport) return &netdev_vport->dev->NETDEV_DEV_MEMBER.kobj; } -int netdev_get_stats(const struct vport *vport, struct rtnl_link_stats64 *stats) -{ - const struct netdev_vport *netdev_vport = netdev_vport_priv(vport); - dev_get_stats(netdev_vport->dev, stats); - return 0; -} - unsigned netdev_get_dev_flags(const struct vport *vport) { const struct netdev_vport *netdev_vport = netdev_vport_priv(vport); @@ -410,8 +390,7 @@ struct vport *netdev_get_vport(struct net_device *dev) const struct vport_ops netdev_vport_ops = { .type = OVS_VPORT_TYPE_NETDEV, - .flags = (VPORT_F_REQUIRED | - (USE_VPORT_STATS ? VPORT_F_GEN_STATS : 0)), + .flags = VPORT_F_REQUIRED, .init = netdev_init, .exit = netdev_exit, .create = netdev_create, @@ -420,7 +399,6 @@ const struct vport_ops netdev_vport_ops = { .get_name = netdev_get_name, .get_addr = netdev_get_addr, .get_kobj = netdev_get_kobj, - .get_stats = netdev_get_stats, .get_dev_flags = netdev_get_dev_flags, .is_running = netdev_is_running, .get_operstate = netdev_get_operstate, diff --git a/datapath/vport-netdev.h b/datapath/vport-netdev.h index 7a743d24..9b138be3 100644 --- a/datapath/vport-netdev.h +++ b/datapath/vport-netdev.h @@ -30,7 +30,6 @@ const char *netdev_get_name(const struct vport *); const unsigned char *netdev_get_addr(const struct vport *); const char *netdev_get_config(const struct vport *); struct kobject *netdev_get_kobj(const struct vport *); -int netdev_get_stats(const struct vport *, struct rtnl_link_stats64 *); unsigned netdev_get_dev_flags(const struct vport *); int netdev_is_running(const struct vport *); unsigned char netdev_get_operstate(const struct vport *); diff --git a/datapath/vport-patch.c b/datapath/vport-patch.c index 1ec3a4c9..9554f121 100644 --- a/datapath/vport-patch.c +++ b/datapath/vport-patch.c @@ -287,7 +287,6 @@ static int patch_send(struct vport *vport, struct sk_buff *skb) const struct vport_ops patch_vport_ops = { .type = OVS_VPORT_TYPE_PATCH, - .flags = VPORT_F_GEN_STATS, .init = patch_init, .exit = patch_exit, .create = patch_create, diff --git a/datapath/vport.c b/datapath/vport.c index ca802b4b..71fdd841 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -184,13 +184,11 @@ struct vport *vport_alloc(int priv_size, const struct vport_ops *ops, const stru vport->kobj.kset = NULL; kobject_init(&vport->kobj, &brport_ktype); - if (vport->ops->flags & VPORT_F_GEN_STATS) { - vport->percpu_stats = alloc_percpu(struct vport_percpu_stats); - if (!vport->percpu_stats) - return ERR_PTR(-ENOMEM); + vport->percpu_stats = alloc_percpu(struct vport_percpu_stats); + if (!vport->percpu_stats) + return ERR_PTR(-ENOMEM); - spin_lock_init(&vport->stats_lock); - } + spin_lock_init(&vport->stats_lock); return vport; } @@ -207,8 +205,7 @@ struct vport *vport_alloc(int priv_size, const struct vport_ops *ops, const stru */ void vport_free(struct vport *vport) { - if (vport->ops->flags & VPORT_F_GEN_STATS) - free_percpu(vport->percpu_stats); + free_percpu(vport->percpu_stats); kobject_put(&vport->kobj); } @@ -320,18 +317,13 @@ int vport_set_addr(struct vport *vport, const unsigned char *addr) * * Must be called with RTNL lock. */ -int vport_set_stats(struct vport *vport, struct rtnl_link_stats64 *stats) +void vport_set_stats(struct vport *vport, struct ovs_vport_stats *stats) { ASSERT_RTNL(); - if (vport->ops->flags & VPORT_F_GEN_STATS) { - spin_lock_bh(&vport->stats_lock); - vport->offset_stats = *stats; - spin_unlock_bh(&vport->stats_lock); - - return 0; - } else - return -EOPNOTSUPP; + spin_lock_bh(&vport->stats_lock); + vport->offset_stats = *stats; + spin_unlock_bh(&vport->stats_lock); } /** @@ -389,17 +381,6 @@ struct kobject *vport_get_kobj(const struct vport *vport) return NULL; } -static int vport_call_get_stats(struct vport *vport, struct rtnl_link_stats64 *stats) -{ - int err; - - rcu_read_lock(); - err = vport->ops->get_stats(vport, stats); - rcu_read_unlock(); - - return err; -} - /** * vport_get_stats - retrieve device stats * @@ -410,19 +391,20 @@ static int vport_call_get_stats(struct vport *vport, struct rtnl_link_stats64 *s * * Must be called with RTNL lock or rcu_read_lock. */ -int vport_get_stats(struct vport *vport, struct rtnl_link_stats64 *stats) +void vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) { int i; - if (!(vport->ops->flags & VPORT_F_GEN_STATS)) - return vport_call_get_stats(vport, stats); - /* We potentially have 3 sources of stats that need to be * combined: those we have collected (split into err_stats and * percpu_stats), offset_stats from set_stats(), and device - * error stats from get_stats() (for errors that happen + * error stats from netdev->get_stats() (for errors that happen * downstream and therefore aren't reported through our - * vport_record_error() function). */ + * vport_record_error() function). + * Stats from first two sources are merged and reported by ovs over + * OVS_VPORT_ATTR_STATS. + * netdev-stats can be directly read over netlink-ioctl. + */ spin_lock_bh(&vport->stats_lock); @@ -435,35 +417,6 @@ int vport_get_stats(struct vport *vport, struct rtnl_link_stats64 *stats) spin_unlock_bh(&vport->stats_lock); - if (vport->ops->get_stats) { - struct rtnl_link_stats64 dev_stats; - int err; - - err = vport_call_get_stats(vport, &dev_stats); - if (err) - return err; - - stats->rx_errors += dev_stats.rx_errors; - stats->tx_errors += dev_stats.tx_errors; - stats->rx_dropped += dev_stats.rx_dropped; - stats->tx_dropped += dev_stats.tx_dropped; - stats->multicast += dev_stats.multicast; - stats->collisions += dev_stats.collisions; - stats->rx_length_errors += dev_stats.rx_length_errors; - stats->rx_over_errors += dev_stats.rx_over_errors; - stats->rx_crc_errors += dev_stats.rx_crc_errors; - stats->rx_frame_errors += dev_stats.rx_frame_errors; - stats->rx_fifo_errors += dev_stats.rx_fifo_errors; - stats->rx_missed_errors += dev_stats.rx_missed_errors; - stats->tx_aborted_errors += dev_stats.tx_aborted_errors; - stats->tx_carrier_errors += dev_stats.tx_carrier_errors; - stats->tx_fifo_errors += dev_stats.tx_fifo_errors; - stats->tx_heartbeat_errors += dev_stats.tx_heartbeat_errors; - stats->tx_window_errors += dev_stats.tx_window_errors; - stats->rx_compressed += dev_stats.rx_compressed; - stats->tx_compressed += dev_stats.tx_compressed; - } - for_each_possible_cpu(i) { const struct vport_percpu_stats *percpu_stats; struct vport_percpu_stats local_stats; @@ -481,8 +434,6 @@ int vport_get_stats(struct vport *vport, struct rtnl_link_stats64 *stats) stats->tx_bytes += local_stats.tx_bytes; stats->tx_packets += local_stats.tx_packets; } - - return 0; } /** @@ -610,19 +561,17 @@ int vport_get_options(const struct vport *vport, struct sk_buff *skb) */ void vport_receive(struct vport *vport, struct sk_buff *skb) { - if (vport->ops->flags & VPORT_F_GEN_STATS) { - struct vport_percpu_stats *stats; + struct vport_percpu_stats *stats; - local_bh_disable(); - stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); + local_bh_disable(); + stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); - write_seqcount_begin(&stats->seqlock); - stats->rx_packets++; - stats->rx_bytes += skb->len; - write_seqcount_end(&stats->seqlock); + write_seqcount_begin(&stats->seqlock); + stats->rx_packets++; + stats->rx_bytes += skb->len; + write_seqcount_end(&stats->seqlock); - local_bh_enable(); - } + local_bh_enable(); if (!(vport->ops->flags & VPORT_F_FLOW)) OVS_CB(skb)->flow = NULL; @@ -644,21 +593,18 @@ void vport_receive(struct vport *vport, struct sk_buff *skb) */ int vport_send(struct vport *vport, struct sk_buff *skb) { + struct vport_percpu_stats *stats; int sent = vport->ops->send(vport, skb); - if (vport->ops->flags & VPORT_F_GEN_STATS && sent > 0) { - struct vport_percpu_stats *stats; - - local_bh_disable(); - stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); + local_bh_disable(); + stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); - write_seqcount_begin(&stats->seqlock); - stats->tx_packets++; - stats->tx_bytes += sent; - write_seqcount_end(&stats->seqlock); + write_seqcount_begin(&stats->seqlock); + stats->tx_packets++; + stats->tx_bytes += sent; + write_seqcount_end(&stats->seqlock); - local_bh_enable(); - } + local_bh_enable(); return sent; } @@ -674,28 +620,25 @@ int vport_send(struct vport *vport, struct sk_buff *skb) */ void vport_record_error(struct vport *vport, enum vport_err_type err_type) { - if (vport->ops->flags & VPORT_F_GEN_STATS) { - - spin_lock_bh(&vport->stats_lock); + spin_lock_bh(&vport->stats_lock); - switch (err_type) { - case VPORT_E_RX_DROPPED: - vport->err_stats.rx_dropped++; - break; + switch (err_type) { + case VPORT_E_RX_DROPPED: + vport->err_stats.rx_dropped++; + break; - case VPORT_E_RX_ERROR: - vport->err_stats.rx_errors++; - break; + case VPORT_E_RX_ERROR: + vport->err_stats.rx_errors++; + break; - case VPORT_E_TX_DROPPED: - vport->err_stats.tx_dropped++; - break; + case VPORT_E_TX_DROPPED: + vport->err_stats.tx_dropped++; + break; - case VPORT_E_TX_ERROR: - vport->err_stats.tx_errors++; - break; - }; + case VPORT_E_TX_ERROR: + vport->err_stats.tx_errors++; + break; + }; - spin_unlock_bh(&vport->stats_lock); - } + spin_unlock_bh(&vport->stats_lock); } diff --git a/datapath/vport.h b/datapath/vport.h index 6c4da24f..e7d2eb5c 100644 --- a/datapath/vport.h +++ b/datapath/vport.h @@ -31,14 +31,14 @@ void vport_del(struct vport *); struct vport *vport_locate(const char *name); int vport_set_addr(struct vport *, const unsigned char *); -int vport_set_stats(struct vport *, struct rtnl_link_stats64 *); +void vport_set_stats(struct vport *, struct ovs_vport_stats *); const char *vport_get_name(const struct vport *); enum ovs_vport_type vport_get_type(const struct vport *); const unsigned char *vport_get_addr(const struct vport *); struct kobject *vport_get_kobj(const struct vport *); -int vport_get_stats(struct vport *, struct rtnl_link_stats64 *); +void vport_get_stats(struct vport *, struct ovs_vport_stats *); unsigned vport_get_flags(const struct vport *); int vport_is_running(const struct vport *); @@ -84,11 +84,9 @@ struct vport_err_stats { * regardless of whether they were actually chosen and sent down to userspace. * @hash_node: Element in @dev_table hash table in vport.c. * @ops: Class structure. - * @percpu_stats: Points to per-CPU statistics used and maintained by the vport - * code if %VPORT_F_GEN_STATS is set to 1 in @ops flags, otherwise unused. + * @percpu_stats: Points to per-CPU statistics used and maintained by vport * @stats_lock: Protects @err_stats and @offset_stats. - * @err_stats: Points to error statistics used and maintained by the vport code - * if %VPORT_F_GEN_STATS is set to 1 in @ops flags, otherwise unused. + * @err_stats: Points to error statistics used and maintained by vport * @offset_stats: Added to actual statistics as a sop to compatibility with * XAPI for Citrix XenServer. Deprecated. */ @@ -108,13 +106,12 @@ struct vport { spinlock_t stats_lock; struct vport_err_stats err_stats; - struct rtnl_link_stats64 offset_stats; + struct ovs_vport_stats offset_stats; }; #define VPORT_F_REQUIRED (1 << 0) /* If init fails, module loading fails. */ -#define VPORT_F_GEN_STATS (1 << 1) /* Track stats at the generic layer. */ -#define VPORT_F_FLOW (1 << 2) /* Sets OVS_CB(skb)->flow. */ -#define VPORT_F_TUN_ID (1 << 3) /* Sets OVS_CB(skb)->tun_id. */ +#define VPORT_F_FLOW (1 << 1) /* Sets OVS_CB(skb)->flow. */ +#define VPORT_F_TUN_ID (1 << 2) /* Sets OVS_CB(skb)->tun_id. */ /** * struct vport_parms - parameters for creating a new vport @@ -160,10 +157,6 @@ struct vport_parms { * @get_addr: Get the device's MAC address. * @get_config: Get the device's configuration. * @get_kobj: Get the kobj associated with the device (may return null). - * @get_stats: Fill in the transmit/receive stats. May be null if stats are - * not supported or if generic stats are in use. If defined and - * VPORT_F_GEN_STATS is also set, the error stats are added to those already - * collected. * @get_dev_flags: Get the device's flags. * @is_running: Checks whether the device is running. * @get_operstate: Get the device's operating state. @@ -195,7 +188,6 @@ struct vport_ops { const unsigned char *(*get_addr)(const struct vport *); void (*get_config)(const struct vport *, void *); struct kobject *(*get_kobj)(const struct vport *); - int (*get_stats)(const struct vport *, struct rtnl_link_stats64 *); unsigned (*get_dev_flags)(const struct vport *); int (*is_running)(const struct vport *); diff --git a/include/automake.mk b/include/automake.mk index f34e5c9b..9ec5b72e 100644 --- a/include/automake.mk +++ b/include/automake.mk @@ -1,4 +1,3 @@ -include include/linux/automake.mk include include/openflow/automake.mk include include/openvswitch/automake.mk include include/sparse/automake.mk diff --git a/include/linux/automake.mk b/include/linux/automake.mk deleted file mode 100644 index a0a963d0..00000000 --- a/include/linux/automake.mk +++ /dev/null @@ -1,2 +0,0 @@ -noinst_HEADERS += \ - include/linux/if_link.h diff --git a/include/linux/if_link.h b/include/linux/if_link.h deleted file mode 100644 index 55d99e46..00000000 --- a/include/linux/if_link.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __LINUX_IF_LINK_WRAPPER_H -#define __LINUX_IF_LINK_WRAPPER_H 1 - -#include - -#ifdef HAVE_RTNL_LINK_STATS64 -#include_next -#else /* !HAVE_RTNL_LINK_STATS64 */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19) -#include_next -#else -/* Before 2.6.19 there was no . Instead all of the types now - * declared there were in . Unfortunately from 2.6.18 - * conflicts badly enough with to break the userspace build. All - * we really need from is struct rtnl_link_stats64, which in - * turn only really needs __u64. */ -#include -#include -#endif /* kernel < 2.6.19 */ - -/* The main device statistics structure */ -struct rtnl_link_stats64 { - __u64 rx_packets; /* total packets received */ - __u64 tx_packets; /* total packets transmitted */ - __u64 rx_bytes; /* total bytes received */ - __u64 tx_bytes; /* total bytes transmitted */ - __u64 rx_errors; /* bad packets received */ - __u64 tx_errors; /* packet transmit problems */ - __u64 rx_dropped; /* no space in linux buffers */ - __u64 tx_dropped; /* no space available in linux */ - __u64 multicast; /* multicast packets received */ - __u64 collisions; - - /* detailed rx_errors: */ - __u64 rx_length_errors; - __u64 rx_over_errors; /* receiver ring buff overflow */ - __u64 rx_crc_errors; /* recved pkt with crc error */ - __u64 rx_frame_errors; /* recv'd frame alignment error */ - __u64 rx_fifo_errors; /* recv'r fifo overrun */ - __u64 rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - __u64 tx_aborted_errors; - __u64 tx_carrier_errors; - __u64 tx_fifo_errors; - __u64 tx_heartbeat_errors; - __u64 tx_window_errors; - - /* for cslip etc */ - __u64 rx_compressed; - __u64 tx_compressed; -}; -#endif /* !HAVE_RTNL_LINK_STATS64 */ - -#endif diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h index 5687792d..8ed1c7f4 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -51,7 +51,6 @@ #include #endif -#include #include /* datapaths. */ @@ -136,6 +135,17 @@ struct ovs_dp_stats { uint64_t n_flows; /* Number of flows present */ }; +struct ovs_vport_stats { + uint64_t rx_packets; /* total packets received */ + uint64_t tx_packets; /* total packets transmitted */ + uint64_t rx_bytes; /* total bytes received */ + uint64_t tx_bytes; /* total bytes transmitted */ + uint64_t rx_errors; /* bad packets received */ + uint64_t tx_errors; /* packet transmit problems */ + uint64_t rx_dropped; /* no space in linux buffers */ + int64_t tx_dropped; /* no space available in linux */ +}; + /* Logical ports. */ #define OVSP_LOCAL ((uint16_t)0) @@ -219,7 +229,7 @@ enum ovs_vport_cmd { * @OVS_VPORT_ATTR_NAME: Name of vport. For a vport based on a network device * this is the name of the network device. Maximum length %IFNAMSIZ-1 bytes * plus a null terminator. - * @OVS_VPORT_ATTR_STATS: A &struct rtnl_link_stats64 giving statistics for + * @OVS_VPORT_ATTR_STATS: A &struct ovs_vport_stats giving statistics for * packets sent or received through the vport. * @OVS_VPORT_ATTR_ADDRESS: A 6-byte Ethernet address for the vport. * @OVS_VPORT_ATTR_IFINDEX: ifindex of the underlying network device, if any. @@ -247,7 +257,7 @@ enum ovs_vport_attr { OVS_VPORT_ATTR_PORT_NO, /* port number within datapath */ OVS_VPORT_ATTR_TYPE, /* 32-bit OVS_VPORT_TYPE_* constant. */ OVS_VPORT_ATTR_NAME, /* string name, up to IFNAMSIZ bytes long */ - OVS_VPORT_ATTR_STATS, /* struct rtnl_link_stats64 */ + OVS_VPORT_ATTR_STATS, /* struct ovs_vport_stats */ OVS_VPORT_ATTR_ADDRESS, /* hardware address */ OVS_VPORT_ATTR_OPTIONS, /* nested attributes, varies by vport type */ OVS_VPORT_ATTR_IFINDEX, /* 32-bit ifindex of backing netdev */ diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 9533e148..3d081aab 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -463,12 +463,6 @@ dpif_linux_port_query__(const struct dpif *dpif, uint32_t port_no, dpif_port->name = xstrdup(reply.name); dpif_port->type = xstrdup(netdev_vport_get_netdev_type(&reply)); dpif_port->port_no = reply.port_no; - if (reply.stats) { - netdev_stats_from_rtnl_link_stats64(&dpif_port->stats, - reply.stats); - } else { - memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats); - } ofpbuf_delete(buf); } return error; @@ -564,11 +558,6 @@ dpif_linux_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_, dpif_port->name = (char *) vport.name; dpif_port->type = (char *) netdev_vport_get_netdev_type(&vport); dpif_port->port_no = vport.port_no; - if (vport.stats) { - netdev_stats_from_rtnl_link_stats64(&dpif_port->stats, vport.stats); - } else { - memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats); - } return 0; } @@ -1231,8 +1220,8 @@ dpif_linux_vport_from_ofpbuf(struct dpif_linux_vport *vport, [OVS_VPORT_ATTR_TYPE] = { .type = NL_A_U32 }, [OVS_VPORT_ATTR_NAME] = { .type = NL_A_STRING, .max_len = IFNAMSIZ }, [OVS_VPORT_ATTR_STATS] = { .type = NL_A_UNSPEC, - .min_len = sizeof(struct rtnl_link_stats64), - .max_len = sizeof(struct rtnl_link_stats64), + .min_len = sizeof(struct ovs_vport_stats), + .max_len = sizeof(struct ovs_vport_stats), .optional = true }, [OVS_VPORT_ATTR_ADDRESS] = { .type = NL_A_UNSPEC, .min_len = ETH_ADDR_LEN, diff --git a/lib/dpif-linux.h b/lib/dpif-linux.h index c673beeb..727a9e52 100644 --- a/lib/dpif-linux.h +++ b/lib/dpif-linux.h @@ -34,7 +34,7 @@ struct dpif_linux_vport { /* Attributes. */ const char *name; /* OVS_VPORT_ATTR_NAME. */ - const struct rtnl_link_stats64 *stats; /* OVS_VPORT_ATTR_STATS. */ + const struct ovs_vport_stats *stats; /* OVS_VPORT_ATTR_STATS. */ const uint8_t *address; /* OVS_VPORT_ATTR_ADDRESS. */ const struct nlattr *options; /* OVS_VPORT_ATTR_OPTIONS. */ size_t options_len; diff --git a/lib/dpif.c b/lib/dpif.c index 8cf7cfe4..ad143c8e 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -469,7 +469,6 @@ dpif_port_clone(struct dpif_port *dst, const struct dpif_port *src) dst->name = xstrdup(src->name); dst->type = xstrdup(src->type); dst->port_no = src->port_no; - dst->stats = src->stats; } /* Frees memory allocated to members of 'dpif_port'. diff --git a/lib/dpif.h b/lib/dpif.h index 1f352065..c01010db 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -72,7 +72,6 @@ struct dpif_port { char *name; /* Network device name, e.g. "eth0". */ char *type; /* Network device type, e.g. "system". */ uint32_t port_no; /* Port number within datapath. */ - struct netdev_stats stats; /* Port statistics. */ }; void dpif_port_clone(struct dpif_port *, const struct dpif_port *); void dpif_port_destroy(struct dpif_port *); diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index fc61d452..ee3c5f52 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -115,9 +115,8 @@ enum { 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 + VALID_POLICING = 1 << 6, + VALID_HAVE_VPORT_STATS = 1 << 7 }; struct tap_state { @@ -369,8 +368,6 @@ struct netdev_dev_linux { struct in6_addr in6; int mtu; int carrier; - bool is_internal; /* Is this an openvswitch internal device? */ - bool is_tap; /* Is this a tuntap device? */ uint32_t kbits_rate; /* Policing data. */ uint32_t kbits_burst; bool have_vport_stats; @@ -1246,21 +1243,6 @@ check_for_working_netlink_stats(void) } } -/* Brings the 'is_internal' and 'is_tap' members of 'netdev_dev' up-to-date. */ -static void -netdev_linux_update_is_pseudo(struct netdev_dev_linux *netdev_dev) -{ - if (!(netdev_dev->cache_valid & VALID_IS_PSEUDO)) { - const char *name = netdev_dev_get_name(&netdev_dev->netdev_dev); - const char *type = netdev_dev_get_type(&netdev_dev->netdev_dev); - - netdev_dev->is_tap = !strcmp(type, "tap"); - netdev_dev->is_internal = (!netdev_dev->is_tap - && dpif_linux_is_internal_device(name)); - netdev_dev->cache_valid |= VALID_IS_PSEUDO; - } -} - static void swap_uint64(uint64_t *a, uint64_t *b) { @@ -1269,37 +1251,123 @@ swap_uint64(uint64_t *a, uint64_t *b) *b = tmp; } -/* Retrieves current device stats for 'netdev'. */ -static int -netdev_linux_get_stats(const struct netdev *netdev_, - struct netdev_stats *stats) +static void +get_stats_via_vport(const struct netdev *netdev_, + struct netdev_stats *stats) { struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev_)); - static int use_netlink_stats = -1; - int error; if (netdev_dev->have_vport_stats || !(netdev_dev->cache_valid & VALID_HAVE_VPORT_STATS)) { + int error; error = netdev_vport_get_stats(netdev_, stats); + if (error) { + VLOG_WARN_RL(&rl, "%s: obtaining netdev stats via vport failed %d", + netdev_get_name(netdev_), error); + } netdev_dev->have_vport_stats = !error; netdev_dev->cache_valid |= VALID_HAVE_VPORT_STATS; } +} - if (!netdev_dev->have_vport_stats) { - if (use_netlink_stats < 0) { - use_netlink_stats = check_for_working_netlink_stats(); +static int +netdev_linux_sys_get_stats(const struct netdev *netdev_, + struct netdev_stats *stats) +{ + static int use_netlink_stats = -1; + int error; + + 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); } - if (use_netlink_stats) { - int ifindex; + } else { + error = get_stats_via_proc(netdev_get_name(netdev_), stats); + } - error = get_ifindex(netdev_, &ifindex); - if (!error) { - error = get_stats_via_netlink(ifindex, stats); - } + if (error) { + VLOG_WARN_RL(&rl, "%s: linux-sys get stats failed %d", + netdev_get_name(netdev_), error); + } + return error; + +} + +/* Retrieves current device stats for 'netdev-linux'. */ +static int +netdev_linux_get_stats(const struct netdev *netdev_, + struct netdev_stats *stats) +{ + struct netdev_dev_linux *netdev_dev = + netdev_dev_linux_cast(netdev_get_dev(netdev_)); + struct netdev_stats dev_stats; + int error; + + get_stats_via_vport(netdev_, stats); + + error = netdev_linux_sys_get_stats(netdev_, &dev_stats); + + if (error) { + if (!netdev_dev->have_vport_stats) { + return error; } else { - error = get_stats_via_proc(netdev_get_name(netdev_), stats); + return 0; + } + } + + if (!netdev_dev->have_vport_stats) { + /* stats not available from OVS then use ioctl stats. */ + *stats = dev_stats; + } else { + stats->rx_errors += dev_stats.rx_errors; + stats->tx_errors += dev_stats.tx_errors; + stats->rx_dropped += dev_stats.rx_dropped; + stats->tx_dropped += dev_stats.tx_dropped; + stats->multicast += dev_stats.multicast; + stats->collisions += dev_stats.collisions; + stats->rx_length_errors += dev_stats.rx_length_errors; + stats->rx_over_errors += dev_stats.rx_over_errors; + stats->rx_crc_errors += dev_stats.rx_crc_errors; + stats->rx_frame_errors += dev_stats.rx_frame_errors; + stats->rx_fifo_errors += dev_stats.rx_fifo_errors; + stats->rx_missed_errors += dev_stats.rx_missed_errors; + stats->tx_aborted_errors += dev_stats.tx_aborted_errors; + stats->tx_carrier_errors += dev_stats.tx_carrier_errors; + stats->tx_fifo_errors += dev_stats.tx_fifo_errors; + stats->tx_heartbeat_errors += dev_stats.tx_heartbeat_errors; + stats->tx_window_errors += dev_stats.tx_window_errors; + } + return 0; +} + +/* Retrieves current device stats for 'netdev-tap' netdev or + * netdev-internal. */ +static int +netdev_pseudo_get_stats(const struct netdev *netdev_, + struct netdev_stats *stats) +{ + struct netdev_dev_linux *netdev_dev = + netdev_dev_linux_cast(netdev_get_dev(netdev_)); + struct netdev_stats dev_stats; + int error; + + get_stats_via_vport(netdev_, stats); + + error = netdev_linux_sys_get_stats(netdev_, &dev_stats); + if (error) { + if (!netdev_dev->have_vport_stats) { + return error; + } else { + return 0; } } @@ -1309,9 +1377,8 @@ netdev_linux_get_stats(const struct netdev *netdev_, * 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->have_vport_stats && - (netdev_dev->is_internal || netdev_dev->is_tap)) { + if (!netdev_dev->have_vport_stats) { + *stats = dev_stats; swap_uint64(&stats->rx_packets, &stats->tx_packets); swap_uint64(&stats->rx_bytes, &stats->tx_bytes); swap_uint64(&stats->rx_errors, &stats->tx_errors); @@ -1327,9 +1394,17 @@ netdev_linux_get_stats(const struct netdev *netdev_, stats->tx_fifo_errors = 0; stats->tx_heartbeat_errors = 0; stats->tx_window_errors = 0; - } + } else { + stats->rx_dropped += dev_stats.tx_dropped; + stats->tx_dropped += dev_stats.rx_dropped; - return error; + stats->rx_errors += dev_stats.tx_errors; + stats->tx_errors += dev_stats.rx_errors; + + stats->multicast += dev_stats.multicast; + stats->collisions += dev_stats.collisions; + } + return 0; } /* Stores the features supported by 'netdev' into each of '*current', @@ -2263,7 +2338,7 @@ netdev_linux_change_seq(const struct netdev *netdev) return netdev_dev_linux_cast(netdev_get_dev(netdev))->change_seq; } -#define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, SET_STATS) \ +#define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, GET_STATS, SET_STATS) \ { \ NAME, \ \ @@ -2296,7 +2371,7 @@ netdev_linux_change_seq(const struct netdev *netdev) netdev_linux_get_ifindex, \ netdev_linux_get_carrier, \ netdev_linux_set_miimon_interval, \ - netdev_linux_get_stats, \ + GET_STATS, \ SET_STATS, \ \ netdev_linux_get_features, \ @@ -2333,6 +2408,7 @@ const struct netdev_class netdev_linux_class = "system", netdev_linux_create, netdev_linux_enumerate, + netdev_linux_get_stats, NULL); /* set_stats */ const struct netdev_class netdev_tap_class = @@ -2340,6 +2416,7 @@ const struct netdev_class netdev_tap_class = "tap", netdev_linux_create_tap, NULL, /* enumerate */ + netdev_pseudo_get_stats, NULL); /* set_stats */ const struct netdev_class netdev_internal_class = @@ -2347,6 +2424,7 @@ const struct netdev_class netdev_internal_class = "internal", netdev_linux_create, NULL, /* enumerate */ + netdev_pseudo_get_stats, netdev_vport_set_stats); /* HTB traffic control class. */ @@ -3956,56 +4034,34 @@ tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes) return tc_bytes_to_ticks(Bps, MAX(burst_bytes, min_burst)); } -/* Public utility functions. */ - -#define COPY_NETDEV_STATS \ - 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 - /* Copies 'src' into 'dst', performing format conversion in the process. */ -void +static void netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst, const struct rtnl_link_stats *src) { - COPY_NETDEV_STATS; -} - -/* Copies 'src' into 'dst', performing format conversion in the process. */ -void -netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst, - const struct rtnl_link_stats64 *src) -{ - COPY_NETDEV_STATS; + 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; } -/* Copies 'src' into 'dst', performing format conversion in the process. */ -void -netdev_stats_to_rtnl_link_stats64(struct rtnl_link_stats64 *dst, - const struct netdev_stats *src) -{ - COPY_NETDEV_STATS; - dst->rx_compressed = 0; - dst->tx_compressed = 0; -} /* Utility functions. */ diff --git a/lib/netdev-linux.h b/lib/netdev-linux.h index d34a4401..c00a846b 100644 --- a/lib/netdev-linux.h +++ b/lib/netdev-linux.h @@ -19,6 +19,7 @@ #include #include +#include "openvswitch/datapath-protocol.h" /* These functions are Linux specific, so they should be used directly only by * Linux-specific code. */ @@ -26,14 +27,6 @@ struct netdev; struct netdev_stats; struct rtnl_link_stats; -struct rtnl_link_stats64; - -void netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst, - const struct rtnl_link_stats *src); -void netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst, - const struct rtnl_link_stats64 *src); -void netdev_stats_to_rtnl_link_stats64(struct rtnl_link_stats64 *dst, - const struct netdev_stats *src); int netdev_linux_ethtool_set_flag(struct netdev *netdev, uint32_t flag, const char *flag_name, bool enable); diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index cf475b24..d85d5284 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -361,6 +361,45 @@ netdev_vport_get_etheraddr(const struct netdev *netdev, return error; } +#define COPY_OVS_STATS \ + 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; + +/* Copies 'src' into 'dst', performing format conversion in the process. */ +static void +netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst, + const struct ovs_vport_stats *src) +{ + COPY_OVS_STATS + dst->multicast = 0; + dst->collisions = 0; + dst->rx_length_errors = 0; + dst->rx_over_errors = 0; + dst->rx_crc_errors = 0; + dst->rx_frame_errors = 0; + dst->rx_fifo_errors = 0; + dst->rx_missed_errors = 0; + dst->tx_aborted_errors = 0; + dst->tx_carrier_errors = 0; + dst->tx_fifo_errors = 0; + dst->tx_heartbeat_errors = 0; + dst->tx_window_errors = 0; +} + +/* Copies 'src' into 'dst', performing format conversion in the process. */ +static void +netdev_stats_to_ovs_vport_stats(struct ovs_vport_stats *dst, + const struct netdev_stats *src) +{ + COPY_OVS_STATS +} + int netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats) { @@ -376,7 +415,7 @@ netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats) return EOPNOTSUPP; } - netdev_stats_from_rtnl_link_stats64(stats, reply.stats); + netdev_stats_from_ovs_vport_stats(stats, reply.stats); ofpbuf_delete(buf); @@ -386,11 +425,11 @@ netdev_vport_get_stats(const struct netdev *netdev, struct netdev_stats *stats) int netdev_vport_set_stats(struct netdev *netdev, const struct netdev_stats *stats) { - struct rtnl_link_stats64 rtnl_stats; + struct ovs_vport_stats rtnl_stats; struct dpif_linux_vport vport; int err; - netdev_stats_to_rtnl_link_stats64(&rtnl_stats, stats); + netdev_stats_to_ovs_vport_stats(&rtnl_stats, stats); dpif_linux_vport_init(&vport); vport.cmd = OVS_VPORT_CMD_SET; diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4 index 7aaf67a2..c59d5d4c 100644 --- a/m4/openvswitch.m4 +++ b/m4/openvswitch.m4 @@ -46,25 +46,6 @@ AC_DEFUN([OVS_CHECK_NDEBUG], [ndebug=false]) AM_CONDITIONAL([NDEBUG], [test x$ndebug = xtrue])]) -dnl Checks for struct rtnl_link_stats64. -dnl -dnl (OVS checks for this structure in both kernel and userspace headers. This -dnl is not redundant, because the kernel and userspace builds have completely -dnl different include paths. It is possible for the kernel to have this -dnl structure but not userspace, and vice versa.) -AC_DEFUN([OVS_CHECK_RTNL_LINK_STATS64], - [AC_REQUIRE([OVS_CHECK_NETLINK]) - if test $HAVE_NETLINK = yes; then - AC_CHECK_MEMBER( - [struct rtnl_link_stats64.tx_packets], - [AC_DEFINE([HAVE_RTNL_LINK_STATS64], [1], - [Define to 1 if defines - struct rtnl_link_stats64.])], - [], [#include /* Provides sa_family_t. */ -#include -]) - fi]) - dnl Checks for Netlink support. AC_DEFUN([OVS_CHECK_NETLINK], [AC_CHECK_HEADER([linux/netlink.h], diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index 0e6c16fa..e724e745 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -367,6 +367,7 @@ show_dpif(struct dpif *dpif) struct dpif_port_dump dump; struct dpif_port dpif_port; struct ovs_dp_stats stats; + struct netdev *netdev; printf("%s:\n", dpif_name(dpif)); if (!dpif_get_dp_stats(dpif, &stats)) { @@ -381,7 +382,6 @@ show_dpif(struct dpif *dpif) printf("\tport %u: %s", dpif_port.port_no, dpif_port.name); if (strcmp(dpif_port.type, "system")) { - struct netdev *netdev; int error; printf (" (%s", dpif_port.type); @@ -418,29 +418,42 @@ show_dpif(struct dpif *dpif) putchar('\n'); if (print_statistics) { - const struct netdev_stats *s = &dpif_port.stats; + struct netdev_stats s; + int error; + + error = netdev_open(dpif_port.name, dpif_port.type, &netdev); + if (error) { + printf(", open failed (%s)", strerror(error)); + continue; + } + error = netdev_get_stats(netdev, &s); + if (error) { + printf(", could not retrieve stats (%s)", strerror(error)); + continue; + } - print_stat("\t\tRX packets:", s->rx_packets); - print_stat(" errors:", s->rx_errors); - print_stat(" dropped:", s->rx_dropped); - print_stat(" overruns:", s->rx_over_errors); - print_stat(" frame:", s->rx_frame_errors); + netdev_close(netdev); + print_stat("\t\tRX packets:", s.rx_packets); + print_stat(" errors:", s.rx_errors); + print_stat(" dropped:", s.rx_dropped); + print_stat(" overruns:", s.rx_over_errors); + print_stat(" frame:", s.rx_frame_errors); printf("\n"); - print_stat("\t\tTX packets:", s->tx_packets); - print_stat(" errors:", s->tx_errors); - print_stat(" dropped:", s->tx_dropped); - print_stat(" aborted:", s->tx_aborted_errors); - print_stat(" carrier:", s->tx_carrier_errors); + print_stat("\t\tTX packets:", s.tx_packets); + print_stat(" errors:", s.tx_errors); + print_stat(" dropped:", s.tx_dropped); + print_stat(" aborted:", s.tx_aborted_errors); + print_stat(" carrier:", s.tx_carrier_errors); printf("\n"); - print_stat("\t\tcollisions:", s->collisions); + print_stat("\t\tcollisions:", s.collisions); printf("\n"); - print_stat("\t\tRX bytes:", s->rx_bytes); - print_human_size(s->rx_bytes); - print_stat(" TX bytes:", s->tx_bytes); - print_human_size(s->tx_bytes); + print_stat("\t\tRX bytes:", s.rx_bytes); + print_human_size(s.rx_bytes); + print_stat(" TX bytes:", s.tx_bytes); + print_human_size(s.tx_bytes); printf("\n"); } } -- 2.30.2