From bf388125f6b294224d31366b81c69908543d2671 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Wed, 14 Oct 2015 11:32:12 -0700 Subject: [PATCH] ovn-controller: Support multiple encaps simultaneously. Signed-off-by: Justin Pettit Acked-by: Ben Pfaff --- ovn/controller/chassis.c | 91 ++++++++++++++++++++++------- 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, 112 insertions(+), 36 deletions(-) diff --git a/ovn/controller/chassis.c b/ovn/controller/chassis.c index abe2e4df9..6617bf3b5 100644 --- a/ovn/controller/chassis.c +++ b/ovn/controller/chassis.c @@ -16,6 +16,7 @@ #include #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(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,48 @@ 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); + /* Compare desired tunnels against those currently in the database. */ + uint32_t cur_tunnels = 0; + bool same = true; + for (int i = 0; i < chassis_rec->n_encaps; i++) { + cur_tunnels |= get_tunnel_type(chassis_rec->encaps[i]->type); + same = same && strcmp(chassis_rec->encaps[i]->ip, encap_ip); + } + same = same && req_tunnels == cur_tunnels; + + if (same) { + /* 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 +129,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 de1aef3a7..dfb11c081 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 4aaf97b86..e79e66508 100644 --- a/ovn/controller/ovn-controller.8.xml +++ b/ovn/controller/ovn-controller.8.xml @@ -104,7 +104,13 @@

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 ovn-encap-ip. +

+ +

+ Supported tunnel types for connecting hypervisors are geneve and stt. Gateways may use geneve, vxlan, or stt. @@ -120,7 +126,7 @@

external_ids:ovn-encap-ip
The IP address that a chassis should use to connect to this node - using encapsulation type specified by + using encapsulation types specified by external_ids:ovn-encap-type.
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 85df099e1..3bd072aa3 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -73,6 +73,20 @@ get_chassis(struct ovsdb_idl *ovnsb_idl, const char *chassis_id) return chassis_rec; } +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 85e13a658..ded7fce95 100644 --- a/ovn/controller/ovn-controller.h +++ b/ovn/controller/ovn-controller.h @@ -34,4 +34,15 @@ struct controller_ctx { const struct sbrec_chassis *get_chassis(struct ovsdb_idl *, const char *chassis_id); +/* 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 17fa63588..1f5f71630 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 * -- 2.20.1