X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=166728262b81f4b6e80ac1e54ae94c4b3de7d9d2;hb=82d6256ac9f800f8cbe06cf2be41a7b76ab8b322;hp=3a17a8f5d622274f57ca47331a4a78bdbb07f793;hpb=9fe3b9a2eeace9689def807e78e35c79e4b1814b;p=openvswitch diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 3a17a8f5..16672826 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -15,6 +15,9 @@ */ #include + +#include "netdev-linux.h" + #include #include #include @@ -64,7 +67,8 @@ #include "rtnetlink-link.h" #include "socket-util.h" #include "shash.h" -#include "svec.h" +#include "sset.h" +#include "timer.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(netdev_linux); @@ -342,6 +346,11 @@ struct netdev_dev_linux { struct shash_node *shash_node; unsigned int cache_valid; + unsigned int change_seq; + + bool miimon; /* Link status of last poll. */ + long long int miimon_interval; /* Miimon Poll rate. Disabled if <= 0. */ + struct timer miimon_timer; /* The following are figured out "on demand" only. They are only valid * when the corresponding VALID_* bit in 'cache_valid' is set. */ @@ -368,21 +377,12 @@ struct netdev_linux { int fd; }; -/* An AF_INET socket (used for ioctl operations). */ -static int af_inet_sock = -1; +/* Sockets used for ioctl operations. */ +static int af_inet_sock = -1; /* AF_INET, SOCK_DGRAM. */ /* A Netlink routing socket that is not subscribed to any multicast groups. */ static struct nl_sock *rtnl_sock; -struct netdev_linux_notifier { - struct netdev_notifier notifier; - struct list node; -}; - -static struct shash netdev_linux_notifiers = - SHASH_INITIALIZER(&netdev_linux_notifiers); -static struct rtnetlink_notifier netdev_linux_poll_notifier; - /* This is set pretty low because we probably won't learn anything from the * additional log messages. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); @@ -407,6 +407,9 @@ static int set_etheraddr(const char *netdev_name, int hwaddr_family, const uint8_t[ETH_ADDR_LEN]); static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats); static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats); +static int af_packet_sock(void); +static void netdev_linux_miimon_run(void); +static void netdev_linux_miimon_wait(void); static bool is_netdev_linux_class(const struct netdev_class *netdev_class) @@ -461,12 +464,24 @@ static void netdev_linux_run(void) { rtnetlink_link_notifier_run(); + netdev_linux_miimon_run(); } static void netdev_linux_wait(void) { rtnetlink_link_notifier_wait(); + netdev_linux_miimon_wait(); +} + +static void +netdev_dev_linux_changed(struct netdev_dev_linux *dev) +{ + dev->change_seq++; + if (!dev->change_seq) { + dev->change_seq++; + } + dev->cache_valid = 0; } static void @@ -482,7 +497,7 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, if (is_netdev_linux_class(netdev_class)) { dev = netdev_dev_linux_cast(base_dev); - dev->cache_valid = 0; + netdev_dev_linux_changed(dev); } } } else { @@ -493,7 +508,7 @@ netdev_linux_cache_cb(const struct rtnetlink_link_change *change, netdev_dev_get_devices(&netdev_linux_class, &device_shash); SHASH_FOR_EACH (node, &device_shash) { dev = node->data; - dev->cache_valid = 0; + netdev_dev_linux_changed(dev); } shash_destroy(&device_shash); } @@ -523,7 +538,8 @@ netdev_linux_create(const struct netdev_class *class, cache_notifier_refcount++; netdev_dev = xzalloc(sizeof *netdev_dev); - netdev_dev_init(&netdev_dev->netdev_dev, name, class); + netdev_dev->change_seq = 1; + netdev_dev_init(&netdev_dev->netdev_dev, name, args, class); *netdev_devp = &netdev_dev->netdev_dev; return 0; @@ -563,7 +579,7 @@ netdev_linux_create_tap(const struct netdev_class *class OVS_UNUSED, /* Create tap device. */ ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); if (ioctl(state->fd, TUNSETIFF, &ifr) == -1) { VLOG_WARN("%s: creating tap device failed: %s", name, strerror(errno)); @@ -577,7 +593,7 @@ netdev_linux_create_tap(const struct netdev_class *class OVS_UNUSED, goto error; } - netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_tap_class); + netdev_dev_init(&netdev_dev->netdev_dev, name, args, &netdev_tap_class); *netdev_devp = &netdev_dev->netdev_dev; return 0; @@ -669,7 +685,8 @@ netdev_linux_open(struct netdev_dev *netdev_dev_, int ethertype, protocol = (ethertype == NETDEV_ETH_TYPE_ANY ? ETH_P_ALL : ethertype == NETDEV_ETH_TYPE_802_2 ? ETH_P_802_2 : ethertype); - netdev->fd = socket(PF_PACKET, SOCK_RAW, htons(protocol)); + netdev->fd = socket(PF_PACKET, SOCK_RAW, + (OVS_FORCE int) htons(protocol)); if (netdev->fd < 0) { error = errno; goto error; @@ -729,9 +746,9 @@ netdev_linux_close(struct netdev *netdev_) free(netdev); } -/* Initializes 'svec' with a list of the names of all known network devices. */ +/* Initializes 'sset' with a list of the names of all known network devices. */ static int -netdev_linux_enumerate(struct svec *svec) +netdev_linux_enumerate(struct sset *sset) { struct if_nameindex *names; @@ -740,7 +757,7 @@ netdev_linux_enumerate(struct svec *svec) size_t i; for (i = 0; names[i].if_name != NULL; i++) { - svec_add(svec, names[i].if_name); + sset_add(sset, names[i].if_name); } if_freenameindex(names); return 0; @@ -820,15 +837,54 @@ static int netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + for (;;) { + ssize_t retval; - /* XXX should support sending even if 'ethertype' was NETDEV_ETH_TYPE_NONE. - */ - if (netdev->fd < 0) { - return EPIPE; - } + if (netdev->fd < 0) { + /* Use our AF_PACKET socket to send to this device. */ + struct sockaddr_ll sll; + struct msghdr msg; + struct iovec iov; + int ifindex; + int error; + int sock; + + sock = af_packet_sock(); + if (sock < 0) { + return sock; + } + + error = get_ifindex(netdev_, &ifindex); + if (error) { + return error; + } + + /* We don't bother setting most fields in sockaddr_ll because the + * kernel ignores them for SOCK_RAW. */ + memset(&sll, 0, sizeof sll); + sll.sll_family = AF_PACKET; + sll.sll_ifindex = ifindex; + + iov.iov_base = (void *) data; + iov.iov_len = size; + + msg.msg_name = &sll; + msg.msg_namelen = sizeof sll; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + retval = sendmsg(sock, &msg, 0); + } else { + /* Use the netdev's own fd to send to this device. This is + * essential for tap devices, because packets sent to a tap device + * with an AF_PACKET socket will loop back to be *received* again + * on the tap device. */ + retval = write(netdev->fd, data, size); + } - for (;;) { - ssize_t retval = write(netdev->fd, data, size); if (retval < 0) { /* The Linux AF_PACKET implementation never blocks waiting for room * for packets, instead returning ENOBUFS. Translate this into @@ -960,6 +1016,11 @@ netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier) char *fn = NULL; int fd = -1; + if (netdev_dev->miimon_interval > 0) { + *carrier = netdev_dev->miimon; + return 0; + } + if (!(netdev_dev->cache_valid & VALID_CARRIER)) { char line[8]; int retval; @@ -1010,36 +1071,34 @@ exit: } static int -netdev_linux_do_miimon(const struct netdev *netdev, int cmd, - const char *cmd_name, struct mii_ioctl_data *data) +netdev_linux_do_miimon(const char *name, int cmd, const char *cmd_name, + struct mii_ioctl_data *data) { struct ifreq ifr; int error; memset(&ifr, 0, sizeof ifr); memcpy(&ifr.ifr_data, data, sizeof *data); - error = netdev_linux_do_ioctl(netdev_get_name(netdev), - &ifr, cmd, cmd_name); + error = netdev_linux_do_ioctl(name, &ifr, cmd, cmd_name); memcpy(data, &ifr.ifr_data, sizeof *data); return error; } static int -netdev_linux_get_miimon(const struct netdev *netdev, bool *miimon) +netdev_linux_get_miimon(const char *name, bool *miimon) { - const char *name = netdev_get_name(netdev); struct mii_ioctl_data data; int error; *miimon = false; memset(&data, 0, sizeof data); - error = netdev_linux_do_miimon(netdev, SIOCGMIIPHY, "SIOCGMIIPHY", &data); + error = netdev_linux_do_miimon(name, SIOCGMIIPHY, "SIOCGMIIPHY", &data); if (!error) { /* data.phy_id is filled out by previous SIOCGMIIPHY miimon call. */ data.reg_num = MII_BMSR; - error = netdev_linux_do_miimon(netdev, SIOCGMIIREG, "SIOCGMIIREG", + error = netdev_linux_do_miimon(name, SIOCGMIIREG, "SIOCGMIIREG", &data); if (!error) { @@ -1069,6 +1128,69 @@ netdev_linux_get_miimon(const struct netdev *netdev, bool *miimon) return error; } +static int +netdev_linux_set_miimon_interval(struct netdev *netdev_, + long long int interval) +{ + struct netdev_dev_linux *netdev_dev; + + netdev_dev = netdev_dev_linux_cast(netdev_get_dev(netdev_)); + + interval = interval > 0 ? MAX(interval, 100) : 0; + if (netdev_dev->miimon_interval != interval) { + netdev_dev->miimon_interval = interval; + timer_set_expired(&netdev_dev->miimon_timer); + } + + return 0; +} + +static void +netdev_linux_miimon_run(void) +{ + struct shash device_shash; + struct shash_node *node; + + shash_init(&device_shash); + netdev_dev_get_devices(&netdev_linux_class, &device_shash); + SHASH_FOR_EACH (node, &device_shash) { + struct netdev_dev_linux *dev = node->data; + bool miimon; + + if (dev->miimon_interval <= 0 || !timer_expired(&dev->miimon_timer)) { + continue; + } + + netdev_linux_get_miimon(dev->netdev_dev.name, &miimon); + if (miimon != dev->miimon) { + dev->miimon = miimon; + netdev_dev_linux_changed(dev); + } + + timer_set_duration(&dev->miimon_timer, dev->miimon_interval); + } + + shash_destroy(&device_shash); +} + +static void +netdev_linux_miimon_wait(void) +{ + struct shash device_shash; + struct shash_node *node; + + shash_init(&device_shash); + netdev_dev_get_devices(&netdev_linux_class, &device_shash); + SHASH_FOR_EACH (node, &device_shash) { + struct netdev_dev_linux *dev = node->data; + + if (dev->miimon_interval > 0) { + timer_wait(&dev->miimon_timer); + } + } + shash_destroy(&device_shash); +} + /* Check whether we can we use RTM_GETLINK to get network device statistics. * In pre-2.6.19 kernels, this was only available if wireless extensions were * enabled. */ @@ -1115,9 +1237,9 @@ 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; + uint64_t tmp = *a; + *a = *b; + *b = tmp; } /* Retrieves current device stats for 'netdev'. */ @@ -1510,14 +1632,14 @@ netdev_linux_set_policing(struct netdev *netdev, static int netdev_linux_get_qos_types(const struct netdev *netdev OVS_UNUSED, - struct svec *types) + struct sset *types) { const struct tc_ops **opsp; for (opsp = tcs; *opsp != NULL; opsp++) { const struct tc_ops *ops = *opsp; if (ops->tc_install && ops->ovs_name[0] != '\0') { - svec_add(types, ops->ovs_name); + sset_add(types, ops->ovs_name); } } return 0; @@ -1924,7 +2046,7 @@ do_set_addr(struct netdev *netdev, int ioctl_nr, const char *ioctl_name, struct in_addr addr) { struct ifreq ifr; - strncpy(ifr.ifr_name, netdev_get_name(netdev), sizeof ifr.ifr_name); + ovs_strzcpy(ifr.ifr_name, netdev_get_name(netdev), sizeof ifr.ifr_name); make_in4_sockaddr(&ifr.ifr_addr, addr); return netdev_linux_do_ioctl(netdev_get_name(netdev), &ifr, ioctl_nr, @@ -1971,7 +2093,7 @@ netdev_linux_get_next_hop(const struct in_addr *host, struct in_addr *next_hop, while (fgets(line, sizeof line, stream)) { if (++ln >= 2) { char iface[17]; - uint32_t dest, gateway, mask; + ovs_be32 dest, gateway, mask; int refcnt, metric, mtu; unsigned int flags, use, window, irtt; @@ -2038,20 +2160,21 @@ netdev_linux_get_status(const struct netdev *netdev, struct shash *sh) * ENXIO indicates that there is not ARP table entry for 'ip' on 'netdev'. */ static int netdev_linux_arp_lookup(const struct netdev *netdev, - uint32_t ip, uint8_t mac[ETH_ADDR_LEN]) + ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN]) { struct arpreq r; struct sockaddr_in sin; int retval; memset(&r, 0, sizeof r); + memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ip; sin.sin_port = 0; memcpy(&r.arp_pa, &sin, sizeof sin); r.arp_ha.sa_family = ARPHRD_ETHER; r.arp_flags = 0; - strncpy(r.arp_dev, netdev_get_name(netdev), sizeof r.arp_dev); + ovs_strzcpy(r.arp_dev, netdev_get_name(netdev), sizeof r.arp_dev); COVERAGE_INC(netdev_arp_lookup); retval = ioctl(af_inet_sock, SIOCGARP, &r) < 0 ? errno : 0; if (!retval) { @@ -2107,88 +2230,10 @@ netdev_linux_update_flags(struct netdev *netdev, enum netdev_flags off, return error; } -static void -poll_notify(struct list *list) -{ - struct netdev_linux_notifier *notifier; - LIST_FOR_EACH (notifier, node, list) { - struct netdev_notifier *n = ¬ifier->notifier; - n->cb(n); - } -} - -static void -netdev_linux_poll_cb(const struct rtnetlink_link_change *change, - void *aux OVS_UNUSED) -{ - if (change) { - struct list *list = shash_find_data(&netdev_linux_notifiers, - change->ifname); - if (list) { - poll_notify(list); - } - } else { - struct shash_node *node; - SHASH_FOR_EACH (node, &netdev_linux_notifiers) { - poll_notify(node->data); - } - } -} - -static int -netdev_linux_poll_add(struct netdev *netdev, - void (*cb)(struct netdev_notifier *), void *aux, - struct netdev_notifier **notifierp) +static unsigned int +netdev_linux_change_seq(const struct netdev *netdev) { - const char *netdev_name = netdev_get_name(netdev); - struct netdev_linux_notifier *notifier; - struct list *list; - - if (shash_is_empty(&netdev_linux_notifiers)) { - int error; - error = rtnetlink_link_notifier_register(&netdev_linux_poll_notifier, - netdev_linux_poll_cb, NULL); - if (error) { - return error; - } - } - - list = shash_find_data(&netdev_linux_notifiers, netdev_name); - if (!list) { - list = xmalloc(sizeof *list); - list_init(list); - shash_add(&netdev_linux_notifiers, netdev_name, list); - } - - notifier = xmalloc(sizeof *notifier); - netdev_notifier_init(¬ifier->notifier, netdev, cb, aux); - list_push_back(list, ¬ifier->node); - *notifierp = ¬ifier->notifier; - return 0; -} - -static void -netdev_linux_poll_remove(struct netdev_notifier *notifier_) -{ - struct netdev_linux_notifier *notifier = - CONTAINER_OF(notifier_, struct netdev_linux_notifier, notifier); - struct list *list; - - /* Remove 'notifier' from its list. */ - list = list_remove(¬ifier->node); - if (list_is_empty(list)) { - /* The list is now empty. Remove it from the hash and free it. */ - const char *netdev_name = netdev_get_name(notifier->notifier.netdev); - shash_delete(&netdev_linux_notifiers, - shash_find(&netdev_linux_notifiers, netdev_name)); - free(list); - } - free(notifier); - - /* If that was the last notifier, unregister. */ - if (shash_is_empty(&netdev_linux_notifiers)) { - rtnetlink_link_notifier_unregister(&netdev_linux_poll_notifier); - } + return netdev_dev_linux_cast(netdev_get_dev(netdev))->change_seq; } #define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, SET_STATS) \ @@ -2201,7 +2246,8 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_) \ CREATE, \ netdev_linux_destroy, \ - NULL, /* reconfigure */ \ + NULL, /* set_config */ \ + NULL, /* config_equal */ \ \ netdev_linux_open, \ netdev_linux_close, \ @@ -2220,7 +2266,7 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_) netdev_linux_get_mtu, \ netdev_linux_get_ifindex, \ netdev_linux_get_carrier, \ - netdev_linux_get_miimon, \ + netdev_linux_set_miimon_interval, \ netdev_linux_get_stats, \ SET_STATS, \ \ @@ -2250,8 +2296,7 @@ netdev_linux_poll_remove(struct netdev_notifier *notifier_) \ netdev_linux_update_flags, \ \ - netdev_linux_poll_add, \ - netdev_linux_poll_remove \ + netdev_linux_change_seq \ } const struct netdev_class netdev_linux_class = @@ -2300,7 +2345,7 @@ htb_get__(const struct netdev *netdev) return CONTAINER_OF(netdev_dev->tc, struct htb, tc); } -static struct htb * +static void htb_install__(struct netdev *netdev, uint64_t max_rate) { struct netdev_dev_linux *netdev_dev = @@ -2312,8 +2357,6 @@ htb_install__(struct netdev *netdev, uint64_t max_rate) htb->max_rate = max_rate; netdev_dev->tc = &htb->tc; - - return htb; } /* Create an HTB qdisc. @@ -2365,6 +2408,11 @@ htb_setup_class__(struct netdev *netdev, unsigned int handle, int mtu; netdev_get_mtu(netdev, &mtu); + if (mtu == INT_MAX) { + VLOG_WARN_RL(&rl, "cannot set up HTB on device %s that lacks MTU", + netdev_get_name(netdev)); + return EINVAL; + } memset(&opt, 0, sizeof opt); tc_fill_rate(&opt.rate, class->min_rate, mtu); @@ -2484,13 +2532,17 @@ htb_parse_class_details__(struct netdev *netdev, const char *priority_s = shash_find_data(details, "priority"); int mtu; - /* min-rate. Don't allow a min-rate below 1500 bytes/s. */ - if (!min_rate_s) { - /* min-rate is required. */ + netdev_get_mtu(netdev, &mtu); + if (mtu == INT_MAX) { + VLOG_WARN_RL(&rl, "cannot parse HTB class on device %s that lacks MTU", + netdev_get_name(netdev)); return EINVAL; } - hc->min_rate = strtoull(min_rate_s, NULL, 10) / 8; - hc->min_rate = MAX(hc->min_rate, 1500); + + /* HTB requires at least an mtu sized min-rate to send any traffic even + * on uncongested links. */ + hc->min_rate = min_rate_s ? strtoull(min_rate_s, NULL, 10) / 8 : 0; + hc->min_rate = MAX(hc->min_rate, mtu); hc->min_rate = MIN(hc->min_rate, htb->max_rate); /* max-rate */ @@ -2509,7 +2561,6 @@ htb_parse_class_details__(struct netdev *netdev, * doesn't include the Ethernet header, we need to add at least 14 (18?) to * the MTU. We actually add 64, instead of 14, as a guard against * additional headers get tacked on somewhere that we're not aware of. */ - netdev_get_mtu(netdev, &mtu); hc->burst = burst_s ? strtoull(burst_s, NULL, 10) / 8 : 0; hc->burst = MAX(hc->burst, mtu + 64); @@ -2591,12 +2642,11 @@ htb_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED) struct ofpbuf msg; struct nl_dump dump; struct htb_class hc; - struct htb *htb; /* Get qdisc options. */ hc.max_rate = 0; htb_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL); - htb = htb_install__(netdev, hc.max_rate); + htb_install__(netdev, hc.max_rate); /* Get queues. */ if (!start_queue_dump(netdev, &dump)) { @@ -2780,7 +2830,7 @@ hfsc_class_cast__(const struct tc_queue *queue) return CONTAINER_OF(queue, struct hfsc_class, tc_queue); } -static struct hfsc * +static void hfsc_install__(struct netdev *netdev, uint32_t max_rate) { struct netdev_dev_linux * netdev_dev; @@ -2791,8 +2841,6 @@ hfsc_install__(struct netdev *netdev, uint32_t max_rate) tc_init(&hfsc->tc, &tc_ops_hfsc); hfsc->max_rate = max_rate; netdev_dev->tc = &hfsc->tc; - - return hfsc; } static void @@ -2965,12 +3013,8 @@ hfsc_parse_class_details__(struct netdev *netdev, min_rate_s = shash_find_data(details, "min-rate"); max_rate_s = shash_find_data(details, "max-rate"); - if (!min_rate_s) { - return EINVAL; - } - - min_rate = strtoull(min_rate_s, NULL, 10) / 8; - min_rate = MAX(min_rate, 1500); + min_rate = min_rate_s ? strtoull(min_rate_s, NULL, 10) / 8 : 0; + min_rate = MAX(min_rate, 1); min_rate = MIN(min_rate, hfsc->max_rate); max_rate = (max_rate_s @@ -3095,13 +3139,12 @@ static int hfsc_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg OVS_UNUSED) { struct ofpbuf msg; - struct hfsc *hfsc; struct nl_dump dump; struct hfsc_class hc; hc.max_rate = 0; hfsc_query_class__(netdev, tc_make_handle(1, 0xfffe), 0, &hc, NULL); - hfsc = hfsc_install__(netdev, hc.max_rate); + hfsc_install__(netdev, hc.max_rate); if (!start_queue_dump(netdev, &dump)) { return ENODEV; @@ -3883,7 +3926,57 @@ tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes) unsigned int min_burst = tc_buffer_per_jiffy(Bps) + mtu; 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 +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; +} + +/* 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. */ @@ -3903,7 +3996,6 @@ get_stats_via_netlink(int ifindex, struct netdev_stats *stats) struct ofpbuf request; struct ofpbuf *reply; struct ifinfomsg *ifi; - const struct rtnl_link_stats *rtnl_stats; struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)]; int error; @@ -3931,28 +4023,7 @@ get_stats_via_netlink(int ifindex, struct netdev_stats *stats) return EPROTO; } - rtnl_stats = nl_attr_get(attrs[IFLA_STATS]); - stats->rx_packets = rtnl_stats->rx_packets; - stats->tx_packets = rtnl_stats->tx_packets; - stats->rx_bytes = rtnl_stats->rx_bytes; - stats->tx_bytes = rtnl_stats->tx_bytes; - stats->rx_errors = rtnl_stats->rx_errors; - stats->tx_errors = rtnl_stats->tx_errors; - stats->rx_dropped = rtnl_stats->rx_dropped; - stats->tx_dropped = rtnl_stats->tx_dropped; - stats->multicast = rtnl_stats->multicast; - stats->collisions = rtnl_stats->collisions; - stats->rx_length_errors = rtnl_stats->rx_length_errors; - stats->rx_over_errors = rtnl_stats->rx_over_errors; - stats->rx_crc_errors = rtnl_stats->rx_crc_errors; - stats->rx_frame_errors = rtnl_stats->rx_frame_errors; - stats->rx_fifo_errors = rtnl_stats->rx_fifo_errors; - stats->rx_missed_errors = rtnl_stats->rx_missed_errors; - stats->tx_aborted_errors = rtnl_stats->tx_aborted_errors; - stats->tx_carrier_errors = rtnl_stats->tx_carrier_errors; - stats->tx_fifo_errors = rtnl_stats->tx_fifo_errors; - stats->tx_heartbeat_errors = rtnl_stats->tx_heartbeat_errors; - stats->tx_window_errors = rtnl_stats->tx_window_errors; + netdev_stats_from_rtnl_link_stats(stats, nl_attr_get(attrs[IFLA_STATS])); ofpbuf_delete(reply); @@ -4043,7 +4114,7 @@ do_get_ifindex(const char *netdev_name) { struct ifreq ifr; - strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); + ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); COVERAGE_INC(netdev_get_ifindex); if (ioctl(af_inet_sock, SIOCGIFINDEX, &ifr) < 0) { VLOG_WARN_RL(&rl, "ioctl(SIOCGIFINDEX) on %s device failed: %s", @@ -4078,7 +4149,7 @@ get_etheraddr(const char *netdev_name, uint8_t ea[ETH_ADDR_LEN]) int hwaddr_family; memset(&ifr, 0, sizeof ifr); - strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); + ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); COVERAGE_INC(netdev_get_hwaddr); if (ioctl(af_inet_sock, SIOCGIFHWADDR, &ifr) < 0) { VLOG_ERR("ioctl(SIOCGIFHWADDR) on %s device failed: %s", @@ -4101,7 +4172,7 @@ set_etheraddr(const char *netdev_name, int hwaddr_family, struct ifreq ifr; memset(&ifr, 0, sizeof ifr); - strncpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); + ovs_strzcpy(ifr.ifr_name, netdev_name, sizeof ifr.ifr_name); ifr.ifr_hwaddr.sa_family = hwaddr_family; memcpy(ifr.ifr_hwaddr.sa_data, mac, ETH_ADDR_LEN); COVERAGE_INC(netdev_set_hwaddr); @@ -4120,7 +4191,7 @@ netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *ecmd, struct ifreq ifr; memset(&ifr, 0, sizeof ifr); - strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + ovs_strzcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); ifr.ifr_data = (caddr_t) ecmd; ecmd->cmd = cmd; @@ -4143,7 +4214,7 @@ static int netdev_linux_do_ioctl(const char *name, struct ifreq *ifr, int cmd, const char *cmd_name) { - strncpy(ifr->ifr_name, name, sizeof ifr->ifr_name); + ovs_strzcpy(ifr->ifr_name, name, sizeof ifr->ifr_name); if (ioctl(af_inet_sock, cmd, ifr) == -1) { VLOG_DBG_RL(&rl, "%s: ioctl(%s) failed: %s", name, cmd_name, strerror(errno)); @@ -4167,3 +4238,22 @@ netdev_linux_get_ipv4(const struct netdev *netdev, struct in_addr *ip, } return error; } + +/* Returns an AF_PACKET raw socket or a negative errno value. */ +static int +af_packet_sock(void) +{ + static int sock = INT_MIN; + + if (sock == INT_MIN) { + sock = socket(AF_PACKET, SOCK_RAW, 0); + if (sock >= 0) { + set_nonblocking(sock); + } else { + sock = -errno; + VLOG_ERR("failed to create packet socket: %s", strerror(errno)); + } + } + + return sock; +}