ovn-controller: Tolerate missing 'chassis_id'.
[cascardo/ovs.git] / ovn / controller / ovn-controller.c
index 962d6de..8cb5534 100644 (file)
@@ -42,6 +42,7 @@
 #include "ofctrl.h"
 #include "binding.h"
 #include "chassis.h"
+#include "encaps.h"
 #include "physical.h"
 #include "pipeline.h"
 
@@ -82,9 +83,18 @@ get_bridge(struct controller_ctx *ctx, const char *name)
         }
     }
 
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+    VLOG_WARN_RL(&rl, "%s: integration bridge does not exist", name);
     return NULL;
 }
 
+static const char *
+get_chassis_id(const struct ovsdb_idl *ovs_idl)
+{
+    const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);
+    return cfg ? smap_get(&cfg->external_ids, "system-id") : NULL;
+}
+
 /* Retrieve the OVN integration bridge from the "external-ids:ovn-bridge"
  * key, the remote location from the "external-ids:ovn-remote" key, and
  * the chassis name from the "external-ids:system-id" key in the
@@ -93,7 +103,7 @@ get_bridge(struct controller_ctx *ctx, const char *name)
  * xxx ovn-controller does not support changing any of these mid-run,
  * xxx but that should be addressed later. */
 static void
-get_core_config(struct controller_ctx *ctx)
+get_core_config(struct controller_ctx *ctx, char **br_int_namep)
 {
     while (1) {
         ovsdb_idl_run(ctx->ovs_idl);
@@ -106,21 +116,12 @@ get_core_config(struct controller_ctx *ctx)
             exit(EXIT_FAILURE);
         }
 
-        const struct ovsrec_bridge *br_int;
-        const char *remote, *system_id, *br_int_name;
+        const char *remote, *br_int_name;
 
         br_int_name = smap_get(&cfg->external_ids, "ovn-bridge");
         if (!br_int_name) {
             br_int_name = DEFAULT_BRIDGE_NAME;
         }
-        ctx->br_int_name = xstrdup(br_int_name);
-
-        br_int = get_bridge(ctx, ctx->br_int_name);
-        if (!br_int) {
-            VLOG_INFO("Integration bridge '%s' does not exist.  Waiting...",
-                      ctx->br_int_name);
-            goto try_again;
-        }
 
         remote = smap_get(&cfg->external_ids, "ovn-remote");
         if (!remote) {
@@ -128,14 +129,8 @@ get_core_config(struct controller_ctx *ctx)
             goto try_again;
         }
 
-        system_id = smap_get(&cfg->external_ids, "system-id");
-        if (!system_id) {
-            VLOG_INFO("system-id not specified.  Waiting...");
-            goto try_again;
-        }
-
         ovnsb_remote = xstrdup(remote);
-        ctx->chassis_id = xstrdup(system_id);
+        *br_int_namep = xstrdup(br_int_name);
         return;
 
 try_again:
@@ -189,28 +184,40 @@ idl_loop_commit_and_wait(struct idl_loop *loop)
     struct ovsdb_idl_txn *txn = loop->committing_txn;
     if (txn) {
         enum ovsdb_idl_txn_status status = ovsdb_idl_txn_commit(txn);
-        switch (status) {
-        case TXN_INCOMPLETE:
-            break;
+        if (status != TXN_INCOMPLETE) {
+            switch (status) {
+            case TXN_TRY_AGAIN:
+                /* We want to re-evaluate the database when it's changed from
+                 * the contents that it had when we started the commit.  (That
+                 * might have already happened.) */
+                loop->skip_seqno = loop->precommit_seqno;
+                if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
+                    poll_immediate_wake();
+                }
+                break;
+
+            case TXN_SUCCESS:
+                /* If the database has already changed since we started the
+                 * commit, re-evaluate it immediately to avoid missing a change
+                 * for a while. */
+                if (ovsdb_idl_get_seqno(loop->idl) != loop->precommit_seqno) {
+                    poll_immediate_wake();
+                }
+                break;
+
+            case TXN_UNCHANGED:
+            case TXN_ABORTED:
+            case TXN_NOT_LOCKED:
+            case TXN_ERROR:
+                break;
+
+            case TXN_UNCOMMITTED:
+            case TXN_INCOMPLETE:
+                OVS_NOT_REACHED();
 
-        case TXN_TRY_AGAIN:
-            loop->skip_seqno = loop->precommit_seqno;
-            if (ovsdb_idl_get_seqno(loop->idl) != loop->skip_seqno) {
-                poll_immediate_wake();
             }
-            /* Fall through. */
-        case TXN_UNCHANGED:
-        case TXN_ABORTED:
-        case TXN_SUCCESS:
-        case TXN_NOT_LOCKED:
-        case TXN_ERROR:
             ovsdb_idl_txn_destroy(txn);
             loop->committing_txn = NULL;
-            break;
-
-        case TXN_UNCOMMITTED:
-            OVS_NOT_REACHED();
-
         }
     }
 
@@ -221,7 +228,7 @@ int
 main(int argc, char *argv[])
 {
     struct unixctl_server *unixctl;
-    struct controller_ctx ctx = { .chassis_id = NULL };
+    struct controller_ctx ctx = { .ovs_idl = NULL };
     bool exiting;
     int retval;
 
@@ -255,13 +262,15 @@ main(int argc, char *argv[])
     ovsdb_idl_add_column(ctx.ovs_idl, &ovsrec_open_vswitch_col_external_ids);
 
     chassis_init(&ctx);
+    encaps_init(&ctx);
     binding_init(&ctx);
     physical_init(&ctx);
     pipeline_init();
 
     get_initial_snapshot(ctx.ovs_idl);
 
-    get_core_config(&ctx);
+    char *br_int_name;
+    get_core_config(&ctx, &br_int_name);
 
     ctx.ovnsb_idl = ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class,
                                      true, true);
@@ -276,23 +285,25 @@ main(int argc, char *argv[])
         ctx.ovnsb_idl_txn = idl_loop_run(&ovnsb_idl_loop);
         ctx.ovs_idl_txn = idl_loop_run(&ovs_idl_loop);
 
-        /* xxx If run into any surprising changes, we exit.  We should
-         * xxx handle this more gracefully. */
-        ctx.br_int = get_bridge(&ctx, ctx.br_int_name);
-        if (!ctx.br_int) {
-            VLOG_ERR("Integration bridge '%s' disappeared",
-                     ctx.br_int_name);
-            retval = EXIT_FAILURE;
-            goto exit;
+        const struct ovsrec_bridge *br_int = get_bridge(&ctx, br_int_name);
+        const char *chassis_id = get_chassis_id(ctx.ovs_idl);
+
+        if (chassis_id) {
+            chassis_run(&ctx, chassis_id);
+            encaps_run(&ctx, br_int, chassis_id);
+            binding_run(&ctx, br_int, chassis_id);
         }
 
-        ofctrl_clear_flows();
+        if (br_int) {
+            struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
+            pipeline_run(&ctx, &flow_table);
+            if (chassis_id) {
+                physical_run(&ctx, br_int, chassis_id, &flow_table);
+            }
+            ofctrl_run(br_int, &flow_table);
+            hmap_destroy(&flow_table);
+        }
 
-        chassis_run(&ctx);
-        binding_run(&ctx);
-        pipeline_run(&ctx);
-        physical_run(&ctx);
-        ofctrl_run(&ctx);
         unixctl_server_run(unixctl);
 
         unixctl_server_wait(unixctl);
@@ -303,7 +314,9 @@ main(int argc, char *argv[])
         idl_loop_commit_and_wait(&ovnsb_idl_loop);
         idl_loop_commit_and_wait(&ovs_idl_loop);
 
-        ofctrl_wait();
+        if (br_int) {
+            ofctrl_wait();
+        }
         poll_block();
     }
 
@@ -313,20 +326,14 @@ main(int argc, char *argv[])
         ctx.ovnsb_idl_txn = idl_loop_run(&ovnsb_idl_loop);
         ctx.ovs_idl_txn = idl_loop_run(&ovs_idl_loop);
 
-        /* xxx If run into any surprising changes, we exit.  We should
-         * xxx handle this more gracefully. */
-        ctx.br_int = get_bridge(&ctx, ctx.br_int_name);
-        if (!ctx.br_int) {
-            VLOG_ERR("Integration bridge '%s' disappeared",
-                     ctx.br_int_name);
-            retval = EXIT_FAILURE;
-            goto exit;
-        }
+        const struct ovsrec_bridge *br_int = get_bridge(&ctx, br_int_name);
+        const char *chassis_id = get_chassis_id(ctx.ovs_idl);
 
-        /* Run both the binding and chassis cleanup, even if one of them
-         * returns false.  We're done if both return true. */
-        done = binding_cleanup(&ctx);
-        done = chassis_cleanup(&ctx) && done;
+        /* Run all of the cleanup functions, even if one of them returns false.
+         * We're done if all of them return true. */
+        done = binding_cleanup(&ctx, chassis_id);
+        done = chassis_cleanup(&ctx, chassis_id) && done;
+        done = encaps_cleanup(&ctx, br_int) && done;
         if (done) {
             poll_immediate_wake();
         }
@@ -336,7 +343,6 @@ main(int argc, char *argv[])
         poll_block();
     }
 
-exit:
     unixctl_server_destroy(unixctl);
     pipeline_destroy(&ctx);
     ofctrl_destroy();
@@ -344,8 +350,7 @@ exit:
     idl_loop_destroy(&ovs_idl_loop);
     idl_loop_destroy(&ovnsb_idl_loop);
 
-    free(ctx.br_int_name);
-    free(ctx.chassis_id);
+    free(br_int_name);
     free(ovnsb_remote);
     free(ovs_remote);