vlan-bitmap: New data structure.
[sliver-openvswitch.git] / vswitchd / bridge.c
index f5918be..e3e5a4c 100644 (file)
@@ -73,6 +73,7 @@
 #include "xenserver.h"
 #include "vlog.h"
 #include "sflow_api.h"
+#include "vlan-bitmap.h"
 
 VLOG_DEFINE_THIS_MODULE(bridge);
 
@@ -185,6 +186,11 @@ struct bridge {
 
     /* Port mirroring. */
     struct mirror *mirrors[MAX_MIRRORS];
+
+    /* Synthetic local port if necessary. */
+    struct ovsrec_port synth_local_port;
+    struct ovsrec_interface synth_local_iface;
+    struct ovsrec_interface *synth_local_ifacep;
 };
 
 /* List of all bridges. */
@@ -264,6 +270,7 @@ static void iface_update_qos(struct iface *, const struct ovsrec_qos *);
 static void iface_update_cfm(struct iface *);
 static bool iface_refresh_cfm_stats(struct iface *iface);
 static bool iface_get_carrier(const struct iface *);
+static bool iface_is_synthetic(const struct iface *);
 
 static void shash_from_ovs_idl_map(char **keys, char **values, size_t n,
                                    struct shash *);
@@ -658,6 +665,13 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
                     dpif_port = NULL;
                 }
                 if (iface) {
+                    if (iface->port->bond) {
+                        /* The bond has a pointer to the netdev, so remove it
+                         * from the bond before closing the netdev.  The slave
+                         * will get added back to the bond later, after a new
+                         * netdev is available. */
+                        bond_slave_unregister(iface->port->bond, iface);
+                    }
                     netdev_close(iface->netdev);
                     iface->netdev = NULL;
                 }
@@ -1140,6 +1154,10 @@ iface_refresh_status(struct iface *iface)
     int64_t mtu_64;
     int error;
 
+    if (iface_is_synthetic(iface)) {
+        return;
+    }
+
     shash_init(&sh);
 
     if (!netdev_get_status(iface->netdev, &sh)) {
@@ -1282,6 +1300,10 @@ iface_refresh_stats(struct iface *iface)
 
     struct netdev_stats stats;
 
+    if (iface_is_synthetic(iface)) {
+        return;
+    }
+
     /* Intentionally ignore return value, since errors will set 'stats' to
      * all-1s, and we will deal with that correctly below. */
     netdev_get_stats(iface->netdev, &stats);
@@ -1696,10 +1718,14 @@ bridge_destroy(struct bridge *br)
     if (br) {
         struct port *port, *next;
         int error;
+        int i;
 
         HMAP_FOR_EACH_SAFE (port, next, hmap_node, &br->ports) {
             port_destroy(port);
         }
+        for (i = 0; i < MAX_MIRRORS; i++) {
+            mirror_destroy(br->mirrors[i]);
+        }
         list_remove(&br->node);
         ofproto_destroy(br->ofproto);
         error = dpif_delete(br->dpif);
@@ -1712,6 +1738,7 @@ bridge_destroy(struct bridge *br)
         hmap_destroy(&br->ifaces);
         hmap_destroy(&br->ports);
         shash_destroy(&br->iface_by_name);
+        free(br->synth_local_iface.type);
         free(br->name);
         free(br);
     }
@@ -1837,22 +1864,28 @@ bridge_reconfigure_one(struct bridge *br)
                       br->name, name);
         }
     }
