ovs-vsctl: Prevent creating duplicate VLAN bridges.
authorBen Pfaff <blp@nicira.com>
Thu, 6 Nov 2014 22:59:40 +0000 (14:59 -0800)
committerBen Pfaff <blp@nicira.com>
Tue, 25 Nov 2014 17:02:52 +0000 (09:02 -0800)
ovs-vsctl has the concept of a VLAN (or "fake") bridge, which is a
sort of a sub-bridge that receives only packets on a particular VLAN.
There is no way to distinguish two VLAN bridges with the same parent on the
same VLAN, but until now ovs-vsctl did not prevent creating duplicates or
report them.  This commit fixes the problem.

Reported-by: rwxybh
Reported-at: https://github.com/openvswitch/ovs/issues/21
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Thomas Graf <tgraf@noironetworks.com>
tests/ovs-vsctl.at
utilities/ovs-vsctl.8.in
utilities/ovs-vsctl.c

index efe7817..f6e6994 100644 (file)
@@ -483,6 +483,9 @@ AT_CHECK([RUN_OVS_VSCTL([--may-exist add-br xapi1 xxx $1])], [1], [],
 AT_CHECK([RUN_OVS_VSCTL([--may-exist add-br xapi1 xenbr0 10])], [1], [],
   [ovs-vsctl: "--may-exist add-br xapi1 xenbr0 10" but xapi1 is a VLAN bridge for the wrong VLAN $1
 ], [OVS_VSCTL_CLEANUP])
+AT_CHECK([RUN_OVS_VSCTL([--may-exist add-br dup xenbr0 $1])], [1], [],
+  [ovs-vsctl: bridge xenbr0 already has a child VLAN bridge xapi1 on VLAN $1
+], [OVS_VSCTL_CLEANUP])
 CHECK_BRIDGES([xapi1, xenbr0, $1], [xenbr0, xenbr0, 0])
 CHECK_PORTS([xenbr0], [eth0])
 CHECK_IFACES([xenbr0], [eth0])
index 1c6334a..bb030e4 100644 (file)
@@ -192,7 +192,8 @@ nothing if \fIbridge\fR already exists as a real bridge.
 Creates a ``fake bridge'' named \fIbridge\fR within the existing Open
 vSwitch bridge \fIparent\fR, which must already exist and must not
 itself be a fake bridge.  The new fake bridge will be on 802.1Q VLAN
-\fIvlan\fR, which must be an integer between 0 and 4095.  Initially
+\fIvlan\fR, which must be an integer between 0 and 4095.  The parent
+bridge must not already have a fake bridge for \fIvlan\fR.  Initially
 \fIbridge\fR will have no ports (other than \fIbridge\fR itself).
 .IP
 Without \fB\-\-may\-exist\fR, attempting to create a bridge that
index 8ac6d10..e33d79d 100644 (file)
@@ -814,6 +814,9 @@ struct vsctl_iface {
     struct vsctl_port *port;
 };
 
+static struct vsctl_bridge *find_vlan_bridge(struct vsctl_bridge *parent,
+                                             int vlan);
+
 static char *
 vsctl_context_to_string(const struct vsctl_context *ctx)
 {
@@ -870,7 +873,15 @@ add_bridge_to_cache(struct vsctl_context *ctx,
     br->vlan = vlan;
     hmap_init(&br->children);
     if (parent) {
-        hmap_insert(&parent->children, &br->children_node, hash_int(vlan, 0));
+        struct vsctl_bridge *conflict = find_vlan_bridge(parent, vlan);
+        if (conflict) {
+            VLOG_WARN("%s: bridge has multiple VLAN bridges (%s and %s) "
+                      "for VLAN %d, but only one is allowed",
+                      parent->name, name, conflict->name, vlan);
+        } else {
+            hmap_insert(&parent->children, &br->children_node,
+                        hash_int(vlan, 0));
+        }
     }
     shash_add(&ctx->bridges, br->name, br);
     return br;
@@ -1660,6 +1671,7 @@ cmd_add_br(struct vsctl_context *ctx)
 
         ovs_insert_bridge(ctx->ovs, br);
     } else {
+        struct vsctl_bridge *conflict;
         struct vsctl_bridge *parent;
         struct ovsrec_port *port;
         struct ovsrec_bridge *br;
@@ -1672,6 +1684,11 @@ cmd_add_br(struct vsctl_context *ctx)
         if (!parent) {
             vsctl_fatal("parent bridge %s does not exist", parent_name);
         }
+        conflict = find_vlan_bridge(parent, vlan);
+        if (conflict) {
+            vsctl_fatal("bridge %s already has a child VLAN bridge %s "
+                        "on VLAN %d", parent_name, conflict->name, vlan);
+        }
         br = parent->br_cfg;
 
         iface = ovsrec_interface_insert(ctx->txn);