X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fnetdev-linux.c;h=e569750088cc33f2368cdd4a43b2b4a49e8c7c43;hb=863838160e892f625a050e0234ed638af26f106d;hp=5c36094f4dc283b552507f3a11dc502402f5e296;hpb=cee873383204463420c9704644c4238ec664c4ea;p=sliver-openvswitch.git diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 5c36094f4..e56975008 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -352,6 +352,9 @@ static int tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes); struct netdev_linux { struct netdev up; + /* Protects all members below. */ + struct ovs_mutex mutex; + unsigned int cache_valid; unsigned int change_seq; @@ -448,9 +451,11 @@ netdev_rx_linux_cast(const struct netdev_rx *rx) } static void netdev_linux_update(struct netdev_linux *netdev, - const struct rtnetlink_link_change *); + const struct rtnetlink_link_change *) + OVS_REQUIRES(netdev->mutex); static void netdev_linux_changed(struct netdev_linux *netdev, - unsigned int ifi_flags, unsigned int mask); + unsigned int ifi_flags, unsigned int mask) + OVS_REQUIRES(netdev->mutex); /* Returns a NETLINK_ROUTE socket listening for RTNLGRP_LINK changes, or NULL * if no such socket could be created. */ @@ -504,7 +509,11 @@ netdev_linux_run(void) struct netdev *netdev_ = netdev_from_name(change.ifname); if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + + ovs_mutex_lock(&netdev->mutex); netdev_linux_update(netdev, &change); + ovs_mutex_unlock(&netdev->mutex); + netdev_close(netdev_); } } @@ -521,8 +530,11 @@ netdev_linux_run(void) struct netdev_linux *netdev = netdev_linux_cast(netdev_); unsigned int flags; + ovs_mutex_lock(&netdev->mutex); get_flags(netdev_, &flags); netdev_linux_changed(netdev, flags, 0); + ovs_mutex_unlock(&netdev->mutex); + netdev_close(netdev_); } shash_destroy(&device_shash); @@ -549,6 +561,7 @@ netdev_linux_wait(void) static void netdev_linux_changed(struct netdev_linux *dev, unsigned int ifi_flags, unsigned int mask) + OVS_REQUIRES(dev->mutex) { dev->change_seq++; if (!dev->change_seq) { @@ -566,6 +579,7 @@ netdev_linux_changed(struct netdev_linux *dev, static void netdev_linux_update(struct netdev_linux *dev, const struct rtnetlink_link_change *change) + OVS_REQUIRES(dev->mutex) { if (change->nlmsg_type == RTM_NEWLINK) { /* Keep drv-info */ @@ -603,6 +617,7 @@ netdev_linux_alloc(void) static void netdev_linux_common_construct(struct netdev_linux *netdev) { + ovs_mutex_init(&netdev->mutex, PTHREAD_MUTEX_NORMAL); netdev->change_seq = 1; } @@ -693,6 +708,8 @@ netdev_linux_destruct(struct netdev *netdev_) { close(netdev->tap_fd); } + + ovs_mutex_destroy(&netdev->mutex); } static void @@ -717,6 +734,7 @@ netdev_linux_rx_construct(struct netdev_rx *rx_) struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + ovs_mutex_lock(&netdev->mutex); rx->is_tap = is_tap_netdev(netdev_); if (rx->is_tap) { rx->fd = netdev->tap_fd; @@ -776,6 +794,7 @@ netdev_linux_rx_construct(struct netdev_rx *rx_) goto error; } } + ovs_mutex_unlock(&netdev->mutex); return 0; @@ -783,6 +802,7 @@ error: if (rx->fd >= 0) { close(rx->fd); } + ovs_mutex_unlock(&netdev->mutex); return error; } @@ -873,7 +893,6 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) struct msghdr msg; struct iovec iov; int ifindex; - int error; int sock; sock = af_packet_sock(); @@ -881,9 +900,9 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size) return -sock; } - error = get_ifindex(netdev_, &ifindex); - if (error) { - return error; + ifindex = netdev_get_ifindex(netdev_); + if (ifindex < 0) { + return -ifindex; } /* We don't bother setting most fields in sockaddr_ll because the @@ -964,12 +983,12 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, struct netdev_saved_flags *sf = NULL; int error; + ovs_mutex_lock(&netdev->mutex); + if (netdev->cache_valid & VALID_ETHERADDR) { - if (netdev->ether_addr_error) { - return netdev->ether_addr_error; - } - if (eth_addr_equals(netdev->etheraddr, mac)) { - return 0; + error = netdev->ether_addr_error; + if (error || eth_addr_equals(netdev->etheraddr, mac)) { + goto exit; } netdev->cache_valid &= ~VALID_ETHERADDR; } @@ -989,6 +1008,8 @@ netdev_linux_set_etheraddr(struct netdev *netdev_, netdev_restore_flags(sf); +exit: + ovs_mutex_unlock(&netdev->mutex); return error; } @@ -998,20 +1019,22 @@ netdev_linux_get_etheraddr(const struct netdev *netdev_, uint8_t mac[ETH_ADDR_LEN]) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + int error; + ovs_mutex_lock(&netdev->mutex); if (!(netdev->cache_valid & VALID_ETHERADDR)) { - int error = get_etheraddr(netdev_get_name(netdev_), - netdev->etheraddr); - - netdev->ether_addr_error = error; + netdev->ether_addr_error = get_etheraddr(netdev_get_name(netdev_), + netdev->etheraddr); netdev->cache_valid |= VALID_ETHERADDR; } - if (!netdev->ether_addr_error) { + error = netdev->ether_addr_error; + if (!error) { memcpy(mac, netdev->etheraddr, ETH_ADDR_LEN); } + ovs_mutex_unlock(&netdev->mutex); - return netdev->ether_addr_error; + return error; } /* Returns the maximum size of transmitted (and received) packets on 'netdev', @@ -1021,22 +1044,25 @@ static int netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + int error; + + ovs_mutex_lock(&netdev->mutex); if (!(netdev->cache_valid & VALID_MTU)) { struct ifreq ifr; - int error; - - error = af_inet_ifreq_ioctl(netdev_get_name(netdev_), &ifr, - SIOCGIFMTU, "SIOCGIFMTU"); - netdev->netdev_mtu_error = error; + netdev->netdev_mtu_error = af_inet_ifreq_ioctl( + netdev_get_name(netdev_), &ifr, SIOCGIFMTU, "SIOCGIFMTU"); netdev->mtu = ifr.ifr_mtu; netdev->cache_valid |= VALID_MTU; } - if (!netdev->netdev_mtu_error) { + error = netdev->netdev_mtu_error; + if (!error) { *mtup = netdev->mtu; } - return netdev->netdev_mtu_error; + ovs_mutex_unlock(&netdev->mutex); + + return error; } /* Sets the maximum size of transmitted (MTU) for given device using linux @@ -1049,12 +1075,11 @@ netdev_linux_set_mtu(const struct netdev *netdev_, int mtu) struct ifreq ifr; int error; + ovs_mutex_lock(&netdev->mutex); if (netdev->cache_valid & VALID_MTU) { - if (netdev->netdev_mtu_error) { - return netdev->netdev_mtu_error; - } - if (netdev->mtu == mtu) { - return 0; + error = netdev->netdev_mtu_error; + if (error || netdev->mtu == mtu) { + goto exit; } netdev->cache_valid &= ~VALID_MTU; } @@ -1066,17 +1091,23 @@ netdev_linux_set_mtu(const struct netdev *netdev_, int mtu) netdev->mtu = ifr.ifr_mtu; netdev->cache_valid |= VALID_MTU; } +exit: + ovs_mutex_unlock(&netdev->mutex); return error; } /* Returns the ifindex of 'netdev', if successful, as a positive number. * On failure, returns a negative errno value. */ static int -netdev_linux_get_ifindex(const struct netdev *netdev) +netdev_linux_get_ifindex(const struct netdev *netdev_) { + struct netdev_linux *netdev = netdev_linux_cast(netdev_); int ifindex, error; - error = get_ifindex(netdev, &ifindex); + ovs_mutex_lock(&netdev->mutex); + error = get_ifindex(netdev_, &ifindex); + ovs_mutex_unlock(&netdev->mutex); + return error ? -error : ifindex; } @@ -1085,19 +1116,28 @@ netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + ovs_mutex_lock(&netdev->mutex); if (netdev->miimon_interval > 0) { *carrier = netdev->miimon; } else { *carrier = (netdev->ifi_flags & IFF_RUNNING) != 0; } + ovs_mutex_unlock(&netdev->mutex); return 0; } static long long int -netdev_linux_get_carrier_resets(const struct netdev *netdev) +netdev_linux_get_carrier_resets(const struct netdev *netdev_) { - return netdev_linux_cast(netdev)->carrier_resets; + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + long long int carrier_resets; + + ovs_mutex_lock(&netdev->mutex); + carrier_resets = netdev->carrier_resets; + ovs_mutex_unlock(&netdev->mutex); + + return carrier_resets; } static int @@ -1165,11 +1205,13 @@ netdev_linux_set_miimon_interval(struct netdev *netdev_, { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + ovs_mutex_lock(&netdev->mutex); interval = interval > 0 ? MAX(interval, 100) : 0; if (netdev->miimon_interval != interval) { netdev->miimon_interval = interval; timer_set_expired(&netdev->miimon_timer); } + ovs_mutex_unlock(&netdev->mutex); return 0; } @@ -1187,18 +1229,17 @@ netdev_linux_miimon_run(void) struct netdev_linux *dev = netdev_linux_cast(netdev); bool miimon; - if (dev->miimon_interval <= 0 || !timer_expired(&dev->miimon_timer)) { - netdev_close(netdev); - continue; - } + ovs_mutex_lock(&dev->mutex); + if (dev->miimon_interval > 0 && timer_expired(&dev->miimon_timer)) { + netdev_linux_get_miimon(dev->up.name, &miimon); + if (miimon != dev->miimon) { + dev->miimon = miimon; + netdev_linux_changed(dev, dev->ifi_flags, 0); + } - netdev_linux_get_miimon(dev->up.name, &miimon); - if (miimon != dev->miimon) { - dev->miimon = miimon; - netdev_linux_changed(dev, dev->ifi_flags, 0); + timer_set_duration(&dev->miimon_timer, dev->miimon_interval); } - - timer_set_duration(&dev->miimon_timer, dev->miimon_interval); + ovs_mutex_unlock(&dev->mutex); netdev_close(netdev); } @@ -1217,9 +1258,11 @@ netdev_linux_miimon_wait(void) struct netdev *netdev = node->data; struct netdev_linux *dev = netdev_linux_cast(netdev); + ovs_mutex_lock(&dev->mutex); if (dev->miimon_interval > 0) { timer_wait(&dev->miimon_timer); } + ovs_mutex_unlock(&dev->mutex); netdev_close(netdev); } shash_destroy(&device_shash); @@ -1336,7 +1379,7 @@ get_stats_via_vport(const struct netdev *netdev_, static int netdev_linux_sys_get_stats(const struct netdev *netdev_, - struct netdev_stats *stats) + struct netdev_stats *stats) { static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; static int use_netlink_stats; @@ -1375,19 +1418,14 @@ netdev_linux_get_stats(const struct netdev *netdev_, struct netdev_stats dev_stats; int error; + ovs_mutex_lock(&netdev->mutex); get_stats_via_vport(netdev_, stats); - error = netdev_linux_sys_get_stats(netdev_, &dev_stats); - if (error) { - if (netdev->vport_stats_error) { - return error; - } else { - return 0; + if (!netdev->vport_stats_error) { + error = 0; } - } - - if (netdev->vport_stats_error) { + } else if (netdev->vport_stats_error) { /* stats not available from OVS then use ioctl stats. */ *stats = dev_stats; } else { @@ -1409,7 +1447,9 @@ netdev_linux_get_stats(const struct netdev *netdev_, stats->tx_heartbeat_errors += dev_stats.tx_heartbeat_errors; stats->tx_window_errors += dev_stats.tx_window_errors; } - return 0; + ovs_mutex_unlock(&netdev->mutex); + + return error; } /* Retrieves current device stats for 'netdev-tap' netdev or @@ -1421,24 +1461,20 @@ netdev_tap_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) struct netdev_stats dev_stats; int error; + ovs_mutex_lock(&netdev->mutex); get_stats_via_vport(netdev_, stats); - error = netdev_linux_sys_get_stats(netdev_, &dev_stats); if (error) { - if (netdev->vport_stats_error) { - return error; - } else { - return 0; + if (!netdev->vport_stats_error) { + error = 0; } - } + } else if (netdev->vport_stats_error) { + /* 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. This does not + * apply if we are getting stats from the vport layer because it always + * tracks stats from the perspective of the switch. */ - /* 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. This does not apply if we are getting stats from the - * vport layer because it always tracks stats from the perspective of the - * switch. */ - if (netdev->vport_stats_error) { *stats = dev_stats; swap_uint64(&stats->rx_packets, &stats->tx_packets); swap_uint64(&stats->rx_bytes, &stats->tx_bytes); @@ -1465,7 +1501,9 @@ netdev_tap_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) stats->multicast += dev_stats.multicast; stats->collisions += dev_stats.collisions; } - return 0; + ovs_mutex_unlock(&netdev->mutex); + + return error; } static int @@ -1473,9 +1511,14 @@ netdev_internal_get_stats(const struct netdev *netdev_, struct netdev_stats *stats) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + int error; + ovs_mutex_lock(&netdev->mutex); get_stats_via_vport(netdev_, stats); - return netdev->vport_stats_error; + error = netdev->vport_stats_error; + ovs_mutex_unlock(&netdev->mutex); + + return error; } static int @@ -1515,6 +1558,7 @@ netdev_internal_set_stats(struct netdev *netdev, static void netdev_linux_read_features(struct netdev_linux *netdev) + OVS_REQUIRES(netdev->mutex) { struct ethtool_cmd ecmd; uint32_t speed; @@ -1656,32 +1700,39 @@ netdev_linux_get_features(const struct netdev *netdev_, enum netdev_features *peer) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + int error; + ovs_mutex_lock(&netdev->mutex); netdev_linux_read_features(netdev); - if (!netdev->get_features_error) { *current = netdev->current; *advertised = netdev->advertised; *supported = netdev->supported; *peer = 0; /* XXX */ } - return netdev->get_features_error; + error = netdev->get_features_error; + ovs_mutex_unlock(&netdev->mutex); + + return error; } /* Set the features advertised by 'netdev' to 'advertise'. */ static int -netdev_linux_set_advertisements(struct netdev *netdev, +netdev_linux_set_advertisements(struct netdev *netdev_, enum netdev_features advertise) { + struct netdev_linux *netdev = netdev_linux_cast(netdev_); struct ethtool_cmd ecmd; int error; + ovs_mutex_lock(&netdev->mutex); + COVERAGE_INC(netdev_get_ethtool); memset(&ecmd, 0, sizeof ecmd); - error = netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd, + error = netdev_linux_do_ethtool(netdev_get_name(netdev_), &ecmd, ETHTOOL_GSET, "ETHTOOL_GSET"); if (error) { - return error; + goto exit; } ecmd.advertising = 0; @@ -1722,8 +1773,12 @@ netdev_linux_set_advertisements(struct netdev *netdev, ecmd.advertising |= ADVERTISED_Asym_Pause; } COVERAGE_INC(netdev_set_ethtool); - return netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd, - ETHTOOL_SSET, "ETHTOOL_SSET"); + error = netdev_linux_do_ethtool(netdev_get_name(netdev_), &ecmd, + ETHTOOL_SSET, "ETHTOOL_SSET"); + +exit: + ovs_mutex_unlock(&netdev->mutex); + return error; } /* Attempts to set input rate limiting (policing) policy. Returns 0 if @@ -1736,20 +1791,17 @@ netdev_linux_set_policing(struct netdev *netdev_, const char *netdev_name = netdev_get_name(netdev_); int error; - kbits_burst = (!kbits_rate ? 0 /* Force to 0 if no rate specified. */ : !kbits_burst ? 1000 /* Default to 1000 kbits if 0. */ : kbits_burst); /* Stick with user-specified value. */ + ovs_mutex_lock(&netdev->mutex); if (netdev->cache_valid & VALID_POLICING) { - if (netdev->netdev_policing_error) { - return netdev->netdev_policing_error; - } - - if (netdev->kbits_rate == kbits_rate && - netdev->kbits_burst == kbits_burst) { + error = netdev->netdev_policing_error; + if (error || (netdev->kbits_rate == kbits_rate && + netdev->kbits_burst == kbits_burst)) { /* Assume that settings haven't changed since we last set them. */ - return 0; + goto out; } netdev->cache_valid &= ~VALID_POLICING; } @@ -1787,6 +1839,7 @@ out: netdev->netdev_policing_error = error; netdev->cache_valid |= VALID_POLICING; } + ovs_mutex_unlock(&netdev->mutex); return error; } @@ -1874,15 +1927,17 @@ netdev_linux_get_qos(const struct netdev *netdev_, struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); - if (error) { - return error; + if (!error) { + *typep = netdev->tc->ops->ovs_name; + error = (netdev->tc->ops->qdisc_get + ? netdev->tc->ops->qdisc_get(netdev_, details) + : 0); } + ovs_mutex_unlock(&netdev->mutex); - *typep = netdev->tc->ops->ovs_name; - return (netdev->tc->ops->qdisc_get - ? netdev->tc->ops->qdisc_get(netdev_, details) - : 0); + return error; } static int @@ -1898,27 +1953,30 @@ netdev_linux_set_qos(struct netdev *netdev_, return EOPNOTSUPP; } + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); if (error) { - return error; + goto exit; } if (new_ops == netdev->tc->ops) { - return new_ops->qdisc_set ? new_ops->qdisc_set(netdev_, details) : 0; + error = new_ops->qdisc_set ? new_ops->qdisc_set(netdev_, details) : 0; } else { /* Delete existing qdisc. */ error = tc_del_qdisc(netdev_); if (error) { - return error; + goto exit; } ovs_assert(netdev->tc == NULL); /* Install new qdisc. */ error = new_ops->tc_install(netdev_, details); ovs_assert((error == 0) == (netdev->tc != NULL)); - - return error; } + +exit: + ovs_mutex_unlock(&netdev->mutex); + return error; } static int @@ -1928,15 +1986,17 @@ netdev_linux_get_queue(const struct netdev *netdev_, struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); - if (error) { - return error; - } else { + if (!error) { struct tc_queue *queue = tc_find_queue(netdev_, queue_id); - return (queue + error = (queue ? netdev->tc->ops->class_get(netdev_, queue, details) : ENOENT); } + ovs_mutex_unlock(&netdev->mutex); + + return error; } static int @@ -1946,15 +2006,17 @@ netdev_linux_set_queue(struct netdev *netdev_, struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); - if (error) { - return error; - } else if (queue_id >= netdev->tc->ops->n_queues - || !netdev->tc->ops->class_set) { - return EINVAL; + if (!error) { + error = (queue_id < netdev->tc->ops->n_queues + && netdev->tc->ops->class_set + ? netdev->tc->ops->class_set(netdev_, queue_id, details) + : EINVAL); } + ovs_mutex_unlock(&netdev->mutex); - return netdev->tc->ops->class_set(netdev_, queue_id, details); + return error; } static int @@ -1963,17 +2025,21 @@ netdev_linux_delete_queue(struct netdev *netdev_, unsigned int queue_id) struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); - if (error) { - return error; - } else if (!netdev->tc->ops->class_delete) { - return EINVAL; - } else { - struct tc_queue *queue = tc_find_queue(netdev_, queue_id); - return (queue - ? netdev->tc->ops->class_delete(netdev_, queue) - : ENOENT); + if (!error) { + if (netdev->tc->ops->class_delete) { + struct tc_queue *queue = tc_find_queue(netdev_, queue_id); + error = (queue + ? netdev->tc->ops->class_delete(netdev_, queue) + : ENOENT); + } else { + error = EINVAL; + } } + ovs_mutex_unlock(&netdev->mutex); + + return error; } static int @@ -1984,19 +2050,25 @@ netdev_linux_get_queue_stats(const struct netdev *netdev_, struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); - if (error) { - return error; - } else if (!netdev->tc->ops->class_get_stats) { - return EOPNOTSUPP; - } else { - const struct tc_queue *queue = tc_find_queue(netdev_, queue_id); - if (!queue) { - return ENOENT; + if (!error) { + if (netdev->tc->ops->class_get_stats) { + const struct tc_queue *queue = tc_find_queue(netdev_, queue_id); + if (queue) { + stats->created = queue->created; + error = netdev->tc->ops->class_get_stats(netdev_, queue, + stats); + } else { + error = ENOENT; + } + } else { + error = EOPNOTSUPP; } - stats->created = queue->created; - return netdev->tc->ops->class_get_stats(netdev_, queue, stats); } + ovs_mutex_unlock(&netdev->mutex); + + return error; } static bool @@ -2020,34 +2092,37 @@ netdev_linux_dump_queues(const struct netdev *netdev_, netdev_dump_queues_cb *cb, void *aux) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); - struct tc_queue *queue, *next_queue; - struct smap details; - int last_error; int error; + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); - if (error) { - return error; - } else if (!netdev->tc->ops->class_get) { - return EOPNOTSUPP; - } + if (!error) { + if (netdev->tc->ops->class_get) { + struct tc_queue *queue, *next_queue; + struct smap details; - last_error = 0; - smap_init(&details); - HMAP_FOR_EACH_SAFE (queue, next_queue, hmap_node, - &netdev->tc->queues) { - smap_clear(&details); + smap_init(&details); + HMAP_FOR_EACH_SAFE (queue, next_queue, hmap_node, + &netdev->tc->queues) { + int retval; - error = netdev->tc->ops->class_get(netdev_, queue, &details); - if (!error) { - (*cb)(queue->queue_id, &details, aux); + smap_clear(&details); + + retval = netdev->tc->ops->class_get(netdev_, queue, &details); + if (!retval) { + (*cb)(queue->queue_id, &details, aux); + } else { + error = retval; + } + } + smap_destroy(&details); } else { - last_error = error; + error = EOPNOTSUPP; } } - smap_destroy(&details); + ovs_mutex_unlock(&netdev->mutex); - return last_error; + return error; } static int @@ -2055,31 +2130,38 @@ netdev_linux_dump_queue_stats(const struct netdev *netdev_, netdev_dump_queue_stats_cb *cb, void *aux) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); - struct nl_dump dump; - struct ofpbuf msg; - int last_error; int error; + ovs_mutex_lock(&netdev->mutex); error = tc_query_qdisc(netdev_); - if (error) { - return error; - } else if (!netdev->tc->ops->class_dump_stats) { - return EOPNOTSUPP; - } + if (!error) { + struct nl_dump dump; - last_error = 0; - if (!start_queue_dump(netdev_, &dump)) { - return ENODEV; - } - while (nl_dump_next(&dump, &msg)) { - error = netdev->tc->ops->class_dump_stats(netdev_, &msg, cb, aux); - if (error) { - last_error = error; + if (!netdev->tc->ops->class_dump_stats) { + error = EOPNOTSUPP; + } else if (!start_queue_dump(netdev_, &dump)) { + error = ENODEV; + } else { + struct ofpbuf msg; + int retval; + + while (nl_dump_next(&dump, &msg)) { + retval = netdev->tc->ops->class_dump_stats(netdev_, &msg, + cb, aux); + if (retval) { + error = retval; + } + } + + retval = nl_dump_done(&dump); + if (retval) { + error = retval; + } } } + ovs_mutex_unlock(&netdev->mutex); - error = nl_dump_done(&dump); - return error ? error : last_error; + return error; } static int @@ -2087,27 +2169,34 @@ netdev_linux_get_in4(const struct netdev *netdev_, struct in_addr *address, struct in_addr *netmask) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + int error; + ovs_mutex_lock(&netdev->mutex); if (!(netdev->cache_valid & VALID_IN4)) { - int error; - error = netdev_linux_get_ipv4(netdev_, &netdev->address, SIOCGIFADDR, "SIOCGIFADDR"); - if (error) { - return error; + if (!error) { + error = netdev_linux_get_ipv4(netdev_, &netdev->netmask, + SIOCGIFNETMASK, "SIOCGIFNETMASK"); + if (!error) { + netdev->cache_valid |= VALID_IN4; + } } + } else { + error = 0; + } - error = netdev_linux_get_ipv4(netdev_, &netdev->netmask, - SIOCGIFNETMASK, "SIOCGIFNETMASK"); - if (error) { - return error; + if (!error) { + if (netdev->address.s_addr != INADDR_ANY) { + *address = netdev->address; + *netmask = netdev->netmask; + } else { + error = EADDRNOTAVAIL; } - - netdev->cache_valid |= VALID_IN4; } - *address = netdev->address; - *netmask = netdev->netmask; - return address->s_addr == INADDR_ANY ? EADDRNOTAVAIL : 0; + ovs_mutex_unlock(&netdev->mutex); + + return error; } static int @@ -2117,6 +2206,7 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address, struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error; + ovs_mutex_lock(&netdev->mutex); error = do_set_addr(netdev_, SIOCSIFADDR, "SIOCSIFADDR", address); if (!error) { netdev->cache_valid |= VALID_IN4; @@ -2127,6 +2217,8 @@ netdev_linux_set_in4(struct netdev *netdev_, struct in_addr address, "SIOCSIFNETMASK", netmask); } } + ovs_mutex_unlock(&netdev->mutex); + return error; } @@ -2152,6 +2244,8 @@ static int netdev_linux_get_in6(const struct netdev *netdev_, struct in6_addr *in6) { struct netdev_linux *netdev = netdev_linux_cast(netdev_); + + ovs_mutex_lock(&netdev->mutex); if (!(netdev->cache_valid & VALID_IN6)) { FILE *file; char line[128]; @@ -2176,6 +2270,8 @@ netdev_linux_get_in6(const struct netdev *netdev_, struct in6_addr *in6) netdev->cache_valid |= VALID_IN6; } *in6 = netdev->in6; + ovs_mutex_unlock(&netdev->mutex); + return 0; } @@ -2290,6 +2386,7 @@ netdev_linux_get_status(const struct netdev *netdev_, struct smap *smap) struct netdev_linux *netdev = netdev_linux_cast(netdev_); int error = 0; + ovs_mutex_lock(&netdev->mutex); if (!(netdev->cache_valid & VALID_DRVINFO)) { struct ethtool_cmd *cmd = (struct ethtool_cmd *) &netdev->drvinfo; @@ -2309,6 +2406,8 @@ netdev_linux_get_status(const struct netdev *netdev_, struct smap *smap) smap_add(smap, "driver_version", netdev->drvinfo.version); smap_add(smap, "firmware_version", netdev->drvinfo.fw_version); } + ovs_mutex_unlock(&netdev->mutex); + return error; } @@ -2387,6 +2486,7 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off, int old_flags, new_flags; int error = 0; + ovs_mutex_lock(&netdev->mutex); old_flags = netdev->ifi_flags; *old_flagsp = iff_to_nd_flags(old_flags); new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on); @@ -2394,13 +2494,22 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off, error = set_flags(netdev_get_name(netdev_), new_flags); get_flags(netdev_, &netdev->ifi_flags); } + ovs_mutex_unlock(&netdev->mutex); + return error; } static unsigned int -netdev_linux_change_seq(const struct netdev *netdev) +netdev_linux_change_seq(const struct netdev *netdev_) { - return netdev_linux_cast(netdev)->change_seq; + struct netdev_linux *netdev = netdev_linux_cast(netdev_); + unsigned int change_seq; + + ovs_mutex_lock(&netdev->mutex); + change_seq = netdev->change_seq; + ovs_mutex_unlock(&netdev->mutex); + + return change_seq; } #define NETDEV_LINUX_CLASS(NAME, CONSTRUCT, GET_STATS, SET_STATS, \