[ovs-dev] [PATCH 14/17] rstp: shift learned MAC addresses to new Root port.

Daniele Venturino daniele.venturino at m3s.it
Thu Nov 6 15:31:12 UTC 2014


      All MAC addresses previously learned on a Root Port can be moved to an
      Alternate Port that becomes the new Root Port; i.e., Dynamic Filtering
      Entries for those addresses may be modified to show the new Root Port as
      their source, reducing the need to flood frames when recovering from
      some component failures.

Signed-off-by: Daniele Venturino <daniele.venturino at m3s.it>
---
 lib/rstp-common.h         |  4 ++++
 lib/rstp-state-machines.c | 21 +++++++++++++++++++
 lib/rstp.c                | 51 ++++++++++++++++++++++++++++++++++++++---------
 lib/rstp.h                | 10 ++++++++++
 ofproto/ofproto-dpif.c    | 39 ++++++++++++++++++++++++++++++++++--
 5 files changed, 114 insertions(+), 11 deletions(-)

diff --git a/lib/rstp-common.h b/lib/rstp-common.h
index 6e56958..271db2a 100644
--- a/lib/rstp-common.h
+++ b/lib/rstp-common.h
@@ -868,6 +868,10 @@ struct rstp {
     /* Interface to client. */
     void (*send_bpdu)(struct ofpbuf *bpdu, void *port_aux, void *rstp_aux);
     void *aux;
+
+    bool root_changed;
+    void *old_root_aux;
+    void *new_root_aux;
 };
 
 #endif /* rstp-common.h */
diff --git a/lib/rstp-state-machines.c b/lib/rstp-state-machines.c
index 516093f..40eeea5 100644
--- a/lib/rstp-state-machines.c
+++ b/lib/rstp-state-machines.c
@@ -287,7 +287,14 @@ updt_roles_tree__(struct rstp *r)
     struct rstp_port *p;
     int vsel;
     struct rstp_priority_vector best_vector, candidate_vector;
+    enum rstp_port_role new_root_old_role = ROLE_DESIGNATED;
+    uint16_t old_root_port_number = 0;
+    uint16_t new_root_port_number = 0;
 
+    old_root_port_number = r->root_port_id & 0x00ff;
+    if (old_root_port_number) {
+        r->old_root_aux = rstp_get_port_aux(r, old_root_port_number);
+    }
     vsel = -1;
     best_vector = r->bridge_priority;
     /* Letter c1) */
@@ -317,12 +324,26 @@ updt_roles_tree__(struct rstp *r)
             r->root_times = p->port_times;
             r->root_times.message_age++;
             vsel = p->port_number;
+            new_root_old_role = p->role;
         }
     }
     r->root_priority = best_vector;
     r->root_port_id = best_vector.bridge_port_id;
     VLOG_DBG("%s: new Root is "RSTP_ID_FMT, r->name,
              RSTP_ID_ARGS(r->root_priority.root_bridge_id));
+    new_root_port_number = r->root_port_id & 0x00ff;
+    if (new_root_port_number) {
+        r->new_root_aux = rstp_get_port_aux(r, new_root_port_number);
+    }
+    /* Shift learned MAC addresses from an old Root Port to an existing
+     * Alternate Port. */
+    if (!r->root_changed
+            && new_root_old_role == ROLE_ALTERNATE
+            && new_root_port_number
+            && old_root_port_number
+            && new_root_port_number != old_root_port_number) {
+        r->root_changed = true;
+    }
     /* Letters d) e) */
     HMAP_FOR_EACH (p, node, &r->ports) {
         p->designated_priority_vector.root_bridge_id =
diff --git a/lib/rstp.c b/lib/rstp.c
index fd42a7d..5256740 100644
--- a/lib/rstp.c
+++ b/lib/rstp.c
@@ -867,6 +867,42 @@ out:
     return aux;
 }
 
+bool
+rstp_shift_root_learned_address(struct rstp *rstp) {
+    bool ret = false;
+    ovs_mutex_lock(&rstp_mutex);
+    if (rstp->root_changed) {
+        ret = true;
+    }
+    ovs_mutex_unlock(&rstp_mutex);
+    return ret;
+}
+
+void *
+rstp_get_old_root_aux(struct rstp *rstp) {
+    void *aux = NULL;
+    ovs_mutex_lock(&rstp_mutex);
+    aux = rstp->old_root_aux;
+    ovs_mutex_unlock(&rstp_mutex);
+    return aux;
+}
+
+void *
+rstp_get_new_root_aux(struct rstp *rstp) {
+    void *aux = NULL;
+    ovs_mutex_lock(&rstp_mutex);
+    aux = rstp->new_root_aux;
+    ovs_mutex_unlock(&rstp_mutex);
+    return aux;
+}
+
+void
+rstp_reset_root_changed(struct rstp *rstp) {
+    ovs_mutex_lock(&rstp_mutex);
+    rstp->root_changed = false;
+    ovs_mutex_unlock(&rstp_mutex);
+}
+
 /* Returns the port in 'rstp' with number 'port_number'.
  *
  * XXX: May only be called while concurrent deletion of ports is excluded. */
