struct netdev_linux {
struct netdev up;
+ /* Protects all members below. */
+ struct ovs_mutex mutex;
+
unsigned int cache_valid;
unsigned int change_seq;
int cmd, const char *cmd_name);
static int get_flags(const struct netdev *, unsigned int *flags);
static int set_flags(const char *, unsigned int flags);
+static int update_flags(struct netdev_linux *netdev, enum netdev_flags off,
+ enum netdev_flags on, enum netdev_flags *old_flagsp)
+ OVS_REQUIRES(netdev->mutex);
static int do_get_ifindex(const char *netdev_name);
static int get_ifindex(const struct netdev *, int *ifindexp);
static int do_set_addr(struct netdev *netdev,
}
\f
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. */
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);
- netdev_close(netdev_);
+ ovs_mutex_unlock(&netdev->mutex);
}
+ netdev_close(netdev_);
}
} else if (error == ENOBUFS) {
struct shash device_shash;
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);
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) {
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 */
static void
netdev_linux_common_construct(struct netdev_linux *netdev)
{
+ ovs_mutex_init(&netdev->mutex);
netdev->change_seq = 1;
}
{
close(netdev->tap_fd);
}
+
+ ovs_mutex_destroy(&netdev->mutex);
}
static void
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;
goto error;
}
}
+ ovs_mutex_unlock(&netdev->mutex);
return 0;
if (rx->fd >= 0) {
close(rx->fd);
}
+ ovs_mutex_unlock(&netdev->mutex);
return error;
}
struct msghdr msg;
struct iovec iov;
int ifindex;
- int error;
int sock;
sock = af_packet_sock();
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
const uint8_t mac[ETH_ADDR_LEN])
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
- struct netdev_saved_flags *sf = NULL;
+ enum netdev_flags old_flags = 0;
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;
}
/* Tap devices must be brought down before setting the address. */
if (is_tap_netdev(netdev_)) {
- netdev_turn_flags_off(netdev_, NETDEV_UP, &sf);
+ update_flags(netdev, NETDEV_UP, 0, &old_flags);
}
error = set_etheraddr(netdev_get_name(netdev_), mac);
if (!error || error == ENODEV) {
}
}
- netdev_restore_flags(sf);
+ if (is_tap_netdev(netdev_) && old_flags & NETDEV_UP) {
+ update_flags(netdev, 0, NETDEV_UP, &old_flags);
+ }
+exit:
+ ovs_mutex_unlock(&netdev->mutex);
return error;
}
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',
- * in bytes, not including the hardware header; thus, this is typically 1500
- * bytes for Ethernet devices. */
static int
-netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup)
+netdev_linux_get_mtu__(struct netdev_linux *netdev, int *mtup)
{
- struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ int error;
+
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->up), &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;
+
+ return error;
+}
+
+/* Returns the maximum size of transmitted (and received) packets on 'netdev',
+ * in bytes, not including the hardware header; thus, this is typically 1500
+ * bytes for Ethernet devices. */
+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);
+ error = netdev_linux_get_mtu__(netdev, mtup);
+ ovs_mutex_unlock(&netdev->mutex);
+
+ return error;
}
/* Sets the maximum size of transmitted (MTU) for given device using linux
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;
}
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;
}
{
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
{
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;
}
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);
}
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);
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;
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 {
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
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);
stats->multicast += dev_stats.multicast;
stats->collisions += dev_stats.collisions;
}
- return 0;
+ ovs_mutex_unlock(&netdev->mutex);
+
+ return error;
}
static int
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
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;
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
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;
}
netdev->netdev_policing_error = error;
netdev->cache_valid |= VALID_POLICING;
}
+ ovs_mutex_unlock(&netdev->mutex);
return error;
}
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
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
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
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
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
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
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
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
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
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;
"SIOCSIFNETMASK", netmask);
}
}
+ ovs_mutex_unlock(&netdev->mutex);
+
return error;
}
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];
netdev->cache_valid |= VALID_IN6;
}
*in6 = netdev->in6;
+ ovs_mutex_unlock(&netdev->mutex);
+
return 0;
}
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;
smap_add(smap, "driver_version", netdev->drvinfo.version);
smap_add(smap, "firmware_version", netdev->drvinfo.fw_version);
}
+ ovs_mutex_unlock(&netdev->mutex);
+
return error;
}
}
static int
-netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
- enum netdev_flags on, enum netdev_flags *old_flagsp)
+update_flags(struct netdev_linux *netdev, enum netdev_flags off,
+ enum netdev_flags on, enum netdev_flags *old_flagsp)
+ OVS_REQUIRES(netdev->mutex)
{
- struct netdev_linux *netdev = netdev_linux_cast(netdev_);
int old_flags, new_flags;
int error = 0;
*old_flagsp = iff_to_nd_flags(old_flags);
new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
if (new_flags != old_flags) {
- error = set_flags(netdev_get_name(netdev_), new_flags);
- get_flags(netdev_, &netdev->ifi_flags);
+ error = set_flags(netdev_get_name(&netdev->up), new_flags);
+ get_flags(&netdev->up, &netdev->ifi_flags);
}
+
+ return error;
+}
+
+static int
+netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
+ enum netdev_flags on, enum netdev_flags *old_flagsp)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ int error;
+
+ ovs_mutex_lock(&netdev->mutex);
+ error = update_flags(netdev, off, on, old_flagsp);
+ 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, \
int error;
int mtu;
- error = netdev_get_mtu(netdev, &mtu);
+ error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu);
if (error) {
VLOG_WARN_RL(&rl, "cannot set up HTB on device %s that lacks MTU",
netdev_get_name(netdev));
}
static void
-htb_parse_qdisc_details__(struct netdev *netdev,
+htb_parse_qdisc_details__(struct netdev *netdev_,
const struct smap *details, struct htb_class *hc)
{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
const char *max_rate_s;
max_rate_s = smap_get(details, "max-rate");
if (!hc->max_rate) {
enum netdev_features current;
- netdev_get_features(netdev, ¤t, NULL, NULL, NULL);
+ netdev_linux_read_features(netdev);
+ current = !netdev->get_features_error ? netdev->current : 0;
hc->max_rate = netdev_features_to_bps(current, 100 * 1000 * 1000) / 8;
}
hc->min_rate = hc->max_rate;
const char *priority_s = smap_get(details, "priority");
int mtu, error;
- error = netdev_get_mtu(netdev, &mtu);
+ error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu);
if (error) {
VLOG_WARN_RL(&rl, "cannot parse HTB class on device %s that lacks MTU",
netdev_get_name(netdev));
}
static void
-hfsc_parse_qdisc_details__(struct netdev *netdev, const struct smap *details,
+hfsc_parse_qdisc_details__(struct netdev *netdev_, const struct smap *details,
struct hfsc_class *class)
{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
uint32_t max_rate;
const char *max_rate_s;
if (!max_rate) {
enum netdev_features current;
- netdev_get_features(netdev, ¤t, NULL, NULL, NULL);
+ netdev_linux_read_features(netdev);
+ current = !netdev->get_features_error ? netdev->current : 0;
max_rate = netdev_features_to_bps(current, 100 * 1000 * 1000) / 8;
}