This patch adds a new field to "struct ofproto" to track which protocols
are active on that bridge. This is updated whenever bfd, cfm, lacp or
stp is enabled. In instant_stats_run(), we query this to determine
whether it is worthwhile to poll a port's status for each of these
protocols.

In a test environment running 5000 tunnel ports with only bfd running,
we would previously see about 60% CPU usage when a port flapped twice
per second. With this patch, average CPU usage decreases to around 55%
in this case.

Signed-off-by: Joe Stringer <joestrin...@nicira.com>
---
 ofproto/ofproto-dpif.c     |    9 +++++++++
 ofproto/ofproto-provider.h |    1 +
 ofproto/ofproto.c          |   12 ++++++++++++
 ofproto/ofproto.h          |   12 ++++++++++++
 vswitchd/bridge.c          |   46 +++++++++++++++++++++++++++-----------------
 5 files changed, 62 insertions(+), 18 deletions(-)

diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index c33a008..d6b5764 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1940,6 +1940,9 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings 
*s)
         }
 
         if (cfm_configure(ofport->cfm, s)) {
+            if (ofport->cfm) {
+                ofproto_set_active_modules(ofport->up.ofproto, PSM_CFM);
+            }
             error = 0;
             goto out;
         }
@@ -1987,6 +1990,10 @@ set_bfd(struct ofport *ofport_, const struct smap *cfg)
     }
     ofproto_dpif_monitor_port_update(ofport, ofport->bfd, ofport->cfm,
                                      ofport->up.pp.hw_addr);
+
+    if (ofport->bfd) {
+        ofproto_set_active_modules(&ofproto->up, PSM_BFD);
+    }
     return 0;
 }
 
@@ -2053,6 +2060,7 @@ set_stp(struct ofproto *ofproto_, const struct 
ofproto_stp_settings *s)
         stp_set_hello_time(ofproto->stp, s->hello_time);
         stp_set_max_age(ofproto->stp, s->max_age);
         stp_set_forward_delay(ofproto->stp, s->fwd_delay);
