rstp: Refactor rstp_check_and_reset_fdb_flush().
authorJarno Rajahalme <jrajahalme@nicira.com>
Fri, 14 Nov 2014 22:07:50 +0000 (14:07 -0800)
committerJarno Rajahalme <jrajahalme@nicira.com>
Fri, 14 Nov 2014 22:07:50 +0000 (14:07 -0800)
With this commit, RSTP is able to flush from the MAC learning table
entries pertaining to a single port.  Before this commit the whole
table was flushed every time a port requested flushing actions.

Signed-off-by: Daniele Venturino <daniele.venturino@m3s.it>
Acked-by: Jarno Rajahalme <jrajahalme@nicira.com>
lib/rstp.c
lib/rstp.h
ofproto/ofproto-dpif.c

index f63bb57..12fd647 100644 (file)
@@ -775,31 +775,51 @@ rstp_get_root_path_cost(const struct rstp *rstp)
     return cost;
 }
 
-/* Returns true if something has happened to 'rstp' which necessitates
- * flushing the client's MAC learning table.
- */
-bool
-rstp_check_and_reset_fdb_flush(struct rstp *rstp)
+/* Finds a port which needs to flush its own MAC learning table.  A NULL
+ * pointer is returned if no port needs to flush its MAC learning table.
+ * '*port' needs to be NULL in the first call to start the iteration.  If
+ * '*port' is passed as non-NULL, it must be the value set by the last
+ * invocation of this function. */
+void *
+rstp_check_and_reset_fdb_flush(struct rstp *rstp, struct rstp_port **port)
     OVS_EXCLUDED(rstp_mutex)
 {
-    bool needs_flush;
-    struct rstp_port *p;
-
-    needs_flush = false;
+    void *aux = NULL;
 
     ovs_mutex_lock(&rstp_mutex);
-    HMAP_FOR_EACH (p, node, &rstp->ports) {
-        if (p->fdb_flush) {
-            needs_flush = true;
-            /* fdb_flush should be reset by the filtering database
-             * once the entries are removed if rstp_version is TRUE, and
-             * immediately if stp_version is TRUE.*/
-            p->fdb_flush = false;
+    if (*port == NULL) {
+        struct rstp_port *p;
+
+        HMAP_FOR_EACH (p, node, &rstp->ports) {
+            if (p->fdb_flush) {
+                aux = p->aux;
+                *port = p;
+                goto out;
+            }
         }
+    } else { /* continue */
+        struct rstp_port *p = *port;
+
+        HMAP_FOR_EACH_CONTINUE (p, node, &rstp->ports) {
+            if (p->fdb_flush) {
+                aux = p->aux;
+                *port = p;
+                goto out;
+            }
+        }
+    }
+    /* No port needs flushing. */
+    *port = NULL;
+out:
+    /* fdb_flush should be reset by the filtering database
+     * once the entries are removed if rstp_version is TRUE, and
+     * immediately if stp_version is TRUE.*/
+    if (*port != NULL) {
+        (*port)->fdb_flush = false;
     }
     ovs_mutex_unlock(&rstp_mutex);
-    return needs_flush;
-}
+    return aux;
+    }
 
 /* Finds a port whose state has changed, and returns the aux pointer set for
  * the port.  A NULL pointer is returned when no changed port is found.  On
index b429e35..b05cdf2 100644 (file)
@@ -157,7 +157,7 @@ void rstp_tick_timers(struct rstp *)
 void rstp_port_received_bpdu(struct rstp_port *, const void *bpdu,
                              size_t bpdu_size)
     OVS_EXCLUDED(rstp_mutex);
-bool rstp_check_and_reset_fdb_flush(struct rstp *)
+void *rstp_check_and_reset_fdb_flush(struct rstp *, struct rstp_port **)
     OVS_EXCLUDED(rstp_mutex);
 void *rstp_get_next_changed_port_aux(struct rstp *, struct rstp_port **)
     OVS_EXCLUDED(rstp_mutex);
index fd7340d..5b2ae5d 100644 (file)
@@ -140,6 +140,7 @@ static void bundle_destroy(struct ofbundle *);
 static void bundle_del_port(struct ofport_dpif *);
 static void bundle_run(struct ofbundle *);
 static void bundle_wait(struct ofbundle *);
+static void bundle_flush_macs(struct ofbundle *, bool);
 
 static void stp_run(struct ofproto_dpif *ofproto);
 static void stp_wait(struct ofproto_dpif *ofproto);
@@ -2127,11 +2128,11 @@ update_rstp_port_state(struct ofport_dpif *ofport)
                  rstp_state_name(ofport->rstp_state),
                  rstp_state_name(state));
         if (rstp_learn_in_state(ofport->rstp_state)
-                != rstp_learn_in_state(state)) {
-            /* xxx Learning action flows should also be flushed. */
-            ovs_rwlock_wrlock(&ofproto->ml->rwlock);
-            mac_learning_flush(ofproto->ml);
-            ovs_rwlock_unlock(&ofproto->ml->rwlock);
+            != rstp_learn_in_state(state)) {
+            /* XXX: Learning action flows should also be flushed. */
+            if (ofport->bundle) {
+                bundle_flush_macs(ofport->bundle, false);
+            }
         }
         fwd_change = rstp_forward_in_state(ofport->rstp_state)
             != rstp_forward_in_state(state);
@@ -2171,16 +2172,13 @@ rstp_run(struct ofproto_dpif *ofproto)
         while ((ofport = rstp_get_next_changed_port_aux(ofproto->rstp, &rp))) {
             update_rstp_port_state(ofport);
         }
+        rp = NULL;
+        ofport = NULL;
         /* FIXME: This check should be done on-event (i.e., when setting
          * p->fdb_flush) and not periodically.
          */
-        if (rstp_check_and_reset_fdb_flush(ofproto->rstp)) {
-            ovs_rwlock_wrlock(&ofproto->ml->rwlock);
-            /* FIXME: RSTP should be able to flush the entries pertaining to a
-             * single port, not the whole table.
-             */
-            mac_learning_flush(ofproto->ml);
-            ovs_rwlock_unlock(&ofproto->ml->rwlock);
+        while ((ofport = rstp_check_and_reset_fdb_flush(ofproto->rstp, &rp))) {
+            bundle_flush_macs(ofport->bundle, false);
         }
     }
 }