[ovs-dev] [PATCH 4/5] ovn-controller: Support multiple encaps simultaneously.

Justin Pettit jpettit at nicira.com
Thu Oct 15 08:54:59 UTC 2015


Signed-off-by: Justin Pettit <jpettit at nicira.com>
---
 ovn/controller/chassis.c            |   88 ++++++++++++++++++++++++++---------
 ovn/controller/encaps.c             |   20 ++++----
 ovn/controller/ovn-controller.8.xml |   10 +++-
 ovn/controller/ovn-controller.c     |   14 ++++++
 ovn/controller/ovn-controller.h     |   11 ++++
 ovn/controller/physical.c           |    2 +-
 6 files changed, 109 insertions(+), 36 deletions(-)

diff --git a/ovn/controller/chassis.c b/ovn/controller/chassis.c
index 9d6a77a..894000d 100644
--- a/ovn/controller/chassis.c
+++ b/ovn/controller/chassis.c
@@ -16,6 +16,7 @@
 #include <config.h>
 #include "chassis.h"
 
+#include "lib/dynamic-string.h"
 #include "lib/vswitch-idl.h"
 #include "openvswitch/vlog.h"
 #include "ovn/lib/ovn-sb-idl.h"
@@ -30,6 +31,23 @@ chassis_register_ovs_idl(struct ovsdb_idl *ovs_idl)
     ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_external_ids);
 }
 
+static const char *
+pop_tunnel_name(uint32_t *type)
+{
+    if (*type & GENEVE) {
+        *type &= ~GENEVE;
+        return "geneve";
+    } else if (*type & STT) {
+        *type &= ~STT;
+        return "stt";
+    } else if (*type & VXLAN) {
+        *type &= ~VXLAN;
+        return "vxlan";
+    }
+
+    OVS_NOT_REACHED();
+}
+
 void
 chassis_run(struct controller_ctx *ctx, const char *chassis_id)
 {
@@ -40,13 +58,10 @@ chassis_run(struct controller_ctx *ctx, const char *chassis_id)
     const struct sbrec_chassis *chassis_rec;
     const struct ovsrec_open_vswitch *cfg;
     const char *encap_type, *encap_ip;
-    struct sbrec_encap *encap_rec;
     static bool inited = false;
 
     chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, chassis_id);
 
-    /* xxx Need to support more than one encap.  Also need to support
-     * xxx encap options. */
     cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
     if (!cfg) {
         VLOG_INFO("No Open_vSwitch row defined.");
@@ -60,23 +75,45 @@ chassis_run(struct controller_ctx *ctx, const char *chassis_id)
         return;
     }
 
+    char *tokstr = xstrdup(encap_type);
+    char *save_ptr = NULL;
+    char *token;
+    uint32_t req_tunnels = 0;
+    for (token = strtok_r(tokstr, ",", &save_ptr); token != NULL;
+         token = strtok_r(NULL, ",", &save_ptr)) {
+        uint32_t type = get_tunnel_type(token);
+        if (!type) {
+            VLOG_INFO("Unknown tunnel type: %s", token);
+        }
+        req_tunnels |= type;
+    }
+    free(tokstr);
+
     if (chassis_rec) {
-        int i;
-
-        for (i = 0; i < chassis_rec->n_encaps; i++) {
-            if (!strcmp(chassis_rec->encaps[i]->type, encap_type)
-                && !strcmp(chassis_rec->encaps[i]->ip, encap_ip)) {
-                /* Nothing changed. */
-                inited = true;
-                return;
-            } else if (!inited) {
-                VLOG_WARN("Chassis config changing on startup, make sure "
-                          "multiple chassis are not configured : %s/%s->%s/%s",
-                          chassis_rec->encaps[i]->type,
-                          chassis_rec->encaps[i]->ip,
-                          encap_type, encap_ip);
-            }
+        uint32_t cur_tunnels = 0;
+        for (int i = 0; i < chassis_rec->n_encaps; i++) {
+            cur_tunnels |= get_tunnel_type(chassis_rec->encaps[i]->type);
+        }
 
+        if (req_tunnels == cur_tunnels
+            && !strcmp(chassis_rec->encaps[0]->ip, encap_ip)) {
+            /* Nothing changed. */
+            inited = true;
+            return;
+        } else if (!inited) {
+            struct ds cur_encaps = DS_EMPTY_INITIALIZER;
+            for (int i = 0; i < chassis_rec->n_encaps; i++) {
+                ds_put_format(&cur_encaps, "%s,",
+                              chassis_rec->encaps[i]->type);
+            }
+            ds_chomp(&cur_encaps, ',');
+
+            VLOG_WARN("Chassis config changing on startup, make sure "
+                      "multiple chassis are not configured : %s/%s->%s/%s",
+                      ds_cstr(&cur_encaps),
+                      chassis_rec->encaps[0]->ip,
+                      encap_type, encap_ip);
+            ds_destroy(&cur_encaps);
         }
     }
 
@@ -89,12 +126,19 @@ chassis_run(struct controller_ctx *ctx, const char *chassis_id)
         sbrec_chassis_set_name(chassis_rec, chassis_id);
     }
 
