mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 14:25:26 +00:00
Update fake bond devices' statistics with the sum of bond slaves' stats.
Needed by XAPI to accurately report bond statistics. Ugh. Bug NIC-63.
This commit is contained in:
@@ -50,6 +50,8 @@
|
||||
#include "netlink.h"
|
||||
#include "ofpbuf.h"
|
||||
#include "openflow/openflow.h"
|
||||
#include "openvswitch/internal_dev.h"
|
||||
#include "openvswitch/gre.h"
|
||||
#include "packets.h"
|
||||
#include "poll-loop.h"
|
||||
#include "rtnetlink.h"
|
||||
@@ -79,7 +81,7 @@ enum {
|
||||
VALID_IN6 = 1 << 3,
|
||||
VALID_MTU = 1 << 4,
|
||||
VALID_CARRIER = 1 << 5,
|
||||
VALID_IS_INTERNAL = 1 << 6
|
||||
VALID_IS_PSEUDO = 1 << 6 /* Represents is_internal and is_tap. */
|
||||
};
|
||||
|
||||
struct tap_state {
|
||||
@@ -96,13 +98,16 @@ struct netdev_dev_linux {
|
||||
struct shash_node *shash_node;
|
||||
unsigned int cache_valid;
|
||||
|
||||
/* The following are figured out "on demand" only. They are only valid
|
||||
* when the corresponding VALID_* bit in 'cache_valid' is set. */
|
||||
int ifindex;
|
||||
uint8_t etheraddr[ETH_ADDR_LEN];
|
||||
struct in_addr address, netmask;
|
||||
struct in6_addr in6;
|
||||
int mtu;
|
||||
int carrier;
|
||||
bool is_internal;
|
||||
bool is_internal; /* Is this an openvswitch internal device? */
|
||||
bool is_tap; /* Is this a tuntap device? */
|
||||
|
||||
union {
|
||||
struct tap_state tap;
|
||||
@@ -899,6 +904,35 @@ 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 = false;
|
||||
if (!netdev_dev->is_tap) {
|
||||
struct ethtool_drvinfo drvinfo;
|
||||
int error;
|
||||
|
||||
memset(&drvinfo, 0, sizeof drvinfo);
|
||||
error = netdev_linux_do_ethtool(name,
|
||||
(struct ethtool_cmd *)&drvinfo,
|
||||
ETHTOOL_GDRVINFO,
|
||||
"ETHTOOL_GDRVINFO");
|
||||
|
||||
if (!error && !strcmp(drvinfo.driver, "openvswitch")) {
|
||||
netdev_dev->is_internal = true;
|
||||
}
|
||||
}
|
||||
|
||||
netdev_dev->cache_valid |= VALID_IS_PSEUDO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Retrieves current device stats for 'netdev'.
|
||||
*
|
||||
* XXX All of the members of struct netdev_stats are 64 bits wide, but on
|
||||
@@ -916,26 +950,7 @@ netdev_linux_get_stats(const struct netdev *netdev_,
|
||||
|
||||
COVERAGE_INC(netdev_get_stats);
|
||||
|
||||
if (!(netdev_dev->cache_valid & VALID_IS_INTERNAL)) {
|
||||
netdev_dev->is_internal = !strcmp(netdev_get_type(netdev_), "tap");
|
||||
if (!netdev_dev->is_internal) {
|
||||
struct ethtool_drvinfo drvinfo;
|
||||
|
||||
memset(&drvinfo, 0, sizeof drvinfo);
|
||||
error = netdev_linux_do_ethtool(netdev_get_name(netdev_),
|
||||
(struct ethtool_cmd *)&drvinfo,
|
||||
ETHTOOL_GDRVINFO,
|
||||
"ETHTOOL_GDRVINFO");
|
||||
|
||||
if (!error) {
|
||||
netdev_dev->is_internal = !strcmp(drvinfo.driver,
|
||||
"openvswitch");
|
||||
}
|
||||
}
|
||||
|
||||
netdev_dev->cache_valid |= VALID_IS_INTERNAL;
|
||||
}
|
||||
|
||||
netdev_linux_update_is_pseudo(netdev_dev);
|
||||
if (netdev_dev->is_internal) {
|
||||
collect_stats = &raw_stats;
|
||||
}
|
||||
@@ -958,7 +973,7 @@ netdev_linux_get_stats(const struct netdev *netdev_,
|
||||
* 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. */
|
||||
if (!error && netdev_dev->is_internal) {
|
||||
if (!error && (netdev_dev->is_internal || netdev_dev->is_tap)) {
|
||||
stats->rx_packets = raw_stats.tx_packets;
|
||||
stats->tx_packets = raw_stats.rx_packets;
|
||||
stats->rx_bytes = raw_stats.tx_bytes;
|
||||
@@ -985,6 +1000,41 @@ netdev_linux_get_stats(const struct netdev *netdev_,
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
netdev_linux_set_stats(struct netdev *netdev,
|
||||
const struct netdev_stats *stats)
|
||||
{
|
||||
struct netdev_dev_linux *netdev_dev =
|
||||
netdev_dev_linux_cast(netdev_get_dev(netdev));
|
||||
struct internal_dev_stats dp_dev_stats;
|
||||
struct ifreq ifr;
|
||||
|
||||
/* We must reject this call if 'netdev' is not an Open vSwitch internal
|
||||
* port, because the ioctl that we are about to execute is in the "device
|
||||
* private ioctls" range, which means that executing it on a device that
|
||||
* is not the type we expect could do any random thing.
|
||||
*
|
||||
* (Amusingly, these ioctl numbers are commented "THESE IOCTLS ARE
|
||||
* _DEPRECATED_ AND WILL DISAPPEAR IN 2.5.X" in linux/sockios.h. I guess
|
||||
* DaveM is a little behind on that.) */
|
||||
netdev_linux_update_is_pseudo(netdev_dev);
|
||||
if (!netdev_dev->is_internal) {
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* This actually only sets the *offset* that the dp_dev applies, but in our
|
||||
* usage for fake bond devices the dp_dev never has any traffic of it own
|
||||
* so it has the same effect. */
|
||||
dp_dev_stats.rx_packets = stats->rx_packets;
|
||||
dp_dev_stats.rx_bytes = stats->rx_bytes;
|
||||
dp_dev_stats.tx_packets = stats->tx_packets;
|
||||
dp_dev_stats.tx_bytes = stats->tx_bytes;
|
||||
ifr.ifr_data = (void *) &dp_dev_stats;
|
||||
return netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr,
|
||||
INTERNAL_DEV_SET_STATS,
|
||||
"INTERNAL_DEV_SET_STATS");
|
||||
}
|
||||
|
||||
/* Stores the features supported by 'netdev' into each of '*current',
|
||||
* '*advertised', '*supported', and '*peer' that are non-null. Each value is a
|
||||
* bitmap of "enum ofp_port_features" bits, in host byte order. Returns 0 if
|
||||
@@ -1668,6 +1718,7 @@ const struct netdev_class netdev_linux_class = {
|
||||
netdev_linux_get_ifindex,
|
||||
netdev_linux_get_carrier,
|
||||
netdev_linux_get_stats,
|
||||
netdev_linux_set_stats,
|
||||
|
||||
netdev_linux_get_features,
|
||||
netdev_linux_set_advertisements,
|
||||
@@ -1716,6 +1767,7 @@ const struct netdev_class netdev_tap_class = {
|
||||
netdev_linux_get_ifindex,
|
||||
netdev_linux_get_carrier,
|
||||
netdev_linux_get_stats,
|
||||
NULL, /* set_stats */
|
||||
|
||||
netdev_linux_get_features,
|
||||
netdev_linux_set_advertisements,
|
||||
@@ -1764,6 +1816,7 @@ const struct netdev_class netdev_patch_class = {
|
||||
netdev_linux_get_ifindex,
|
||||
netdev_linux_get_carrier,
|
||||
netdev_linux_get_stats,
|
||||
NULL, /* set_stats */
|
||||
|
||||
netdev_linux_get_features,
|
||||
netdev_linux_set_advertisements,
|
||||
|
Reference in New Issue
Block a user