+        ofproto_set_active_modules(ofproto_, PSM_STP);
     }  else {
         struct ofport *ofport;
 
@@ -2459,6 +2467,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         if (!bundle->lacp) {
             ofproto->backer->need_revalidate = REV_RECONFIGURE;
             bundle->lacp = lacp_create();
+            ofproto_set_active_modules(ofproto_, PSM_LACP);
         }
         lacp_configure(bundle->lacp, s->lacp);
     } else {
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index cad12ef..4026955 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -77,6 +77,7 @@ struct ofproto {
     char *serial_desc;          /* Serial number (NULL for default). */
     char *dp_desc;              /* Datapath description (NULL for default). */
     enum ofp_config_flags frag_handling; /* One of OFPC_*.  */
+    uint16_t active_modules;    /* Active modules such as bfd, cfm, etc. */
 
     /* Datapath. */
     struct hmap ports;          /* Contains "struct ofport"s. */
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 1eae517..3804e9c 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -505,6 +505,7 @@ ofproto_create(const char *datapath_name, const char 
*datapath_type,
     ofproto->serial_desc = NULL;
     ofproto->dp_desc = NULL;
     ofproto->frag_handling = OFPC_FRAG_NORMAL;
+    ofproto->active_modules = 0;
     hmap_init(&ofproto->ports);
     hmap_init(&ofproto->ofport_usage);
     shash_init(&ofproto->port_by_name);
@@ -812,6 +813,17 @@ ofproto_get_flow_restore_wait(void)
 }
 
 
+void
+ofproto_set_active_modules(struct ofproto *ofproto, enum port_status_modules m)
+{
+    ofproto->active_modules |= m;
+}
+
+uint16_t
+ofproto_get_active_modules(const struct ofproto *ofproto)
+{
+    return ofproto->active_modules;
+}
 /* Spanning Tree Protocol (STP) configuration. */
 
 /* Configures STP on 'ofproto' using the settings defined in 's'.  If
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 903d1f4..bf74709 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -423,6 +423,18 @@ struct ofproto_cfm_status {
 bool ofproto_port_get_cfm_status(const struct ofproto *,
                                  ofp_port_t ofp_port,
                                  struct ofproto_cfm_status *);
+
+/* Active modules that may affect port status. This is used by the bridge to
+ * determine what kind of status updates it needs to gather. */
+enum port_status_modules {
+    PSM_CFM = 1 << 0,
+    PSM_BFD = 1 << 1,
+    PSM_STP = 1 << 2,
+    PSM_LACP = 1 << 3,
+};
+
+void ofproto_set_active_modules(struct ofproto *, enum port_status_modules);
+uint16_t ofproto_get_active_modules(const struct ofproto *ofproto);
 
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
  *
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index fdf0000..08a8c53 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -2221,6 +2221,7 @@ instant_stats_run(void)
             struct iface *iface;
             struct port *port;
             uint64_t seq;
+            uint16_t status_mask = ofproto_get_active_modules(br->ofproto);
 
             seq = netdev_change_seq();
             if (seq == br->change_seq) {
@@ -2229,10 +2230,12 @@ instant_stats_run(void)
                 br->change_seq = seq;
             }
 
-            br_refresh_stp_status(br);
+            if (status_mask | PSM_STP) {
+                br_refresh_stp_status(br);
 
-            HMAP_FOR_EACH (port, hmap_node, &br->ports) {
-                port_refresh_stp_status(port);
+                HMAP_FOR_EACH (port, hmap_node, &br->ports) {
+                    port_refresh_stp_status(port);
+                }
             }
 
             HMAP_FOR_EACH (iface, name_node, &br->iface_by_name) {
@@ -2246,15 +2249,7 @@ instant_stats_run(void)
                     continue;
                 }
 
-                current = ofproto_port_is_lacp_current(br->ofproto,
-                                                       iface->ofp_port);
-                if (current >= 0) {
-                    bool bl = current;
-                    ovsrec_interface_set_lacp_current(iface->cfg, &bl, 1);
-                } else {
-                    ovsrec_interface_set_lacp_current(iface->cfg, NULL, 0);
-                }
-
+                /* Admin and carrier status is always performed. */
                 error = netdev_get_flags(iface->netdev, &flags);
                 if (!error) {
                     const char *state = flags & NETDEV_UP ? "up" : "down";
@@ -2269,13 +2264,28 @@ instant_stats_run(void)
                 link_resets = netdev_get_carrier_resets(iface->netdev);
                 ovsrec_interface_set_link_resets(iface->cfg, &link_resets, 1);
 
-                iface_refresh_cfm_stats(iface);
+                if (status_mask | PSM_LACP) {
+                    current = ofproto_port_is_lacp_current(br->ofproto,
+                                                           iface->ofp_port);
+                    if (current >= 0) {
+                        bool bl = current;
+                        ovsrec_interface_set_lacp_current(iface->cfg, &bl, 1);
+                    } else {
+                        ovsrec_interface_set_lacp_current(iface->cfg, NULL, 0);
+                    }
+                }
 
-                smap_init(&smap);
-                ofproto_port_get_bfd_status(br->ofproto, iface->ofp_port,
-                                            &smap);
-                ovsrec_interface_set_bfd_status(iface->cfg, &smap);
-                smap_destroy(&smap);
+                if (status_mask | PSM_CFM) {
+                    iface_refresh_cfm_stats(iface);
+                }
+
+                if (status_mask | PSM_BFD) {
+                    smap_init(&smap);
+                    ofproto_port_get_bfd_status(br->ofproto, iface->ofp_port,
+                                                &smap);
+                    ovsrec_interface_set_bfd_status(iface->cfg, &smap);
+                    smap_destroy(&smap);
+                }
             }
         }
     }
-- 
1.7.9.5

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to