json: Move from lib to include/openvswitch.
[cascardo/ovs.git] / ovn / controller / chassis.c
index 37287c1..502e74d 100644 (file)
  */
 
 #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.");
@@ -96,62 +88,130 @@ chassis_run(struct controller_ctx *ctx)
         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;
 }