vswitchd: Revalidate all flows upon bridge configuration change.
authorBen Pfaff <blp@nicira.com>
Tue, 30 Dec 2008 00:01:16 +0000 (16:01 -0800)
committerBen Pfaff <blp@nicira.com>
Tue, 30 Dec 2008 00:02:29 +0000 (16:02 -0800)
Otherwise, now-invalid flows can linger, causing trouble.

vswitchd/bridge.c

index a99171fc0b1f7eca2e6d0fe7ecdae68421d4c5b1..d58e635a309b6b05702155bcb158e07e9585aef9 100644 (file)
@@ -141,6 +141,7 @@ struct bridge {
     /* Flow tracking. */
     struct ft *ft;
     struct tag_set revalidate_set;
+    bool flush;
 
     /* Flow statistics gathering. */
     struct stats_mgr *stats_mgr;
@@ -352,6 +353,20 @@ bridge_wait(void)
         stats_mgr_wait(br->stats_mgr);
         flowstats_wait(br);
         bond_wait(br);
+        if (!tag_set_is_empty(&br->revalidate_set)) {
+            poll_immediate_wake();
+        }
+    }
+}
+
+/* Forces 'br' to revalidate all of its flows.  This is appropriate when 'br''s
+ * configuration changes.  */
+void
+bridge_flush(struct bridge *br)
+{
+    br->flush = true;
+    if (br->ml) {
+        mac_learning_flush(br->ml);
     }
 }
 \f
@@ -386,6 +401,8 @@ bridge_create(const char *name)
     port_array_init(&br->ifaces);
 
     br->ft = ft_create();
+    tag_set_init(&br->revalidate_set);
+    br->flush = false;
 
     br->stats_mgr = stats_mgr_create(br->rconn);
 
@@ -659,8 +676,6 @@ bridge_run_one(struct bridge *br)
         }
     }
 
-    tag_set_init(&br->revalidate_set);
-
     /* Now do the things that may want to revalidate flows. */
     for (iteration = 0; iteration < 50 && !bridge_is_backlogged(br);
          iteration++) {
@@ -679,19 +694,22 @@ bridge_run_one(struct bridge *br)
     flowstats_run(br);
     bond_run(br);
 
+    /* Start or restart secchan if necessary. */
+    run_secchan(br);
+
     /* Now revalidate any flows that need it. */
-    if (!tag_set_is_empty(&br->revalidate_set)) {
+    if (br->flush || !tag_set_is_empty(&br->revalidate_set)) {
         struct ft_flow *f, *next;
 
         HMAP_FOR_EACH_SAFE (f, next, struct ft_flow, node, &br->ft->flows) {
-            if (tag_set_intersects(&br->revalidate_set, f->tags)) {
+            if (br->flush
+                || tag_set_intersects(&br->revalidate_set, f->tags)) {
                 revalidate_flow(br, f);
             }
         }
     }
-
-    /* Start or restart secchan if necessary. */
-    run_secchan(br);
+    tag_set_init(&br->revalidate_set);
+    br->flush = false;
 }
 
 static void
@@ -1391,9 +1409,6 @@ process_flow(struct bridge *br, const struct flow *flow,
         uint16_t out_port_idx;
         bool may_learn;
 
-        /* XXX flush learning table entries when port indexes change due to
-         * reconfiguration */
-
         if (!pkt->buf) {
             /* Don't try to learn from revalidation. */
             may_learn = false;
@@ -1978,6 +1993,7 @@ port_create(struct bridge *br, const char *name)
     br->ports[br->n_ports++] = port;
 
     VLOG_WARN("created port %s on bridge %s", port->name, br->name);
+    bridge_flush(br);
 }
 
 static void
@@ -1985,6 +2001,7 @@ port_reconfigure(struct port *port)
 {
     bool bonded = cfg_has_section("bonding.%s", port->name);
     struct svec old_ifaces, new_ifaces;
+    int vlan;
     size_t i;
 
     /* Collect old and new interfaces. */
@@ -2032,18 +2049,16 @@ port_reconfigure(struct port *port)
     }
 
     /* Get VLAN tag. */
-    port->vlan = 0;
+    vlan = 0;
     if (cfg_has("vlan.%s.tag", port->name)) {
         if (!bonded) {
-            int vlan = cfg_get_int(0, "vlan.%s.tag", port->name);
-            if (port->vlan >= 0 && port->vlan <= 4095) {
-                VLOG_DBG("port %s: assigning VLAN tag %d",
-                         port->name, port->vlan);
-                port->vlan = vlan;
+            vlan = cfg_get_int(0, "vlan.%s.tag", port->name);
+            if (vlan >= 0 && vlan <= 4095) {
+                VLOG_DBG("port %s: assigning VLAN tag %d", port->name, vlan);
             } else {
                 VLOG_WARN("port %s: ignoring VLAN tag %d because it is not in "
-                          "the valid range from 0 to 4095",
-                          port->name, port->vlan);
+                          "the valid range from 0 to 4095", port->name, vlan);
+                vlan = 0;
             }
         } else {
             /* It's possible that bonded, VLAN-tagged ports make sense.  Maybe
@@ -2052,6 +2067,10 @@ port_reconfigure(struct port *port)
                       port->name);
         }
     }
+    if (port->vlan != vlan) {
+        port->vlan = vlan;
+        bridge_flush(port->bridge);
+    }
     svec_destroy(&old_ifaces);
     svec_destroy(&new_ifaces);
 }
@@ -2072,6 +2091,7 @@ port_destroy(struct port *port)
         }
         free(port->ifaces);
         free(port);
+        bridge_flush(br);
     }
 }
 
@@ -2128,6 +2148,7 @@ iface_create(struct port *port, const char *name)
     VLOG_DBG("attached network device %s to port %s", iface->name, port->name);
 
     port_update_bonding(port);
+    bridge_flush(port->bridge);
 }
 
 static void
@@ -2140,6 +2161,7 @@ iface_destroy(struct iface *iface)
         free(iface);
 
         port_update_bonding(port);
+        bridge_flush(port->bridge);
     }
 }