ovn-controller: Factor patch port management into new "patch" module.
authorBen Pfaff <blp@nicira.com>
Thu, 1 Oct 2015 16:37:53 +0000 (09:37 -0700)
committerBen Pfaff <blp@nicira.com>
Sat, 17 Oct 2015 03:15:08 +0000 (20:15 -0700)
Upcoming patches will introduce new extensive use of patch ports and it
seems reasonable to put it into its own file.

This is mostly code motion.  Code changes are limited to those necessary
to make the separated code compile, except for renaming
init_bridge_mappings() to patch_run().

Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Justin Pettit <jpettit@nicira.com>
ovn/controller/automake.mk
ovn/controller/ovn-controller.c
ovn/controller/ovn-controller.h
ovn/controller/patch.c [new file with mode: 0644]
ovn/controller/patch.h [new file with mode: 0644]

index 9c91420..fec9bf1 100644 (file)
@@ -10,6 +10,8 @@ ovn_controller_ovn_controller_SOURCES = \
        ovn/controller/lflow.h \
        ovn/controller/ofctrl.c \
        ovn/controller/ofctrl.h \
+       ovn/controller/patch.c \
+       ovn/controller/patch.h \
        ovn/controller/ovn-controller.c \
        ovn/controller/ovn-controller.h \
        ovn/controller/physical.c \
index 3bd072a..3f29b25 100644 (file)
@@ -44,6 +44,7 @@
 #include "binding.h"
 #include "chassis.h"
 #include "encaps.h"
+#include "patch.h"
 #include "physical.h"
 #include "lflow.h"
 
@@ -87,7 +88,7 @@ get_tunnel_type(const char *name)
     return 0;
 }
 
-static const struct ovsrec_bridge *
+const struct ovsrec_bridge *
 get_bridge(struct ovsdb_idl *ovs_idl, const char *br_name)
 {
     const struct ovsrec_bridge *br;
@@ -169,214 +170,6 @@ get_chassis_id(const struct ovsdb_idl *ovs_idl)
     return cfg ? smap_get(&cfg->external_ids, "system-id") : NULL;
 }
 
