ovs-openflowd: Remove documentation for obsolete --mgmt-id option.
[openvswitch] / vswitchd / ovs-brcompatd.c
index 6b6594797a0b59f699158861ecfef5a33447896e..b5037056e41ac28cc452b1ff27c8e763fb937f8e 100644 (file)
@@ -463,7 +463,6 @@ add_bridge(struct ovsdb_idl *idl, const struct ovsrec_open_vswitch *ovs,
     struct ovsrec_port *port;
     struct ovsrec_interface *iface;
     struct ovsdb_idl_txn *txn;
-    char *comment;
 
     if (find_bridge(ovs, br_name)) {
         VLOG_WARN("addbr %s: bridge %s exists", br_name, br_name);
@@ -492,9 +491,7 @@ add_bridge(struct ovsdb_idl *idl, const struct ovsrec_open_vswitch *ovs,
 
     txn = ovsdb_idl_txn_create(idl);
 
-    comment = xasprintf("ovs-brcompatd: addbr %s", br_name);
-    ovsdb_idl_txn_add_comment(txn, comment);
-    free(comment);
+    ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: addbr %s", br_name);
 
     iface = ovsrec_interface_insert(txn_from_openvswitch(ovs));
     ovsrec_interface_set_name(iface, br_name);
@@ -538,41 +535,98 @@ add_port(const struct ovsrec_open_vswitch *ovs,
     free(ports);
 }
 
+/* Deletes 'port' from 'br'.
+ *
+ * After calling this function, 'port' must not be referenced again. */
 static void
-del_port(const struct ovsrec_bridge *br, const char *port_name)
+del_port(const struct ovsrec_bridge *br, const struct ovsrec_port *port)
 {
-    size_t i, j;
-    struct ovsrec_port *port_rec = NULL;
+    struct ovsrec_port **ports;
+    size_t i, n;
+
+    /* Remove 'port' from the bridge's list of ports. */
+    ports = xmalloc(sizeof *br->ports * br->n_ports);
+    for (i = n = 0; i < br->n_ports; i++) {
+        if (br->ports[i] != port) {
+            ports[n++] = br->ports[i];
+        }
+    }
+    ovsrec_bridge_set_ports(br, ports, n);
+    free(ports);
+
+    /* Delete all of the port's interfaces. */
+    for (i = 0; i < port->n_interfaces; i++) {
+        ovsrec_interface_delete(port->interfaces[i]);
+    }
+
+    /* Delete the port itself. */
+    ovsrec_port_delete(port);
+}
+
+/* Delete 'iface' from 'port' (which must be within 'br').  If 'iface' was
+ * 'port''s only interface, delete 'port' from 'br' also.
+ *
+ * After calling this function, 'iface' must not be referenced again. */
+static void
+del_interface(const struct ovsrec_bridge *br,
+              const struct ovsrec_port *port,
+              const struct ovsrec_interface *iface)
+{
+    if (port->n_interfaces == 1) {
+        del_port(br, port);
+    } else {
+        struct ovsrec_interface **ifaces;
+        size_t i, n;
+
+        ifaces = xmalloc(sizeof *port->interfaces * port->n_interfaces);
+        for (i = n = 0; i < port->n_interfaces; i++) {
+            if (port->interfaces[i] != iface) {
+                ifaces[n++] = port->interfaces[i];
+            }
+        }
+        ovsrec_port_set_interfaces(port, ifaces, n);
+        free(ifaces);
+        ovsrec_interface_delete(iface);
+    }
+}
+
+/* Find and return a port within 'br' named 'port_name'. */
+static const struct ovsrec_port *
+find_port(const struct ovsrec_bridge *br, const char *port_name)
+{
+    size_t i;
 
     for (i = 0; i < br->n_ports; i++) {
         struct ovsrec_port *port = br->ports[i];
         if (!strcmp(port_name, port->name)) {
-            port_rec = port;
-        }
-        for (j = 0; j < port->n_interfaces; j++) {
-            struct ovsrec_interface *iface = port->interfaces[j];
-            if (!strcmp(port_name, iface->name)) {
-                ovsrec_interface_delete(iface);
-            }
+            return port;
         }
     }
+    return NULL;
+}
 
-    /* xxx Probably can move this into the "for" loop. */
-    if (port_rec) {
-        struct ovsrec_port **ports;
-        size_t n;
+/* Find and return an interface within 'br' named 'iface_name'. */
+static const struct ovsrec_interface *
+find_interface(const struct ovsrec_bridge *br, const char *iface_name,
+               struct ovsrec_port **portp)
+{
+    size_t i;
+
+    for (i = 0; i < br->n_ports; i++) {
+        struct ovsrec_port *port = br->ports[i];
+        size_t j;
 
-        ports = xmalloc(sizeof *br->ports * br->n_ports);
-        for (i = n = 0; i < br->n_ports; i++) {
-            if (br->ports[i] != port_rec) {
-                ports[n++] = br->ports[i];
+        for (j = 0; j < port->n_interfaces; j++) {
+            struct ovsrec_interface *iface = port->interfaces[j];
+            if (!strcmp(iface->name, iface_name)) {
+                *portp = port;
+                return iface;
             }
         }
-        ovsrec_bridge_set_ports(br, ports, n);
-        free(ports);
-
-        ovsrec_port_delete(port_rec);
     }
+
+    *portp = NULL;
+    return NULL;
 }
 
 static int
@@ -582,7 +636,6 @@ del_bridge(struct ovsdb_idl *idl,
     struct ovsrec_bridge *br = find_bridge(ovs, br_name);
     struct ovsrec_bridge **bridges;
     struct ovsdb_idl_txn *txn;
-    char *comment;
     size_t i, n;
 
     if (!br) {
@@ -592,12 +645,27 @@ del_bridge(struct ovsdb_idl *idl,
 
     txn = ovsdb_idl_txn_create(idl);
 
-    comment = xasprintf("ovs-brcompatd: delbr %s", br_name);
-    ovsdb_idl_txn_add_comment(txn, comment);
-    free(comment);
+    ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: delbr %s", br_name);
 
-    del_port(br, br_name);
+    /* Delete everything that the bridge points to, then delete the bridge
+     * itself. */
+    while (br->n_ports > 0) {
+        del_port(br, br->ports[0]);
+    }
+    for (i = 0; i < br->n_mirrors; i++) {
+        ovsrec_mirror_delete(br->mirrors[i]);
+    }
+    if (br->netflow) {
+        ovsrec_netflow_delete(br->netflow);
+    }
+    if (br->sflow) {
+        ovsrec_sflow_delete(br->sflow);
+    }
+    if (br->controller) {
+        ovsrec_controller_delete(br->controller);
+    }
 
+    /* Remove 'br' from the vswitch's list of bridges. */
     bridges = xmalloc(sizeof *ovs->bridges * ovs->n_bridges);
     for (i = n = 0; i < ovs->n_bridges; i++) {
         if (ovs->bridges[i] != br) {
@@ -738,19 +806,21 @@ handle_port_cmd(struct ovsdb_idl *idl,
         } else {
             do {
                 struct ovsdb_idl_txn *txn = ovsdb_idl_txn_create(idl);
-                char *comment;
 
                 if (add) {
-                    comment = xasprintf("ovs-brcompatd: add-if %s", port_name);
+                    ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: add-if %s",
+                                              port_name);
                     add_port(ovs, br, port_name);
                 } else {
-                    comment = xasprintf("ovs-brcompatd: del-if %s", port_name);
-                    del_port(br, port_name);
+                    const struct ovsrec_port *port = find_port(br, port_name);
+                    if (port) {
+                        ovsdb_idl_txn_add_comment(txn,
+                                                  "ovs-brcompatd: del-if %s",
+                                                  port_name);
+                        del_port(br, port);
+                    }
                 }
 
-                ovsdb_idl_txn_add_comment(txn, comment);
-                free(comment);
-
                 error = commit_txn(txn, true);
                 VLOG_INFO_RL(&rl, "%s %s %s: %s",
                              cmd_name, br_name, port_name, strerror(error));
@@ -1199,8 +1269,9 @@ rtnl_recv_update(struct ovsdb_idl *idl,
             if (!netdev_exists(port_name)) {
                 /* Network device is really gone. */
                 struct ovsdb_idl_txn *txn;
+                const struct ovsrec_interface *iface;
+                struct ovsrec_port *port;
                 struct ovsrec_bridge *br;
-                char *comment;
 
                 VLOG_INFO("network device %s destroyed, "
                           "removing from bridge %s", port_name, br_name);
@@ -1215,12 +1286,14 @@ rtnl_recv_update(struct ovsdb_idl *idl,
 
                 txn = ovsdb_idl_txn_create(idl);
 
-                comment = xasprintf("ovs-brcompatd: destroy port %s",
-                        port_name);
-                ovsdb_idl_txn_add_comment(txn, comment);
-                free(comment);
+                iface = find_interface(br, port_name, &port);
+                if (iface) {
+                    del_interface(br, port, iface);
+                    ovsdb_idl_txn_add_comment(txn,
+                                              "ovs-brcompatd: destroy port %s",
+                                              port_name);
+                }
 
-                del_port(br, port_name);
                 commit_txn(txn, false);
             } else {
                 /* A network device by that name exists even though the kernel