vswitch: Don't push bad flows to datapath during reconfiguration.
authorBen Pfaff <blp@nicira.com>
Wed, 3 Jun 2009 16:36:06 +0000 (09:36 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 3 Jun 2009 16:36:06 +0000 (09:36 -0700)
When reconfiguration adds a new port to a bridge, it initially has
dp_ifidx of -1, indicating that the datapath port number is unknown.  (It
can't be known because ports are added to the datapath later on.)  But
during configuration of the controller we may add or modify flows using
ofproto_add_flow(), which can update flows in the datapath.  The -1
dp_ifidx will then get converted to uint16_t as 65535, which the datapath
will reject as a bad port number.

This commit solves the problem by configuring the controller later, after
datapath port numbers have been assigned.

vswitchd/bridge.c

index 65be78b021a319a44744d629f8828bcc4db5e036..2353c344128623ed3b695e650de4befafa9d6816 100644 (file)
@@ -198,6 +198,7 @@ static void bridge_destroy(struct bridge *);
 static struct bridge *bridge_lookup(const char *name);
 static int bridge_run_one(struct bridge *);
 static void bridge_reconfigure_one(struct bridge *);
+static void bridge_reconfigure_controller(struct bridge *);
 static void bridge_get_all_ifaces(const struct bridge *, struct svec *ifaces);
 static void bridge_fetch_dp_ifaces(struct bridge *);
 static void bridge_flush(struct bridge *);
@@ -548,12 +549,16 @@ bridge_reconfigure(void)
                     br->name);
         }
 
-        /* Set the controller.  (It would be more straightforward to do
-         * this in bridge_reconfigure_one(), but then the
-         * ofproto_set_datapath_id() above would disconnect right away, and
-         * we can't call ofproto_set_datapath_id() until we know the set of
-         * ports actually in the bridge, hence not until now.) */
-        ofproto_set_controller(br->ofproto, br->controller);
+        /* Update the controller and related settings.  It would be more
+         * straightforward to call this from bridge_reconfigure_one(), but we
+         * can't do it there for two reasons.  First, and most importantly, at
+         * that point we don't know the dp_ifidx of any interfaces that have
+         * been added to the bridge (because we haven't actually added them to
+         * the datapath).  Second, at that point we haven't set the datapath ID
+         * yet; when a controller is configured, resetting the datapath ID will
+         * immediately disconnect from the controller, so it's better to set
+         * the datapath ID before the controller. */
+        bridge_reconfigure_controller(br);
     }
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         for (i = 0; i < br->n_ports; i++) {
@@ -564,6 +569,16 @@ bridge_reconfigure(void)
     LIST_FOR_EACH (br, struct bridge, node, &all_bridges) {
         brstp_reconfigure(br);
     }
+    LIST_FOR_EACH_SAFE (br, next, struct bridge, node, &all_bridges) {
+        for (i = 0; i < br->n_ports; i++) {
+            struct port *port = br->ports[i];
+            for (j = 0; j < port->n_ifaces; j++) {
+                struct iface *iface = port->ifaces[j];
+                VLOG_WARN("dp%u: %s on port %d",
+                          dpif_id(&br->dpif), iface->name, iface->dp_ifidx);
+            }
+        }
+    }
 }
 
 static void
@@ -901,20 +916,25 @@ bridge_run_one(struct bridge *br)
     return error;
 }
 