@@ -878,8 +914,7 @@ rstp_get_port__(struct rstp *rstp, uint16_t port_number)
 
     ovs_assert(rstp && port_number > 0 && port_number <= RSTP_MAX_PORTS);
 
-    HMAP_FOR_EACH_WITH_HASH (port, node, hash_int(port_number, 0),
-                             &rstp->ports) {
+    HMAP_FOR_EACH (port, node, &rstp->ports) {
         if (port->port_number == port_number) {
             return port;
         }
@@ -901,16 +936,14 @@ rstp_get_port(struct rstp *rstp, uint16_t port_number)
 
 void *
 rstp_get_port_aux(struct rstp *rstp, uint16_t port_number)
-    OVS_EXCLUDED(rstp_mutex)
+    OVS_REQUIRES(rstp_mutex)
 {
     struct rstp_port *p;
-    void *aux;
-
-    ovs_mutex_lock(&rstp_mutex);
     p = rstp_get_port__(rstp, port_number);
-    aux = p->aux;
-    ovs_mutex_unlock(&rstp_mutex);
-    return aux;
+    if (p) {
+        return p->aux;
+    }
+    return NULL;
 }
 
 /* Updates the port_enabled parameter. */
diff --git a/lib/rstp.h b/lib/rstp.h
index b05cdf2..3b40a00 100644
--- a/lib/rstp.h
+++ b/lib/rstp.h
@@ -164,6 +164,16 @@ void *rstp_get_next_changed_port_aux(struct rstp *, struct rstp_port **)
 void rstp_port_set_mac_operational(struct rstp_port *,
                                    bool new_mac_operational)
     OVS_EXCLUDED(rstp_mutex);
+bool
+rstp_shift_root_learned_address(struct rstp *rstp)
+    OVS_EXCLUDED(rstp_mutex);
+void *rstp_get_old_root_aux(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+void *rstp_get_new_root_aux(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
+void
+rstp_reset_root_changed(struct rstp *)
+    OVS_EXCLUDED(rstp_mutex);
 
 /* Bridge setters */
 void rstp_set_bridge_address(struct rstp *, rstp_identifier bridge_address)
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 2fd9896..2389a18 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -141,6 +141,7 @@ 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 bundle_move(struct ofbundle *, struct ofbundle *);
 
 static void stp_run(struct ofproto_dpif *ofproto);
 static void stp_wait(struct ofproto_dpif *ofproto);
@@ -2096,11 +2097,15 @@ update_rstp_port_state(struct ofport_dpif *ofport)
                  netdev_get_name(ofport->up.netdev),
                  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. */
             if (ofport->bundle) {
-                bundle_flush_macs(ofport->bundle, false);
+                if(!rstp_shift_root_learned_address(ofproto->rstp)
+                    || ofport != rstp_get_old_root_aux(ofproto->rstp)) {
+                    bundle_flush_macs(ofport->bundle, false);
+                }
             }
         }
         fwd_change = rstp_forward_in_state(ofport->rstp_state)
@@ -2147,8 +2152,21 @@ rstp_run(struct ofproto_dpif *ofproto)
          * p->fdb_flush) and not periodically.
          */
         while ((ofport = rstp_check_and_reset_fdb_flush(ofproto->rstp, &rp))) {
-            bundle_flush_macs(ofport->bundle, false);
+            if (!rstp_shift_root_learned_address(ofproto->rstp)
+                || ofport != rstp_get_old_root_aux(ofproto->rstp)) {
+                bundle_flush_macs(ofport->bundle, false);
+            }
+        }
+
+        struct ofport_dpif *old_root;
+        struct ofport_dpif *new_root;
+        if (rstp_shift_root_learned_address(ofproto->rstp)) {
+            old_root = rstp_get_old_root_aux(ofproto->rstp);
+            new_root = rstp_get_new_root_aux(ofproto->rstp);
+            bundle_move(old_root->bundle, new_root->bundle);
+            rstp_reset_root_changed(ofproto->rstp);
         }
+
     }
 }
 
@@ -2495,6 +2513,23 @@ bundle_flush_macs(struct ofbundle *bundle, bool all_ofprotos)
     ovs_rwlock_unlock(&ml->rwlock);
 }
 
+static void bundle_move(struct ofbundle *old, struct ofbundle *new) {
+    struct ofproto_dpif *old_ofproto = old->ofproto;
+    struct ofproto_dpif *new_ofproto = new->ofproto;
+    struct mac_learning *old_ml = old_ofproto->ml;
+    struct mac_entry *mac, *next_mac;
+
+    old_ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    new_ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    ovs_rwlock_wrlock(&old_ml->rwlock);
+    LIST_FOR_EACH_SAFE (mac, next_mac, lru_node, &old_ml->lrus) {
+        if (mac->port.p == old) {
+            mac->port.p = new;
+        }
+    }
+    ovs_rwlock_unlock(&old_ml->rwlock);
+}
+
 static struct ofbundle *
 bundle_lookup(const struct ofproto_dpif *ofproto, void *aux)
 {
-- 
1.8.1.2




More information about the dev mailing list