get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/1523310/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 1523310,
    "url": "http://patchwork.ozlabs.org/api/patches/1523310/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/ovn/patch/20210901164139.2554647-3-mark.d.gray@redhat.com/",
    "project": {
        "id": 68,
        "url": "http://patchwork.ozlabs.org/api/projects/68/?format=api",
        "name": "Open Virtual Network development",
        "link_name": "ovn",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20210901164139.2554647-3-mark.d.gray@redhat.com>",
    "list_archive_url": null,
    "date": "2021-09-01T16:41:39",
    "name": "[ovs-dev,v2,2/2] northd: Split northd.c",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "96248b72e360564715a029d9b07b9856aed494f8",
    "submitter": {
        "id": 79963,
        "url": "http://patchwork.ozlabs.org/api/people/79963/?format=api",
        "name": "Mark Gray",
        "email": "mark.d.gray@redhat.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/ovn/patch/20210901164139.2554647-3-mark.d.gray@redhat.com/mbox/",
    "series": [
        {
            "id": 260600,
            "url": "http://patchwork.ozlabs.org/api/series/260600/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/ovn/list/?series=260600",
            "date": "2021-09-01T16:41:37",
            "name": "northd: Split northd",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/260600/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/1523310/comments/",
    "check": "fail",
    "checks": "http://patchwork.ozlabs.org/api/patches/1523310/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<ovs-dev-bounces@openvswitch.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "dev@openvswitch.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "ovs-dev@lists.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=Ks0IdLha;\n\tdkim-atps=neutral",
            "ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=140.211.166.138; helo=smtp1.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN>)",
            "smtp2.osuosl.org (amavisd-new);\n dkim=fail (1024-bit key) reason=\"fail (body has been altered)\"\n header.d=redhat.com",
            "relay.mimecast.com;\n auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=mark.d.gray@redhat.com"
        ],
        "Received": [
            "from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest\n SHA256)\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 4H08wX6lNCz9sXN\n\tfor <incoming@patchwork.ozlabs.org>; Thu,  2 Sep 2021 02:42:04 +1000 (AEST)",
            "from localhost (localhost [127.0.0.1])\n\tby smtp1.osuosl.org (Postfix) with ESMTP id B2DEB8295A;\n\tWed,  1 Sep 2021 16:42:02 +0000 (UTC)",
            "from smtp1.osuosl.org ([127.0.0.1])\n\tby localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id idyktg9Bp1rV; Wed,  1 Sep 2021 16:41:58 +0000 (UTC)",
            "from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp1.osuosl.org (Postfix) with ESMTPS id B5BAD81DBF;\n\tWed,  1 Sep 2021 16:41:57 +0000 (UTC)",
            "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 8BDECC0010;\n\tWed,  1 Sep 2021 16:41:57 +0000 (UTC)",
            "from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id A019BC0010\n for <dev@openvswitch.org>; Wed,  1 Sep 2021 16:41:56 +0000 (UTC)",
            "from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 6E56740289\n for <dev@openvswitch.org>; Wed,  1 Sep 2021 16:41:56 +0000 (UTC)",
            "from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n with ESMTP id xhdg6eZ8lU7k for <dev@openvswitch.org>;\n Wed,  1 Sep 2021 16:41:51 +0000 (UTC)",
            "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [216.205.24.124])\n by smtp2.osuosl.org (Postfix) with ESMTPS id 8D966401CE\n for <dev@openvswitch.org>; Wed,  1 Sep 2021 16:41:51 +0000 (UTC)",
            "from mail-wr1-f72.google.com (mail-wr1-f72.google.com\n [209.85.221.72]) (Using TLS) by relay.mimecast.com with ESMTP id\n us-mta-337-t-keNrtGM6aDDtygvbw78w-1; Wed, 01 Sep 2021 12:41:49 -0400",
            "by mail-wr1-f72.google.com with SMTP id\n d10-20020adffbca000000b00157bc86d94eso84651wrs.20\n for <dev@openvswitch.org>; Wed, 01 Sep 2021 09:41:49 -0700 (PDT)",
            "from wsfd-netdev91.ntdv.lab.eng.bos.redhat.com\n (nat-pool-bos-t.redhat.com. [66.187.233.206])\n by smtp.gmail.com with ESMTPSA id d28sm4093wrc.4.2021.09.01.09.41.43\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Wed, 01 Sep 2021 09:41:44 -0700 (PDT)"
        ],
        "X-Virus-Scanned": [
            "amavisd-new at osuosl.org",
            "amavisd-new at osuosl.org"
        ],
        "X-Greylist": "domain auto-whitelisted by SQLgrey-1.8.0",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1630514510;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding:\n in-reply-to:in-reply-to:references:references;\n bh=/eoQGazqgycmY398VH2IxmYWyZY1T3HKpfd/e/JmBn4=;\n b=Ks0IdLham4gqEsrk0sjVRbWsu992ovFshP+M0NCC57JpzJvDYMF5khdsfErpzD7ohQgOsa\n PVPf7OBYBX2yErNCXAP4g7TomcH9u/YbNLH8G11ttoqQXe1YH+1SE8A3N+IItbYXdndPfQ\n O7azq82lto1+Ayx8TPLOkPJ+WYD4Yo0=",
        "X-MC-Unique": "t-keNrtGM6aDDtygvbw78w-1",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20161025;\n h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n :references:mime-version:content-transfer-encoding;\n bh=IJmJTqa5cqWfqPqAYW/7ilQOHwnGgcRzkKcnPxuSCIY=;\n b=TxziTc8guUtCVMThJbuwt7OKC3z3/vpF+M6umuhuur3MZubyCrGbYR85oRKZoonczm\n swZYEWEhZG8mrUcjmOUpucrM+rAN15kPBXyG3/UWdgpx5LH354jY59OiHgNs/yv+QsnM\n bxv1GFULgvoXTp4ND9UhFGz2V/C4Wh9wRhKNyosyUsAY8an4cbdEJ81N7OHkEfkLS9p+\n wu1lKE7oe31RHAW4tbGU0OSG+StOs1CexTBJPthrZ0sD+Ovz+3JDmoBcVZI/Byu/UoRS\n JY83sigRjPKzCIzIYYIc9IrjA57UUG5L2U0/IwccV2YuxXsTWq/tAL77uDSJMeVd7jnY\n W+9g==",
        "X-Gm-Message-State": "AOAM533j2Lh3GT3hC7FjiZfbPsibXOKXppd/z20AojtjIy2dgXDX4u64\n zm7ojX7dzROqfOIO6l/twqQuSKad3C5fmez5iC4+VPaPhHowN5iKRvFy8+RKz7cCRiScFArvqB2\n lt4HY7WS+APREC1Er+/SZEOR01vq9cFNo7BMP6RO1K7zmVXk2JLTT8EtGLHNqUN0XnSUN",
        "X-Received": [
            "by 2002:a05:600c:294:: with SMTP id\n 20mr454703wmk.180.1630514506420;\n Wed, 01 Sep 2021 09:41:46 -0700 (PDT)",
            "by 2002:a05:600c:294:: with SMTP id\n 20mr454564wmk.180.1630514505233;\n Wed, 01 Sep 2021 09:41:45 -0700 (PDT)"
        ],
        "X-Google-Smtp-Source": "\n ABdhPJxYTuwd7icDDXZy3P8w9FHibDIH5wrpTkIXRLh901wsWKUAX2Uv/q82J/XGwlUf9Y81B2DnUA==",
        "From": "Mark Gray <mark.d.gray@redhat.com>",
        "To": "dev@openvswitch.org",
        "Date": "Wed,  1 Sep 2021 12:41:39 -0400",
        "Message-Id": "<20210901164139.2554647-3-mark.d.gray@redhat.com>",
        "X-Mailer": "git-send-email 2.27.0",
        "In-Reply-To": "<20210901164139.2554647-1-mark.d.gray@redhat.com>",
        "References": "<20210901164139.2554647-1-mark.d.gray@redhat.com>",
        "MIME-Version": "1.0",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-Originator": "redhat.com",
        "Cc": "numans@redhat.com",
        "Subject": "[ovs-dev] [PATCH ovn v2 2/2] northd: Split northd.c",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>",
        "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>",
        "List-Post": "<mailto:ovs-dev@openvswitch.org>",
        "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>",
        "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Errors-To": "ovs-dev-bounces@openvswitch.org",
        "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>"
    },
    "content": "This commit splits northd into two parts. One part, ovn-northd.c,\nis responsible for the `ovn-northd` application, and the other is\nresponsible for northd processing.\n\nThis takes one step towards a more modular northd code base.\n\nSigned-off-by: Mark Gray <mark.d.gray@redhat.com>\n---\n northd/automake.mk  |    2 +\n northd/northd.c     | 1108 +------------------------------------------\n northd/northd.h     |   42 ++\n northd/ovn-northd.c | 1100 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 1161 insertions(+), 1091 deletions(-)\n create mode 100644 northd/northd.h\n create mode 100644 northd/ovn-northd.c",
    "diff": "diff --git a/northd/automake.mk b/northd/automake.mk\nindex 306b533a486b..35ad8c09d9ba 100644\n--- a/northd/automake.mk\n+++ b/northd/automake.mk\n@@ -2,6 +2,8 @@\n bin_PROGRAMS += northd/ovn-northd\n northd_ovn_northd_SOURCES = \\\n \tnorthd/northd.c \\\n+\tnorthd/northd.h \\\n+\tnorthd/ovn-northd.c \\\n \tnorthd/ipam.c \\\n \tnorthd/ipam.h\n northd_ovn_northd_LDADD = \\\ndiff --git a/northd/northd.c b/northd/northd.c\nindex e9a8492880e4..262c7755e718 100644\n--- a/northd/northd.c\n+++ b/northd/northd.c\n@@ -14,17 +14,13 @@\n \n #include <config.h>\n \n-#include <getopt.h>\n #include <stdlib.h>\n #include <stdio.h>\n \n #include \"bitmap.h\"\n-#include \"command-line.h\"\n-#include \"daemon.h\"\n #include \"dirs.h\"\n #include \"ipam.h\"\n #include \"openvswitch/dynamic-string.h\"\n-#include \"fatal-signal.h\"\n #include \"hash.h\"\n #include \"hmapx.h\"\n #include \"openvswitch/hmap.h\"\n@@ -40,13 +36,12 @@\n #include \"lib/ovn-util.h\"\n #include \"lib/lb.h\"\n #include \"memory.h\"\n-#include \"ovs-numa.h\"\n+#include \"northd.h\"\n #include \"lib/ovn-parallel-hmap.h\"\n #include \"ovn/actions.h\"\n #include \"ovn/features.h\"\n #include \"ovn/logical-fields.h\"\n #include \"packets.h\"\n-#include \"openvswitch/poll-loop.h\"\n #include \"simap.h\"\n #include \"smap.h\"\n #include \"sset.h\"\n@@ -54,41 +49,12 @@\n #include \"stopwatch.h\"\n #include \"lib/stopwatch-names.h\"\n #include \"stream.h\"\n-#include \"stream-ssl.h\"\n #include \"timeval.h\"\n-#include \"unixctl.h\"\n #include \"util.h\"\n #include \"uuid.h\"\n #include \"openvswitch/vlog.h\"\n \n-VLOG_DEFINE_THIS_MODULE(ovn_northd);\n-\n-static unixctl_cb_func ovn_northd_exit;\n-static unixctl_cb_func ovn_northd_pause;\n-static unixctl_cb_func ovn_northd_resume;\n-static unixctl_cb_func ovn_northd_is_paused;\n-static unixctl_cb_func ovn_northd_status;\n-static unixctl_cb_func cluster_state_reset_cmd;\n-\n-struct northd_context {\n-    struct ovsdb_idl *ovnnb_idl;\n-    struct ovsdb_idl *ovnsb_idl;\n-    struct ovsdb_idl_txn *ovnnb_txn;\n-    struct ovsdb_idl_txn *ovnsb_txn;\n-    struct ovsdb_idl_index *sbrec_chassis_by_name;\n-    struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;\n-    struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp;\n-    struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;\n-};\n-\n-struct northd_state {\n-    bool had_lock;\n-    bool paused;\n-};\n-\n-static const char *ovnnb_db;\n-static const char *ovnsb_db;\n-static const char *unixctl_path;\n+VLOG_DEFINE_THIS_MODULE(northd);\n \n static bool controller_event_en;\n \n@@ -110,12 +76,6 @@ static bool use_ct_inv_match = true;\n #define DEFAULT_PROBE_INTERVAL_MSEC 5000\n static int northd_probe_interval_nb = 0;\n static int northd_probe_interval_sb = 0;\n-\n-/* SSL options */\n-static const char *ssl_private_key_file;\n-static const char *ssl_certificate_file;\n-static const char *ssl_ca_cert_file;\n-\n #define MAX_OVN_TAGS 4096\n \f\n /* Pipeline stages. */\n@@ -403,29 +363,6 @@ ovn_stage_to_datapath_type(enum ovn_stage stage)\n     }\n }\n \f\n-static void\n-usage(void)\n-{\n-    printf(\"\\\n-%s: OVN northbound management daemon\\n\\\n-usage: %s [OPTIONS]\\n\\\n-\\n\\\n-Options:\\n\\\n-  --ovnnb-db=DATABASE       connect to ovn-nb database at DATABASE\\n\\\n-                            (default: %s)\\n\\\n-  --ovnsb-db=DATABASE       connect to ovn-sb database at DATABASE\\n\\\n-                            (default: %s)\\n\\\n-  --dry-run                 start in paused state (do not commit db changes)\\n\\\n-  --unixctl=SOCKET          override default control socket name\\n\\\n-  -h, --help                display this help message\\n\\\n-  -o, --options             list available options\\n\\\n-  -V, --version             display version information\\n\\\n-\", program_name, program_name, default_nb_db(), default_sb_db());\n-    daemon_usage();\n-    vlog_usage();\n-    stream_usage(\"database\", true, true, false);\n-}\n-\f\n struct ovn_chassis_qdisc_queues {\n     struct hmap_node key_node;\n     uint32_t queue_id;\n@@ -4358,9 +4295,9 @@ ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,\n /* If this option is 'true' northd will combine logical flows that differ by\n  * logical datapath only by creating a datapath group. */\n static bool use_logical_dp_groups = false;\n-static bool use_parallel_build = true;\n+static bool use_parallel_build = false;\n \n-static struct hashrow_locks lflow_locks;\n+static struct hashrow_locks *lflow_locks;\n \n /* Adds a row with the specified contents to the Logical_Flow table.\n  * Version to use when locking is required.\n@@ -4454,10 +4391,10 @@ ovn_dp_group_add_with_reference(struct ovn_lflow *lflow_ref,\n         return false;\n     }\n \n-    if (use_parallel_build) {\n-        lock_hash_row(&lflow_locks, hash);\n+    if (use_logical_dp_groups && use_parallel_build) {\n+        lock_hash_row(lflow_locks, hash);\n         hmapx_add(&lflow_ref->od_group, od);\n-        unlock_hash_row(&lflow_locks, hash);\n+        unlock_hash_row(lflow_locks, hash);\n     } else {\n         hmapx_add(&lflow_ref->od_group, od);\n     }\n@@ -13171,7 +13108,7 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,\n \n     fast_hmap_size_for(&lflows, max_seen_lflow_size);\n     if (use_parallel_build) {\n-        update_hashrow_locks(&lflows, &lflow_locks);\n+        update_hashrow_locks(&lflows, lflow_locks);\n     }\n     build_lswitch_and_lrouter_flows(datapaths, ports,\n                                     port_groups, &lflows, mcgroups,\n@@ -14239,8 +14176,11 @@ ovnnb_db_run(struct northd_context *ctx,\n     smap_destroy(&options);\n \n     /* Update the probe interval. */\n-    northd_probe_interval_nb = get_probe_interval(ovnnb_db, nb);\n-    northd_probe_interval_sb = get_probe_interval(ovnsb_db, nb);\n+    northd_probe_interval_nb = get_probe_interval(ctx->ovnnb_db, nb);\n+    northd_probe_interval_sb = get_probe_interval(ctx->ovnsb_db, nb);\n+\n+    ovsdb_idl_set_probe_interval(ctx->ovnnb_idl, northd_probe_interval_nb);\n+    ovsdb_idl_set_probe_interval(ctx->ovnsb_idl, northd_probe_interval_sb);\n \n     use_parallel_build =\n         (smap_get_bool(&nb->options, \"use_parallel_build\", false) &&\n@@ -14532,373 +14472,6 @@ handle_port_binding_changes(struct northd_context *ctx, struct hmap *ports,\n     }\n }\n \n-static struct gen_opts_map supported_dhcp_opts[] = {\n-    OFFERIP,\n-    DHCP_OPT_NETMASK,\n-    DHCP_OPT_ROUTER,\n-    DHCP_OPT_DNS_SERVER,\n-    DHCP_OPT_LOG_SERVER,\n-    DHCP_OPT_LPR_SERVER,\n-    DHCP_OPT_SWAP_SERVER,\n-    DHCP_OPT_POLICY_FILTER,\n-    DHCP_OPT_ROUTER_SOLICITATION,\n-    DHCP_OPT_NIS_SERVER,\n-    DHCP_OPT_NTP_SERVER,\n-    DHCP_OPT_SERVER_ID,\n-    DHCP_OPT_TFTP_SERVER,\n-    DHCP_OPT_CLASSLESS_STATIC_ROUTE,\n-    DHCP_OPT_MS_CLASSLESS_STATIC_ROUTE,\n-    DHCP_OPT_IP_FORWARD_ENABLE,\n-    DHCP_OPT_ROUTER_DISCOVERY,\n-    DHCP_OPT_ETHERNET_ENCAP,\n-    DHCP_OPT_DEFAULT_TTL,\n-    DHCP_OPT_TCP_TTL,\n-    DHCP_OPT_MTU,\n-    DHCP_OPT_LEASE_TIME,\n-    DHCP_OPT_T1,\n-    DHCP_OPT_T2,\n-    DHCP_OPT_WPAD,\n-    DHCP_OPT_BOOTFILE,\n-    DHCP_OPT_PATH_PREFIX,\n-    DHCP_OPT_TFTP_SERVER_ADDRESS,\n-    DHCP_OPT_HOSTNAME,\n-    DHCP_OPT_DOMAIN_NAME,\n-    DHCP_OPT_ARP_CACHE_TIMEOUT,\n-    DHCP_OPT_TCP_KEEPALIVE_INTERVAL,\n-    DHCP_OPT_DOMAIN_SEARCH_LIST,\n-    DHCP_OPT_BOOTFILE_ALT,\n-    DHCP_OPT_BROADCAST_ADDRESS,\n-    DHCP_OPT_NETBIOS_NAME_SERVER,\n-    DHCP_OPT_NETBIOS_NODE_TYPE,\n-};\n-\n-static struct gen_opts_map supported_dhcpv6_opts[] = {\n-    DHCPV6_OPT_IA_ADDR,\n-    DHCPV6_OPT_SERVER_ID,\n-    DHCPV6_OPT_DOMAIN_SEARCH,\n-    DHCPV6_OPT_DNS_SERVER\n-};\n-\n-static void\n-check_and_add_supported_dhcp_opts_to_sb_db(struct northd_context *ctx)\n-{\n-    struct hmap dhcp_opts_to_add = HMAP_INITIALIZER(&dhcp_opts_to_add);\n-    for (size_t i = 0; (i < sizeof(supported_dhcp_opts) /\n-                            sizeof(supported_dhcp_opts[0])); i++) {\n-        hmap_insert(&dhcp_opts_to_add, &supported_dhcp_opts[i].hmap_node,\n-                    dhcp_opt_hash(supported_dhcp_opts[i].name));\n-    }\n-\n-    const struct sbrec_dhcp_options *opt_row, *opt_row_next;\n-    SBREC_DHCP_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) {\n-        struct gen_opts_map *dhcp_opt =\n-            dhcp_opts_find(&dhcp_opts_to_add, opt_row->name);\n-        if (dhcp_opt) {\n-            if (!strcmp(dhcp_opt->type, opt_row->type) &&\n-                 dhcp_opt->code == opt_row->code) {\n-                hmap_remove(&dhcp_opts_to_add, &dhcp_opt->hmap_node);\n-            } else {\n-                sbrec_dhcp_options_delete(opt_row);\n-            }\n-        } else {\n-            sbrec_dhcp_options_delete(opt_row);\n-        }\n-    }\n-\n-    struct gen_opts_map *opt;\n-    HMAP_FOR_EACH (opt, hmap_node, &dhcp_opts_to_add) {\n-        struct sbrec_dhcp_options *sbrec_dhcp_option =\n-            sbrec_dhcp_options_insert(ctx->ovnsb_txn);\n-        sbrec_dhcp_options_set_name(sbrec_dhcp_option, opt->name);\n-        sbrec_dhcp_options_set_code(sbrec_dhcp_option, opt->code);\n-        sbrec_dhcp_options_set_type(sbrec_dhcp_option, opt->type);\n-    }\n-\n-    hmap_destroy(&dhcp_opts_to_add);\n-}\n-\n-static void\n-check_and_add_supported_dhcpv6_opts_to_sb_db(struct northd_context *ctx)\n-{\n-    struct hmap dhcpv6_opts_to_add = HMAP_INITIALIZER(&dhcpv6_opts_to_add);\n-    for (size_t i = 0; (i < sizeof(supported_dhcpv6_opts) /\n-                            sizeof(supported_dhcpv6_opts[0])); i++) {\n-        hmap_insert(&dhcpv6_opts_to_add, &supported_dhcpv6_opts[i].hmap_node,\n-                    dhcp_opt_hash(supported_dhcpv6_opts[i].name));\n-    }\n-\n-    const struct sbrec_dhcpv6_options *opt_row, *opt_row_next;\n-    SBREC_DHCPV6_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) {\n-        struct gen_opts_map *dhcp_opt =\n-            dhcp_opts_find(&dhcpv6_opts_to_add, opt_row->name);\n-        if (dhcp_opt) {\n-            hmap_remove(&dhcpv6_opts_to_add, &dhcp_opt->hmap_node);\n-        } else {\n-            sbrec_dhcpv6_options_delete(opt_row);\n-        }\n-    }\n-\n-    struct gen_opts_map *opt;\n-    HMAP_FOR_EACH(opt, hmap_node, &dhcpv6_opts_to_add) {\n-        struct sbrec_dhcpv6_options *sbrec_dhcpv6_option =\n-            sbrec_dhcpv6_options_insert(ctx->ovnsb_txn);\n-        sbrec_dhcpv6_options_set_name(sbrec_dhcpv6_option, opt->name);\n-        sbrec_dhcpv6_options_set_code(sbrec_dhcpv6_option, opt->code);\n-        sbrec_dhcpv6_options_set_type(sbrec_dhcpv6_option, opt->type);\n-    }\n-\n-    hmap_destroy(&dhcpv6_opts_to_add);\n-}\n-\n-static const char *rbac_chassis_auth[] =\n-    {\"name\"};\n-static const char *rbac_chassis_update[] =\n-    {\"nb_cfg\", \"external_ids\", \"encaps\", \"vtep_logical_switches\",\n-     \"other_config\", \"transport_zones\"};\n-\n-static const char *rbac_chassis_private_auth[] =\n-    {\"name\"};\n-static const char *rbac_chassis_private_update[] =\n-    {\"nb_cfg\", \"nb_cfg_timestamp\", \"chassis\", \"external_ids\"};\n-\n-static const char *rbac_encap_auth[] =\n-    {\"chassis_name\"};\n-static const char *rbac_encap_update[] =\n-    {\"type\", \"options\", \"ip\"};\n-\n-static const char *rbac_controller_event_auth[] =\n-    {\"\"};\n-static const char *rbac_controller_event_update[] =\n-    {\"chassis\", \"event_info\", \"event_type\", \"seq_num\"};\n-\n-\n-static const char *rbac_fdb_auth[] =\n-    {\"\"};\n-static const char *rbac_fdb_update[] =\n-    {\"dp_key\", \"mac\", \"port_key\"};\n-\n-static const char *rbac_port_binding_auth[] =\n-    {\"\"};\n-static const char *rbac_port_binding_update[] =\n-    {\"chassis\", \"encap\", \"up\", \"virtual_parent\"};\n-\n-static const char *rbac_mac_binding_auth[] =\n-    {\"\"};\n-static const char *rbac_mac_binding_update[] =\n-    {\"logical_port\", \"ip\", \"mac\", \"datapath\"};\n-\n-static const char *rbac_svc_monitor_auth[] =\n-    {\"\"};\n-static const char *rbac_svc_monitor_auth_update[] =\n-    {\"status\"};\n-static const char *rbac_igmp_group_auth[] =\n-    {\"\"};\n-static const char *rbac_igmp_group_update[] =\n-    {\"address\", \"chassis\", \"datapath\", \"ports\"};\n-\n-static struct rbac_perm_cfg {\n-    const char *table;\n-    const char **auth;\n-    int n_auth;\n-    bool insdel;\n-    const char **update;\n-    int n_update;\n-    const struct sbrec_rbac_permission *row;\n-} rbac_perm_cfg[] = {\n-    {\n-        .table = \"Chassis\",\n-        .auth = rbac_chassis_auth,\n-        .n_auth = ARRAY_SIZE(rbac_chassis_auth),\n-        .insdel = true,\n-        .update = rbac_chassis_update,\n-        .n_update = ARRAY_SIZE(rbac_chassis_update),\n-        .row = NULL\n-    },{\n-        .table = \"Chassis_Private\",\n-        .auth = rbac_chassis_private_auth,\n-        .n_auth = ARRAY_SIZE(rbac_chassis_private_auth),\n-        .insdel = true,\n-        .update = rbac_chassis_private_update,\n-        .n_update = ARRAY_SIZE(rbac_chassis_private_update),\n-        .row = NULL\n-    },{\n-        .table = \"Controller_Event\",\n-        .auth = rbac_controller_event_auth,\n-        .n_auth = ARRAY_SIZE(rbac_controller_event_auth),\n-        .insdel = true,\n-        .update = rbac_controller_event_update,\n-        .n_update = ARRAY_SIZE(rbac_controller_event_update),\n-        .row = NULL\n-    },{\n-        .table = \"Encap\",\n-        .auth = rbac_encap_auth,\n-        .n_auth = ARRAY_SIZE(rbac_encap_auth),\n-        .insdel = true,\n-        .update = rbac_encap_update,\n-        .n_update = ARRAY_SIZE(rbac_encap_update),\n-        .row = NULL\n-    },{\n-        .table = \"FDB\",\n-        .auth = rbac_fdb_auth,\n-        .n_auth = ARRAY_SIZE(rbac_fdb_auth),\n-        .insdel = true,\n-        .update = rbac_fdb_update,\n-        .n_update = ARRAY_SIZE(rbac_fdb_update),\n-        .row = NULL\n-    },{\n-        .table = \"Port_Binding\",\n-        .auth = rbac_port_binding_auth,\n-        .n_auth = ARRAY_SIZE(rbac_port_binding_auth),\n-        .insdel = false,\n-        .update = rbac_port_binding_update,\n-        .n_update = ARRAY_SIZE(rbac_port_binding_update),\n-        .row = NULL\n-    },{\n-        .table = \"MAC_Binding\",\n-        .auth = rbac_mac_binding_auth,\n-        .n_auth = ARRAY_SIZE(rbac_mac_binding_auth),\n-        .insdel = true,\n-        .update = rbac_mac_binding_update,\n-        .n_update = ARRAY_SIZE(rbac_mac_binding_update),\n-        .row = NULL\n-    },{\n-        .table = \"Service_Monitor\",\n-        .auth = rbac_svc_monitor_auth,\n-        .n_auth = ARRAY_SIZE(rbac_svc_monitor_auth),\n-        .insdel = false,\n-        .update = rbac_svc_monitor_auth_update,\n-        .n_update = ARRAY_SIZE(rbac_svc_monitor_auth_update),\n-        .row = NULL\n-    },{\n-        .table = \"IGMP_Group\",\n-        .auth = rbac_igmp_group_auth,\n-        .n_auth = ARRAY_SIZE(rbac_igmp_group_auth),\n-        .insdel = true,\n-        .update = rbac_igmp_group_update,\n-        .n_update = ARRAY_SIZE(rbac_igmp_group_update),\n-        .row = NULL\n-    },{\n-        .table = NULL,\n-        .auth = NULL,\n-        .n_auth = 0,\n-        .insdel = false,\n-        .update = NULL,\n-        .n_update = 0,\n-        .row = NULL\n-    }\n-};\n-\n-static bool\n-ovn_rbac_validate_perm(const struct sbrec_rbac_permission *perm)\n-{\n-    struct rbac_perm_cfg *pcfg;\n-    int i, j, n_found;\n-\n-    for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) {\n-        if (!strcmp(perm->table, pcfg->table)) {\n-            break;\n-        }\n-    }\n-    if (!pcfg->table) {\n-        return false;\n-    }\n-    if (perm->n_authorization != pcfg->n_auth ||\n-        perm->n_update != pcfg->n_update) {\n-        return false;\n-    }\n-    if (perm->insert_delete != pcfg->insdel) {\n-        return false;\n-    }\n-    /* verify perm->authorization vs. pcfg->auth */\n-    n_found = 0;\n-    for (i = 0; i < pcfg->n_auth; i++) {\n-        for (j = 0; j < perm->n_authorization; j++) {\n-            if (!strcmp(pcfg->auth[i], perm->authorization[j])) {\n-                n_found++;\n-                break;\n-            }\n-        }\n-    }\n-    if (n_found != pcfg->n_auth) {\n-        return false;\n-    }\n-\n-    /* verify perm->update vs. pcfg->update */\n-    n_found = 0;\n-    for (i = 0; i < pcfg->n_update; i++) {\n-        for (j = 0; j < perm->n_update; j++) {\n-            if (!strcmp(pcfg->update[i], perm->update[j])) {\n-                n_found++;\n-                break;\n-            }\n-        }\n-    }\n-    if (n_found != pcfg->n_update) {\n-        return false;\n-    }\n-\n-    /* Success, db state matches expected state */\n-    pcfg->row = perm;\n-    return true;\n-}\n-\n-static void\n-ovn_rbac_create_perm(struct rbac_perm_cfg *pcfg,\n-                     struct northd_context *ctx,\n-                     const struct sbrec_rbac_role *rbac_role)\n-{\n-    struct sbrec_rbac_permission *rbac_perm;\n-\n-    rbac_perm = sbrec_rbac_permission_insert(ctx->ovnsb_txn);\n-    sbrec_rbac_permission_set_table(rbac_perm, pcfg->table);\n-    sbrec_rbac_permission_set_authorization(rbac_perm,\n-                                            pcfg->auth,\n-                                            pcfg->n_auth);\n-    sbrec_rbac_permission_set_insert_delete(rbac_perm, pcfg->insdel);\n-    sbrec_rbac_permission_set_update(rbac_perm,\n-                                     pcfg->update,\n-                                     pcfg->n_update);\n-    sbrec_rbac_role_update_permissions_setkey(rbac_role, pcfg->table,\n-                                              rbac_perm);\n-}\n-\n-static void\n-check_and_update_rbac(struct northd_context *ctx)\n-{\n-    const struct sbrec_rbac_role *rbac_role = NULL;\n-    const struct sbrec_rbac_permission *perm_row, *perm_next;\n-    const struct sbrec_rbac_role *role_row, *role_row_next;\n-    struct rbac_perm_cfg *pcfg;\n-\n-    for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) {\n-        pcfg->row = NULL;\n-    }\n-\n-    SBREC_RBAC_PERMISSION_FOR_EACH_SAFE (perm_row, perm_next, ctx->ovnsb_idl) {\n-        if (!ovn_rbac_validate_perm(perm_row)) {\n-            sbrec_rbac_permission_delete(perm_row);\n-        }\n-    }\n-    SBREC_RBAC_ROLE_FOR_EACH_SAFE (role_row, role_row_next, ctx->ovnsb_idl) {\n-        if (strcmp(role_row->name, \"ovn-controller\")) {\n-            sbrec_rbac_role_delete(role_row);\n-        } else {\n-            rbac_role = role_row;\n-        }\n-    }\n-\n-    if (!rbac_role) {\n-        rbac_role = sbrec_rbac_role_insert(ctx->ovnsb_txn);\n-        sbrec_rbac_role_set_name(rbac_role, \"ovn-controller\");\n-    }\n-\n-    for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) {\n-        if (!pcfg->row) {\n-            ovn_rbac_create_perm(pcfg, ctx, rbac_role);\n-        }\n-    }\n-}\n-\n /* Updates the sb_cfg and hv_cfg columns in the northbound NB_Global table. */\n static void\n update_northbound_cfg(struct northd_context *ctx,\n@@ -14971,7 +14544,7 @@ ovnsb_db_run(struct northd_context *ctx,\n     shash_destroy(&ha_ref_chassis_map);\n }\n \n-static void\n+void\n ovn_db_run(struct northd_context *ctx,\n            struct ovsdb_idl_index *sbrec_chassis_by_name,\n            struct ovsdb_idl_loop *ovnsb_idl_loop,\n@@ -14982,6 +14555,8 @@ ovn_db_run(struct northd_context *ctx,\n     ovs_list_init(&lr_list);\n     hmap_init(&datapaths);\n     hmap_init(&ports);\n+    use_parallel_build = ctx->use_parallel_build;\n+    lflow_locks = ctx->lflow_locks;\n \n     int64_t start_time = time_wall_msec();\n     stopwatch_start(OVNNB_DB_RUN_STOPWATCH_NAME, time_msec());\n@@ -14994,653 +14569,4 @@ ovn_db_run(struct northd_context *ctx,\n     stopwatch_stop(OVNSB_DB_RUN_STOPWATCH_NAME, time_msec());\n     destroy_datapaths_and_ports(&datapaths, &ports, &lr_list);\n }\n-\f\n-static void\n-parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED,\n-              bool *paused)\n-{\n-    enum {\n-        OVN_DAEMON_OPTION_ENUMS,\n-        VLOG_OPTION_ENUMS,\n-        SSL_OPTION_ENUMS,\n-        OPT_DRY_RUN,\n-        OPT_DUMMY_NUMA,\n-    };\n-    static const struct option long_options[] = {\n-        {\"ovnsb-db\", required_argument, NULL, 'd'},\n-        {\"ovnnb-db\", required_argument, NULL, 'D'},\n-        {\"unixctl\", required_argument, NULL, 'u'},\n-        {\"help\", no_argument, NULL, 'h'},\n-        {\"options\", no_argument, NULL, 'o'},\n-        {\"version\", no_argument, NULL, 'V'},\n-        {\"dry-run\", no_argument, NULL, OPT_DRY_RUN},\n-        {\"dummy-numa\", required_argument, NULL, OPT_DUMMY_NUMA},\n-        OVN_DAEMON_LONG_OPTIONS,\n-        VLOG_LONG_OPTIONS,\n-        STREAM_SSL_LONG_OPTIONS,\n-        {NULL, 0, NULL, 0},\n-    };\n-    char *short_options = ovs_cmdl_long_options_to_short_options(long_options);\n-\n-    for (;;) {\n-        int c;\n-\n-        c = getopt_long(argc, argv, short_options, long_options, NULL);\n-        if (c == -1) {\n-            break;\n-        }\n-\n-        switch (c) {\n-        OVN_DAEMON_OPTION_HANDLERS;\n-        VLOG_OPTION_HANDLERS;\n-\n-        case 'p':\n-            ssl_private_key_file = optarg;\n-            break;\n-\n-        case 'c':\n-            ssl_certificate_file = optarg;\n-            break;\n-\n-        case 'C':\n-            ssl_ca_cert_file = optarg;\n-            break;\n-\n-        case 'd':\n-            ovnsb_db = optarg;\n-            break;\n-\n-        case 'D':\n-            ovnnb_db = optarg;\n-            break;\n-\n-        case 'u':\n-            unixctl_path = optarg;\n-            break;\n-\n-        case 'h':\n-            usage();\n-            exit(EXIT_SUCCESS);\n-\n-        case 'o':\n-            ovs_cmdl_print_options(long_options);\n-            exit(EXIT_SUCCESS);\n-\n-        case 'V':\n-            ovn_print_version(0, 0);\n-            exit(EXIT_SUCCESS);\n-\n-        case OPT_DUMMY_NUMA:\n-            ovs_numa_set_dummy(optarg);\n-            break;\n-\n-        case OPT_DRY_RUN:\n-            *paused = true;\n-            break;\n-\n-        default:\n-            break;\n-        }\n-    }\n-\n-    if (!ovnsb_db || !ovnsb_db[0]) {\n-        ovnsb_db = default_sb_db();\n-    }\n-\n-    if (!ovnnb_db || !ovnnb_db[0]) {\n-        ovnnb_db = default_nb_db();\n-    }\n-\n-    free(short_options);\n-}\n-\n-static void\n-add_column_noalert(struct ovsdb_idl *idl,\n-                   const struct ovsdb_idl_column *column)\n-{\n-    ovsdb_idl_add_column(idl, column);\n-    ovsdb_idl_omit_alert(idl, column);\n-}\n-\n-static void\n-update_ssl_config(void)\n-{\n-    if (ssl_private_key_file && ssl_certificate_file) {\n-        stream_ssl_set_key_and_cert(ssl_private_key_file,\n-                                    ssl_certificate_file);\n-    }\n-    if (ssl_ca_cert_file) {\n-        stream_ssl_set_ca_cert_file(ssl_ca_cert_file, false);\n-    }\n-}\n-\n-int\n-main(int argc, char *argv[])\n-{\n-    int res = EXIT_SUCCESS;\n-    struct unixctl_server *unixctl;\n-    int retval;\n-    bool exiting;\n-    struct northd_state state = {\n-        .had_lock = false,\n-        .paused = false\n-    };\n-\n-    fatal_ignore_sigpipe();\n-    ovs_cmdl_proctitle_init(argc, argv);\n-    ovn_set_program_name(argv[0]);\n-    service_start(&argc, &argv);\n-    parse_options(argc, argv, &state.paused);\n-\n-    daemonize_start(false);\n-\n-    char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path);\n-    retval = unixctl_server_create(abs_unixctl_path, &unixctl);\n-    free(abs_unixctl_path);\n-\n-    if (retval) {\n-        exit(EXIT_FAILURE);\n-    }\n-    unixctl_command_register(\"exit\", \"\", 0, 0, ovn_northd_exit, &exiting);\n-    unixctl_command_register(\"pause\", \"\", 0, 0, ovn_northd_pause, &state);\n-    unixctl_command_register(\"resume\", \"\", 0, 0, ovn_northd_resume, &state);\n-    unixctl_command_register(\"is-paused\", \"\", 0, 0, ovn_northd_is_paused,\n-                             &state);\n-    unixctl_command_register(\"status\", \"\", 0, 0, ovn_northd_status, &state);\n-\n-    bool reset_ovnsb_idl_min_index = false;\n-    unixctl_command_register(\"sb-cluster-state-reset\", \"\", 0, 0,\n-                             cluster_state_reset_cmd,\n-                             &reset_ovnsb_idl_min_index);\n-\n-    bool reset_ovnnb_idl_min_index = false;\n-    unixctl_command_register(\"nb-cluster-state-reset\", \"\", 0, 0,\n-                             cluster_state_reset_cmd,\n-                             &reset_ovnnb_idl_min_index);\n-\n-    daemonize_complete();\n-\n-    init_hash_row_locks(&lflow_locks);\n-    use_parallel_build = can_parallelize_hashes(false);\n-\n-    /* We want to detect (almost) all changes to the ovn-nb db. */\n-    struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(\n-        ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, true, true));\n-    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl,\n-                         &nbrec_nb_global_col_nb_cfg_timestamp);\n-    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_sb_cfg);\n-    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl,\n-                         &nbrec_nb_global_col_sb_cfg_timestamp);\n-    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_hv_cfg);\n-    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl,\n-                         &nbrec_nb_global_col_hv_cfg_timestamp);\n-\n-    unixctl_command_register(\"nb-connection-status\", \"\", 0, 0,\n-                             ovn_conn_show, ovnnb_idl_loop.idl);\n-\n-    /* We want to detect only selected changes to the ovn-sb db. */\n-    struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(\n-        ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true));\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_sb_global);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_nb_cfg);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_options);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_ipsec);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_logical_flow);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_logical_flow_col_logical_datapath);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_logical_flow_col_logical_dp_group);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_pipeline);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_table_id);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_priority);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_actions);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_logical_flow_col_controller_meter);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_logical_flow_col_external_ids);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl,\n-                        &sbrec_table_logical_dp_group);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_logical_dp_group_col_datapaths);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_multicast_group);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_multicast_group_col_datapath);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_multicast_group_col_tunnel_key);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_name);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_ports);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_datapath_binding_col_tunnel_key);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_datapath_binding_col_load_balancers);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_datapath_binding_col_external_ids);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_datapath);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_port_binding_col_logical_port);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_port_binding_col_tunnel_key);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_port_binding_col_parent_port);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_tag);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_type);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_options);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_port_binding_col_nat_addresses);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_port_binding_col_gateway_chassis);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_port_binding_col_ha_chassis_group);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_port_binding_col_virtual_parent);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_port_binding_col_up);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_gateway_chassis_col_chassis);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_gateway_chassis_col_name);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_gateway_chassis_col_priority);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_gateway_chassis_col_external_ids);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_gateway_chassis_col_options);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_port_binding_col_external_ids);\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_mac_binding);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_datapath);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_ip);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_mac);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_mac_binding_col_logical_port);\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcp_options);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_code);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_type);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_name);\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcpv6_options);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_code);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_type);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_name);\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_address_set);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_name);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_addresses);\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_group);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_name);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_ports);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dns);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_datapaths);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_records);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_external_ids);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_role);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_name);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_permissions);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_permission);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_rbac_permission_col_table);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_rbac_permission_col_authorization);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_rbac_permission_col_insert_delete);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_permission_col_update);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_name);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_unit);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_bands);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter_band);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_action);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_rate);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_burst_size);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_encap);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_type);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis_private);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_chassis_private_col_name);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_chassis_private_col_chassis);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_chassis_private_col_nb_cfg);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_chassis_private_col_nb_cfg_timestamp);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ha_chassis_col_chassis);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ha_chassis_col_priority);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ha_chassis_col_external_ids);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis_group);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ha_chassis_group_col_name);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ha_chassis_group_col_ha_chassis);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ha_chassis_group_col_external_ids);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ha_chassis_group_col_ref_chassis);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_igmp_group);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_address);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_datapath);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_chassis);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_ports);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ip_multicast);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_datapath);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_enabled);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_querier);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_eth_src);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_ip4_src);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_ip6_src);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_table_size);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_idle_timeout);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_query_interval);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_ip_multicast_col_query_max_resp);\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_service_monitor);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_ip);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_logical_port);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_port);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_options);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n-                         &sbrec_service_monitor_col_status);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_protocol);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_src_mac);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_src_ip);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_service_monitor_col_external_ids);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_load_balancer);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_datapaths);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_name);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_vips);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_protocol);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_options);\n-    add_column_noalert(ovnsb_idl_loop.idl,\n-                       &sbrec_load_balancer_col_external_ids);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_bfd);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_logical_port);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_dst_ip);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_status);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_tx);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_rx);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_detect_mult);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_disc);\n-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_src_port);\n-\n-    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_fdb);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_mac);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_dp_key);\n-    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_port_key);\n-\n-    struct ovsdb_idl_index *sbrec_chassis_by_name\n-        = chassis_index_create(ovnsb_idl_loop.idl);\n-\n-    struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name\n-        = ha_chassis_group_index_create(ovnsb_idl_loop.idl);\n-\n-    struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp\n-        = mcast_group_index_create(ovnsb_idl_loop.idl);\n-\n-    struct ovsdb_idl_index *sbrec_ip_mcast_by_dp\n-        = ip_mcast_index_create(ovnsb_idl_loop.idl);\n-\n-    unixctl_command_register(\"sb-connection-status\", \"\", 0, 0,\n-                             ovn_conn_show, ovnsb_idl_loop.idl);\n-\n-    char *ovn_internal_version = ovn_get_internal_version();\n-    VLOG_INFO(\"OVN internal version is : [%s]\", ovn_internal_version);\n-\n-    stopwatch_create(NORTHD_LOOP_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(OVNNB_DB_RUN_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(OVNSB_DB_RUN_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(BUILD_LFLOWS_CTX_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(CLEAR_LFLOWS_CTX_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(BUILD_LFLOWS_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(LFLOWS_DATAPATHS_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(LFLOWS_PORTS_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(LFLOWS_LBS_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(LFLOWS_IGMP_STOPWATCH_NAME, SW_MS);\n-    stopwatch_create(LFLOWS_DP_GROUPS_STOPWATCH_NAME, SW_MS);\n-\n-    /* Main loop. */\n-    exiting = false;\n-\n-    while (!exiting) {\n-        update_ssl_config();\n-        memory_run();\n-        if (memory_should_report()) {\n-            struct simap usage = SIMAP_INITIALIZER(&usage);\n-\n-            /* Nothing special to report yet. */\n-            memory_report(&usage);\n-            simap_destroy(&usage);\n-        }\n-\n-        if (!state.paused) {\n-            if (!ovsdb_idl_has_lock(ovnsb_idl_loop.idl) &&\n-                !ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl))\n-            {\n-                /* Ensure that only a single ovn-northd is active in the\n-                 * deployment by acquiring a lock called \"ovn_northd\" on the\n-                 * southbound database and then only performing DB transactions\n-                 * if the lock is held.\n-                 */\n-                ovsdb_idl_set_lock(ovnsb_idl_loop.idl, \"ovn_northd\");\n-            }\n-\n-            struct northd_context ctx = {\n-                .ovnnb_idl = ovnnb_idl_loop.idl,\n-                .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop),\n-                .ovnsb_idl = ovnsb_idl_loop.idl,\n-                .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),\n-                .sbrec_chassis_by_name = sbrec_chassis_by_name,\n-                .sbrec_ha_chassis_grp_by_name = sbrec_ha_chassis_grp_by_name,\n-                .sbrec_mcast_group_by_name_dp = sbrec_mcast_group_by_name_dp,\n-                .sbrec_ip_mcast_by_dp = sbrec_ip_mcast_by_dp,\n-            };\n-\n-            if (!state.had_lock && ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {\n-                VLOG_INFO(\"ovn-northd lock acquired. \"\n-                        \"This ovn-northd instance is now active.\");\n-                state.had_lock = true;\n-            } else if (state.had_lock &&\n-                       !ovsdb_idl_has_lock(ovnsb_idl_loop.idl))\n-            {\n-                VLOG_INFO(\"ovn-northd lock lost. \"\n-                        \"This ovn-northd instance is now on standby.\");\n-                state.had_lock = false;\n-            }\n-\n-            if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {\n-                ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop,\n-                           ovn_internal_version);\n-                if (ctx.ovnsb_txn) {\n-                    check_and_add_supported_dhcp_opts_to_sb_db(&ctx);\n-                    check_and_add_supported_dhcpv6_opts_to_sb_db(&ctx);\n-                    check_and_update_rbac(&ctx);\n-                }\n-            }\n-\n-            ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);\n-            ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);\n-        } else {\n-            /* ovn-northd is paused\n-             *    - we still want to handle any db updates and update the\n-             *      local IDL. Otherwise, when it is resumed, the local IDL\n-             *      copy will be out of sync.\n-             *    - but we don't want to create any txns.\n-             * */\n-            if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl) ||\n-                ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl))\n-            {\n-                /* make sure we don't hold the lock while paused */\n-                VLOG_INFO(\"This ovn-northd instance is now paused.\");\n-                ovsdb_idl_set_lock(ovnsb_idl_loop.idl, NULL);\n-                state.had_lock = false;\n-            }\n-\n-            ovsdb_idl_run(ovnnb_idl_loop.idl);\n-            ovsdb_idl_run(ovnsb_idl_loop.idl);\n-            ovsdb_idl_wait(ovnnb_idl_loop.idl);\n-            ovsdb_idl_wait(ovnsb_idl_loop.idl);\n-        }\n-\n-        unixctl_server_run(unixctl);\n-        unixctl_server_wait(unixctl);\n-        memory_wait();\n-        if (exiting) {\n-            poll_immediate_wake();\n-        }\n-\n-\n-        ovsdb_idl_set_probe_interval(ovnnb_idl_loop.idl,\n-                                     northd_probe_interval_nb);\n-        ovsdb_idl_set_probe_interval(ovnsb_idl_loop.idl,\n-                                     northd_probe_interval_sb);\n-\n-        if (reset_ovnsb_idl_min_index) {\n-            VLOG_INFO(\"Resetting southbound database cluster state\");\n-            ovsdb_idl_reset_min_index(ovnsb_idl_loop.idl);\n-            reset_ovnsb_idl_min_index = false;\n-        }\n-\n-        if (reset_ovnnb_idl_min_index) {\n-            VLOG_INFO(\"Resetting northbound database cluster state\");\n-            ovsdb_idl_reset_min_index(ovnnb_idl_loop.idl);\n-            reset_ovnnb_idl_min_index = false;\n-        }\n-\n-        stopwatch_stop(NORTHD_LOOP_STOPWATCH_NAME, time_msec());\n-        poll_block();\n-        if (should_service_stop()) {\n-            exiting = true;\n-        }\n-        stopwatch_start(NORTHD_LOOP_STOPWATCH_NAME, time_msec());\n-    }\n-\n-\n-    free(ovn_internal_version);\n-    unixctl_server_destroy(unixctl);\n-    ovsdb_idl_loop_destroy(&ovnnb_idl_loop);\n-    ovsdb_idl_loop_destroy(&ovnsb_idl_loop);\n-    service_stop();\n-\n-    exit(res);\n-}\n-\n-static void\n-ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,\n-                const char *argv[] OVS_UNUSED, void *exiting_)\n-{\n-    bool *exiting = exiting_;\n-    *exiting = true;\n-\n-    unixctl_command_reply(conn, NULL);\n-}\n-\n-static void\n-ovn_northd_pause(struct unixctl_conn *conn, int argc OVS_UNUSED,\n-                const char *argv[] OVS_UNUSED, void *state_)\n-{\n-    struct northd_state  *state = state_;\n-    state->paused = true;\n-\n-    unixctl_command_reply(conn, NULL);\n-}\n-\n-static void\n-ovn_northd_resume(struct unixctl_conn *conn, int argc OVS_UNUSED,\n-                  const char *argv[] OVS_UNUSED, void *state_)\n-{\n-    struct northd_state *state = state_;\n-    state->paused = false;\n-\n-    unixctl_command_reply(conn, NULL);\n-}\n-\n-static void\n-ovn_northd_is_paused(struct unixctl_conn *conn, int argc OVS_UNUSED,\n-                     const char *argv[] OVS_UNUSED, void *state_)\n-{\n-    struct northd_state *state = state_;\n-    if (state->paused) {\n-        unixctl_command_reply(conn, \"true\");\n-    } else {\n-        unixctl_command_reply(conn, \"false\");\n-    }\n-}\n-\n-static void\n-ovn_northd_status(struct unixctl_conn *conn, int argc OVS_UNUSED,\n-                  const char *argv[] OVS_UNUSED, void *state_)\n-{\n-    struct northd_state *state = state_;\n-    char *status;\n-\n-    if (state->paused) {\n-        status = \"paused\";\n-    } else {\n-        status = state->had_lock ? \"active\" : \"standby\";\n-    }\n-\n-    /*\n-     * Use a labelled formatted output so we can add more to the status command\n-     * later without breaking any consuming scripts\n-     */\n-    struct ds s = DS_EMPTY_INITIALIZER;\n-    ds_put_format(&s, \"Status: %s\\n\", status);\n-    unixctl_command_reply(conn, ds_cstr(&s));\n-    ds_destroy(&s);\n-}\n-\n-static void\n-cluster_state_reset_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,\n-               const char *argv[] OVS_UNUSED, void *idl_reset_)\n-{\n-    bool *idl_reset = idl_reset_;\n-\n-    *idl_reset = true;\n-    poll_immediate_wake();\n-    unixctl_command_reply(conn, NULL);\n-}\n+    \ndiff --git a/northd/northd.h b/northd/northd.h\nnew file mode 100644\nindex 000000000000..3209d4224803\n--- /dev/null\n+++ b/northd/northd.h\n@@ -0,0 +1,42 @@\n+/*\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at:\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+#ifndef NORTHD_H\n+#define NORTHD_H 1\n+\n+#include \"ovsdb-idl.h\"\n+#include \"lib/ovn-parallel-hmap.h\"\n+\n+struct northd_context {\n+    const char *ovnnb_db;\n+    const char *ovnsb_db;\n+    struct ovsdb_idl *ovnnb_idl;\n+    struct ovsdb_idl *ovnsb_idl;\n+    struct ovsdb_idl_txn *ovnnb_txn;\n+    struct ovsdb_idl_txn *ovnsb_txn;\n+    struct ovsdb_idl_index *sbrec_chassis_by_name;\n+    struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;\n+    struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp;\n+    struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;\n+\n+    bool use_parallel_build;\n+    struct hashrow_locks *lflow_locks;\n+};\n+\n+void\n+ovn_db_run(struct northd_context *ctx,\n+           struct ovsdb_idl_index *sbrec_chassis_by_name,\n+           struct ovsdb_idl_loop *ovnsb_idl_loop,\n+           const char *ovn_internal_version);\n+\n+#endif /* NORTHD_H */\ndiff --git a/northd/ovn-northd.c b/northd/ovn-northd.c\nnew file mode 100644\nindex 000000000000..ecee14e644af\n--- /dev/null\n+++ b/northd/ovn-northd.c\n@@ -0,0 +1,1100 @@\n+/*\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at:\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#include <config.h>\n+\n+#include <getopt.h>\n+#include <stdlib.h>\n+#include <stdio.h>\n+\n+#include \"lib/chassis-index.h\"\n+#include \"command-line.h\"\n+#include \"daemon.h\"\n+#include \"fatal-signal.h\"\n+#include \"lib/ip-mcast-index.h\"\n+#include \"lib/mcast-group-index.h\"\n+#include \"memory.h\"\n+#include \"northd.h\"\n+#include \"ovs-numa.h\"\n+#include \"ovsdb-idl.h\"\n+#include \"lib/ovn-l7.h\"\n+#include \"lib/ovn-nb-idl.h\"\n+#include \"lib/ovn-parallel-hmap.h\"\n+#include \"lib/ovn-sb-idl.h\"\n+#include \"openvswitch/poll-loop.h\"\n+#include \"simap.h\"\n+#include \"stopwatch.h\"\n+#include \"lib/stopwatch-names.h\"\n+#include \"stream.h\"\n+#include \"stream-ssl.h\"\n+#include \"unixctl.h\"\n+#include \"util.h\"\n+#include \"openvswitch/vlog.h\"\n+\n+VLOG_DEFINE_THIS_MODULE(ovn_northd);\n+\n+static unixctl_cb_func ovn_northd_exit;\n+static unixctl_cb_func ovn_northd_pause;\n+static unixctl_cb_func ovn_northd_resume;\n+static unixctl_cb_func ovn_northd_is_paused;\n+static unixctl_cb_func ovn_northd_status;\n+static unixctl_cb_func cluster_state_reset_cmd;\n+\n+struct northd_state {\n+    bool had_lock;\n+    bool paused;\n+};\n+\n+static const char *ovnnb_db;\n+static const char *ovnsb_db;\n+static const char *unixctl_path;\n+\n+/* SSL options */\n+static const char *ssl_private_key_file;\n+static const char *ssl_certificate_file;\n+static const char *ssl_ca_cert_file;\n+\n+static bool use_parallel_build = true;\n+static struct hashrow_locks lflow_locks;\n+\n+static const char *rbac_chassis_auth[] =\n+    {\"name\"};\n+static const char *rbac_chassis_update[] =\n+    {\"nb_cfg\", \"external_ids\", \"encaps\", \"vtep_logical_switches\",\n+     \"other_config\", \"transport_zones\"};\n+\n+static const char *rbac_chassis_private_auth[] =\n+    {\"name\"};\n+static const char *rbac_chassis_private_update[] =\n+    {\"nb_cfg\", \"nb_cfg_timestamp\", \"chassis\", \"external_ids\"};\n+\n+static const char *rbac_encap_auth[] =\n+    {\"chassis_name\"};\n+static const char *rbac_encap_update[] =\n+    {\"type\", \"options\", \"ip\"};\n+\n+static const char *rbac_controller_event_auth[] =\n+    {\"\"};\n+static const char *rbac_controller_event_update[] =\n+    {\"chassis\", \"event_info\", \"event_type\", \"seq_num\"};\n+\n+\n+static const char *rbac_fdb_auth[] =\n+    {\"\"};\n+static const char *rbac_fdb_update[] =\n+    {\"dp_key\", \"mac\", \"port_key\"};\n+\n+static const char *rbac_port_binding_auth[] =\n+    {\"\"};\n+static const char *rbac_port_binding_update[] =\n+    {\"chassis\", \"encap\", \"up\", \"virtual_parent\"};\n+\n+static const char *rbac_mac_binding_auth[] =\n+    {\"\"};\n+static const char *rbac_mac_binding_update[] =\n+    {\"logical_port\", \"ip\", \"mac\", \"datapath\"};\n+\n+static const char *rbac_svc_monitor_auth[] =\n+    {\"\"};\n+static const char *rbac_svc_monitor_auth_update[] =\n+    {\"status\"};\n+static const char *rbac_igmp_group_auth[] =\n+    {\"\"};\n+static const char *rbac_igmp_group_update[] =\n+    {\"address\", \"chassis\", \"datapath\", \"ports\"};\n+\n+static struct rbac_perm_cfg {\n+    const char *table;\n+    const char **auth;\n+    int n_auth;\n+    bool insdel;\n+    const char **update;\n+    int n_update;\n+    const struct sbrec_rbac_permission *row;\n+} rbac_perm_cfg[] = {\n+    {\n+        .table = \"Chassis\",\n+        .auth = rbac_chassis_auth,\n+        .n_auth = ARRAY_SIZE(rbac_chassis_auth),\n+        .insdel = true,\n+        .update = rbac_chassis_update,\n+        .n_update = ARRAY_SIZE(rbac_chassis_update),\n+        .row = NULL\n+    },{\n+        .table = \"Chassis_Private\",\n+        .auth = rbac_chassis_private_auth,\n+        .n_auth = ARRAY_SIZE(rbac_chassis_private_auth),\n+        .insdel = true,\n+        .update = rbac_chassis_private_update,\n+        .n_update = ARRAY_SIZE(rbac_chassis_private_update),\n+        .row = NULL\n+    },{\n+        .table = \"Controller_Event\",\n+        .auth = rbac_controller_event_auth,\n+        .n_auth = ARRAY_SIZE(rbac_controller_event_auth),\n+        .insdel = true,\n+        .update = rbac_controller_event_update,\n+        .n_update = ARRAY_SIZE(rbac_controller_event_update),\n+        .row = NULL\n+    },{\n+        .table = \"Encap\",\n+        .auth = rbac_encap_auth,\n+        .n_auth = ARRAY_SIZE(rbac_encap_auth),\n+        .insdel = true,\n+        .update = rbac_encap_update,\n+        .n_update = ARRAY_SIZE(rbac_encap_update),\n+        .row = NULL\n+    },{\n+        .table = \"FDB\",\n+        .auth = rbac_fdb_auth,\n+        .n_auth = ARRAY_SIZE(rbac_fdb_auth),\n+        .insdel = true,\n+        .update = rbac_fdb_update,\n+        .n_update = ARRAY_SIZE(rbac_fdb_update),\n+        .row = NULL\n+    },{\n+        .table = \"Port_Binding\",\n+        .auth = rbac_port_binding_auth,\n+        .n_auth = ARRAY_SIZE(rbac_port_binding_auth),\n+        .insdel = false,\n+        .update = rbac_port_binding_update,\n+        .n_update = ARRAY_SIZE(rbac_port_binding_update),\n+        .row = NULL\n+    },{\n+        .table = \"MAC_Binding\",\n+        .auth = rbac_mac_binding_auth,\n+        .n_auth = ARRAY_SIZE(rbac_mac_binding_auth),\n+        .insdel = true,\n+        .update = rbac_mac_binding_update,\n+        .n_update = ARRAY_SIZE(rbac_mac_binding_update),\n+        .row = NULL\n+    },{\n+        .table = \"Service_Monitor\",\n+        .auth = rbac_svc_monitor_auth,\n+        .n_auth = ARRAY_SIZE(rbac_svc_monitor_auth),\n+        .insdel = false,\n+        .update = rbac_svc_monitor_auth_update,\n+        .n_update = ARRAY_SIZE(rbac_svc_monitor_auth_update),\n+        .row = NULL\n+    },{\n+        .table = \"IGMP_Group\",\n+        .auth = rbac_igmp_group_auth,\n+        .n_auth = ARRAY_SIZE(rbac_igmp_group_auth),\n+        .insdel = true,\n+        .update = rbac_igmp_group_update,\n+        .n_update = ARRAY_SIZE(rbac_igmp_group_update),\n+        .row = NULL\n+    },{\n+        .table = NULL,\n+        .auth = NULL,\n+        .n_auth = 0,\n+        .insdel = false,\n+        .update = NULL,\n+        .n_update = 0,\n+        .row = NULL\n+    }\n+};\n+\n+static struct gen_opts_map supported_dhcp_opts[] = {\n+    OFFERIP,\n+    DHCP_OPT_NETMASK,\n+    DHCP_OPT_ROUTER,\n+    DHCP_OPT_DNS_SERVER,\n+    DHCP_OPT_LOG_SERVER,\n+    DHCP_OPT_LPR_SERVER,\n+    DHCP_OPT_SWAP_SERVER,\n+    DHCP_OPT_POLICY_FILTER,\n+    DHCP_OPT_ROUTER_SOLICITATION,\n+    DHCP_OPT_NIS_SERVER,\n+    DHCP_OPT_NTP_SERVER,\n+    DHCP_OPT_SERVER_ID,\n+    DHCP_OPT_TFTP_SERVER,\n+    DHCP_OPT_CLASSLESS_STATIC_ROUTE,\n+    DHCP_OPT_MS_CLASSLESS_STATIC_ROUTE,\n+    DHCP_OPT_IP_FORWARD_ENABLE,\n+    DHCP_OPT_ROUTER_DISCOVERY,\n+    DHCP_OPT_ETHERNET_ENCAP,\n+    DHCP_OPT_DEFAULT_TTL,\n+    DHCP_OPT_TCP_TTL,\n+    DHCP_OPT_MTU,\n+    DHCP_OPT_LEASE_TIME,\n+    DHCP_OPT_T1,\n+    DHCP_OPT_T2,\n+    DHCP_OPT_WPAD,\n+    DHCP_OPT_BOOTFILE,\n+    DHCP_OPT_PATH_PREFIX,\n+    DHCP_OPT_TFTP_SERVER_ADDRESS,\n+    DHCP_OPT_HOSTNAME,\n+    DHCP_OPT_DOMAIN_NAME,\n+    DHCP_OPT_ARP_CACHE_TIMEOUT,\n+    DHCP_OPT_TCP_KEEPALIVE_INTERVAL,\n+    DHCP_OPT_DOMAIN_SEARCH_LIST,\n+    DHCP_OPT_BOOTFILE_ALT,\n+    DHCP_OPT_BROADCAST_ADDRESS,\n+    DHCP_OPT_NETBIOS_NAME_SERVER,\n+    DHCP_OPT_NETBIOS_NODE_TYPE,\n+};\n+\n+static struct gen_opts_map supported_dhcpv6_opts[] = {\n+    DHCPV6_OPT_IA_ADDR,\n+    DHCPV6_OPT_SERVER_ID,\n+    DHCPV6_OPT_DOMAIN_SEARCH,\n+    DHCPV6_OPT_DNS_SERVER\n+};\n+\n+static bool\n+ovn_rbac_validate_perm(const struct sbrec_rbac_permission *perm)\n+{\n+    struct rbac_perm_cfg *pcfg;\n+    int i, j, n_found;\n+\n+    for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) {\n+        if (!strcmp(perm->table, pcfg->table)) {\n+            break;\n+        }\n+    }\n+    if (!pcfg->table) {\n+        return false;\n+    }\n+    if (perm->n_authorization != pcfg->n_auth ||\n+        perm->n_update != pcfg->n_update) {\n+        return false;\n+    }\n+    if (perm->insert_delete != pcfg->insdel) {\n+        return false;\n+    }\n+    /* verify perm->authorization vs. pcfg->auth */\n+    n_found = 0;\n+    for (i = 0; i < pcfg->n_auth; i++) {\n+        for (j = 0; j < perm->n_authorization; j++) {\n+            if (!strcmp(pcfg->auth[i], perm->authorization[j])) {\n+                n_found++;\n+                break;\n+            }\n+        }\n+    }\n+    if (n_found != pcfg->n_auth) {\n+        return false;\n+    }\n+\n+    /* verify perm->update vs. pcfg->update */\n+    n_found = 0;\n+    for (i = 0; i < pcfg->n_update; i++) {\n+        for (j = 0; j < perm->n_update; j++) {\n+            if (!strcmp(pcfg->update[i], perm->update[j])) {\n+                n_found++;\n+                break;\n+            }\n+        }\n+    }\n+    if (n_found != pcfg->n_update) {\n+        return false;\n+    }\n+\n+    /* Success, db state matches expected state */\n+    pcfg->row = perm;\n+    return true;\n+}\n+\n+static void\n+ovn_rbac_create_perm(struct rbac_perm_cfg *pcfg,\n+                     struct northd_context *ctx,\n+                     const struct sbrec_rbac_role *rbac_role)\n+{\n+    struct sbrec_rbac_permission *rbac_perm;\n+\n+    rbac_perm = sbrec_rbac_permission_insert(ctx->ovnsb_txn);\n+    sbrec_rbac_permission_set_table(rbac_perm, pcfg->table);\n+    sbrec_rbac_permission_set_authorization(rbac_perm,\n+                                            pcfg->auth,\n+                                            pcfg->n_auth);\n+    sbrec_rbac_permission_set_insert_delete(rbac_perm, pcfg->insdel);\n+    sbrec_rbac_permission_set_update(rbac_perm,\n+                                     pcfg->update,\n+                                     pcfg->n_update);\n+    sbrec_rbac_role_update_permissions_setkey(rbac_role, pcfg->table,\n+                                              rbac_perm);\n+}\n+\n+static void\n+check_and_update_rbac(struct northd_context *ctx)\n+{\n+    const struct sbrec_rbac_role *rbac_role = NULL;\n+    const struct sbrec_rbac_permission *perm_row, *perm_next;\n+    const struct sbrec_rbac_role *role_row, *role_row_next;\n+    struct rbac_perm_cfg *pcfg;\n+\n+    for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) {\n+        pcfg->row = NULL;\n+    }\n+\n+    SBREC_RBAC_PERMISSION_FOR_EACH_SAFE (perm_row, perm_next, ctx->ovnsb_idl) {\n+        if (!ovn_rbac_validate_perm(perm_row)) {\n+            sbrec_rbac_permission_delete(perm_row);\n+        }\n+    }\n+    SBREC_RBAC_ROLE_FOR_EACH_SAFE (role_row, role_row_next, ctx->ovnsb_idl) {\n+        if (strcmp(role_row->name, \"ovn-controller\")) {\n+            sbrec_rbac_role_delete(role_row);\n+        } else {\n+            rbac_role = role_row;\n+        }\n+    }\n+\n+    if (!rbac_role) {\n+        rbac_role = sbrec_rbac_role_insert(ctx->ovnsb_txn);\n+        sbrec_rbac_role_set_name(rbac_role, \"ovn-controller\");\n+    }\n+\n+    for (pcfg = rbac_perm_cfg; pcfg->table; pcfg++) {\n+        if (!pcfg->row) {\n+            ovn_rbac_create_perm(pcfg, ctx, rbac_role);\n+        }\n+    }\n+}\n+\n+static void\n+check_and_add_supported_dhcp_opts_to_sb_db(struct northd_context *ctx)\n+{\n+    struct hmap dhcp_opts_to_add = HMAP_INITIALIZER(&dhcp_opts_to_add);\n+    for (size_t i = 0; (i < sizeof(supported_dhcp_opts) /\n+                            sizeof(supported_dhcp_opts[0])); i++) {\n+        hmap_insert(&dhcp_opts_to_add, &supported_dhcp_opts[i].hmap_node,\n+                    dhcp_opt_hash(supported_dhcp_opts[i].name));\n+    }\n+\n+    const struct sbrec_dhcp_options *opt_row, *opt_row_next;\n+    SBREC_DHCP_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) {\n+        struct gen_opts_map *dhcp_opt =\n+            dhcp_opts_find(&dhcp_opts_to_add, opt_row->name);\n+        if (dhcp_opt) {\n+            if (!strcmp(dhcp_opt->type, opt_row->type) &&\n+                 dhcp_opt->code == opt_row->code) {\n+                hmap_remove(&dhcp_opts_to_add, &dhcp_opt->hmap_node);\n+            } else {\n+                sbrec_dhcp_options_delete(opt_row);\n+            }\n+        } else {\n+            sbrec_dhcp_options_delete(opt_row);\n+        }\n+    }\n+\n+    struct gen_opts_map *opt;\n+    HMAP_FOR_EACH (opt, hmap_node, &dhcp_opts_to_add) {\n+        struct sbrec_dhcp_options *sbrec_dhcp_option =\n+            sbrec_dhcp_options_insert(ctx->ovnsb_txn);\n+        sbrec_dhcp_options_set_name(sbrec_dhcp_option, opt->name);\n+        sbrec_dhcp_options_set_code(sbrec_dhcp_option, opt->code);\n+        sbrec_dhcp_options_set_type(sbrec_dhcp_option, opt->type);\n+    }\n+\n+    hmap_destroy(&dhcp_opts_to_add);\n+}\n+\n+static void\n+check_and_add_supported_dhcpv6_opts_to_sb_db(struct northd_context *ctx)\n+{\n+    struct hmap dhcpv6_opts_to_add = HMAP_INITIALIZER(&dhcpv6_opts_to_add);\n+    for (size_t i = 0; (i < sizeof(supported_dhcpv6_opts) /\n+                            sizeof(supported_dhcpv6_opts[0])); i++) {\n+        hmap_insert(&dhcpv6_opts_to_add, &supported_dhcpv6_opts[i].hmap_node,\n+                    dhcp_opt_hash(supported_dhcpv6_opts[i].name));\n+    }\n+\n+    const struct sbrec_dhcpv6_options *opt_row, *opt_row_next;\n+    SBREC_DHCPV6_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) {\n+        struct gen_opts_map *dhcp_opt =\n+            dhcp_opts_find(&dhcpv6_opts_to_add, opt_row->name);\n+        if (dhcp_opt) {\n+            hmap_remove(&dhcpv6_opts_to_add, &dhcp_opt->hmap_node);\n+        } else {\n+            sbrec_dhcpv6_options_delete(opt_row);\n+        }\n+    }\n+\n+    struct gen_opts_map *opt;\n+    HMAP_FOR_EACH(opt, hmap_node, &dhcpv6_opts_to_add) {\n+        struct sbrec_dhcpv6_options *sbrec_dhcpv6_option =\n+            sbrec_dhcpv6_options_insert(ctx->ovnsb_txn);\n+        sbrec_dhcpv6_options_set_name(sbrec_dhcpv6_option, opt->name);\n+        sbrec_dhcpv6_options_set_code(sbrec_dhcpv6_option, opt->code);\n+        sbrec_dhcpv6_options_set_type(sbrec_dhcpv6_option, opt->type);\n+    }\n+\n+    hmap_destroy(&dhcpv6_opts_to_add);\n+}\n+\f\n+static void\n+usage(void)\n+{\n+    printf(\"\\\n+%s: OVN northbound management daemon\\n\\\n+usage: %s [OPTIONS]\\n\\\n+\\n\\\n+Options:\\n\\\n+  --ovnnb-db=DATABASE       connect to ovn-nb database at DATABASE\\n\\\n+                            (default: %s)\\n\\\n+  --ovnsb-db=DATABASE       connect to ovn-sb database at DATABASE\\n\\\n+                            (default: %s)\\n\\\n+  --dry-run                 start in paused state (do not commit db changes)\\n\\\n+  --unixctl=SOCKET          override default control socket name\\n\\\n+  -h, --help                display this help message\\n\\\n+  -o, --options             list available options\\n\\\n+  -V, --version             display version information\\n\\\n+\", program_name, program_name, default_nb_db(), default_sb_db());\n+    daemon_usage();\n+    vlog_usage();\n+    stream_usage(\"database\", true, true, false);\n+}\n+\f\n+static void\n+parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED,\n+              bool *paused)\n+{\n+    enum {\n+        OVN_DAEMON_OPTION_ENUMS,\n+        VLOG_OPTION_ENUMS,\n+        SSL_OPTION_ENUMS,\n+        OPT_DRY_RUN,\n+        OPT_DUMMY_NUMA,\n+    };\n+    static const struct option long_options[] = {\n+        {\"ovnsb-db\", required_argument, NULL, 'd'},\n+        {\"ovnnb-db\", required_argument, NULL, 'D'},\n+        {\"unixctl\", required_argument, NULL, 'u'},\n+        {\"help\", no_argument, NULL, 'h'},\n+        {\"options\", no_argument, NULL, 'o'},\n+        {\"version\", no_argument, NULL, 'V'},\n+        {\"dry-run\", no_argument, NULL, OPT_DRY_RUN},\n+        {\"dummy-numa\", required_argument, NULL, OPT_DUMMY_NUMA},\n+        OVN_DAEMON_LONG_OPTIONS,\n+        VLOG_LONG_OPTIONS,\n+        STREAM_SSL_LONG_OPTIONS,\n+        {NULL, 0, NULL, 0},\n+    };\n+    char *short_options = ovs_cmdl_long_options_to_short_options(long_options);\n+\n+    for (;;) {\n+        int c;\n+\n+        c = getopt_long(argc, argv, short_options, long_options, NULL);\n+        if (c == -1) {\n+            break;\n+        }\n+\n+        switch (c) {\n+        OVN_DAEMON_OPTION_HANDLERS;\n+        VLOG_OPTION_HANDLERS;\n+\n+        case 'p':\n+            ssl_private_key_file = optarg;\n+            break;\n+\n+        case 'c':\n+            ssl_certificate_file = optarg;\n+            break;\n+\n+        case 'C':\n+            ssl_ca_cert_file = optarg;\n+            break;\n+\n+        case 'd':\n+            ovnsb_db = optarg;\n+            break;\n+\n+        case 'D':\n+            ovnnb_db = optarg;\n+            break;\n+\n+        case 'u':\n+            unixctl_path = optarg;\n+            break;\n+\n+        case 'h':\n+            usage();\n+            exit(EXIT_SUCCESS);\n+\n+        case 'o':\n+            ovs_cmdl_print_options(long_options);\n+            exit(EXIT_SUCCESS);\n+\n+        case 'V':\n+            ovn_print_version(0, 0);\n+            exit(EXIT_SUCCESS);\n+\n+        case OPT_DUMMY_NUMA:\n+            ovs_numa_set_dummy(optarg);\n+            break;\n+\n+        case OPT_DRY_RUN:\n+            *paused = true;\n+            break;\n+\n+        default:\n+            break;\n+        }\n+    }\n+\n+    if (!ovnsb_db || !ovnsb_db[0]) {\n+        ovnsb_db = default_sb_db();\n+    }\n+\n+    if (!ovnnb_db || !ovnnb_db[0]) {\n+        ovnnb_db = default_nb_db();\n+    }\n+\n+    free(short_options);\n+}\n+\n+static void\n+add_column_noalert(struct ovsdb_idl *idl,\n+                   const struct ovsdb_idl_column *column)\n+{\n+    ovsdb_idl_add_column(idl, column);\n+    ovsdb_idl_omit_alert(idl, column);\n+}\n+\n+static void\n+update_ssl_config(void)\n+{\n+    if (ssl_private_key_file && ssl_certificate_file) {\n+        stream_ssl_set_key_and_cert(ssl_private_key_file,\n+                                    ssl_certificate_file);\n+    }\n+    if (ssl_ca_cert_file) {\n+        stream_ssl_set_ca_cert_file(ssl_ca_cert_file, false);\n+    }\n+}\n+\n+int\n+main(int argc, char *argv[])\n+{\n+    int res = EXIT_SUCCESS;\n+    struct unixctl_server *unixctl;\n+    int retval;\n+    bool exiting;\n+    struct northd_state state = {\n+        .had_lock = false,\n+        .paused = false\n+    };\n+\n+    fatal_ignore_sigpipe();\n+    ovs_cmdl_proctitle_init(argc, argv);\n+    ovn_set_program_name(argv[0]);\n+    service_start(&argc, &argv);\n+    parse_options(argc, argv, &state.paused);\n+\n+    daemonize_start(false);\n+\n+    char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path);\n+    retval = unixctl_server_create(abs_unixctl_path, &unixctl);\n+    free(abs_unixctl_path);\n+\n+    if (retval) {\n+        exit(EXIT_FAILURE);\n+    }\n+    unixctl_command_register(\"exit\", \"\", 0, 0, ovn_northd_exit, &exiting);\n+    unixctl_command_register(\"pause\", \"\", 0, 0, ovn_northd_pause, &state);\n+    unixctl_command_register(\"resume\", \"\", 0, 0, ovn_northd_resume, &state);\n+    unixctl_command_register(\"is-paused\", \"\", 0, 0, ovn_northd_is_paused,\n+                             &state);\n+    unixctl_command_register(\"status\", \"\", 0, 0, ovn_northd_status, &state);\n+\n+    bool reset_ovnsb_idl_min_index = false;\n+    unixctl_command_register(\"sb-cluster-state-reset\", \"\", 0, 0,\n+                             cluster_state_reset_cmd,\n+                             &reset_ovnsb_idl_min_index);\n+\n+    bool reset_ovnnb_idl_min_index = false;\n+    unixctl_command_register(\"nb-cluster-state-reset\", \"\", 0, 0,\n+                             cluster_state_reset_cmd,\n+                             &reset_ovnnb_idl_min_index);\n+\n+    daemonize_complete();\n+\n+    init_hash_row_locks(&lflow_locks);\n+    use_parallel_build = can_parallelize_hashes(false);\n+\n+    /* We want to detect (almost) all changes to the ovn-nb db. */\n+    struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(\n+        ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, true, true));\n+    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl,\n+                         &nbrec_nb_global_col_nb_cfg_timestamp);\n+    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_sb_cfg);\n+    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl,\n+                         &nbrec_nb_global_col_sb_cfg_timestamp);\n+    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl, &nbrec_nb_global_col_hv_cfg);\n+    ovsdb_idl_omit_alert(ovnnb_idl_loop.idl,\n+                         &nbrec_nb_global_col_hv_cfg_timestamp);\n+\n+    unixctl_command_register(\"nb-connection-status\", \"\", 0, 0,\n+                             ovn_conn_show, ovnnb_idl_loop.idl);\n+\n+    /* We want to detect only selected changes to the ovn-sb db. */\n+    struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(\n+        ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true));\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_sb_global);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_nb_cfg);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_options);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_sb_global_col_ipsec);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_logical_flow);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_logical_flow_col_logical_datapath);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_logical_flow_col_logical_dp_group);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_pipeline);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_table_id);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_priority);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_actions);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_logical_flow_col_controller_meter);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_logical_flow_col_external_ids);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl,\n+                        &sbrec_table_logical_dp_group);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_logical_dp_group_col_datapaths);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_multicast_group);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_multicast_group_col_datapath);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_multicast_group_col_tunnel_key);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_name);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_ports);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_datapath_binding_col_tunnel_key);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_datapath_binding_col_load_balancers);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_datapath_binding_col_external_ids);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_datapath);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_port_binding_col_logical_port);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_port_binding_col_tunnel_key);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_port_binding_col_parent_port);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_tag);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_type);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_options);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_port_binding_col_nat_addresses);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_port_binding_col_gateway_chassis);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_port_binding_col_ha_chassis_group);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_port_binding_col_virtual_parent);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_port_binding_col_up);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_gateway_chassis_col_chassis);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_gateway_chassis_col_name);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_gateway_chassis_col_priority);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_gateway_chassis_col_external_ids);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_gateway_chassis_col_options);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_port_binding_col_external_ids);\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_mac_binding);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_datapath);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_ip);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_mac_binding_col_mac);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_mac_binding_col_logical_port);\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcp_options);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_code);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_type);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_name);\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcpv6_options);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_code);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_type);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_name);\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_address_set);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_name);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_addresses);\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_group);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_name);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_group_col_ports);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dns);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_datapaths);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_records);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_external_ids);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_role);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_name);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_role_col_permissions);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_rbac_permission);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_rbac_permission_col_table);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_rbac_permission_col_authorization);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_rbac_permission_col_insert_delete);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_permission_col_update);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_name);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_unit);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_bands);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter_band);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_action);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_rate);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_burst_size);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_encap);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_type);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis_private);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_chassis_private_col_name);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_chassis_private_col_chassis);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_chassis_private_col_nb_cfg);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_chassis_private_col_nb_cfg_timestamp);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ha_chassis_col_chassis);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ha_chassis_col_priority);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ha_chassis_col_external_ids);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ha_chassis_group);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ha_chassis_group_col_name);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ha_chassis_group_col_ha_chassis);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ha_chassis_group_col_external_ids);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ha_chassis_group_col_ref_chassis);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_igmp_group);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_address);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_datapath);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_chassis);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_igmp_group_col_ports);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_ip_multicast);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_datapath);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_enabled);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_querier);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_eth_src);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_ip4_src);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_ip6_src);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_table_size);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_idle_timeout);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_query_interval);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_ip_multicast_col_query_max_resp);\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_service_monitor);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_ip);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_logical_port);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_port);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_options);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,\n+                         &sbrec_service_monitor_col_status);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_protocol);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_src_mac);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_src_ip);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_service_monitor_col_external_ids);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_load_balancer);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_datapaths);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_name);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_vips);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_protocol);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_load_balancer_col_options);\n+    add_column_noalert(ovnsb_idl_loop.idl,\n+                       &sbrec_load_balancer_col_external_ids);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_bfd);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_logical_port);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_dst_ip);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_status);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_tx);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_min_rx);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_detect_mult);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_disc);\n+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_bfd_col_src_port);\n+\n+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_fdb);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_mac);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_dp_key);\n+    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_fdb_col_port_key);\n+\n+    struct ovsdb_idl_index *sbrec_chassis_by_name\n+        = chassis_index_create(ovnsb_idl_loop.idl);\n+\n+    struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name\n+        = ha_chassis_group_index_create(ovnsb_idl_loop.idl);\n+\n+    struct ovsdb_idl_index *sbrec_mcast_group_by_name_dp\n+        = mcast_group_index_create(ovnsb_idl_loop.idl);\n+\n+    struct ovsdb_idl_index *sbrec_ip_mcast_by_dp\n+        = ip_mcast_index_create(ovnsb_idl_loop.idl);\n+\n+    unixctl_command_register(\"sb-connection-status\", \"\", 0, 0,\n+                             ovn_conn_show, ovnsb_idl_loop.idl);\n+\n+    char *ovn_internal_version = ovn_get_internal_version();\n+    VLOG_INFO(\"OVN internal version is : [%s]\", ovn_internal_version);\n+\n+    stopwatch_create(NORTHD_LOOP_STOPWATCH_NAME, SW_MS);\n+    stopwatch_create(OVNNB_DB_RUN_STOPWATCH_NAME, SW_MS);\n+    stopwatch_create(OVNSB_DB_RUN_STOPWATCH_NAME, SW_MS);\n+\n+    /* Main loop. */\n+    exiting = false;\n+\n+    while (!exiting) {\n+        update_ssl_config();\n+        memory_run();\n+        if (memory_should_report()) {\n+            struct simap usage = SIMAP_INITIALIZER(&usage);\n+\n+            /* Nothing special to report yet. */\n+            memory_report(&usage);\n+            simap_destroy(&usage);\n+        }\n+\n+        if (!state.paused) {\n+            if (!ovsdb_idl_has_lock(ovnsb_idl_loop.idl) &&\n+                !ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl))\n+            {\n+                /* Ensure that only a single ovn-northd is active in the\n+                 * deployment by acquiring a lock called \"ovn_northd\" on the\n+                 * southbound database and then only performing DB transactions\n+                 * if the lock is held.\n+                 */\n+                ovsdb_idl_set_lock(ovnsb_idl_loop.idl, \"ovn_northd\");\n+            }\n+\n+            struct northd_context ctx = {\n+                .ovnnb_db = ovnnb_db,\n+                .ovnsb_db = ovnsb_db,\n+                .ovnnb_idl = ovnnb_idl_loop.idl,\n+                .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop),\n+                .ovnsb_idl = ovnsb_idl_loop.idl,\n+                .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),\n+                .sbrec_chassis_by_name = sbrec_chassis_by_name,\n+                .sbrec_ha_chassis_grp_by_name = sbrec_ha_chassis_grp_by_name,\n+                .sbrec_mcast_group_by_name_dp = sbrec_mcast_group_by_name_dp,\n+                .sbrec_ip_mcast_by_dp = sbrec_ip_mcast_by_dp,\n+                .lflow_locks = &lflow_locks,\n+                .use_parallel_build = use_parallel_build,\n+            };\n+\n+            if (!state.had_lock && ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {\n+                VLOG_INFO(\"ovn-northd lock acquired. \"\n+                        \"This ovn-northd instance is now active.\");\n+                state.had_lock = true;\n+            } else if (state.had_lock &&\n+                       !ovsdb_idl_has_lock(ovnsb_idl_loop.idl))\n+            {\n+                VLOG_INFO(\"ovn-northd lock lost. \"\n+                        \"This ovn-northd instance is now on standby.\");\n+                state.had_lock = false;\n+            }\n+\n+            if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {\n+\n+                ovn_db_run(&ctx, sbrec_chassis_by_name, &ovnsb_idl_loop,\n+                           ovn_internal_version);\n+                if (ctx.ovnsb_txn) {\n+                    check_and_add_supported_dhcp_opts_to_sb_db(&ctx);\n+                    check_and_add_supported_dhcpv6_opts_to_sb_db(&ctx);\n+                    check_and_update_rbac(&ctx);\n+                }\n+            }\n+\n+            ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);\n+            ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);\n+        } else {\n+            /* ovn-northd is paused\n+             *    - we still want to handle any db updates and update the\n+             *      local IDL. Otherwise, when it is resumed, the local IDL\n+             *      copy will be out of sync.\n+             *    - but we don't want to create any txns.\n+             * */\n+            if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl) ||\n+                ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl))\n+            {\n+                /* make sure we don't hold the lock while paused */\n+                VLOG_INFO(\"This ovn-northd instance is now paused.\");\n+                ovsdb_idl_set_lock(ovnsb_idl_loop.idl, NULL);\n+                state.had_lock = false;\n+            }\n+\n+            ovsdb_idl_run(ovnnb_idl_loop.idl);\n+            ovsdb_idl_run(ovnsb_idl_loop.idl);\n+            ovsdb_idl_wait(ovnnb_idl_loop.idl);\n+            ovsdb_idl_wait(ovnsb_idl_loop.idl);\n+        }\n+\n+        stopwatch_stop(NORTHD_LOOP_STOPWATCH_NAME, time_msec());\n+        stopwatch_start(NORTHD_LOOP_STOPWATCH_NAME, time_msec());\n+        unixctl_server_run(unixctl);\n+        unixctl_server_wait(unixctl);\n+        memory_wait();\n+        if (exiting) {\n+            poll_immediate_wake();\n+        }\n+\n+        if (reset_ovnsb_idl_min_index) {\n+            VLOG_INFO(\"Resetting southbound database cluster state\");\n+            ovsdb_idl_reset_min_index(ovnsb_idl_loop.idl);\n+            reset_ovnsb_idl_min_index = false;\n+        }\n+\n+        if (reset_ovnnb_idl_min_index) {\n+            VLOG_INFO(\"Resetting northbound database cluster state\");\n+            ovsdb_idl_reset_min_index(ovnnb_idl_loop.idl);\n+            reset_ovnnb_idl_min_index = false;\n+        }\n+\n+        poll_block();\n+        if (should_service_stop()) {\n+            exiting = true;\n+        }\n+    }\n+\n+\n+    free(ovn_internal_version);\n+    unixctl_server_destroy(unixctl);\n+    ovsdb_idl_loop_destroy(&ovnnb_idl_loop);\n+    ovsdb_idl_loop_destroy(&ovnsb_idl_loop);\n+    service_stop();\n+\n+    exit(res);\n+}\n+\n+static void\n+ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,\n+                const char *argv[] OVS_UNUSED, void *exiting_)\n+{\n+    bool *exiting = exiting_;\n+    *exiting = true;\n+\n+    unixctl_command_reply(conn, NULL);\n+}\n+\n+static void\n+ovn_northd_pause(struct unixctl_conn *conn, int argc OVS_UNUSED,\n+                const char *argv[] OVS_UNUSED, void *state_)\n+{\n+    struct northd_state  *state = state_;\n+    state->paused = true;\n+\n+    unixctl_command_reply(conn, NULL);\n+}\n+\n+static void\n+ovn_northd_resume(struct unixctl_conn *conn, int argc OVS_UNUSED,\n+                  const char *argv[] OVS_UNUSED, void *state_)\n+{\n+    struct northd_state *state = state_;\n+    state->paused = false;\n+\n+    unixctl_command_reply(conn, NULL);\n+}\n+\n+static void\n+ovn_northd_is_paused(struct unixctl_conn *conn, int argc OVS_UNUSED,\n+                     const char *argv[] OVS_UNUSED, void *state_)\n+{\n+    struct northd_state *state = state_;\n+    if (state->paused) {\n+        unixctl_command_reply(conn, \"true\");\n+    } else {\n+        unixctl_command_reply(conn, \"false\");\n+    }\n+}\n+\n+static void\n+ovn_northd_status(struct unixctl_conn *conn, int argc OVS_UNUSED,\n+                  const char *argv[] OVS_UNUSED, void *state_)\n+{\n+    struct northd_state *state = state_;\n+    char *status;\n+\n+    if (state->paused) {\n+        status = \"paused\";\n+    } else {\n+        status = state->had_lock ? \"active\" : \"standby\";\n+    }\n+\n+    /*\n+     * Use a labelled formatted output so we can add more to the status command\n+     * later without breaking any consuming scripts\n+     */\n+    struct ds s = DS_EMPTY_INITIALIZER;\n+    ds_put_format(&s, \"Status: %s\\n\", status);\n+    unixctl_command_reply(conn, ds_cstr(&s));\n+    ds_destroy(&s);\n+}\n+\n+static void\n+cluster_state_reset_cmd(struct unixctl_conn *conn, int argc OVS_UNUSED,\n+               const char *argv[] OVS_UNUSED, void *idl_reset_)\n+{\n+    bool *idl_reset = idl_reset_;\n+\n+    *idl_reset = true;\n+    poll_immediate_wake();\n+    unixctl_command_reply(conn, NULL);\n+}\n",
    "prefixes": [
        "ovs-dev",
        "v2",
        "2/2"
    ]
}