{"id":2186652,"url":"http://patchwork.ozlabs.org/api/1.0/patches/2186652/?format=json","project":{"id":68,"url":"http://patchwork.ozlabs.org/api/1.0/projects/68/?format=json","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":""},"msgid":"<20260120114948.2289909-3-guilherme.paulo@luizalabs.com>","date":"2026-01-20T11:49:41","name":"[ovs-dev,v0,2/9] ovn-ic: Add a new engine-node 'enum-datapath'.","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"550aae9f369e9adfae269e423b44027271837473","submitter":{"id":90256,"url":"http://patchwork.ozlabs.org/api/1.0/people/90256/?format=json","name":"Paulo Guilherme Silva","email":"guilherme.paulo@luizalabs.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/ovn/patch/20260120114948.2289909-3-guilherme.paulo@luizalabs.com/mbox/","series":[{"id":489037,"url":"http://patchwork.ozlabs.org/api/1.0/series/489037/?format=json","date":"2026-01-20T11:49:40","name":"Create multiple engines nodes for ovn-ic.","version":0,"mbox":"http://patchwork.ozlabs.org/series/489037/mbox/"}],"check":"success","checks":"http://patchwork.ozlabs.org/api/patches/2186652/checks/","tags":{},"headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","ovs-dev@lists.linuxfoundation.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=luizalabs.com header.i=@luizalabs.com\n header.a=rsa-sha256 header.s=google header.b=dkRCq0Bq;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)","smtp3.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=luizalabs.com header.i=@luizalabs.com header.a=rsa-sha256\n header.s=google header.b=dkRCq0Bq","smtp2.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=luizalabs.com","smtp2.osuosl.org; dkim=pass (1024-bit key,\n unprotected) header.d=luizalabs.com header.i=@luizalabs.com\n header.a=rsa-sha256 header.s=google header.b=dkRCq0Bq"],"Received":["from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4dwQck3MlCz1xsW\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 20 Jan 2026 22:50:30 +1100 (AEDT)","from localhost (localhost [127.0.0.1])\n\tby smtp3.osuosl.org (Postfix) with ESMTP id 41E1E6FD17;\n\tTue, 20 Jan 2026 11:50:27 +0000 (UTC)","from smtp3.osuosl.org ([127.0.0.1])\n by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id z5Th8ykO1mCE; Tue, 20 Jan 2026 11:50:23 +0000 (UTC)","from lists.linuxfoundation.org (lf-lists.osuosl.org\n [IPv6:2605:bc80:3010:104::8cd3:938])\n\tby smtp3.osuosl.org (Postfix) with ESMTPS id 685AD6FD1B;\n\tTue, 20 Jan 2026 11:50:23 +0000 (UTC)","from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 3F8D0C02A6;\n\tTue, 20 Jan 2026 11:50:23 +0000 (UTC)","from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 5DF4BC02A5\n for <dev@openvswitch.org>; Tue, 20 Jan 2026 11:50:21 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 4D37342F66\n for <dev@openvswitch.org>; Tue, 20 Jan 2026 11:50:21 +0000 (UTC)","from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id muz7G_Edb1ky for <dev@openvswitch.org>;\n Tue, 20 Jan 2026 11:50:19 +0000 (UTC)","from mail-dl1-x1235.google.com (mail-dl1-x1235.google.com\n [IPv6:2607:f8b0:4864:20::1235])\n by smtp2.osuosl.org (Postfix) with ESMTPS id A0BCE403FE\n for <dev@openvswitch.org>; Tue, 20 Jan 2026 11:50:19 +0000 (UTC)","by mail-dl1-x1235.google.com with SMTP id\n a92af1059eb24-121a0bcd364so6546370c88.0\n for <dev@openvswitch.org>; Tue, 20 Jan 2026 03:50:19 -0800 (PST)","from WNLEC-CW22RF4.. ([177.75.155.81])\n by smtp.gmail.com with ESMTPSA id\n 5a478bee46e88-2b6b367cbc9sm18630559eec.32.2026.01.20.03.50.15\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 20 Jan 2026 03:50:16 -0800 (PST)"],"X-Virus-Scanned":["amavis at osuosl.org","amavis at osuosl.org"],"X-Comment":"SPF check N/A for local connections -\n client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ","DKIM-Filter":["OpenDKIM Filter v2.11.0 smtp3.osuosl.org 685AD6FD1B","OpenDKIM Filter v2.11.0 smtp2.osuosl.org A0BCE403FE"],"Received-SPF":"Pass (mailfrom) identity=mailfrom;\n client-ip=2607:f8b0:4864:20::1235; helo=mail-dl1-x1235.google.com;\n envelope-from=guilherme.paulo@luizalabs.com; receiver=<UNKNOWN>","DMARC-Filter":"OpenDMARC Filter v1.4.2 smtp2.osuosl.org A0BCE403FE","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=luizalabs.com; s=google; t=1768909818; x=1769514618; darn=openvswitch.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=54x5FYMiraBqGXIrqTEq+jmGLLozxWGindiMzHLzSp4=;\n b=dkRCq0BqTA0BL8SIH7RzNVCn8NM9H0H5WEVV6aeCaazUuy69dkpwJKZz1uci4jZpO2\n beuCRPVdsm6d3i96aKJ70T9LI78JP4ujLAJ4CmOvUu5jPQ6c5mRg0Yx+tMITtkUenUVC\n UJaxokB2y2OOPpEo3c5UfWY9JxRIiC/YhmP8o=","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1768909818; x=1769514618;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=54x5FYMiraBqGXIrqTEq+jmGLLozxWGindiMzHLzSp4=;\n b=sgtJOj56w3TCAZiwlfrTfvoTT52+zMa239CNpU1YEw8ie6sbPoG8+PWDXc8eA/LE8D\n 3H2SU1V/UxZ51XMGxM0hGjYXiLmBmBLZ2F/oxILKiznoaqESPPYM96Brqe792C+tyxsV\n dB8BavpwKrE50fd3HQjnyy3T//eFVV+A7z0OfT+wKe+eG+EnyVZf+1O/flctGrMtl4iE\n rqewXaxAF6gVxLfAMPbtO7QkCjqZ2mIZ69C19NX/dDnS90ok1EXwP4P+IAD0ldGJvPoV\n czydRSHlgKO6gu5L+k8UftMj7EakLxICvumg0IWVcaEVfJ69jNXYHqNyD6AgN58QBqZ8\n +b+g==","X-Gm-Message-State":"AOJu0YzRkj3Ag7UyO3KrbdXzCL3yscnRv+s/VLWdH6pZMmgOIItFXAgx\n md+Pz2u+mqlTwftZsCvRIXeNaIecoCsYcINhjGb3eT6nMRllxHdQAhB1UTOY0YmKQUjBx+2rcG6\n Oa7B1nixb9xYTu7wTTcLsGveHmwjDmn5ijogb6RbCpqq6koL82HWWSDIBb5SC","X-Gm-Gg":"AY/fxX7WTKjiuHHR1WlKcpuDefGtQ+rN58Zh0V4DfW1yeNiFWYrmGqUcCAEg1hBYvb4\n YedS5qqozyw+mTIm+YYFPCkqT1vwfpXZmUJFwlneqgucBdN5Kb3JUBqVAL85iRWHVW636lIwV4D\n 0Kdb4DqM1b/KvR1uv30JoeDkMS9Gi8JhswDwTupbxv57DRPcT1wztAjDLc1t7OTYNif95/R9vya\n tpKGXv4zUOiP0/r9iucg9DrhLs09/XAXEAwoMY1YttnS9P2S9LYqRjt6OVPJTApjmuYkQevbnTj\n xDJU3A2CwfGCDXbF1y8AfZ4rktuC28wn1piZgzV7gDiwStUh4tkTqupO4UOssPkxSTzVEWE5yZZ\n LwfV2AfMmbBVJYX+by/ytlBdKmV20EqBg7xPoXfwfBHsUjwclIRCEm1xxkrHZVJ5m0EnrwHnqmn\n iTrYKxZ0e6Wibvu39X4o+UwQaqyXnT3hL75yuA8A==","X-Received":"by 2002:a05:7022:6b92:b0:11b:9386:a380 with SMTP id\n a92af1059eb24-1244a790fa0mr11414148c88.47.1768909816561;\n Tue, 20 Jan 2026 03:50:16 -0800 (PST)","To":"dev@openvswitch.org","Date":"Tue, 20 Jan 2026 08:49:41 -0300","Message-Id":"<20260120114948.2289909-3-guilherme.paulo@luizalabs.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20260120114948.2289909-1-guilherme.paulo@luizalabs.com>","References":"<20260120114948.2289909-1-guilherme.paulo@luizalabs.com>","MIME-Version":"1.0","Subject":"[ovs-dev] [PATCH ovn v0 2/9] ovn-ic: Add a new engine-node\n 'enum-datapath'.","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.30","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>","From":"Paulo Guilherme Silva via dev <ovs-dev@openvswitch.org>","Reply-To":"Paulo Guilherme Silva <guilherme.paulo@luizalabs.com>","Content-Type":"text/plain; charset=\"iso-8859-1\"","Content-Transfer-Encoding":"quoted-printable","Errors-To":"ovs-dev-bounces@openvswitch.org","Sender":"\"dev\" <ovs-dev-bounces@openvswitch.org>"},"content":"This new engine now maintains the enum_datapath related data for ovn-ic\ndaemon which was earlier maintained by the ic engine node invoked the\nenumerate_datapaths() function. The inputs to this engine node are\n'en_icnb_transit_switch' and 'en_icsb_datapath_binding'.In order\nto achieve this, we refactor in the following way:\n* Introduce enum_datapaths_init() which initializes this data.\n* Introduce enum_datapaths_destroy() which clears this data for a\n  new iteration.\n* Introduce enum_datapaths_run() which invokes the full recompute\n  of the engine.\n\nThis engine node becomes an input to 'ic' node.\n\nSigned-off-by: Paulo Guilherme Silva <guilherme.paulo@luizalabs.com>\n---\n ic/automake.mk         |   2 +\n ic/en-enum-datapaths.c | 141 +++++++++++++++++++++++++++++++++++++++++\n ic/en-enum-datapaths.h |  30 +++++++++\n ic/en-ic.c             |  29 +++++----\n ic/inc-proc-ic.c       |   6 ++\n ic/ovn-ic.c            |  82 ++++++++++++------------\n ic/ovn-ic.h            |   8 +--\n lib/stopwatch-names.h  |   1 +\n 8 files changed, 244 insertions(+), 55 deletions(-)\n create mode 100644 ic/en-enum-datapaths.c\n create mode 100644 ic/en-enum-datapaths.h","diff":"diff --git a/ic/automake.mk b/ic/automake.mk\nindex a69b1030d..2766483b7 100644\n--- a/ic/automake.mk\n+++ b/ic/automake.mk\n@@ -4,6 +4,8 @@ ic_ovn_ic_SOURCES = ic/ovn-ic.c \\\n \tic/ovn-ic.h \\\n \tic/en-ic.c \\\n \tic/en-ic.h \\\n+\tic/en-enum-datapaths.c \\\n+\tic/en-enum-datapaths.h \\\n \tic/inc-proc-ic.c \\\n \tic/inc-proc-ic.h\n ic_ovn_ic_LDADD = \\\ndiff --git a/ic/en-enum-datapaths.c b/ic/en-enum-datapaths.c\nnew file mode 100644\nindex 000000000..7515c0b85\n--- /dev/null\n+++ b/ic/en-enum-datapaths.c\n@@ -0,0 +1,141 @@\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+/* OVS includes. */\n+#include \"openvswitch/vlog.h\"\n+#include \"openvswitch/shash.h\"\n+#include \"openvswitch/hmap.h\"\n+\n+/* OVN includes. */\n+#include \"ovn-ic.h\"\n+#include \"en-enum-datapaths.h\"\n+#include \"inc-proc-ic.h\"\n+#include \"lib/inc-proc-eng.h\"\n+#include \"lib/ovn-ic-sb-idl.h\"\n+#include \"lib/ovn-util.h\"\n+#include \"lib/stopwatch-names.h\"\n+#include \"coverage.h\"\n+#include \"stopwatch.h\"\n+#include \"stopwatch-names.h\"\n+\n+VLOG_DEFINE_THIS_MODULE(en_enum_datapaths);\n+COVERAGE_DEFINE(enum_datapaths_run);\n+\n+static void\n+enum_datapath_run(const struct icsbrec_datapath_binding_table *dp_table,\n+                  struct ed_type_enum_datapaths *dp_data);\n+static enum ic_datapath_type\n+    ic_dp_get_type(const struct icsbrec_datapath_binding *isb_dp);\n+static void enum_datapaths_init(struct ed_type_enum_datapaths *data);\n+static void enum_datapaths_destroy(struct ed_type_enum_datapaths *data);\n+static void enum_datapaths_clear(struct ed_type_enum_datapaths *data);\n+\n+void *\n+en_enum_datapaths_init(struct engine_node *node OVS_UNUSED,\n+                       struct engine_arg *arg OVS_UNUSED)\n+{\n+    struct ed_type_enum_datapaths *data = xzalloc(sizeof *data);\n+    enum_datapaths_init(data);\n+    return data;\n+}\n+\n+void\n+en_enum_datapaths_cleanup(void *data)\n+{\n+    enum_datapaths_destroy(data);\n+}\n+\n+enum engine_node_state\n+en_enum_datapaths_run(struct engine_node *node, void *data)\n+{\n+    struct ed_type_enum_datapaths *dp_data = data;\n+\n+    enum_datapaths_clear(dp_data);\n+\n+    const struct icsbrec_datapath_binding_table *dp_table =\n+        EN_OVSDB_GET(engine_get_input(\"ICSB_datapath_binding\", node));\n+\n+    COVERAGE_INC(enum_datapaths_run);\n+    stopwatch_start(OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME, time_msec());\n+    enum_datapath_run(dp_table, dp_data);\n+    stopwatch_stop(OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME, time_msec());\n+\n+    return EN_UPDATED;\n+}\n+\n+static void\n+enum_datapath_run(const struct icsbrec_datapath_binding_table *dp_table,\n+                  struct ed_type_enum_datapaths *dp_data)\n+{\n+    const struct icsbrec_datapath_binding *isb_dp;\n+    ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (isb_dp, dp_table) {\n+        /* 1. Adiciona Tunnel ID */\n+        ovn_add_tnlid(&dp_data->dp_tnlids, isb_dp->tunnel_key);\n+\n+        /* 2. Classifica o Datapath */\n+        enum ic_datapath_type dp_type = ic_dp_get_type(isb_dp);\n+        if (dp_type == IC_ROUTER) {\n+            char *uuid_str = uuid_to_string(isb_dp->nb_ic_uuid);\n+            shash_add(&dp_data->isb_tr_dps, uuid_str, (void *) isb_dp);\n+            free(uuid_str);\n+        } else {\n+            shash_add(&dp_data->isb_ts_dps, isb_dp->transit_switch,\n+                      (void *) isb_dp);\n+        }\n+    }\n+}\n+\n+static enum ic_datapath_type\n+ic_dp_get_type(const struct icsbrec_datapath_binding *isb_dp)\n+{\n+    if (isb_dp->type && !strcmp(isb_dp->type, \"transit-router\")) {\n+        return IC_ROUTER;\n+    }\n+\n+    return IC_SWITCH;\n+}\n+\n+static void\n+enum_datapaths_init(struct ed_type_enum_datapaths *data)\n+{\n+    hmap_init(&data->dp_tnlids);\n+    shash_init(&data->isb_ts_dps);\n+    shash_init(&data->isb_tr_dps);\n+}\n+\n+static void\n+enum_datapaths_destroy(struct ed_type_enum_datapaths *data)\n+{\n+    enum_datapaths_clear(data);\n+    ovn_destroy_tnlids(&data->dp_tnlids);\n+\n+    shash_destroy(&data->isb_ts_dps);\n+    shash_destroy(&data->isb_tr_dps);\n+}\n+\n+static void\n+enum_datapaths_clear(struct ed_type_enum_datapaths *data)\n+{\n+    ovn_destroy_tnlids(&data->dp_tnlids);\n+    hmap_init(&data->dp_tnlids);\n+\n+    shash_clear(&data->isb_ts_dps);\n+    shash_clear(&data->isb_tr_dps);\n+}\ndiff --git a/ic/en-enum-datapaths.h b/ic/en-enum-datapaths.h\nnew file mode 100644\nindex 000000000..0aff9fc89\n--- /dev/null\n+++ b/ic/en-enum-datapaths.h\n@@ -0,0 +1,30 @@\n+#ifndef EN_IC_ENUM_DATAPATHS_H\n+#define EN_IC_ENUM_DATAPATHS_H 1\n+\n+#include <config.h>\n+\n+#include <stdbool.h>\n+#include <getopt.h>\n+#include <stdlib.h>\n+#include <stdio.h>\n+\n+/* OVS includes. */\n+#include \"lib/hmapx.h\"\n+#include \"openvswitch/hmap.h\"\n+#include \"openvswitch/shash.h\"\n+\n+/* OVN includes. */\n+#include \"lib/inc-proc-eng.h\"\n+\n+/* struct which maintains the data of the engine node enumerate datapaths. */\n+struct ed_type_enum_datapaths {\n+    struct hmap dp_tnlids;\n+    struct shash isb_ts_dps;\n+    struct shash isb_tr_dps;\n+};\n+\n+void *en_enum_datapaths_init(struct engine_node *, struct engine_arg *);\n+enum engine_node_state en_enum_datapaths_run(struct engine_node *, void *data);\n+void en_enum_datapaths_cleanup(void *data);\n+\n+#endif\n\\ No newline at end of file\ndiff --git a/ic/en-ic.c b/ic/en-ic.c\nindex ce7d5de76..16b0e12bd 100644\n--- a/ic/en-ic.c\n+++ b/ic/en-ic.c\n@@ -24,6 +24,8 @@\n /* OVN includes. */\n #include \"ovn-ic.h\"\n #include \"en-ic.h\"\n+#include \"en-enum-datapaths.h\"\n+#include \"lib/ovn-ic-sb-idl.h\"\n #include \"lib/inc-proc-eng.h\"\n #include \"lib/ovn-util.h\"\n #include \"lib/stopwatch-names.h\"\n@@ -152,18 +154,26 @@ enum engine_node_state\n en_ic_run(struct engine_node *node, void *data)\n {\n     const struct engine_context *eng_ctx = engine_get_context();\n-\n+    struct ic_data *ic_data = data;\n     struct ic_input input_data;\n \n-    ic_destroy(data);\n-    ic_init(data);\n+    struct ed_type_enum_datapaths *dp_node_data =\n+        engine_get_input_data(\"enum_datapaths\", node);\n+\n+    if (!dp_node_data) {\n+        return EN_UNCHANGED;\n+    }\n+\n+    ic_data->dp_tnlids = &dp_node_data->dp_tnlids;\n+    ic_data->isb_ts_dps = &dp_node_data->isb_ts_dps;\n+    ic_data->isb_tr_dps = &dp_node_data->isb_tr_dps;\n \n     ic_get_input_data(node, &input_data);\n     input_data.runned_az = eng_ctx->client_ctx;\n \n     COVERAGE_INC(ic_run);\n     stopwatch_start(IC_OVN_DB_RUN_STOPWATCH_NAME, time_msec());\n-    ovn_db_run(&input_data, data, (struct engine_context *) eng_ctx);\n+    ovn_db_run(&input_data, ic_data, (struct engine_context *) eng_ctx);\n     stopwatch_stop(IC_OVN_DB_RUN_STOPWATCH_NAME, time_msec());\n     return EN_UPDATED;\n }\n@@ -186,17 +196,14 @@ en_ic_cleanup(void *data)\n }\n \n void\n-ic_destroy(struct ic_data *data)\n+ic_destroy(struct ic_data *data OVS_UNUSED)\n {\n-    ovn_destroy_tnlids(&data->dp_tnlids);\n-    shash_destroy(&data->isb_ts_dps);\n-    shash_destroy(&data->isb_tr_dps);\n }\n \n void\n ic_init(struct ic_data *data)\n {\n-    hmap_init(&data->dp_tnlids);\n-    shash_init(&data->isb_ts_dps);\n-    shash_init(&data->isb_tr_dps);\n+    data->dp_tnlids = NULL;\n+    data->isb_ts_dps = NULL;\n+    data->isb_tr_dps = NULL;\n }\ndiff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c\nindex 2f4579464..e907a902a 100644\n--- a/ic/inc-proc-ic.c\n+++ b/ic/inc-proc-ic.c\n@@ -27,6 +27,7 @@\n #include \"openvswitch/vlog.h\"\n #include \"inc-proc-ic.h\"\n #include \"en-ic.h\"\n+#include \"en-enum-datapaths.h\"\n #include \"unixctl.h\"\n #include \"util.h\"\n \n@@ -158,6 +159,7 @@ VLOG_DEFINE_THIS_MODULE(inc_proc_ic);\n /* Define engine nodes for other nodes. They should be defined as static to\n  * avoid sparse errors. */\n static ENGINE_NODE(ic, SB_WRITE);\n+static ENGINE_NODE(enum_datapaths);\n \n void inc_proc_ic_init(struct ovsdb_idl_loop *nb,\n                       struct ovsdb_idl_loop *sb,\n@@ -166,6 +168,10 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb,\n {\n     /* Define relationships between nodes where first argument is dependent\n      * on the second argument */\n+    engine_add_input(&en_enum_datapaths, &en_icnb_transit_switch, NULL);\n+    engine_add_input(&en_enum_datapaths, &en_icsb_datapath_binding, NULL);\n+\n+    engine_add_input(&en_ic, &en_enum_datapaths, NULL);\n     engine_add_input(&en_ic, &en_nb_nb_global, NULL);\n     engine_add_input(&en_ic, &en_nb_logical_router_static_route, NULL);\n     engine_add_input(&en_ic, &en_nb_logical_router, NULL);\ndiff --git a/ic/ovn-ic.c b/ic/ovn-ic.c\nindex f4a97fbca..3ad40583e 100644\n--- a/ic/ovn-ic.c\n+++ b/ic/ovn-ic.c\n@@ -172,16 +172,6 @@ allocate_dp_key(struct hmap *dp_tnlids, bool vxlan_mode, const char *name)\n             &hint);\n }\n \n-static enum ic_datapath_type\n-ic_dp_get_type(const struct icsbrec_datapath_binding *isb_dp)\n-{\n-    if (isb_dp->type && !strcmp(isb_dp->type, \"transit-router\")) {\n-        return IC_ROUTER;\n-    }\n-\n-    return IC_SWITCH;\n-}\n-\n static enum ic_port_binding_type\n ic_pb_get_type(const struct icsbrec_port_binding *isb_pb)\n {\n@@ -192,28 +182,6 @@ ic_pb_get_type(const struct icsbrec_port_binding *isb_pb)\n     return IC_SWITCH_PORT;\n }\n \n-static void\n-enumerate_datapaths(struct ic_input *ic,\n-                    struct hmap *dp_tnlids,\n-                    struct shash *isb_ts_dps,\n-                    struct shash *isb_tr_dps)\n-{\n-    const struct icsbrec_datapath_binding *isb_dp;\n-    ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (isb_dp,\n-        ic->icsbrec_datapath_binding_table) {\n-        ovn_add_tnlid(dp_tnlids, isb_dp->tunnel_key);\n-\n-        enum ic_datapath_type dp_type = ic_dp_get_type(isb_dp);\n-        if (dp_type == IC_ROUTER) {\n-            char *uuid_str = uuid_to_string(isb_dp->nb_ic_uuid);\n-            shash_add(isb_tr_dps, uuid_str, isb_dp);\n-            free(uuid_str);\n-        } else {\n-            shash_add(isb_ts_dps, isb_dp->transit_switch, isb_dp);\n-        }\n-    }\n-}\n-\n static void\n ts_run(struct engine_context *ctx,\n        struct ic_input *ic,\n@@ -275,7 +243,17 @@ ts_run(struct engine_context *ctx,\n \n             const struct icsbrec_datapath_binding *isb_dp;\n             isb_dp = shash_find_data(isb_ts_dps, ts->name);\n-            if (isb_dp) {\n+            if (!isb_dp) {\n+                const struct icsbrec_datapath_binding *raw;\n+                ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (raw,\n+                    ic->icsbrec_datapath_binding_table) {\n+                    if (raw->transit_switch && !strcmp(raw->transit_switch,\n+                                                       ts->name)) {\n+                        isb_dp = raw;\n+                        break;\n+                    }\n+                }\n+            } else {\n                 int64_t nb_tnl_key = smap_get_int(&ls->other_config,\n                                                   \"requested-tnl-key\",\n                                                   0);\n@@ -309,6 +287,24 @@ ts_run(struct engine_context *ctx,\n             ic->icnbrec_transit_switch_table) {\n             const struct icsbrec_datapath_binding *isb_dp =\n                 shash_find_and_delete(isb_ts_dps, ts->name);\n+\n+            if (!isb_dp) {\n+                const struct icsbrec_datapath_binding *raw_isb;\n+                ICSBREC_DATAPATH_BINDING_TABLE_FOR_EACH (raw_isb,\n+                    ic->icsbrec_datapath_binding_table) {\n+                    if (raw_isb->n_nb_ic_uuid > 0 &&\n+                        uuid_equals(&raw_isb->nb_ic_uuid[0],\n+                                    &ts->header_.uuid)) {\n+                        isb_dp = raw_isb;\n+                        if (isb_dp->transit_switch) {\n+                            shash_find_and_delete(isb_ts_dps,\n+                                                  isb_dp->transit_switch);\n+                        }\n+                        break;\n+                    }\n+                }\n+            }\n+\n             if (!isb_dp) {\n                 /* Allocate tunnel key */\n                 int64_t dp_key = allocate_dp_key(dp_tnlids, vxlan_mode,\n@@ -320,6 +316,9 @@ ts_run(struct engine_context *ctx,\n                 isb_dp = icsbrec_datapath_binding_insert(ctx->ovnisb_idl_txn);\n                 icsbrec_datapath_binding_set_transit_switch(isb_dp, ts->name);\n                 icsbrec_datapath_binding_set_tunnel_key(isb_dp, dp_key);\n+                icsbrec_datapath_binding_set_nb_ic_uuid(isb_dp,\n+                                                        &ts->header_.uuid, 1);\n+                icsbrec_datapath_binding_set_type(isb_dp, \"transit-switch\");\n             } else if (dp_key_refresh) {\n                 /* Refresh tunnel key since encap mode has changed. */\n                 int64_t dp_key = allocate_dp_key(dp_tnlids, vxlan_mode,\n@@ -339,9 +338,13 @@ ts_run(struct engine_context *ctx,\n             }\n         }\n \n-        struct shash_node *node;\n-        SHASH_FOR_EACH (node, isb_ts_dps) {\n-            icsbrec_datapath_binding_delete(node->data);\n+        struct shash_node *node, *next;\n+        SHASH_FOR_EACH_SAFE (node, next, isb_ts_dps) {\n+            struct icsbrec_datapath_binding *isb_dp_to_del = node->data;\n+            if (isb_dp_to_del->n_nb_ic_uuid > 0) {\n+                icsbrec_datapath_binding_delete(isb_dp_to_del);\n+            }\n+            shash_delete(isb_ts_dps, node);\n         }\n     }\n }\n@@ -3113,10 +3116,8 @@ ovn_db_run(struct ic_input *input_data,\n            struct engine_context *eng_ctx)\n {\n     gateway_run(eng_ctx, input_data);\n-    enumerate_datapaths(input_data, &ic_data->dp_tnlids,\n-                        &ic_data->isb_ts_dps, &ic_data->isb_tr_dps);\n-    ts_run(eng_ctx, input_data, &ic_data->dp_tnlids, &ic_data->isb_ts_dps);\n-    tr_run(eng_ctx, input_data, &ic_data->dp_tnlids, &ic_data->isb_tr_dps);\n+    ts_run(eng_ctx, input_data, ic_data->dp_tnlids, ic_data->isb_ts_dps);\n+    tr_run(eng_ctx, input_data, ic_data->dp_tnlids, ic_data->isb_tr_dps);\n     port_binding_run(eng_ctx, input_data);\n     route_run(eng_ctx, input_data);\n     sync_service_monitor(eng_ctx, input_data);\n@@ -3522,6 +3523,7 @@ main(int argc, char *argv[])\n \n     stopwatch_create(OVN_IC_LOOP_STOPWATCH_NAME, SW_MS);\n     stopwatch_create(IC_OVN_DB_RUN_STOPWATCH_NAME, SW_MS);\n+    stopwatch_create(OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME, SW_MS);\n \n     /* Initialize incremental processing engine for ovn-northd */\n     inc_proc_ic_init(&ovnnb_idl_loop, &ovnsb_idl_loop,\ndiff --git a/ic/ovn-ic.h b/ic/ovn-ic.h\nindex 2c2efc046..9b0009274 100644\n--- a/ic/ovn-ic.h\n+++ b/ic/ovn-ic.h\n@@ -66,10 +66,10 @@ struct ic_input {\n };\n \n struct ic_data {\n-    /* Global state for 'en-ic'. */\n-    struct hmap dp_tnlids;\n-    struct shash isb_ts_dps;\n-    struct shash isb_tr_dps;\n+    /* Global state for 'en-enum-datapaths'. */\n+    struct hmap *dp_tnlids;\n+    struct shash *isb_ts_dps;\n+    struct shash *isb_tr_dps;\n };\n struct ic_state {\n     bool had_lock;\ndiff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h\nindex 5f1091155..4eef534ed 100644\n--- a/lib/stopwatch-names.h\n+++ b/lib/stopwatch-names.h\n@@ -42,5 +42,6 @@\n \n #define OVN_IC_LOOP_STOPWATCH_NAME \"ovn-ic-loop\"\n #define IC_OVN_DB_RUN_STOPWATCH_NAME \"ovn_db_run\"\n+#define OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME \"enum_datapaths_run\"\n \n #endif\n","prefixes":["ovs-dev","v0","2/9"]}