From 6ae507231be01f14c37dd7f52783de36a70d9d09 Mon Sep 17 00:00:00 2001
From: Ethan Jackson <ethan@nicira.com>
Date: Mon, 16 Jan 2012 15:07:55 -0800
Subject: [PATCH] stp: Flush MAC table on topology change.

Signed-off-by: Ethan Jackson <ethan@nicira.com>
---
 lib/stp.c              | 16 ++++++++++++++++
 lib/stp.h              |  1 +
 ofproto/ofproto-dpif.c |  4 ++++
 3 files changed, 21 insertions(+)

diff --git a/lib/stp.c b/lib/stp.c
index 3e9a5b6a..f7fe53cc 100644
--- a/lib/stp.c
+++ b/lib/stp.c
@@ -131,6 +131,7 @@ struct stp {
     struct stp_port ports[STP_MAX_PORTS];
 
     /* Interface to client. */
+    bool fdb_needs_flush;          /* MAC learning tables needs flushing. */
     struct stp_port *first_changed_port;
     void (*send_bpdu)(struct ofpbuf *bpdu, int port_no, void *aux);
     void *aux;
@@ -448,6 +449,17 @@ stp_get_forward_delay(const struct stp *stp)
     return timer_to_ms(stp->bridge_forward_delay);
 }
 
+/* Returns true if something has happened to 'stp' which necessitates flushing
+ * the client's MAC learning table.  Calling this function resets 'stp' so that
+ * future calls will return false until flushing is required again. */
+bool
+stp_check_and_reset_fdb_flush(struct stp *stp)
+{
+    bool needs_flush = stp->fdb_needs_flush;
+    stp->fdb_needs_flush = false;
+    return needs_flush;
+}
+
 /* Returns the port in 'stp' with index 'port_no', which must be between 0 and
  * STP_MAX_PORTS. */
 struct stp_port *
@@ -1047,6 +1059,7 @@ stp_topology_change_detection(struct stp *stp)
         stp_transmit_tcn(stp);
         stp_start_timer(&stp->tcn_timer, 0);
     }
+    stp->fdb_needs_flush = true;
     stp->topology_change_detected = true;
 }
 
@@ -1095,6 +1108,9 @@ stp_received_config_bpdu(struct stp *stp, struct stp_port *p,
                 if (config->flags & STP_CONFIG_TOPOLOGY_CHANGE_ACK) {
                     stp_topology_change_acknowledged(stp);
                 }
+                if (config->flags & STP_CONFIG_TOPOLOGY_CHANGE) {
+                    stp->fdb_needs_flush = true;
+                }
             }
         } else if (stp_is_designated_port(p)) {
             stp_transmit_config(p);
diff --git a/lib/stp.h b/lib/stp.h
index ec29d9a7..f321dec9 100644
--- a/lib/stp.h
+++ b/lib/stp.h
@@ -76,6 +76,7 @@ int stp_get_root_path_cost(const struct stp *);
 int stp_get_hello_time(const struct stp *);
 int stp_get_max_age(const struct stp *);
 int stp_get_forward_delay(const struct stp *);
+bool stp_check_and_reset_fdb_flush(struct stp *);
 
 /* Obtaining STP ports. */
 struct stp_port *stp_get_port(struct stp *, int port_no);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 1e9b341c..344f9d4d 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -1296,6 +1296,10 @@ stp_run(struct ofproto_dpif *ofproto)
                 update_stp_port_state(ofport);
             }
         }
+
+        if (stp_check_and_reset_fdb_flush(ofproto->stp)) {
+            mac_learning_flush(ofproto->ml, &ofproto->revalidate_set);
+        }
     }
 }
 
-- 
2.30.2