[ovs-dev] [PATCHv4 1/4] netdev: Globally track port status changes

Joe Stringer joestringer at nicira.com
Wed Dec 11 17:10:52 UTC 2013


Previously, we tracked status changes for ofports on a per-device basis.
Each time in the main thread's loop, we would loop through all ofports
and manually check whether the status has changed for corresponding
devices.

This patch shifts change_seq above the netdevice layer, with one atomic
variable tracking status change for all ports. In the average case where
ports are not constantly going up or down, this allows us to check
change_seq once per loop and not poll any ports. In the worst case,
execution is expected to be similar to how it is currently.

As change_seq is no longer tracked per-device, it doesn't make sense to
cache this status in each ofport struct. As such, we shift this into the
ofproto struct.

In a test environment of 5000 internal ports and 50 tunnel ports with
bfd, this reduces CPU usage from about 45% to about 35%.

Signed-off-by: Joe Stringer <joestringer at nicira.com>
---
v4: Rebase
---
 lib/automake.mk            |    2 ++
 lib/connectivity.c         |   62 ++++++++++++++++++++++++++++++++++++++++++++
 lib/connectivity.h         |   46 ++++++++++++++++++++++++++++++++
 lib/netdev-bsd.c           |   36 +++++--------------------
 lib/netdev-dummy.c         |   33 +++--------------------
 lib/netdev-linux.c         |   23 ++--------------
 lib/netdev-provider.h      |   24 ++++++++---------
 lib/netdev-vport.c         |   30 +++------------------
 lib/netdev.c               |   14 ++--------
 lib/netdev.h               |    2 --
 ofproto/bond.c             |    7 +++--
 ofproto/ofproto-provider.h |    2 +-
 ofproto/ofproto.c          |   53 +++++++++++++++++--------------------
 ofproto/tunnel.c           |    7 ++---
 vswitchd/bridge.c          |    4 +++
 15 files changed, 175 insertions(+), 170 deletions(-)
 create mode 100644 lib/connectivity.c
 create mode 100644 lib/connectivity.h

diff --git a/lib/automake.mk b/lib/automake.mk
index fadc4be..4d741f0 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -29,6 +29,8 @@ lib_libopenvswitch_a_SOURCES = \
 	lib/command-line.c \
 	lib/command-line.h \
 	lib/compiler.h \
+	lib/connectivity.c \
+	lib/connectivity.h \
 	lib/coverage.c \
 	lib/coverage.h \
 	lib/crc32c.c \
diff --git a/lib/connectivity.c b/lib/connectivity.c
new file mode 100644
index 0000000..08e5a97
--- /dev/null
+++ b/lib/connectivity.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "connectivity.h"
+#include "ovs-thread.h"
+#include "seq.h"
+
+static struct seq *connectivity_seq;
+
+uint64_t
+connectivity_seq_read(void)
+{
+    return seq_read(connectivity_seq);
+}
+
+void
+connectivity_seq_wait(uint64_t seq)
+{
+    seq_wait(connectivity_seq, seq);
+}
+
+void
+connectivity_seq_notify(void)
+{
+    seq_change(connectivity_seq);
+}
+
+void
+connectivity_seq_init(void)
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+
+    if (ovsthread_once_start(&once)) {
+        connectivity_seq = seq_create();
+        ovsthread_once_done(&once);
+    }
+}
+
+void
+connectivity_seq_destroy(void)
+{
+    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+
+    if (ovsthread_once_start(&once)) {
+        seq_destroy(connectivity_seq);
+        ovsthread_once_done(&once);
+    }
+}
diff --git a/lib/connectivity.h b/lib/connectivity.h
new file mode 100644
index 0000000..c2af6c6
--- /dev/null
+++ b/lib/connectivity.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CONNECTIVITY_H
+#define CONNECTIVITY_H 1
+
+#include <stdint.h>
+
+/* Returns a sequence number which indicates changes in connectivity. The
+ * returned sequence number tracks all connectivity changes globally, and will
+ * change whenever a netdev's flags, features, ethernet address or carrier
+ * changes, or whenever a port's bfd, cfm, lacp or stp status changes. It may
+ * change for other reasons as well. */
+uint64_t connectivity_seq_read(void);
+
+/* Causes the following poll_block() to wake up on any connectivity changes
+ * that happen after 'seq'. This is a thin wrapper over the 'struct seq' API.
+ * seq.h contains examples of how to use this in a thread-safe manner. */
+void connectivity_seq_wait(uint64_t seq);
+
+/* Notifies interested parties that changes have occurred to connectivity.
+ * Connectivity monitoring modules should call this function whenever the
+ * status of a port changes, whether the cause is local or remote. */
+void connectivity_seq_notify(void);
+
+/* Initializes the global sequence tracker for connectivity changes. This
+ * initializes once per process, so can be safely called multiple times. */
+void connectivity_seq_init(void);
+
+/* Cleans up the global sequence tracker. This also occurs only once. */
+void connectivity_seq_destroy(void);
+
+#endif /* connectivity.h */
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index dd27d2d..5437cd1 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -47,6 +47,7 @@
 #endif
 
 #include "rtbsd.h"
