*/
#include <config.h>
+#include <unistd.h>
+
#include "chassis.h"
-#include "lib/poll-loop.h"
-#include "lib/util.h"
+#include "lib/smap.h"
#include "lib/vswitch-idl.h"
+#include "openvswitch/dynamic-string.h"
#include "openvswitch/vlog.h"
#include "ovn/lib/ovn-sb-idl.h"
#include "ovn-controller.h"
+#include "lib/util.h"
VLOG_DEFINE_THIS_MODULE(chassis);
+#ifndef HOST_NAME_MAX
+/* For windows. */
+#define HOST_NAME_MAX 255
+#endif /* HOST_NAME_MAX */
+
void
-chassis_init(struct controller_ctx *ctx)
+chassis_register_ovs_idl(struct ovsdb_idl *ovs_idl)
{
- ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_open_vswitch);
- ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_open_vswitch_col_external_ids);
+ ovsdb_idl_add_table(ovs_idl, &ovsrec_table_open_vswitch);
+ ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_external_ids);
}
-static void
-register_chassis(struct controller_ctx *ctx,
- const struct sbrec_chassis *chassis_rec,
- const char *encap_type, const char *encap_ip)
+static const char *
+pop_tunnel_name(uint32_t *type)
{
- struct sbrec_encap *encap_rec;
- int retval = TXN_TRY_AGAIN;
- struct ovsdb_idl_txn *txn;
-
- txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
- ovsdb_idl_txn_add_comment(txn,
- "ovn-controller: registering chassis '%s'",
- ctx->chassis_id);
-
- if (!chassis_rec) {
- chassis_rec = sbrec_chassis_insert(txn);
- sbrec_chassis_set_name(chassis_rec, ctx->chassis_id);
+ if (*type & GENEVE) {
+ *type &= ~GENEVE;
+ return "geneve";
+ } else if (*type & STT) {
+ *type &= ~STT;
+ return "stt";
+ } else if (*type & VXLAN) {
+ *type &= ~VXLAN;
+ return "vxlan";
}
- encap_rec = sbrec_encap_insert(txn);
-
- sbrec_encap_set_type(encap_rec, encap_type);
- sbrec_encap_set_ip(encap_rec, encap_ip);
-
- sbrec_chassis_set_encaps(chassis_rec, &encap_rec, 1);
+ OVS_NOT_REACHED();
+}
- retval = ovsdb_idl_txn_commit_block(txn);
- if (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) {
- VLOG_INFO("Problem registering chassis: %s",
- ovsdb_idl_txn_status_to_string(retval));
- poll_immediate_wake();
- }
- ovsdb_idl_txn_destroy(txn);
+static const char *
+get_bridge_mappings(const struct smap *ext_ids)
+{
+ const char *bridge_mappings = smap_get(ext_ids, "ovn-bridge-mappings");
+ return bridge_mappings ? bridge_mappings : "";
}
void
-chassis_run(struct controller_ctx *ctx)
+chassis_run(struct controller_ctx *ctx, const char *chassis_id)
{
- const struct sbrec_chassis *chassis_rec;
+ if (!ctx->ovnsb_idl_txn) {
+ return;
+ }
+
const struct ovsrec_open_vswitch *cfg;
const char *encap_type, *encap_ip;
static bool inited = false;
- SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->ovnsb_idl) {
- if (!strcmp(chassis_rec->name, ctx->chassis_id)) {
- break;
- }
- }
-
- /* 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;
}
- 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);
- }
+ 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);
+ const char *hostname = smap_get(&cfg->external_ids, "hostname");
+ char hostname_[HOST_NAME_MAX + 1];
+ if (!hostname || !hostname[0]) {
+ if (gethostname(hostname_, sizeof hostname_)) {
+ hostname_[0] = '\0';
}
+ hostname = hostname_;
}
- register_chassis(ctx, chassis_rec, encap_type, encap_ip);
- inited = true;
-}
+ const char *bridge_mappings = get_bridge_mappings(&cfg->external_ids);
-void
-chassis_destroy(struct controller_ctx *ctx)
-{
- int retval = TXN_TRY_AGAIN;
+ const struct sbrec_chassis *chassis_rec
+ = get_chassis(ctx->ovnsb_idl, chassis_id);
- ovs_assert(ctx->ovnsb_idl);
+ if (chassis_rec) {
+ if (strcmp(hostname, chassis_rec->hostname)) {
+ sbrec_chassis_set_hostname(chassis_rec, hostname);
+ }
- while (retval != TXN_SUCCESS && retval != TXN_UNCHANGED) {
- const struct sbrec_chassis *chassis_rec;
- struct ovsdb_idl_txn *txn;
+ const char *chassis_bridge_mappings
+ = get_bridge_mappings(&chassis_rec->external_ids);
+ if (strcmp(bridge_mappings, chassis_bridge_mappings)) {
+ struct smap new_ids;
+ smap_clone(&new_ids, &chassis_rec->external_ids);
+ smap_replace(&new_ids, "ovn-bridge-mappings", bridge_mappings);
+ sbrec_chassis_verify_external_ids(chassis_rec);
+ sbrec_chassis_set_external_ids(chassis_rec, &new_ids);
+ smap_destroy(&new_ids);
+ }
- SBREC_CHASSIS_FOR_EACH(chassis_rec, ctx->ovnsb_idl) {
- if (!strcmp(chassis_rec->name, ctx->chassis_id)) {
- break;
- }
+ /* 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 (!chassis_rec) {
+ 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);
}
+ }
+
+ ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
+ "ovn-controller: registering chassis '%s'",
+ chassis_id);
+
+ if (!chassis_rec) {
+ struct smap ext_ids = SMAP_CONST1(&ext_ids, "ovn-bridge-mappings",
+ bridge_mappings);
+ chassis_rec = sbrec_chassis_insert(ctx->ovnsb_idl_txn);
+ sbrec_chassis_set_name(chassis_rec, chassis_id);
+ sbrec_chassis_set_hostname(chassis_rec, hostname);
+ sbrec_chassis_set_external_ids(chassis_rec, &ext_ids);
+ }
+
+ 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);
- txn = ovsdb_idl_txn_create(ctx->ovnsb_idl);
- ovsdb_idl_txn_add_comment(txn,
+ sbrec_encap_set_type(encaps[i], type);
+ sbrec_encap_set_ip(encaps[i], encap_ip);
+ }
+
+ sbrec_chassis_set_encaps(chassis_rec, encaps, n_encaps);
+ free(encaps);
+
+ inited = true;
+}
+
+/* Returns true if the database is all cleaned up, false if more work is
+ * required. */
+bool
+chassis_cleanup(struct controller_ctx *ctx, const char *chassis_id)
+{
+ if (!chassis_id) {
+ return true;
+ }
+
+ /* Delete Chassis row. */
+ const struct sbrec_chassis *chassis_rec
+ = get_chassis(ctx->ovnsb_idl, chassis_id);
+ if (!chassis_rec) {
+ return true;
+ }
+ if (ctx->ovnsb_idl_txn) {
+ ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
"ovn-controller: unregistering chassis '%s'",
- ctx->chassis_id);
+ chassis_id);
sbrec_chassis_delete(chassis_rec);
-
- retval = ovsdb_idl_txn_commit_block(txn);
- if (retval == TXN_ERROR) {
- VLOG_INFO("Problem unregistering chassis: %s",
- ovsdb_idl_txn_status_to_string(retval));
- }
- ovsdb_idl_txn_destroy(txn);
}
+ return false;
}