+    if (!shash_find(&new_ports, br->name)) {
+        struct dpif_port dpif_port;
+        char *type;
 
-    /* If we have a controller, then we need a local port.  Complain if the
-     * user didn't specify one.
-     *
-     * XXX perhaps we should synthesize a port ourselves in this case. */
-    if (bridge_get_controllers(br, NULL)) {
-        char local_name[IF_NAMESIZE];
-        int error;
+        VLOG_WARN("bridge %s: no port named %s, synthesizing one",
+                  br->name, br->name);
 
-        error = dpif_port_get_name(br->dpif, ODPP_LOCAL,
-                                   local_name, sizeof local_name);
-        if (!error && !shash_find(&new_ports, local_name)) {
-            VLOG_WARN("bridge %s: controller specified but no local port "
-                      "(port named %s) defined",
-                      br->name, local_name);
-        }
+        dpif_port_query_by_number(br->dpif, ODPP_LOCAL, &dpif_port);
+        type = xstrdup(dpif_port.type ? dpif_port.type : "internal");
+        dpif_port_destroy(&dpif_port);
+
+        br->synth_local_port.interfaces = &br->synth_local_ifacep;
+        br->synth_local_port.n_interfaces = 1;
+        br->synth_local_port.name = br->name;
+
+        br->synth_local_iface.name = br->name;
+        free(br->synth_local_iface.type);
+        br->synth_local_iface.type = type;
+
+        br->synth_local_ifacep = &br->synth_local_iface;
+
+        shash_add(&new_ports, br->name, &br->synth_local_port);
     }
 
     /* Get rid of deleted ports.
@@ -1891,16 +1924,8 @@ bridge_reconfigure_one(struct bridge *br)
                 || !strcmp(br->cfg->fail_mode, "standalone")
                     ? OFPROTO_FAIL_STANDALONE
                     : OFPROTO_FAIL_SECURE;
-    if (ofproto_get_fail_mode(br->ofproto) != fail_mode
-        && !ofproto_has_primary_controller(br->ofproto)) {
-        ofproto_flush_flows(br->ofproto);
-    }
     ofproto_set_fail_mode(br->ofproto, fail_mode);
 
-    /* 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?) */
-
     /* Configure OpenFlow controller connection snooping. */
     if (!ofproto_has_snoops(br->ofproto)) {
         struct sset snoops;
@@ -2001,7 +2026,6 @@ bridge_reconfigure_remotes(struct bridge *br,
 
     struct ovsrec_controller **controllers;
     size_t n_controllers;
-    bool had_primary;
 
     struct ofproto_controller *ocs;
     size_t n_ocs;
@@ -2023,7 +2047,6 @@ bridge_reconfigure_remotes(struct bridge *br,
     } else {
         ofproto_set_extra_in_band_remotes(br->ofproto, managers, n_managers);
     }
-    had_primary = ofproto_has_primary_controller(br->ofproto);
 
     n_controllers = bridge_get_controllers(br, &controllers);
 
@@ -2057,28 +2080,6 @@ bridge_reconfigure_remotes(struct bridge *br,
     ofproto_set_controllers(br->ofproto, ocs, n_ocs);
     free(ocs[0].target); /* From bridge_ofproto_controller_for_mgmt(). */
     free(ocs);
-
-    if (had_primary != ofproto_has_primary_controller(br->ofproto)) {
-        ofproto_flush_flows(br->ofproto);
-    }
-
-    /* If there are no controllers and the bridge is in standalone
-     * mode, set up a flow that matches every packet and directs
-     * them to OFPP_NORMAL (which goes to us).  Otherwise, the
-     * switch is in secure mode and we won't pass any traffic until
-     * a controller has been defined and it tells us to do so. */
-    if (!n_controllers
-        && ofproto_get_fail_mode(br->ofproto) == OFPROTO_FAIL_STANDALONE) {
-        union ofp_action action;
-        struct cls_rule rule;
-
-        memset(&action, 0, sizeof action);
-        action.type = htons(OFPAT_OUTPUT);
-        action.output.len = htons(sizeof action);
-        action.output.port = htons(OFPP_NORMAL);
-        cls_rule_init_catchall(&rule, 0);
-        ofproto_add_flow(br->ofproto, &rule, &action, 1);
-    }
 }
 
 static void
@@ -2225,8 +2226,7 @@ dst_is_duplicate(const struct dst_set *set, const struct dst *test)
 static bool
 port_trunks_vlan(const struct port *port, uint16_t vlan)
 {
-    return (port->vlan < 0
-            && (!port->trunks || bitmap_is_set(port->trunks, vlan)));
+    return (port->vlan < 0 || vlan_bitmap_contains(port->trunks, vlan));
 }
 
 static bool
@@ -2980,35 +2980,16 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
     /* Get trunked VLANs. */
     trunks = NULL;
     if (vlan < 0 && cfg->n_trunks) {
-        size_t n_errors;
-
-        trunks = bitmap_allocate(4096);
-        n_errors = 0;
-        for (i = 0; i < cfg->n_trunks; i++) {
-            int trunk = cfg->trunks[i];
-            if (trunk >= 0) {
-                bitmap_set1(trunks, trunk);
-            } else {
-                n_errors++;
-            }
-        }
-        if (n_errors) {
-            VLOG_ERR("port %s: invalid values for %zu trunk VLANs",
-                     port->name, cfg->n_trunks);
-        }
-        if (n_errors == cfg->n_trunks) {
+        trunks = vlan_bitmap_from_array(cfg->trunks, cfg->n_trunks);
+        if (!trunks) {
             VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
                      port->name);
-            bitmap_free(trunks);
-            trunks = NULL;
         }
     } else if (vlan >= 0 && cfg->n_trunks) {
         VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
                  port->name);
     }
-    if (trunks == NULL
-        ? port->trunks != NULL
-        : port->trunks == NULL || !bitmap_equal(trunks, port->trunks, 4096)) {
+    if (!vlan_bitmap_equal(trunks, port->trunks)) {
         need_flush = true;
     }
     bitmap_free(port->trunks);
@@ -3401,7 +3382,7 @@ iface_set_mac(struct iface *iface)
 static void
 iface_set_ofport(const struct ovsrec_interface *if_cfg, int64_t ofport)
 {
-    if (if_cfg) {
+    if (if_cfg && !ovsdb_idl_row_is_synthetic(&if_cfg->header_)) {
         ovsrec_interface_set_ofport(if_cfg, &ofport, 1);
     }
 }
@@ -3561,6 +3542,14 @@ iface_get_carrier(const struct iface *iface)
     /* XXX */
     return netdev_get_carrier(iface->netdev);
 }
+
+/* Returns true if 'iface' is synthetic, that is, if we constructed it locally
+ * instead of obtaining it from the database. */
+static bool
+iface_is_synthetic(const struct iface *iface)
+{
+    return ovsdb_idl_row_is_synthetic(&iface->cfg->header_);
+}
 \f
 /* Port mirroring. */
 
@@ -3625,19 +3614,8 @@ mirror_reconfigure(struct bridge *br)
     /* Update flooded vlans (for RSPAN). */
     rspan_vlans = NULL;
     if (br->cfg->n_flood_vlans) {
-        rspan_vlans = bitmap_allocate(4096);
-
-        for (i = 0; i < br->cfg->n_flood_vlans; i++) {
-            int64_t vlan = br->cfg->flood_vlans[i];
-            if (vlan >= 0 && vlan < 4096) {
-                bitmap_set1(rspan_vlans, vlan);
-                VLOG_INFO("bridge %s: disabling learning on vlan %"PRId64,
-                          br->name, vlan);
-            } else {
-                VLOG_ERR("bridge %s: invalid value %"PRId64 "for flood VLAN",
-                         br->name, vlan);
-            }
-        }
+        rspan_vlans = vlan_bitmap_from_array(br->cfg->flood_vlans,
+                                             br->cfg->n_flood_vlans);
     }
     if (mac_learning_set_flood_vlans(br->ml, rspan_vlans)) {
         bridge_flush(br);