-    encap_rec = sbrec_encap_insert(ctx->ovnsb_idl_txn);
+    int n_encaps = count_1bits(req_tunnels);
+    struct sbrec_encap **encaps = xmalloc(n_encaps * sizeof *encaps);
+    for (int i = 0; i < n_encaps; i++) {
+        const char *type = pop_tunnel_name(&req_tunnels);
+
+        encaps[i] = sbrec_encap_insert(ctx->ovnsb_idl_txn);
 
-    sbrec_encap_set_type(encap_rec, encap_type);
-    sbrec_encap_set_ip(encap_rec, encap_ip);
+        sbrec_encap_set_type(encaps[i], type);
+        sbrec_encap_set_ip(encaps[i], encap_ip);
+    }
 
-    sbrec_chassis_set_encaps(chassis_rec, &encap_rec, 1);
+    sbrec_chassis_set_encaps(chassis_rec, encaps, n_encaps);
+    free(encaps);
 
     inited = true;
 }
diff --git a/ovn/controller/encaps.c b/ovn/controller/encaps.c
index de1aef3..dfb11c0 100644
--- a/ovn/controller/encaps.c
+++ b/ovn/controller/encaps.c
@@ -210,20 +210,18 @@ bridge_delete_port(const struct ovsrec_bridge *br,
 static struct sbrec_encap *
 preferred_encap(const struct sbrec_chassis *chassis_rec)
 {
-    size_t i;
-
-    /* For hypervisors, we only support Geneve and STT encapsulations.
-     * Sets are returned alphabetically, so "geneve" will be preferred
-     * over "stt".  For gateways, we only support VXLAN encapsulation. */
-    for (i = 0; i < chassis_rec->n_encaps; i++) {
-        if (!strcmp(chassis_rec->encaps[i]->type, "geneve")
-                || !strcmp(chassis_rec->encaps[i]->type, "stt")
-                || !strcmp(chassis_rec->encaps[i]->type, "vxlan")) {
-            return chassis_rec->encaps[i];
+    struct sbrec_encap *best_encap = NULL;
+    uint32_t best_type = 0;
+
+    for (int i = 0; i < chassis_rec->n_encaps; i++) {
+        uint32_t tun_type = get_tunnel_type(chassis_rec->encaps[i]->type);
+        if (tun_type > best_type) {
+            best_type = tun_type;
+            best_encap = chassis_rec->encaps[i];
         }
     }
 
-    return NULL;
+    return best_encap;
 }
 
 void
diff --git a/ovn/controller/ovn-controller.8.xml b/ovn/controller/ovn-controller.8.xml
index b0aee10..24d34ef 100644
--- a/ovn/controller/ovn-controller.8.xml
+++ b/ovn/controller/ovn-controller.8.xml
@@ -104,7 +104,13 @@
       <dd>
         <p>
           The encapsulation type that a chassis should use to connect to
-          this node.  Supported tunnel types for connecting hypervisors
+          this node.  Multiple encapsulation types may be specified with
+          a comma-separated list.  Each listed encapsulation type will
+          be paired with <code>ovn-encap-ip</code>.
+        </p>
+
+        <p>
+          Supported tunnel types for connecting hypervisors
           are <code>geneve</code> and <code>stt</code>.  Gateways may
           use <code>geneve</code>, <code>vxlan</code>, or
           <code>stt</code>.
@@ -120,7 +126,7 @@
       <dt><code>external_ids:ovn-encap-ip</code></dt>
       <dd>
         The IP address that a chassis should use to connect to this node
-        using encapsulation type specified by
+        using encapsulation types specified by
         <code>external_ids:ovn-encap-type</code>.
       </dd>
 
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index f1bc524..eca32b3 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -57,6 +57,20 @@ OVS_NO_RETURN static void usage(void);
 
 static char *ovs_remote;
 
+uint32_t
+get_tunnel_type(const char *name)
+{
+    if (!strcmp(name, "geneve")) {
+        return GENEVE;
+    } else if (!strcmp(name, "stt")) {
+        return STT;
+    } else if (!strcmp(name, "vxlan")) {
+        return VXLAN;
+    }
+
+    return 0;
+}
+
 static const struct ovsrec_bridge *
 get_bridge(struct ovsdb_idl *ovs_idl, const char *br_name)
 {
diff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h
index be89b5f..8b10675 100644
--- a/ovn/controller/ovn-controller.h
+++ b/ovn/controller/ovn-controller.h
@@ -41,4 +41,15 @@ get_chassis_by_name(struct ovsdb_idl *ovnsb_idl, const char *chassis_id)
     return chassis_rec;
 }
 
+/* Must be a bit-field ordered from most-preferred (higher number) to
+ * least-preferred (lower number). */
+enum chassis_tunnel_type {
+    GENEVE = 1 << 2,
+    STT    = 1 << 1,
+    VXLAN  = 1 << 0
+};
+
+uint32_t get_tunnel_type(const char *name);
+
+
 #endif /* ovn/ovn-controller.h */
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index b26db63..ca495c0 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -54,7 +54,7 @@ struct chassis_tunnel {
     struct hmap_node hmap_node;
     const char *chassis_id;
     ofp_port_t ofport;
-    enum chassis_tunnel_type { GENEVE, STT, VXLAN } type;
+    enum chassis_tunnel_type type;
 };
 
 static struct chassis_tunnel *
-- 
1.7.5.4




More information about the dev mailing list