get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

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

{
    "id": 806360,
    "url": "http://patchwork.ozlabs.org/api/patches/806360/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/1503893682-65314-3-git-send-email-zhouhan@gmail.com/",
    "project": {
        "id": 47,
        "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api",
        "name": "Open vSwitch",
        "link_name": "openvswitch",
        "list_id": "ovs-dev.openvswitch.org",
        "list_email": "ovs-dev@openvswitch.org",
        "web_url": "http://openvswitch.org/",
        "scm_url": "git@github.com:openvswitch/ovs.git",
        "webscm_url": "https://github.com/openvswitch/ovs",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1503893682-65314-3-git-send-email-zhouhan@gmail.com>",
    "list_archive_url": null,
    "date": "2017-08-28T04:14:42",
    "name": "[ovs-dev,v4,3/3] ovn-controller: Use separate thread for packet-in processing.",
    "commit_ref": null,
    "pull_url": null,
    "state": "deferred",
    "archived": false,
    "hash": "f7f2f3265721284edff4335287bd61ddd6e2e825",
    "submitter": {
        "id": 67381,
        "url": "http://patchwork.ozlabs.org/api/people/67381/?format=api",
        "name": "Han Zhou",
        "email": "zhouhan@gmail.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/1503893682-65314-3-git-send-email-zhouhan@gmail.com/mbox/",
    "series": [
        {
            "id": 66,
            "url": "http://patchwork.ozlabs.org/api/series/66/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=66",
            "date": "2017-08-28T04:14:40",
            "name": "[ovs-dev,v4,1/3] ovn-controller: readonly mode binding_run and get_br_int",
            "version": 4,
            "mbox": "http://patchwork.ozlabs.org/series/66/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/806360/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/806360/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@mail.linuxfoundation.org"
        ],
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"rfHEVSEz\"; dkim-atps=neutral"
        ],
        "Received": [
            "from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xgdkg2rtYz9sNr\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 28 Aug 2017 14:16:43 +1000 (AEST)",
            "from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 9CD07901;\n\tMon, 28 Aug 2017 04:15:07 +0000 (UTC)",
            "from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id E07358D9\n\tfor <dev@openvswitch.org>; Mon, 28 Aug 2017 04:15:04 +0000 (UTC)",
            "from mail-pf0-f193.google.com (mail-pf0-f193.google.com\n\t[209.85.192.193])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 077C579\n\tfor <dev@openvswitch.org>; Mon, 28 Aug 2017 04:15:03 +0000 (UTC)",
            "by mail-pf0-f193.google.com with SMTP id r187so3339049pfr.4\n\tfor <dev@openvswitch.org>; Sun, 27 Aug 2017 21:15:03 -0700 (PDT)",
            "from localhost.localdomain.localdomain\n\t(c-73-162-150-77.hsd1.ca.comcast.net. [73.162.150.77])\n\tby smtp.gmail.com with ESMTPSA id\n\tm13sm22022684pfg.27.2017.08.27.21.15.02\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tSun, 27 Aug 2017 21:15:02 -0700 (PDT)"
        ],
        "X-Greylist": "whitelisted by SQLgrey-1.7.6",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=f5aoJB/7dI3dYnwfFDt/+YTaabtXkRFjRJWofAVUxXo=;\n\tb=rfHEVSEzleVF87oJ7+LlH72+wmlizMyCmJdubxUpaY5jTo14i7GVArqvIYgvvEOCA1\n\tJ/Q6SOzfPIQ1lop5ULZfqO95re+YBB6xcYKWYMKnYT/RLUJ6zJNlDz4TugaJiwSY8Oc/\n\t+tuZCF3ZbT1SN7cKr1oNHoO9FKQCRzdaocMfwV15wGGWPlDvD3BIxAhNhkLC/RlBYCmO\n\tr/D/BRDnzvieKzu5CXC9H/g1ZgTjQYBvqqaD0hsb4hYy3QpeOaiJ4uODjwK0mcc1Kp2Z\n\tDZhXmG/xfbgdNnomk44AhiNeXrdXUAdf1V3H9m/JI/auQxxvcL9kv9t7alzVM+VKAo1W\n\tbU3g==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=f5aoJB/7dI3dYnwfFDt/+YTaabtXkRFjRJWofAVUxXo=;\n\tb=JLSbS5aQFGXWvOef7RFBrvJkru4ptpZqRAtvdipfAxbpggAHtaU0O2QQF+BiBJbE8/\n\t5XWubG29Nhp7DYBn4FAXXuduYtaVUrmHXQGwt3Uc+ZmCrRPvsbik2ccb/jvWiGWqlSOS\n\tV4PONvmBjddxcXGNzfDzbIMm3rgXl0klc4elE38fjGvznCXohkdAF2VhqugGEIOB7hR8\n\t3lx4B7/sRcEFnYJKRBgcTJ4EH58J+YniKPL4yhEBPYNsqc00V/a8BalmNm8VIGYJyUjd\n\tJH8fSrT6Ib+1YGWw8r0TEx4W4pDq264BJSVOt8Hzxajz/l50U8b+r2OR8zq7O5c37nw+\n\tmz8w==",
        "X-Gm-Message-State": "AHYfb5jsDf4mjZRrJHGLxivs4E2BCXRk/InxtOOe9BBDHUCg19wo6uzi\n\tsv29vVc3K5eI3VFS",
        "X-Received": "by 10.98.82.67 with SMTP id g64mr6089929pfb.308.1503893703248;\n\tSun, 27 Aug 2017 21:15:03 -0700 (PDT)",
        "From": "Han Zhou <zhouhan@gmail.com>",
        "To": "dev@openvswitch.org",
        "Date": "Sun, 27 Aug 2017 21:14:42 -0700",
        "Message-Id": "<1503893682-65314-3-git-send-email-zhouhan@gmail.com>",
        "X-Mailer": "git-send-email 2.1.0",
        "In-Reply-To": "<1503893682-65314-1-git-send-email-zhouhan@gmail.com>",
        "References": "<1503893682-65314-1-git-send-email-zhouhan@gmail.com>",
        "X-Spam-Status": "No, score=0.4 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tDKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,RCVD_IN_SORBS_SPAM\n\tautolearn=disabled version=3.3.1",
        "X-Spam-Checker-Version": "SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org",
        "Subject": "[ovs-dev] [PATCH v4 3/3] ovn-controller: Use separate thread for\n\tpacket-in processing.",
        "X-BeenThere": "ovs-dev@openvswitch.org",
        "X-Mailman-Version": "2.1.12",
        "Precedence": "list",
        "List-Id": "<ovs-dev.openvswitch.org>",
        "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<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\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"us-ascii\"",
        "Content-Transfer-Encoding": "7bit",
        "Sender": "ovs-dev-bounces@openvswitch.org",
        "Errors-To": "ovs-dev-bounces@openvswitch.org"
    },
    "content": "This patch introduces multi-threading for ovn-controller and use\ndedicated thread for packet-in processing as a start. It decouples\npacket-in processing and ovs flow computing, so that packet-in inputs\nwon't trigger flow recomputing, and flow computing won't block\npacket-in processing. In large scale environment this largely reduces\nCPU cost and improves performance.\n\nRelated effort and discussion:\nhttps://mail.openvswitch.org/pipermail/ovs-dev/2017-May/331813.html\n\nSigned-off-by: Han Zhou <zhouhan@gmail.com>\n---\nv3->v4: rebased on master.\n\n ovn/controller/ovn-controller.c |  71 ++++++++++++++++++---------\n ovn/controller/ovn-controller.h |  38 +++++++++++++++\n ovn/controller/pinctrl.c        | 105 ++++++++++++++++++++++++++++++++++++++++\n ovn/controller/pinctrl.h        |   1 +\n 4 files changed, 193 insertions(+), 22 deletions(-)",
    "diff": "diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c\nindex 414443f..cb04244 100644\n--- a/ovn/controller/ovn-controller.c\n+++ b/ovn/controller/ovn-controller.c\n@@ -56,6 +56,8 @@\n #include \"stream.h\"\n #include \"unixctl.h\"\n #include \"util.h\"\n+#include \"latch.h\"\n+#include \"ovs-thread.h\"\n \n VLOG_DEFINE_THIS_MODULE(main);\n \n@@ -66,8 +68,6 @@ static unixctl_cb_func inject_pkt;\n #define DEFAULT_BRIDGE_NAME \"br-int\"\n #define DEFAULT_PROBE_INTERVAL_MSEC 5000\n \n-static void update_probe_interval(struct controller_ctx *,\n-                                  const char *ovnsb_remote);\n static void parse_options(int argc, char *argv[]);\n OVS_NO_RETURN static void usage(void);\n \n@@ -78,7 +78,7 @@ struct pending_pkt {\n     char *flow_s;\n };\n \n-static char *ovs_remote;\n+char *ovs_remote;\n \n struct local_datapath *\n get_local_datapath(const struct hmap *local_datapaths, uint32_t tunnel_key)\n@@ -129,7 +129,7 @@ get_bridge(struct ovsdb_idl *ovs_idl, const char *br_name)\n     return NULL;\n }\n \n-static void\n+void\n update_sb_monitors(struct ovsdb_idl *ovnsb_idl,\n                    const struct sbrec_chassis *chassis,\n                    const struct sset *local_ifaces,\n@@ -257,7 +257,7 @@ create_br_int(struct controller_ctx *ctx)\n     return bridge;\n }\n \n-static const struct ovsrec_bridge *\n+const struct ovsrec_bridge *\n get_br_int(struct controller_ctx *ctx)\n {\n     const struct ovsrec_open_vswitch *cfg;\n@@ -269,7 +269,7 @@ get_br_int(struct controller_ctx *ctx)\n     return get_bridge(ctx->ovs_idl, br_int_name(cfg));\n }\n \n-static const char *\n+const char *\n get_chassis_id(const struct ovsdb_idl *ovs_idl)\n {\n     const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);\n@@ -309,7 +309,7 @@ update_ssl_config(const struct ovsdb_idl *ovs_idl)\n \n /* Retrieves the OVN Southbound remote location from the\n  * \"external-ids:ovn-remote\" key in 'ovs_idl' and returns a copy of it. */\n-static char *\n+char *\n get_ovnsb_remote(struct ovsdb_idl *ovs_idl)\n {\n     while (1) {\n@@ -498,6 +498,22 @@ get_nb_cfg(struct ovsdb_idl *idl)\n }\n \n static void\n+ctrl_thread_create(struct ctrl_thread *thread, const char *name,\n+    void *(*start)(void *))\n+{\n+    latch_init(&thread->exit_latch);\n+    thread->thread = ovs_thread_create(name, start, thread);\n+}\n+\n+static void\n+ctrl_thread_exit(struct ctrl_thread *thread)\n+{\n+    latch_set(&thread->exit_latch);\n+    xpthread_join(thread->thread, NULL);\n+    latch_destroy(&thread->exit_latch);\n+}\n+\n+void\n ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl)\n {\n     /* We do not monitor all tables by default, so modules must register\n@@ -574,6 +590,22 @@ create_ovnsb_indexes(struct ovsdb_idl *ovnsb_idl)\n                                OVSDB_INDEX_ASC, NULL);\n }\n \n+void\n+connect_ovnsb(struct ovsdb_idl_loop *ovnsb_idl_loop,\n+              struct ovnsb_cursors *cursors,\n+              const char *ovnsb_remote)\n+{\n+    ovnsb_idl_loop->idl = ovsdb_idl_create(ovnsb_remote,\n+            &sbrec_idl_class, true, true);\n+\n+    create_ovnsb_indexes(ovnsb_idl_loop->idl);\n+    lport_init(cursors, ovnsb_idl_loop->idl);\n+\n+    ovsdb_idl_omit_alert(ovnsb_idl_loop->idl, &sbrec_chassis_col_nb_cfg);\n+    update_sb_monitors(ovnsb_idl_loop->idl, NULL, NULL, NULL);\n+    ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop->idl);\n+}\n+\n int\n main(int argc, char *argv[])\n {\n@@ -605,7 +637,6 @@ main(int argc, char *argv[])\n     daemonize_complete();\n \n     ofctrl_init(&group_table);\n-    pinctrl_init();\n     lflow_init();\n \n     /* Connect to OVS OVSDB instance. */\n@@ -616,16 +647,9 @@ main(int argc, char *argv[])\n \n     /* Connect to OVN SB database and get a snapshot. */\n     char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);\n-    struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(\n-        ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));\n-\n-    create_ovnsb_indexes(ovnsb_idl_loop.idl);\n+    struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(NULL);\n     struct ovnsb_cursors ovnsb_cursors;\n-    lport_init(ovnsb_cursors, ovnsb_idl_loop.idl);\n-\n-    ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg);\n-    update_sb_monitors(ovnsb_idl_loop.idl, NULL, NULL, NULL);\n-    ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);\n+    connect_ovnsb(&ovnsb_idl_loop, &ovnsb_cursors, ovnsb_remote);\n \n     /* Initialize connection tracking zones. */\n     struct simap ct_zones = SIMAP_INITIALIZER(&ct_zones);\n@@ -641,6 +665,10 @@ main(int argc, char *argv[])\n     unixctl_command_register(\"inject-pkt\", \"MICROFLOW\", 1, 1, inject_pkt,\n                              &pending_pkt);\n \n+\n+    struct ctrl_thread pinctrl_thread;\n+    ctrl_thread_create(&pinctrl_thread, \"pinctrl\", pinctrl_thread_main);\n+\n     /* Main loop. */\n     exiting = false;\n     while (!exiting) {\n@@ -705,8 +733,6 @@ main(int argc, char *argv[])\n             enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int,\n                                                          &pending_ct_zones);\n \n-            pinctrl_run(&ctx, br_int, chassis, &chassis_index,\n-                        &local_datapaths, &active_tunnels);\n             update_ct_zones(&local_lports, &local_datapaths, &ct_zones,\n                             ct_zone_bitmap, &pending_ct_zones);\n             if (ctx.ovs_idl_txn) {\n@@ -791,7 +817,6 @@ main(int argc, char *argv[])\n \n         if (br_int) {\n             ofctrl_wait();\n-            pinctrl_wait(&ctx);\n         }\n         ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);\n \n@@ -840,10 +865,12 @@ main(int argc, char *argv[])\n         poll_block();\n     }\n \n+    /* stop child controller threads */\n+    ctrl_thread_exit(&pinctrl_thread);\n+\n     unixctl_server_destroy(unixctl);\n     lflow_destroy();\n     ofctrl_destroy();\n-    pinctrl_destroy();\n \n     simap_destroy(&ct_zones);\n \n@@ -1000,7 +1027,7 @@ inject_pkt(struct unixctl_conn *conn, int argc OVS_UNUSED,\n \n /* Get the desired SB probe timer from the OVS database and configure it into\n  * the SB database. */\n-static void\n+void\n update_probe_interval(struct controller_ctx *ctx, const char *ovnsb_remote)\n {\n     const struct ovsrec_open_vswitch *cfg\ndiff --git a/ovn/controller/ovn-controller.h b/ovn/controller/ovn-controller.h\nindex f57c557..1234c2b 100644\n--- a/ovn/controller/ovn-controller.h\n+++ b/ovn/controller/ovn-controller.h\n@@ -18,7 +18,9 @@\n #define OVN_CONTROLLER_H 1\n \n #include \"simap.h\"\n+#include \"sset.h\"\n #include \"ovn/lib/ovn-sb-idl.h\"\n+#include \"latch.h\"\n \n /* Linux supports a maximum of 64K zones, which seems like a fine default. */\n #define MAX_CT_ZONES 65535\n@@ -71,6 +73,13 @@ struct local_datapath {\n     size_t n_peer_dps;\n };\n \n+struct ctrl_thread {\n+    pthread_t thread;\n+\n+    /* Controls thread exit. */\n+    struct latch exit_latch;\n+};\n+\n struct local_datapath *get_local_datapath(const struct hmap *,\n                                           uint32_t tunnel_key);\n \n@@ -90,5 +99,34 @@ enum chassis_tunnel_type {\n \n uint32_t get_tunnel_type(const char *name);\n \n+/* Retrieves the OVN Southbound remote location from the\n+ * \"external-ids:ovn-remote\" key in 'ovs_idl' and returns a copy of it. */\n+char *get_ovnsb_remote(struct ovsdb_idl *ovs_idl);\n+\n+void\n+update_sb_monitors(struct ovsdb_idl *ovnsb_idl,\n+                   const struct sbrec_chassis *chassis,\n+                   const struct sset *local_ifaces,\n+                   struct hmap *local_datapaths);\n+\n+/* Get the desired SB probe timer from the OVS database and configure it into\n+ * the SB database. */\n+void\n+update_probe_interval(struct controller_ctx *ctx, const char *ovnsb_remote);\n+\n+const struct ovsrec_bridge *\n+get_br_int(struct controller_ctx *ctx);\n+\n+const char *\n+get_chassis_id(const struct ovsdb_idl *ovs_idl);\n+\n+void\n+ctrl_register_ovs_idl(struct ovsdb_idl *ovs_idl);\n+\n+void\n+connect_ovnsb(struct ovsdb_idl_loop *ovnsb_idl_loop,\n+              struct ovnsb_cursors *cursors,\n+              const char *ovnsb_remote);\n \n+extern char *ovs_remote;\n #endif /* ovn/ovn-controller.h */\ndiff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c\nindex 9412b48..8a30be2 100644\n--- a/ovn/controller/pinctrl.c\n+++ b/ovn/controller/pinctrl.c\n@@ -18,6 +18,7 @@\n \n #include \"pinctrl.h\"\n \n+#include \"bfd.h\"\n #include \"coverage.h\"\n #include \"csum.h\"\n #include \"dirs.h\"\n@@ -41,6 +42,7 @@\n #include \"ovn/lex.h\"\n #include \"ovn/lib/acl-log.h\"\n #include \"ovn/lib/logical-fields.h\"\n+#include \"ovn/lib/chassis-index.h\"\n #include \"ovn/lib/ovn-dhcp.h\"\n #include \"ovn/lib/ovn-util.h\"\n #include \"poll-loop.h\"\n@@ -48,6 +50,8 @@\n #include \"socket-util.h\"\n #include \"timeval.h\"\n #include \"vswitch-idl.h\"\n+#include \"latch.h\"\n+#include \"binding.h\"\n \n VLOG_DEFINE_THIS_MODULE(pinctrl);\n \n@@ -84,6 +88,107 @@ static void reload_metadata(struct ofpbuf *ofpacts,\n \n COVERAGE_DEFINE(pinctrl_drop_put_mac_binding);\n \n+void *\n+pinctrl_thread_main(void *arg)\n+{\n+    struct ctrl_thread *thread = arg;\n+    pinctrl_init();\n+\n+    /* Connect to OVS OVSDB instance. */\n+    struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(\n+        ovsdb_idl_create(ovs_remote, &ovsrec_idl_class, false, true));\n+    ctrl_register_ovs_idl(ovs_idl_loop.idl);\n+    ovsdb_idl_get_initial_snapshot(ovs_idl_loop.idl);\n+\n+    /* Connect to OVN SB database and get a snapshot. */\n+    char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);\n+    struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(NULL);\n+    struct ovnsb_cursors ovnsb_cursors;\n+    connect_ovnsb(&ovnsb_idl_loop, &ovnsb_cursors, ovnsb_remote);\n+\n+    while (!latch_is_set(&thread->exit_latch)) {\n+        /* Below logic is similar as in main loop in ovn-controller.c,\n+         * while the purpose here is packet-in processing only */\n+        char *new_ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);\n+        if (strcmp(ovnsb_remote, new_ovnsb_remote)) {\n+            free(ovnsb_remote);\n+            ovnsb_remote = new_ovnsb_remote;\n+            ovsdb_idl_set_remote(ovnsb_idl_loop.idl, ovnsb_remote, true);\n+        } else {\n+            free(new_ovnsb_remote);\n+        }\n+\n+        struct controller_ctx ctx = {\n+            .ovs_idl = ovs_idl_loop.idl,\n+            .ovs_idl_txn = ovsdb_idl_loop_run(&ovs_idl_loop),\n+            .ovnsb_idl = ovnsb_idl_loop.idl,\n+            .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),\n+            .ovnsb_cursors = &ovnsb_cursors,\n+        };\n+\n+        update_probe_interval(&ctx, ovnsb_remote);\n+\n+        struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);\n+        struct sset local_lports = SSET_INITIALIZER(&local_lports);\n+        struct sset active_tunnels = SSET_INITIALIZER(&active_tunnels);\n+        const struct ovsrec_bridge *br_int = get_br_int(&ctx);\n+        const char *chassis_id = get_chassis_id(ctx.ovs_idl);\n+\n+        struct chassis_index chassis_index;\n+\n+        chassis_index_init(&chassis_index, ctx.ovnsb_idl);\n+\n+        if (ctx.ovnsb_idl_txn) {\n+            const struct sbrec_chassis *chassis = NULL;\n+            if (chassis_id) {\n+                chassis = get_chassis(ctx.ovnsb_idl, chassis_id);\n+                bfd_calculate_active_tunnels(br_int, &active_tunnels);\n+                binding_get(&ctx, br_int, chassis,\n+                            &chassis_index, &active_tunnels, &local_datapaths,\n+                            &local_lports);\n+            }\n+\n+            if (br_int && chassis) {\n+                pinctrl_run(&ctx, br_int, chassis, &chassis_index,\n+                            &local_datapaths, &active_tunnels);\n+                update_sb_monitors(ctx.ovnsb_idl, chassis,\n+                                   &local_lports, &local_datapaths);\n+            }\n+        }\n+\n+        chassis_index_destroy(&chassis_index);\n+        sset_destroy(&local_lports);\n+        sset_destroy(&active_tunnels);\n+\n+        struct local_datapath *cur_node, *next_node;\n+        HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, &local_datapaths) {\n+            free(cur_node->peer_dps);\n+            hmap_remove(&local_datapaths, &cur_node->hmap_node);\n+            free(cur_node);\n+        }\n+        hmap_destroy(&local_datapaths);\n+\n+        if (br_int) {\n+            pinctrl_wait(&ctx);\n+        }\n+        ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);\n+        ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);\n+\n+        latch_wait(&thread->exit_latch);\n+        poll_block();\n+    }\n+\n+    pinctrl_destroy();\n+\n+    ovsdb_idl_loop_destroy(&ovs_idl_loop);\n+    ovsdb_idl_loop_destroy(&ovnsb_idl_loop);\n+\n+    free(ovnsb_remote);\n+\n+    VLOG_INFO(\"pinctrl thread done\");\n+    return NULL;\n+}\n+\n void\n pinctrl_init(void)\n {\ndiff --git a/ovn/controller/pinctrl.h b/ovn/controller/pinctrl.h\nindex fc9cca8..15b12a0 100644\n--- a/ovn/controller/pinctrl.h\n+++ b/ovn/controller/pinctrl.h\n@@ -34,6 +34,7 @@ void pinctrl_run(struct controller_ctx *,\n                  const struct ovsrec_bridge *, const struct sbrec_chassis *,\n                  const struct chassis_index *, struct hmap *local_datapaths,\n                  struct sset *active_tunnels);\n+void *pinctrl_thread_main(void *arg);\n void pinctrl_wait(struct controller_ctx *);\n void pinctrl_destroy(void);\n \n",
    "prefixes": [
        "ovs-dev",
        "v4",
        "3/3"
    ]
}