-static char *
-patch_port_name(const struct ovsrec_bridge *b1, const struct ovsrec_bridge *b2)
-{
-    return xasprintf("patch-%s-to-%s", b1->name, b2->name);
-}
-
-/*
- * Return true if the port is a patch port from b1 to b2
- */
-static bool
-match_patch_port(const struct ovsrec_port *port,
-                 const struct ovsrec_bridge *b1,
-                 const struct ovsrec_bridge *b2)
-{
-    struct ovsrec_interface *iface;
-    size_t i;
-    char *peer_port_name;
-    bool res = false;
-
-    peer_port_name = patch_port_name(b2, b1);
-
-    for (i = 0; i < port->n_interfaces; i++) {
-        iface = port->interfaces[i];
-        if (strcmp(iface->type, "patch")) {
-            continue;
-        }
-        const char *peer;
-        peer = smap_get(&iface->options, "peer");
-        if (peer && !strcmp(peer, peer_port_name)) {
-            res = true;
-            break;
-        }
-    }
-
-    free(peer_port_name);
-
-    return res;
-}
-
-static void
-create_patch_port(struct controller_ctx *ctx,
-                  const char *network,
-                  const struct ovsrec_bridge *b1,
-                  const struct ovsrec_bridge *b2)
-{
-    if (!ctx->ovs_idl_txn) {
-        return;
-    }
-
-    char *port_name = patch_port_name(b1, b2);
-    char *peer_port_name = patch_port_name(b2, b1);
-
-    ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,
-            "ovn-controller: creating patch port '%s' from '%s' to '%s'",
-            port_name, b1->name, b2->name);
-
-    struct ovsrec_interface *iface;
-    iface = ovsrec_interface_insert(ctx->ovs_idl_txn);
-    ovsrec_interface_set_name(iface, port_name);
-    ovsrec_interface_set_type(iface, "patch");
-    const struct smap options = SMAP_CONST1(&options, "peer", peer_port_name);
-    ovsrec_interface_set_options(iface, &options);
-
-    struct ovsrec_port *port;
-    port = ovsrec_port_insert(ctx->ovs_idl_txn);
-    ovsrec_port_set_name(port, port_name);
-    ovsrec_port_set_interfaces(port, &iface, 1);
-    const struct smap ids = SMAP_CONST1(&ids, "ovn-patch-port", network);
-    ovsrec_port_set_external_ids(port, &ids);
-
-    struct ovsrec_port **ports;
-    ports = xmalloc(sizeof *ports * (b1->n_ports + 1));
-    memcpy(ports, b1->ports, sizeof *ports * b1->n_ports);
-    ports[b1->n_ports] = port;
-    ovsrec_bridge_verify_ports(b1);
-    ovsrec_bridge_set_ports(b1, ports, b1->n_ports + 1);
-
-    free(ports);
-    free(port_name);
-    free(peer_port_name);
-}
-
-static void
-create_patch_ports(struct controller_ctx *ctx,
-                   const char *network,
-                   struct shash *existing_ports,
-                   const struct ovsrec_bridge *b1,
-                   const struct ovsrec_bridge *b2)
-{
-    size_t i;
-
-    for (i = 0; i < b1->n_ports; i++) {
-        if (match_patch_port(b1->ports[i], b1, b2)) {
-            /* Patch port already exists on b1 */
-            shash_find_and_delete(existing_ports, b1->ports[i]->name);
-            break;
-        }
-    }
-    if (i == b1->n_ports) {
-        create_patch_port(ctx, network, b1, b2);
-    }
-}
-
-static void
-init_existing_ports(struct controller_ctx *ctx,
-                    struct shash *existing_ports)
-{
-    const struct ovsrec_port *port;
-
-    OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) {
-        if (smap_get(&port->external_ids, "ovn-patch-port")) {
-            shash_add(existing_ports, port->name, port);
-        }
-    }
-}
-
-static void
-remove_port(struct controller_ctx *ctx,
-            const struct ovsrec_port *port)
-{
-    const struct ovsrec_bridge *bridge;
-
-    /* We know the port we want to delete, but we have to find the bridge its on
-     * to do so.  Note this only runs on a config change that should be pretty
-     * rare. */
-    OVSREC_BRIDGE_FOR_EACH (bridge, ctx->ovs_idl) {
-        size_t i;
-        for (i = 0; i < bridge->n_ports; i++) {
-            if (bridge->ports[i] != port) {
-                continue;
-            }
-            struct ovsrec_port **new_ports;
-            new_ports = xmemdup(bridge->ports,
-                    sizeof *new_ports * (bridge->n_ports - 1));
-            if (i != bridge->n_ports - 1) {
-                /* Removed port was not last */
-                new_ports[i] = bridge->ports[bridge->n_ports - 1];
-            }
-            ovsrec_bridge_verify_ports(bridge);
-            ovsrec_bridge_set_ports(bridge, new_ports, bridge->n_ports - 1);
-            free(new_ports);
-            ovsrec_port_delete(port);
-            return;
-        }
-    }
-}
-
-static void
-parse_bridge_mappings(struct controller_ctx *ctx,
-                      const struct ovsrec_bridge *br_int,
-                      const char *mappings_cfg)
-{
-    struct shash existing_ports = SHASH_INITIALIZER(&existing_ports);
-    init_existing_ports(ctx, &existing_ports);
-
-    char *cur, *next, *start;
-    next = start = xstrdup(mappings_cfg);
-    while ((cur = strsep(&next, ",")) && *cur) {
-        char *network, *bridge = cur;
-        const struct ovsrec_bridge *ovs_bridge;
-
-        network = strsep(&bridge, ":");
-        if (!bridge || !*network || !*bridge) {
-            VLOG_ERR("Invalid ovn-bridge-mappings configuration: '%s'",
-                    mappings_cfg);
-            break;
-        }
-
-        ovs_bridge = get_bridge(ctx->ovs_idl, bridge);
-        if (!ovs_bridge) {
-            VLOG_WARN("Bridge '%s' not found for network '%s'",
-                    bridge, network);
-            continue;
-        }
-
-        create_patch_ports(ctx, network, &existing_ports, br_int, ovs_bridge);
-        create_patch_ports(ctx, network, &existing_ports, ovs_bridge, br_int);
-    }
-    free(start);
-
-    /* Any ports left in existing_ports are related to configuration that has
-     * been removed, so we should delete the ports now. */
-    struct shash_node *port_node, *port_next_node;
-    SHASH_FOR_EACH_SAFE (port_node, port_next_node, &existing_ports) {
-        struct ovsrec_port *port = port_node->data;
-        shash_delete(&existing_ports, port_node);
-        remove_port(ctx, port);
-    }
-    shash_destroy(&existing_ports);
-}
-
-static void
-init_bridge_mappings(struct controller_ctx *ctx,
-                     const struct ovsrec_bridge *br_int)
-{
-    const char *mappings_cfg = "";
-    const struct ovsrec_open_vswitch *cfg;
-
-    cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
-    if (cfg) {
-        mappings_cfg = smap_get(&cfg->external_ids, "ovn-bridge-mappings");
-        if (!mappings_cfg) {
-            mappings_cfg = "";
-        }
-    }
-    parse_bridge_mappings(ctx, br_int, mappings_cfg);
-}
-
 /* Retrieves the OVN Southbound remote location from the
  * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it.
  *
@@ -487,7 +280,7 @@ main(int argc, char *argv[])
 
         /* Map bridges to local nets from ovn-bridge-mappings */
         if (br_int) {
-            init_bridge_mappings(&ctx, br_int);
+            patch_run(&ctx, br_int);
         }
 
         if (chassis_id) {
index ded7fce..8c437a7 100644 (file)
@@ -31,6 +31,9 @@ struct controller_ctx {
     struct ovsdb_idl_txn *ovs_idl_txn;
 };
 
+const struct ovsrec_bridge *get_bridge(struct ovsdb_idl *,
+                                       const char *br_name);
+
 const struct sbrec_chassis *get_chassis(struct ovsdb_idl *,
                                         const char *chassis_id);
 
diff --git a/ovn/controller/patch.c b/ovn/controller/patch.c
new file mode 100644 (file)
index 0000000..0d192fa
--- /dev/null
@@ -0,0 +1,232 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "patch.h"
+
+#include "hash.h"
+#include "lib/vswitch-idl.h"
+#include "openvswitch/vlog.h"
+#include "ovn-controller.h"
+
+VLOG_DEFINE_THIS_MODULE(patch);
+
+static char *
+patch_port_name(const struct ovsrec_bridge *b1, const struct ovsrec_bridge *b2)
+{
+    return xasprintf("patch-%s-to-%s", b1->name, b2->name);
+}
+
+/*
+ * Return true if the port is a patch port from b1 to b2
+ */
+static bool
+match_patch_port(const struct ovsrec_port *port,
+                 const struct ovsrec_bridge *b1,
+                 const struct ovsrec_bridge *b2)
+{
+    struct ovsrec_interface *iface;
+    size_t i;
+    char *peer_port_name;
+    bool res = false;
+
+    peer_port_name = patch_port_name(b2, b1);
+
+    for (i = 0; i < port->n_interfaces; i++) {
+        iface = port->interfaces[i];
+        if (strcmp(iface->type, "patch")) {
+            continue;
+        }
+        const char *peer;
+        peer = smap_get(&iface->options, "peer");
+        if (peer && !strcmp(peer, peer_port_name)) {
+            res = true;
+            break;
+        }
+    }
+
+    free(peer_port_name);
+
+    return res;
+}
+
+static void
+create_patch_port(struct controller_ctx *ctx,
+                  const char *network,
+                  const struct ovsrec_bridge *b1,
+                  const struct ovsrec_bridge *b2)
+{
+    if (!ctx->ovs_idl_txn) {
+        return;
+    }
+
+    char *port_name = patch_port_name(b1, b2);
+    char *peer_port_name = patch_port_name(b2, b1);
+
+    ovsdb_idl_txn_add_comment(ctx->ovs_idl_txn,
+            "ovn-controller: creating patch port '%s' from '%s' to '%s'",
+            port_name, b1->name, b2->name);
+
+    struct ovsrec_interface *iface;
+    iface = ovsrec_interface_insert(ctx->ovs_idl_txn);
+    ovsrec_interface_set_name(iface, port_name);
+    ovsrec_interface_set_type(iface, "patch");
+    const struct smap options = SMAP_CONST1(&options, "peer", peer_port_name);
+    ovsrec_interface_set_options(iface, &options);
+
+    struct ovsrec_port *port;
+    port = ovsrec_port_insert(ctx->ovs_idl_txn);
+    ovsrec_port_set_name(port, port_name);
+    ovsrec_port_set_interfaces(port, &iface, 1);
+    const struct smap ids = SMAP_CONST1(&ids, "ovn-patch-port", network);
+    ovsrec_port_set_external_ids(port, &ids);
+
+    struct ovsrec_port **ports;
+    ports = xmalloc(sizeof *ports * (b1->n_ports + 1));
+    memcpy(ports, b1->ports, sizeof *ports * b1->n_ports);
+    ports[b1->n_ports] = port;
+    ovsrec_bridge_verify_ports(b1);
+    ovsrec_bridge_set_ports(b1, ports, b1->n_ports + 1);
+
+    free(ports);
+    free(port_name);
+    free(peer_port_name);
+}
+
+static void
+create_patch_ports(struct controller_ctx *ctx,
+                   const char *network,
+                   struct shash *existing_ports,
+                   const struct ovsrec_bridge *b1,
+                   const struct ovsrec_bridge *b2)
+{
+    size_t i;
+
+    for (i = 0; i < b1->n_ports; i++) {
+        if (match_patch_port(b1->ports[i], b1, b2)) {
+            /* Patch port already exists on b1 */
+            shash_find_and_delete(existing_ports, b1->ports[i]->name);
+            break;
+        }
+    }
+    if (i == b1->n_ports) {
+        create_patch_port(ctx, network, b1, b2);
+    }
+}
+
+static void
+init_existing_ports(struct controller_ctx *ctx,
+                    struct shash *existing_ports)
+{
+    const struct ovsrec_port *port;
+
+    OVSREC_PORT_FOR_EACH (port, ctx->ovs_idl) {
+        if (smap_get(&port->external_ids, "ovn-patch-port")) {
+            shash_add(existing_ports, port->name, port);
+        }
+    }
+}
+
+static void
+remove_port(struct controller_ctx *ctx,
+            const struct ovsrec_port *port)
+{
+    const struct ovsrec_bridge *bridge;
+
+    /* We know the port we want to delete, but we have to find the bridge its
+     * on to do so.  Note this only runs on a config change that should be
+     * pretty rare. */
+    OVSREC_BRIDGE_FOR_EACH (bridge, ctx->ovs_idl) {
+        size_t i;
+        for (i = 0; i < bridge->n_ports; i++) {
+            if (bridge->ports[i] != port) {
+                continue;
+            }
+            struct ovsrec_port **new_ports;
+            new_ports = xmemdup(bridge->ports,
+                    sizeof *new_ports * (bridge->n_ports - 1));
+            if (i != bridge->n_ports - 1) {
+                /* Removed port was not last */
+                new_ports[i] = bridge->ports[bridge->n_ports - 1];
+            }
+            ovsrec_bridge_verify_ports(bridge);
+            ovsrec_bridge_set_ports(bridge, new_ports, bridge->n_ports - 1);
+            free(new_ports);
+            ovsrec_port_delete(port);
+            return;
+        }
+    }
+}
+
+static void
+parse_bridge_mappings(struct controller_ctx *ctx,
+                      const struct ovsrec_bridge *br_int,
+                      const char *mappings_cfg)
+{
+    struct shash existing_ports = SHASH_INITIALIZER(&existing_ports);
+    init_existing_ports(ctx, &existing_ports);
+
+    char *cur, *next, *start;
+    next = start = xstrdup(mappings_cfg);
+    while ((cur = strsep(&next, ",")) && *cur) {
+        char *network, *bridge = cur;
+        const struct ovsrec_bridge *ovs_bridge;
+
+        network = strsep(&bridge, ":");
+        if (!bridge || !*network || !*bridge) {
+            VLOG_ERR("Invalid ovn-bridge-mappings configuration: '%s'",
+                    mappings_cfg);
+            break;
+        }
+
+        ovs_bridge = get_bridge(ctx->ovs_idl, bridge);
+        if (!ovs_bridge) {
+            VLOG_WARN("Bridge '%s' not found for network '%s'",
+                    bridge, network);
+            continue;
+        }
+
+        create_patch_ports(ctx, network, &existing_ports, br_int, ovs_bridge);
+        create_patch_ports(ctx, network, &existing_ports, ovs_bridge, br_int);
+    }
+    free(start);
+
+    /* Any ports left in existing_ports are related to configuration that has
+     * been removed, so we should delete the ports now. */
+    struct shash_node *port_node, *port_next_node;
+    SHASH_FOR_EACH_SAFE (port_node, port_next_node, &existing_ports) {
+        struct ovsrec_port *port = port_node->data;
+        shash_delete(&existing_ports, port_node);
+        remove_port(ctx, port);
+    }
+    shash_destroy(&existing_ports);
+}
+
+void
+patch_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int)
+{
+    const char *mappings_cfg = "";
+    const struct ovsrec_open_vswitch *cfg;
+
+    cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
+    if (cfg) {
+        mappings_cfg = smap_get(&cfg->external_ids, "ovn-bridge-mappings");
+        if (!mappings_cfg) {
+            mappings_cfg = "";
+        }
+    }
+    parse_bridge_mappings(ctx, br_int, mappings_cfg);
+}
diff --git a/ovn/controller/patch.h b/ovn/controller/patch.h
new file mode 100644 (file)
index 0000000..f7db2fc
--- /dev/null
@@ -0,0 +1,30 @@
+/* Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_PATCH_H
+#define OVN_PATCH_H 1
+
+/* Patch Ports
+ * ===========
+ *
+ * This module adds and removes patch ports between the integration bridge and
+ * physical bridges, as directed by other-config:ovn-bridge-mappings. */
+
+struct controller_ctx;
+struct ovsrec_bridge;
+
+void patch_run(struct controller_ctx *, const struct ovsrec_bridge *br_int);
+
+#endif /* ovn/patch.h */