X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=2fa05b66e3e2162f346a0369d1e2c641a3a15c76;hb=1e82e503c5358f8dce9eb2105448f0ec894d57bc;hp=b8d24ed999cad953785f8862d8aa544812221c43;hpb=2158888d8d8f3b4c00dcf979390a19fa7fcf7942;p=openvswitch diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index b8d24ed9..2fa05b66 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -88,6 +88,7 @@ enum { struct tap_state { int fd; + bool opened; }; struct netdev_dev_linux { @@ -371,8 +372,15 @@ netdev_linux_open(struct netdev_dev *netdev_dev_, int ethertype, goto error; } - if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap")) { + if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") && + !netdev_dev->state.tap.opened) { + + /* We assume that the first user of the tap device is the primary user + * and give them the tap FD. Subsequent users probably just expect + * this to be a system device so open it normally to avoid send/receive + * directions appearing to be reversed. */ netdev->fd = netdev_dev->state.tap.fd; + netdev_dev->state.tap.opened = true; } else if (ethertype != NETDEV_ETH_TYPE_NONE) { struct sockaddr_ll sll; int protocol; @@ -779,6 +787,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'. * * XXX All of the members of struct netdev_stats are 64 bits wide, but on @@ -791,16 +807,9 @@ netdev_linux_get_stats(const struct netdev *netdev_, netdev_dev_linux_cast(netdev_get_dev(netdev_)); static int use_netlink_stats = -1; int error; - struct netdev_stats raw_stats; - struct netdev_stats *collect_stats = 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) { use_netlink_stats = check_for_working_netlink_stats(); } @@ -809,27 +818,22 @@ netdev_linux_get_stats(const struct netdev *netdev_, error = get_ifindex(netdev_, &ifindex); if (!error) { - error = get_stats_via_netlink(ifindex, collect_stats); + error = get_stats_via_netlink(ifindex, stats); } } 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 * 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. */ + netdev_linux_update_is_pseudo(netdev_dev); 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; - stats->tx_bytes = raw_stats.rx_bytes; - 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; + swap_uint64(&stats->rx_packets, &stats->tx_packets); + swap_uint64(&stats->rx_bytes, &stats->tx_bytes); + swap_uint64(&stats->rx_errors, &stats->tx_errors); + swap_uint64(&stats->rx_dropped, &stats->tx_dropped); stats->rx_length_errors = 0; stats->rx_over_errors = 0; stats->rx_crc_errors = 0; @@ -1163,7 +1167,7 @@ netdev_linux_remove_policing(struct netdev *netdev) error = nl_sock_transact(rtnl_sock, &request, &reply); ofpbuf_uninit(&request); ofpbuf_delete(reply); - if (error && error != ENOENT) { + if (error && error != ENOENT && error != EINVAL) { VLOG_WARN_RL(&rl, "%s: removing policing failed: %s", netdev_name, strerror(error)); return error;