+#include "connectivity.h"
 #include "coverage.h"
 #include "dynamic-string.h"
 #include "fatal-signal.h"
@@ -86,7 +87,6 @@ struct netdev_bsd {
     struct ovs_mutex mutex;
 
     unsigned int cache_valid;
-    unsigned int change_seq;
 
     int ifindex;
     uint8_t etheraddr[ETH_ADDR_LEN];
@@ -197,15 +197,6 @@ netdev_bsd_wait(void)
     rtbsd_notifier_wait();
 }
 
-static void
-netdev_bsd_changed(struct netdev_bsd *dev)
-{
-    dev->change_seq++;
-    if (!dev->change_seq) {
-        dev->change_seq++;
-    }
-}
-
 /* Invalidate cache in case of interface status change. */
 static void
 netdev_bsd_cache_cb(const struct rtbsd_change *change,
@@ -223,7 +214,7 @@ netdev_bsd_cache_cb(const struct rtbsd_change *change,
             if (is_netdev_bsd_class(netdev_class)) {
                 dev = netdev_bsd_cast(base_dev);
                 dev->cache_valid = 0;
-                netdev_bsd_changed(dev);
+                connectivity_seq_notify();
             }
             netdev_close(base_dev);
         }
@@ -241,7 +232,7 @@ netdev_bsd_cache_cb(const struct rtbsd_change *change,
             struct netdev *netdev = node->data;
             dev = netdev_bsd_cast(netdev);
             dev->cache_valid = 0;
-            netdev_bsd_changed(dev);
+            connectivity_seq_notify();
             netdev_close(netdev);
         }
         shash_destroy(&device_shash);
@@ -294,7 +285,6 @@ netdev_bsd_construct_system(struct netdev *netdev_)
     }
 
     ovs_mutex_init(&netdev->mutex);
-    netdev->change_seq = 1;
     netdev->tap_fd = -1;
     netdev->kernel_name = xstrdup(netdev_->name);
 
@@ -329,7 +319,6 @@ netdev_bsd_construct_tap(struct netdev *netdev_)
      * to retrieve the name of the tap device. */
     ovs_mutex_init(&netdev->mutex);
     netdev->tap_fd = open("/dev/tap", O_RDWR);
-    netdev->change_seq = 1;
     if (netdev->tap_fd < 0) {
         error = errno;
         VLOG_WARN("opening \"/dev/tap\" failed: %s", ovs_strerror(error));
@@ -506,9 +495,6 @@ netdev_bsd_rx_construct(struct netdev_rx *rx_)
         ovs_mutex_lock(&netdev->mutex);
         error = netdev_bsd_open_pcap(netdev_get_kernel_name(netdev_),
                                      &rx->pcap_handle, &rx->fd);
-        if (!error) {
-            netdev_bsd_changed(netdev);
-        }
         ovs_mutex_unlock(&netdev->mutex);
     }
 
@@ -756,7 +742,7 @@ netdev_bsd_set_etheraddr(struct netdev *netdev_,
         if (!error) {
             netdev->cache_valid |= VALID_ETHERADDR;
             memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
-            netdev_bsd_changed(netdev);
+            connectivity_seq_notify();
         }
     }
     ovs_mutex_unlock(&netdev->mutex);
@@ -1165,7 +1151,7 @@ netdev_bsd_set_in4(struct netdev *netdev_, struct in_addr addr,
                 netdev->netmask = mask;
             }
         }
-        netdev_bsd_changed(netdev);
+        connectivity_seq_notify();
     }
     ovs_mutex_unlock(&netdev->mutex);
 
