{"id":806360,"url":"http://patchwork.ozlabs.org/api/1.0/patches/806360/?format=json","project":{"id":47,"url":"http://patchwork.ozlabs.org/api/1.0/projects/47/?format=json","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"},"msgid":"<1503893682-65314-3-git-send-email-zhouhan@gmail.com>","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/1.0/people/67381/?format=json","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/1.0/series/66/?format=json","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/"}],"check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/806360/checks/","tags":{},"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"]}