#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"
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)
{
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.");
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);
}
}
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;
}
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