2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-29 13:27:59 +00:00

netdev-linux: Fix tap device stats.

For tap and internal devices we swap the transmit and receive stats
to appear consistent with other devices.  However, the check whether
to store the stats in a temporary location before the swap did not
include tap devices, which lead to the use of uninitialized memory
when the swap occured.
This commit is contained in:
Jesse Gross 2010-06-01 14:20:46 -07:00
parent b9b0865ac2
commit 92df599cb2

View File

@ -779,6 +779,14 @@ netdev_linux_update_is_pseudo(struct netdev_dev_linux *netdev_dev)
} }
} }
static void
swap_uint64(uint64_t *a, uint64_t *b)
{
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
/* Retrieves current device stats for 'netdev'. /* Retrieves current device stats for 'netdev'.
* *
* XXX All of the members of struct netdev_stats are 64 bits wide, but on * XXX All of the members of struct netdev_stats are 64 bits wide, but on
@ -791,16 +799,9 @@ netdev_linux_get_stats(const struct netdev *netdev_,
netdev_dev_linux_cast(netdev_get_dev(netdev_)); netdev_dev_linux_cast(netdev_get_dev(netdev_));
static int use_netlink_stats = -1; static int use_netlink_stats = -1;
int error; int error;
struct netdev_stats raw_stats;
struct netdev_stats *collect_stats = stats;
COVERAGE_INC(netdev_get_stats); COVERAGE_INC(netdev_get_stats);
netdev_linux_update_is_pseudo(netdev_dev);
if (netdev_dev->is_internal) {
collect_stats = &raw_stats;
}
if (use_netlink_stats < 0) { if (use_netlink_stats < 0) {
use_netlink_stats = check_for_working_netlink_stats(); use_netlink_stats = check_for_working_netlink_stats();
} }
@ -809,27 +810,22 @@ netdev_linux_get_stats(const struct netdev *netdev_,
error = get_ifindex(netdev_, &ifindex); error = get_ifindex(netdev_, &ifindex);
if (!error) { if (!error) {
error = get_stats_via_netlink(ifindex, collect_stats); error = get_stats_via_netlink(ifindex, stats);
} }
} else { } else {
error = get_stats_via_proc(netdev_get_name(netdev_), collect_stats); error = get_stats_via_proc(netdev_get_name(netdev_), stats);
} }
/* If this port is an internal port then the transmit and receive 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 * 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 * one sending the data, not a remote computer. For consistency, we swap
* them back here. */ * them back here. */
netdev_linux_update_is_pseudo(netdev_dev);
if (!error && (netdev_dev->is_internal || netdev_dev->is_tap)) { if (!error && (netdev_dev->is_internal || netdev_dev->is_tap)) {
stats->rx_packets = raw_stats.tx_packets; swap_uint64(&stats->rx_packets, &stats->tx_packets);
stats->tx_packets = raw_stats.rx_packets; swap_uint64(&stats->rx_bytes, &stats->tx_bytes);
stats->rx_bytes = raw_stats.tx_bytes; swap_uint64(&stats->rx_errors, &stats->tx_errors);
stats->tx_bytes = raw_stats.rx_bytes; swap_uint64(&stats->rx_dropped, &stats->tx_dropped);
stats->rx_errors = raw_stats.tx_errors;
stats->tx_errors = raw_stats.rx_errors;
stats->rx_dropped = raw_stats.tx_dropped;
stats->tx_dropped = raw_stats.rx_dropped;
stats->multicast = raw_stats.multicast;
stats->collisions = raw_stats.collisions;
stats->rx_length_errors = 0; stats->rx_length_errors = 0;
stats->rx_over_errors = 0; stats->rx_over_errors = 0;
stats->rx_crc_errors = 0; stats->rx_crc_errors = 0;