@@ -1464,18 +1450,12 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
         new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
         if (new_flags != old_flags) {
             error = set_flags(netdev_get_kernel_name(netdev_), new_flags);
-            netdev_bsd_changed(netdev);
+            connectivity_seq_notify();
         }
     }
     return error;
 }
 
-static unsigned int
-netdev_bsd_change_seq(const struct netdev *netdev)
-{
-    return netdev_bsd_cast(netdev)->change_seq;
-}
-
 
 const struct netdev_class netdev_bsd_class = {
     "system",
@@ -1531,8 +1511,6 @@ const struct netdev_class netdev_bsd_class = {
 
     netdev_bsd_update_flags,
 
-    netdev_bsd_change_seq,
-
     netdev_bsd_rx_alloc,
     netdev_bsd_rx_construct,
     netdev_bsd_rx_destruct,
@@ -1596,8 +1574,6 @@ const struct netdev_class netdev_tap_class = {
 
     netdev_bsd_update_flags,
 
-    netdev_bsd_change_seq,
-
     netdev_bsd_rx_alloc,
     netdev_bsd_rx_construct,
     netdev_bsd_rx_destruct,
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index fd30454..3858b5f 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 
+#include "connectivity.h"
 #include "flow.h"
 #include "list.h"
 #include "netdev-provider.h"
@@ -66,7 +67,6 @@ struct netdev_dummy {
     int mtu OVS_GUARDED;
     struct netdev_stats stats OVS_GUARDED;
     enum netdev_flags flags OVS_GUARDED;
-    unsigned int change_seq OVS_GUARDED;
     int ifindex OVS_GUARDED;
 
     struct pstream *pstream OVS_GUARDED;
@@ -91,8 +91,6 @@ struct netdev_rx_dummy {
 
 static unixctl_cb_func netdev_dummy_set_admin_state;
 static int netdev_dummy_construct(struct netdev *);
-static void netdev_dummy_changed(struct netdev_dummy *netdev)
-    OVS_REQUIRES(netdev->mutex);
 static void netdev_dummy_queue_packet(struct netdev_dummy *, struct ofpbuf *);
 
 static void dummy_stream_close(struct dummy_stream *);
@@ -285,7 +283,6 @@ netdev_dummy_construct(struct netdev *netdev_)
     netdev->hwaddr[5] = n;
     netdev->mtu = 1500;
     netdev->flags = 0;
-    netdev->change_seq = 1;
     netdev->ifindex = -EOPNOTSUPP;
 
     netdev->pstream = NULL;
@@ -571,7 +568,7 @@ netdev_dummy_set_etheraddr(struct netdev *netdev,
     ovs_mutex_lock(&dev->mutex);
     if (!eth_addr_equals(dev->hwaddr, mac)) {
         memcpy(dev->hwaddr, mac, ETH_ADDR_LEN);
-        netdev_dummy_changed(dev);
+        connectivity_seq_notify();
     }
     ovs_mutex_unlock(&dev->mutex);
 
@@ -666,7 +663,7 @@ netdev_dummy_update_flags__(struct netdev_dummy *netdev,
     netdev->flags |= on;
     netdev->flags &= ~off;
     if (*old_flagsp != netdev->flags) {
-        netdev_dummy_changed(netdev);
+        connectivity_seq_notify();
     }
 
     return 0;
@@ -686,31 +683,9 @@ netdev_dummy_update_flags(struct netdev *netdev_,
 
     return error;
 }
-
-static unsigned int
-netdev_dummy_change_seq(const struct netdev *netdev_)
-{
-    struct netdev_dummy *netdev = netdev_dummy_cast(netdev_);
-    unsigned int change_seq;
-
-    ovs_mutex_lock(&netdev->mutex);
-    change_seq = netdev->change_seq;
-    ovs_mutex_unlock(&netdev->mutex);
-
-    return change_seq;
-}
 
 /* Helper functions. */
 
-static void
-netdev_dummy_changed(struct netdev_dummy *dev)
-{
-    dev->change_seq++;
-    if (!dev->change_seq) {
-        dev->change_seq++;
-    }
-}
-
 static const struct netdev_class dummy_class = {
     "dummy",
     NULL,                       /* init */
@@ -766,8 +741,6 @@ static const struct netdev_class dummy_class = {
 
     netdev_dummy_update_flags,
 
-    netdev_dummy_change_seq,
-
     netdev_dummy_rx_alloc,
     netdev_dummy_rx_construct,
     netdev_dummy_rx_destruct,
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 3e0da48..3818408 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -48,6 +48,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "connectivity.h"
 #include "coverage.h"
 #include "dpif-linux.h"
 #include "dynamic-string.h"
@@ -357,7 +358,6 @@ struct netdev_linux {
     struct ovs_mutex mutex;
 
     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. */
@@ -585,10 +585,7 @@ 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) {
-        dev->change_seq++;
-    }
+    connectivity_seq_notify();
 
     if ((dev->ifi_flags ^ ifi_flags) & IFF_RUNNING) {
         dev->carrier_resets++;
@@ -640,7 +637,6 @@ static void
 netdev_linux_common_construct(struct netdev_linux *netdev)
 {
     ovs_mutex_init(&netdev->mutex);
-    netdev->change_seq = 1;
 }
 
 /* Creates system and internal devices. */
@@ -2597,19 +2593,6 @@ netdev_linux_update_flags(struct netdev *netdev_, enum netdev_flags off,
     return error;
 }
 
-static unsigned int
-netdev_linux_change_seq(const struct netdev *netdev_)
-{
-    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,  \
                            GET_FEATURES, GET_STATUS)            \
 {                                                               \
@@ -2668,8 +2651,6 @@ netdev_linux_change_seq(const struct netdev *netdev_)
                                                                 \
     netdev_linux_update_flags,                                  \
                                                                 \
-    netdev_linux_change_seq,                                    \
-                                                                \
     netdev_linux_rx_alloc,                                      \
     netdev_linux_rx_construct,                                  \
     netdev_linux_rx_destruct,                                   \
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 9ab58fb..98f7c15 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -148,7 +148,18 @@ struct netdev *netdev_rx_get_netdev(const struct netdev_rx *);
  * Each "dealloc" function frees raw memory that was allocated by the the
  * "alloc" function.  The memory's base and derived members might not have ever
  * been initialized (but if "construct" returned successfully, then it has been
- * "destruct"ed already).  The "dealloc" function is not allowed to fail. */
+ * "destruct"ed already).  The "dealloc" function is not allowed to fail.
+ *
+ *
+ * Change Notification
+ * ===================
+ *
+ * Minimally, implementations are required to report changes to netdev flags,
+ * features, ethernet address or carrier through connectivity_seq_notify().
+ * Changes to other properties are allowed to cause notification through this
+ * interface, although implementations should try to avoid this. connectivity.h
+ * contains more information about this notification interface; See also
+ * connectivity_seq_read() and connectivity_seq_wait(). */
 struct netdev_class {
     /* Type of netdevs in this class, e.g. "system", "tap", "gre", etc.
      *
@@ -609,17 +620,6 @@ struct netdev_class {
     int (*update_flags)(struct netdev *netdev, enum netdev_flags off,
                         enum netdev_flags on, enum netdev_flags *old_flags);
 
-    /* Returns a sequence number which indicates changes in one of 'netdev''s
-     * properties.  The returned sequence number must be nonzero so that
-     * callers have a value which they may use as a reset when tracking
-     * 'netdev'.
-     *
-     * Minimally, the returned sequence number is required to change whenever
-     * 'netdev''s flags, features, ethernet address, or carrier changes.  The
-     * returned sequence number is allowed to change even when 'netdev' doesn't
-     * change, although implementations should try to avoid this. */
-    unsigned int (*change_seq)(const struct netdev *netdev);
-
 /* ## ------------------- ## */
 /* ## netdev_rx Functions ## */
 /* ## ------------------- ## */
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 07b2381..12920e3 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -25,6 +25,7 @@
 #include <sys/ioctl.h>
 
 #include "byte-order.h"
+#include "connectivity.h"
 #include "daemon.h"
 #include "dirs.h"
 #include "dpif.h"
@@ -52,7 +53,6 @@ struct netdev_vport {
     /* Protects all members below. */
     struct ovs_mutex mutex;
 
-    unsigned int change_seq;
     uint8_t etheraddr[ETH_ADDR_LEN];
     struct netdev_stats stats;
 
@@ -71,8 +71,6 @@ struct vport_class {
 static int netdev_vport_construct(struct netdev *);
 static int get_patch_config(const struct netdev *netdev, struct smap *args);
 static int get_tunnel_config(const struct netdev *, struct smap *args);
-static void netdev_vport_changed(struct netdev_vport *netdev)
-    OVS_REQUIRES(netdev->mutex);
 
 static bool
 is_vport_class(const struct netdev_class *class)
@@ -180,7 +178,6 @@ netdev_vport_construct(struct netdev *netdev_)
     struct netdev_vport *netdev = netdev_vport_cast(netdev_);
 
     ovs_mutex_init(&netdev->mutex);
-    netdev->change_seq = 1;
     eth_addr_random(netdev->etheraddr);
 
     route_table_register();
@@ -213,8 +210,8 @@ netdev_vport_set_etheraddr(struct netdev *netdev_,
 
     ovs_mutex_lock(&netdev->mutex);
     memcpy(netdev->etheraddr, mac, ETH_ADDR_LEN);
-    netdev_vport_changed(netdev);
     ovs_mutex_unlock(&netdev->mutex);
+    connectivity_seq_notify();
 
     return 0;
 }
@@ -272,12 +269,6 @@ netdev_vport_update_flags(struct netdev *netdev OVS_UNUSED,
     return 0;
 }
 
-static unsigned int
-netdev_vport_change_seq(const struct netdev *netdev)
-{
-    return netdev_vport_cast(netdev)->change_seq;
-}
-
 static void
 netdev_vport_run(void)
 {
@@ -290,17 +281,6 @@ netdev_vport_wait(void)
     route_table_wait();
 }
 
-/* Helper functions. */
-
-static void
-netdev_vport_changed(struct netdev_vport *ndv)
-{
-    ndv->change_seq++;
-    if (!ndv->change_seq) {
-        ndv->change_seq++;
-    }
-}
-
 /* Code specific to tunnel types. */
 
 static ovs_be64
@@ -503,7 +483,7 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
 
     ovs_mutex_lock(&dev->mutex);
     dev->tnl_cfg = tnl_cfg;
-    netdev_vport_changed(dev);
+    connectivity_seq_notify();
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
@@ -677,7 +657,7 @@ set_patch_config(struct netdev *dev_, const struct smap *args)
     ovs_mutex_lock(&dev->mutex);
     free(dev->peer);
     dev->peer = xstrdup(peer);
-    netdev_vport_changed(dev);
+    connectivity_seq_notify();
     ovs_mutex_unlock(&dev->mutex);
 
     return 0;
@@ -750,8 +730,6 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats)
                                                             \
     netdev_vport_update_flags,                              \
                                                             \
-    netdev_vport_change_seq,                                \
-                                                            \
     NULL,                   /* rx_alloc */                  \
     NULL,                   /* rx_construct */              \
     NULL,                   /* rx_destruct */               \
diff --git a/lib/netdev.c b/lib/netdev.c
index 5ed6062..da0cecb 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "connectivity.h"
 #include "coverage.h"
 #include "dpif.h"
 #include "dynamic-string.h"
@@ -331,6 +332,7 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp)
                     int old_ref_cnt;
 
                     atomic_add(&rc->ref_cnt, 1, &old_ref_cnt);
+                    connectivity_seq_notify();
                 } else {
                     free(netdev->name);
                     ovs_assert(list_is_empty(&netdev->saved_flags_list));
@@ -1494,18 +1496,6 @@ netdev_dump_queue_stats(const struct netdev *netdev,
             : EOPNOTSUPP);
 }
 
-/* Returns a sequence number which indicates changes in one of 'netdev''s
- * properties.  The returned sequence will be nonzero so that callers have a
- * value which they may use as a reset when tracking 'netdev'.
- *
- * The returned sequence number will change whenever 'netdev''s flags,
- * features, ethernet address, or carrier changes.  It may change for other
- * reasons as well, or no reason at all. */
-unsigned int
-netdev_change_seq(const struct netdev *netdev)
-{
-    return netdev->netdev_class->change_seq(netdev);
-}
 
 /* Returns the class type of 'netdev'.
  *
diff --git a/lib/netdev.h b/lib/netdev.h
index bafa50e..410c35b 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -313,8 +313,6 @@ typedef void netdev_dump_queue_stats_cb(unsigned int queue_id,
 int netdev_dump_queue_stats(const struct netdev *,
                             netdev_dump_queue_stats_cb *, void *aux);
 
-unsigned int netdev_change_seq(const struct netdev *netdev);
-
 #ifdef  __cplusplus
 }
 #endif
diff --git a/ofproto/bond.c b/ofproto/bond.c
index dc0d76b..668203a 100644
--- a/ofproto/bond.c
+++ b/ofproto/bond.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <math.h>
 
+#include "connectivity.h"
 #include "coverage.h"
 #include "dynamic-string.h"
 #include "flow.h"
@@ -441,7 +442,7 @@ bond_run(struct bond *bond, enum lacp_status lacp_status)
     /* Enable slaves based on link status and LACP feedback. */
     HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
         bond_link_status_update(slave);
-        slave->change_seq = netdev_change_seq(slave->netdev);
+        slave->change_seq = connectivity_seq_read();
     }
     if (!bond->active_slave || !bond->active_slave->enabled) {
         bond_choose_active_slave(bond);
@@ -472,9 +473,7 @@ bond_wait(struct bond *bond)
             poll_timer_wait_until(slave->delay_expires);
         }
 
-        if (slave->change_seq != netdev_change_seq(slave->netdev)) {
-            poll_immediate_wake();
-        }
+        connectivity_seq_wait(slave->change_seq);
     }
 
     if (bond->next_fake_iface_update != LLONG_MAX) {
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 54d97f1..9c9332f 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -85,6 +85,7 @@ struct ofproto {
     uint16_t alloc_port_no;     /* Last allocated OpenFlow port number. */
     uint16_t max_ports;         /* Max possible OpenFlow port num, plus one. */
     struct hmap ofport_usage;   /* Map ofport to last used time. */
+    uint64_t change_seq;        /* Change sequence for netdev status. */
 
     /* Flow tables. */
     long long int eviction_group_timer; /* For rate limited reheapification. */
@@ -170,7 +171,6 @@ struct ofport {
     struct netdev *netdev;
     struct ofputil_phy_port pp;
     ofp_port_t ofp_port;        /* OpenFlow port number. */
-    unsigned int change_seq;
     long long int created;      /* Time created, in msec. */
     int mtu;
 };
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 3a60328..a488b27 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -25,6 +25,7 @@
 #include "bitmap.h"
 #include "byte-order.h"
 #include "classifier.h"
+#include "connectivity.h"
 #include "connmgr.h"
 #include "coverage.h"
 #include "dynamic-string.h"
@@ -1427,10 +1428,8 @@ any_pending_ops(const struct ofproto *p)
 int
 ofproto_run(struct ofproto *p)
 {
-    struct sset changed_netdevs;
-    const char *changed_netdev;
-    struct ofport *ofport;
     int error;
+    uint64_t new_seq;
 
     error = p->ofproto_class->run(p);
     if (error && error != EAGAIN) {
@@ -1481,24 +1480,29 @@ ofproto_run(struct ofproto *p)
         }
     }
 
-    /* Update OpenFlow port status for any port whose netdev has changed.
-     *
-     * Refreshing a given 'ofport' can cause an arbitrary ofport to be
-     * destroyed, so it's not safe to update ports directly from the
-     * HMAP_FOR_EACH loop, or even to use HMAP_FOR_EACH_SAFE.  Instead, we
-     * need this two-phase approach. */
-    sset_init(&changed_netdevs);
-    HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
-        unsigned int change_seq = netdev_change_seq(ofport->netdev);
-        if (ofport->change_seq != change_seq) {
-            ofport->change_seq = change_seq;
-            sset_add(&changed_netdevs, netdev_get_name(ofport->netdev));
+    new_seq = connectivity_seq_read();
+    if (new_seq != p->change_seq) {
+        struct sset devnames;
+        const char *devname;
+        struct ofport *ofport;
+
+        /* Update OpenFlow port status for any port whose netdev has changed.
+         *
+         * Refreshing a given 'ofport' can cause an arbitrary ofport to be
+         * destroyed, so it's not safe to update ports directly from the
+         * HMAP_FOR_EACH loop, or even to use HMAP_FOR_EACH_SAFE.  Instead, we
+         * need this two-phase approach. */
+        sset_init(&devnames);
+        HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
+            sset_add(&devnames, netdev_get_name(ofport->netdev));
         }
+        SSET_FOR_EACH (devname, &devnames) {
+            update_port(p, devname);
+        }
+        sset_destroy(&devnames);
+
+        p->change_seq = new_seq;
     }
-    SSET_FOR_EACH (changed_netdev, &changed_netdevs) {
-        update_port(p, changed_netdev);
-    }
-    sset_destroy(&changed_netdevs);
 
     switch (p->state) {
     case S_OPENFLOW:
@@ -1588,18 +1592,11 @@ ofproto_run_fast(struct ofproto *p)
 void
 ofproto_wait(struct ofproto *p)
 {
-    struct ofport *ofport;
-
     p->ofproto_class->wait(p);
     if (p->ofproto_class->port_poll_wait) {
         p->ofproto_class->port_poll_wait(p);
     }
-
-    HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
-        if (ofport->change_seq != netdev_change_seq(ofport->netdev)) {
-            poll_immediate_wake();
-        }
-    }
+    connectivity_seq_wait(p->change_seq);
 
     switch (p->state) {
     case S_OPENFLOW:
@@ -2159,7 +2156,6 @@ ofport_install(struct ofproto *p,
     }
     ofport->ofproto = p;
     ofport->netdev = netdev;
-    ofport->change_seq = netdev_change_seq(netdev);
     ofport->pp = *pp;
     ofport->ofp_port = pp->port_no;
     ofport->created = time_msec();
@@ -2394,7 +2390,6 @@ update_port(struct ofproto *ofproto, const char *name)
              * Don't close the old netdev yet in case port_modified has to
              * remove a retained reference to it.*/
             port->netdev = netdev;
-            port->change_seq = netdev_change_seq(netdev);
 
             if (port->ofproto->ofproto_class->port_modified) {
                 port->ofproto->ofproto_class->port_modified(port);
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index b238cd0..54a9784 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -18,6 +18,7 @@
 #include <errno.h>
 
 #include "byte-order.h"
+#include "connectivity.h"
 #include "dynamic-string.h"
 #include "hash.h"
 #include "hmap.h"
@@ -50,7 +51,7 @@ struct tnl_port {
     struct hmap_node match_node;
 
     const struct ofport_dpif *ofport;
-    unsigned int netdev_seq;
+    unsigned int change_seq;
     struct netdev *netdev;
 
     struct tnl_match match;
@@ -97,7 +98,7 @@ tnl_port_add__(const struct ofport_dpif *ofport, const struct netdev *netdev,
     tnl_port = xzalloc(sizeof *tnl_port);
     tnl_port->ofport = ofport;
     tnl_port->netdev = netdev_ref(netdev);
-    tnl_port->netdev_seq = netdev_change_seq(tnl_port->netdev);
+    tnl_port->change_seq = connectivity_seq_read();
 
     tnl_port->match.in_key = cfg->in_key;
     tnl_port->match.ip_src = cfg->ip_src;
@@ -159,7 +160,7 @@ tnl_port_reconfigure(const struct ofport_dpif *ofport,
         changed = tnl_port_add__(ofport, netdev, odp_port, false);
     } else if (tnl_port->netdev != netdev
                || tnl_port->match.odp_port != odp_port
-               || tnl_port->netdev_seq != netdev_change_seq(netdev)) {
+               || tnl_port->change_seq != connectivity_seq_read()) {
         VLOG_DBG("reconfiguring %s", tnl_port_get_name(tnl_port));
         tnl_port_del__(ofport);
         tnl_port_add__(ofport, netdev, odp_port, true);
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 2b11c5b..6da5e93 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -22,6 +22,7 @@
 #include "bfd.h"
 #include "bitmap.h"
 #include "cfm.h"
+#include "connectivity.h"
 #include "coverage.h"
 #include "daemon.h"
 #include "dirs.h"
@@ -415,6 +416,8 @@ bridge_init(const char *remote)
                              bridge_unixctl_dump_flows, NULL);
     unixctl_command_register("bridge/reconnect", "[bridge]", 0, 1,
                              bridge_unixctl_reconnect, NULL);
+
+    connectivity_seq_init();
     lacp_init();
     bond_init();
     cfm_init();
@@ -429,6 +432,7 @@ bridge_exit(void)
     HMAP_FOR_EACH_SAFE (br, next_br, node, &all_bridges) {
         bridge_destroy(br);
     }
+    connectivity_seq_destroy();
     ovsdb_idl_destroy(idl);
 }
 
-- 
1.7.9.5




More information about the dev mailing list