+static const char *
+bridge_get_controller(const struct bridge *br)
+{
+    const char *controller;
+
+    controller = cfg_get_string(0, "bridge.%s.controller", br->name);
+    if (!controller) {
+        controller = cfg_get_string(0, "mgmt.controller");
+    }
+    return controller && controller[0] ? controller : NULL;
+}
+
 static void
 bridge_reconfigure_one(struct bridge *br)
 {
     struct svec old_ports, new_ports, ifaces;
     struct svec listeners, old_listeners;
     struct svec snoops, old_snoops;
-    const char *controller;
     size_t i, j;
-    char *ctl, *pfx;
-
-    /* Decide on remote controller. */
-    pfx = xasprintf("bridge.%s.controller", br->name);
-    controller = cfg_get_string(0, "%s", pfx);
-    ctl = controller ? xstrdup(controller) : NULL;
 
     /* Collect old ports. */
     svec_init(&old_ports);
@@ -928,7 +948,7 @@ bridge_reconfigure_one(struct bridge *br)
     svec_init(&new_ports);
     cfg_get_all_keys(&new_ports, "bridge.%s.port", br->name);
     svec_sort(&new_ports);
-    if (ctl && !svec_contains(&new_ports, br->name)) {
+    if (bridge_get_controller(br) && !svec_contains(&new_ports, br->name)) {
         svec_add(&new_ports, br->name);
         svec_sort(&new_ports);
     }
@@ -989,26 +1009,74 @@ bridge_reconfigure_one(struct bridge *br)
     }
     svec_destroy(&ifaces);
 
-    /* If a controller is not specified for the bridge, try using the
-     * management channel's settings. */
-    if (!ctl) {
-        controller = cfg_get_string(0, "mgmt.controller");
-        ctl = controller ? xstrdup(controller) : NULL;
-    }
-
     /* Delete all flows if we're switching from connected to standalone or vice
      * versa.  (XXX Should we delete all flows if we are switching from one
      * controller to another?) */
-    if ((br->controller != NULL) != (ctl != NULL)) {
+
+    /* Configure OpenFlow management listeners. */
+    svec_init(&listeners);
+    cfg_get_all_strings(&listeners, "bridge.%s.openflow.listeners", br->name);
+    if (!listeners.n) {
+        svec_add_nocopy(&listeners, xasprintf("punix:%s/%s.mgmt",
+                                              ovs_rundir, br->name));
+    } else if (listeners.n == 1 && !strcmp(listeners.names[0], "none")) {
+        svec_clear(&listeners);
+    }
+    svec_sort_unique(&listeners);
+
+    svec_init(&old_listeners);
+    ofproto_get_listeners(br->ofproto, &old_listeners);
+    svec_sort_unique(&old_listeners);
+
+    if (!svec_equal(&listeners, &old_listeners)) {
+        ofproto_set_listeners(br->ofproto, &listeners);
+    }
+    svec_destroy(&listeners);
+    svec_destroy(&old_listeners);
+
+    /* Configure OpenFlow controller connection snooping. */
+    svec_init(&snoops);
+    cfg_get_all_strings(&snoops, "bridge.%s.openflow.snoops", br->name);
+    if (!snoops.n) {
+        svec_add_nocopy(&snoops, xasprintf("punix:%s/%s.snoop",
+                                           ovs_rundir, br->name));
+    } else if (snoops.n == 1 && !strcmp(snoops.names[0], "none")) {
+        svec_clear(&snoops);
+    }
+    svec_sort_unique(&snoops);
+
+    svec_init(&old_snoops);
+    ofproto_get_snoops(br->ofproto, &old_snoops);
+    svec_sort_unique(&old_snoops);
+
+    if (!svec_equal(&snoops, &old_snoops)) {
+        ofproto_set_snoops(br->ofproto, &snoops);
+    }
+    svec_destroy(&snoops);
+    svec_destroy(&old_snoops);
+
+    mirror_reconfigure(br);
+}
+
+static void
+bridge_reconfigure_controller(struct bridge *br)
+{
+    char *pfx = xasprintf("bridge.%s.controller", br->name);
+    const char *controller;
+
+    controller = bridge_get_controller(br);
+    if ((br->controller != NULL) != (controller != NULL)) {
         ofproto_flush_flows(br->ofproto);
     }
+    free(br->controller);
+    br->controller = controller ? xstrdup(controller) : NULL;
 
-    if (ctl && strlen(ctl) != 0) {
+    if (controller) {
         const char *fail_mode;
         int max_backoff, probe;
         int rate_limit, burst_limit;
 
-        if (!strcmp(ctl, "discover")) {
+        if (!strcmp(controller, "discover")) {
             ofproto_set_discovery(br->ofproto, true,
                                   cfg_get_string(0, "%s.accept-regex", pfx),
                                   cfg_get_bool(0, "%s.update-resolv.conf",
@@ -1065,7 +1133,7 @@ bridge_reconfigure_one(struct bridge *br)
 
         probe = cfg_get_int(0, "%s.inactivity-probe", pfx);
         ofproto_set_probe_interval(br->ofproto,
-                probe ? probe : cfg_get_int(0, "mgmt.inactivity-probe"));
+                                   probe ? probe : cfg_get_int(0, "mgmt.inactivity-probe"));
 
         max_backoff = cfg_get_int(0, "%s.max-backoff", pfx);
         if (!max_backoff) {
@@ -1125,53 +1193,9 @@ bridge_reconfigure_one(struct bridge *br)
         ofproto_set_failure(br->ofproto, false);
         ofproto_set_stp(br->ofproto, false);
     }
-    free(br->controller);
-    br->controller = ctl;
     free(pfx);
 
-    /* Configure OpenFlow management listeners. */
-    svec_init(&listeners);
-    cfg_get_all_strings(&listeners, "bridge.%s.openflow.listeners", br->name);
-    if (!listeners.n) {
-        svec_add_nocopy(&listeners, xasprintf("punix:%s/%s.mgmt",
-                                              ovs_rundir, br->name));
-    } else if (listeners.n == 1 && !strcmp(listeners.names[0], "none")) {
-        svec_clear(&listeners);
-    }
-    svec_sort_unique(&listeners);
-
-    svec_init(&old_listeners);
-    ofproto_get_listeners(br->ofproto, &old_listeners);
-    svec_sort_unique(&old_listeners);
-
-    if (!svec_equal(&listeners, &old_listeners)) {
-        ofproto_set_listeners(br->ofproto, &listeners);
-    }
-    svec_destroy(&listeners);
-    svec_destroy(&old_listeners);
-
-    /* Configure OpenFlow controller connection snooping. */
-    svec_init(&snoops);
-    cfg_get_all_strings(&snoops, "bridge.%s.openflow.snoops", br->name);
-    if (!snoops.n) {
-        svec_add_nocopy(&snoops, xasprintf("punix:%s/%s.snoop",
-                                           ovs_rundir, br->name));
-    } else if (snoops.n == 1 && !strcmp(snoops.names[0], "none")) {
-        svec_clear(&snoops);
-    }
-    svec_sort_unique(&snoops);
-
-    svec_init(&old_snoops);
-    ofproto_get_snoops(br->ofproto, &old_snoops);
-    svec_sort_unique(&old_snoops);
-
-    if (!svec_equal(&snoops, &old_snoops)) {
-        ofproto_set_snoops(br->ofproto, &snoops);
-    }
-    svec_destroy(&snoops);
-    svec_destroy(&old_snoops);
-
-    mirror_reconfigure(br);
+    ofproto_set_controller(br->ofproto, br->controller);
 }
 
 static void