This new engine now maintains the port-binding related data for ovn-ic
daemon which was earlier maintained by the ic
engine node invoked the port_binding_run() function. The inputs to
this engine node are:
   en_icnb_transit_switch;
   en_icnb_transit_router;
   en_icsb_port_binding;
   en_nb_logical_switch;
   en_sb_port_binding;
   en_nb_logical_router;
   en_sb_chassis;
In order to achieve this, we refactor in the following way:
* Introduce port_binding_init() which initializes this data.
* Introduce port_binding_destroy() which clears this data for a new iteration.
* Introduce port_binding_run() which invokes the full recompute of the engine.

This engine node becomes an input to 'ic' node.

Signed-off-by: Paulo Guilherme Silva <[email protected]>
---
 ic/automake.mk        |   2 +
 ic/en-ic.c            |   8 -
 ic/en-port-binding.c  | 853 ++++++++++++++++++++++++++++++++++++++++++
 ic/en-port-binding.h  |  36 ++
 ic/inc-proc-ic.c      |  13 +-
 ic/ovn-ic.c           | 701 ++--------------------------------
 ic/ovn-ic.h           |  25 +-
 lib/stopwatch-names.h |   1 +
 8 files changed, 956 insertions(+), 683 deletions(-)
 create mode 100644 ic/en-port-binding.c
 create mode 100644 ic/en-port-binding.h

diff --git a/ic/automake.mk b/ic/automake.mk
index 2766483b7..91783df0f 100644
--- a/ic/automake.mk
+++ b/ic/automake.mk
@@ -6,6 +6,8 @@ ic_ovn_ic_SOURCES = ic/ovn-ic.c \
        ic/en-ic.h \
        ic/en-enum-datapaths.c \
        ic/en-enum-datapaths.h \
+       ic/en-port-binding.c \
+       ic/en-port-binding.h \
        ic/inc-proc-ic.c \
        ic/inc-proc-ic.h
 ic_ovn_ic_LDADD = \
diff --git a/ic/en-ic.c b/ic/en-ic.c
index 16b0e12bd..e7c7ab71b 100644
--- a/ic/en-ic.c
+++ b/ic/en-ic.c
@@ -116,14 +116,6 @@ ic_get_input_data(struct engine_node *node,
         engine_ovsdb_node_get_index(
             engine_get_input("ICSB_port_binding", node),
             "icsbrec_port_binding_by_az");
-    input_data->icsbrec_port_binding_by_ts =
-        engine_ovsdb_node_get_index(
-            engine_get_input("ICSB_port_binding", node),
-            "icsbrec_port_binding_by_ts");
-    input_data->icsbrec_port_binding_by_ts_az =
-        engine_ovsdb_node_get_index(
-            engine_get_input("ICSB_port_binding", node),
-            "icsbrec_port_binding_by_ts_az");
     input_data->icsbrec_route_by_az =
         engine_ovsdb_node_get_index(
             engine_get_input("ICSB_route", node),
diff --git a/ic/en-port-binding.c b/ic/en-port-binding.c
new file mode 100644
index 000000000..ee9df2830
--- /dev/null
+++ b/ic/en-port-binding.c
@@ -0,0 +1,853 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#include <config.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* OVS includes. */
+#include "openvswitch/vlog.h"
+
+/* OVN includes. */
+#include "ovn-ic.h"
+#include "en-port-binding.h"
+#include "inc-proc-ic.h"
+#include "lib/inc-proc-eng.h"
+#include "lib/ovn-nb-idl.h"
+#include "lib/ovn-sb-idl.h"
+#include "lib/ovn-ic-nb-idl.h"
+#include "lib/ovn-ic-sb-idl.h"
+#include "lib/ovn-util.h"
+#include "lib/stopwatch-names.h"
+#include "coverage.h"
+#include "stopwatch.h"
+#include "stopwatch-names.h"
+
+VLOG_DEFINE_THIS_MODULE(en_port_binding);
+COVERAGE_DEFINE(port_binding_run);
+
+static void
+port_binding_run(const struct engine_context *eng_ctx,
+                 struct pb_input *pb_input,
+                 struct ed_type_port_binding *pb_data,
+                 const struct icnbrec_transit_switch_table *icnb_ts_table,
+                 const struct icnbrec_transit_router_table *icnb_tr_table);
+static void port_binding_init(struct ed_type_port_binding *data);
+static void port_binding_destroy(struct ed_type_port_binding *data);
+static void port_binding_clear(struct ed_type_port_binding *data);
+static void port_binding_get_input_data(struct engine_node *node,
+                                        struct pb_input *input_data);
+static const struct nbrec_logical_router *
+    find_tr_in_nb(struct pb_input *pb, char *tr_name);
+static const struct sbrec_port_binding *
+    find_peer_port(struct pb_input *pb,
+                   const struct sbrec_port_binding *sb_pb);
+static const struct sbrec_port_binding *
+    find_crp_from_lrp(struct pb_input *pb,
+                      const struct sbrec_port_binding *lrp_pb);
+static const struct sbrec_port_binding *
+    find_crp_for_sb_pb(struct pb_input *pb,
+                       const struct sbrec_port_binding *sb_pb);
+static const char *
+    get_lp_address_for_sb_pb(struct pb_input *pb,
+                             const struct sbrec_port_binding *sb_pb);
+static const struct sbrec_chassis *
+    find_sb_chassis(struct pb_input *pb, const char *name);
+static void sync_lsp_tnl_key(const struct nbrec_logical_switch_port *lsp,
+                             int64_t isb_tnl_key);
+static inline void
+    sync_lrp_tnl_key(const struct nbrec_logical_router_port *lrp,
+                     int64_t isb_tnl_key);
+static bool
+    get_router_uuid_by_sb_pb(struct pb_input *pb,
+                             const struct sbrec_port_binding *sb_pb,
+                             struct uuid *router_uuid);
+static void
+    update_isb_pb_external_ids(struct pb_input *pb,
+                               const struct sbrec_port_binding *sb_pb,
+                               const struct icsbrec_port_binding *isb_pb);
+static void
+    sync_local_port(struct pb_input *pb,
+                    const struct icsbrec_port_binding *isb_pb,
+                    const struct sbrec_port_binding *sb_pb,
+                    const struct nbrec_logical_switch_port *lsp);
+static void
+    sync_remote_port(struct pb_input *pb,
+                     const struct icsbrec_port_binding *isb_pb,
+                     const struct nbrec_logical_switch_port *lsp,
+                     const struct sbrec_port_binding *sb_pb);
+static void
+    sync_router_port(const struct icsbrec_port_binding *isb_pb,
+                     const struct icnbrec_transit_router_port *trp,
+                     const struct nbrec_logical_router_port *lrp);
+static void
+    create_nb_lsp(const struct engine_context *ctx,
+                  const struct icsbrec_port_binding *isb_pb,
+                  const struct nbrec_logical_switch *ls);
+static uint32_t allocate_port_key(struct hmap *pb_tnlids);
+static const struct icsbrec_port_binding *
+    create_isb_pb(const struct engine_context *ctx, const char *logical_port,
+                  const struct icsbrec_availability_zone *az,
+                  const char *ts_name, const struct uuid *nb_ic_uuid,
+                  const char *type, struct hmap *pb_tnlids);
+static bool trp_is_remote(struct pb_input *pb, const char *chassis_name);
+static struct nbrec_logical_router_port *
+    lrp_create(const struct engine_context *ctx,
+               const struct nbrec_logical_router *lr,
+               const struct icnbrec_transit_router_port *trp);
+static void
+    sync_ts_isb_pb(struct pb_input *pb, const struct sbrec_port_binding *sb_pb,
+                   const struct icsbrec_port_binding *isb_pb);
+static const struct sbrec_port_binding *
+    find_lsp_in_sb(struct pb_input *pb,
+                   const struct nbrec_logical_switch_port *lsp);
+
+static void
+port_binding_get_input_data(struct engine_node *node,
+                            struct pb_input *input_data)
+{
+    /* Indexes */
+    input_data->icsbrec_port_binding_by_az =
+        engine_ovsdb_node_get_index(
+            engine_get_input("ICSB_port_binding", node),
+            "icsbrec_port_binding_by_az");
+    input_data->icsbrec_port_binding_by_ts =
+        engine_ovsdb_node_get_index(
+            engine_get_input("ICSB_port_binding", node),
+            "icsbrec_port_binding_by_ts");
+    input_data->nbrec_ls_by_name =
+        engine_ovsdb_node_get_index(
+            engine_get_input("NB_logical_switch", node),
+            "nbrec_ls_by_name");
+    input_data->sbrec_port_binding_by_name =
+        engine_ovsdb_node_get_index(
+            engine_get_input("SB_port_binding", node),
+            "sbrec_port_binding_by_name");
+    input_data->nbrec_port_by_name =
+        engine_ovsdb_node_get_index(
+            engine_get_input("NB_logical_switch", node),
+            "nbrec_port_by_name");
+    input_data->nbrec_lr_by_name =
+        engine_ovsdb_node_get_index(
+            engine_get_input("NB_logical_router", node),
+            "nbrec_lr_by_name");
+    input_data->sbrec_chassis_by_name =
+        engine_ovsdb_node_get_index(
+            engine_get_input("SB_chassis", node),
+            "sbrec_chassis_by_name");
+}
+
+enum engine_node_state
+en_port_binding_run(struct engine_node *node, void *data)
+{
+    const struct engine_context *eng_ctx = engine_get_context();
+    struct ed_type_port_binding *pb_data = data;
+    struct pb_input pb_input;
+
+    port_binding_clear(pb_data);
+
+    const struct icnbrec_transit_switch_table *icnb_ts_table =
+        EN_OVSDB_GET(engine_get_input("ICNB_transit_switch", node));
+    const struct icnbrec_transit_router_table *icnb_tr_table =
+        EN_OVSDB_GET(engine_get_input("ICNB_transit_router", node));
+
+    port_binding_get_input_data(node, &pb_input);
+    pb_input.runned_az = eng_ctx->client_ctx;
+
+    COVERAGE_INC(port_binding_run);
+    stopwatch_start(OVN_IC_PORT_BINDING_RUN_STOPWATCH_NAME, time_usec());
+    port_binding_run(eng_ctx, &pb_input, pb_data, icnb_ts_table,
+                     icnb_tr_table);
+    stopwatch_stop(OVN_IC_PORT_BINDING_RUN_STOPWATCH_NAME, time_usec());
+
+    return EN_UPDATED;
+}
+
+void *
+en_port_binding_init(struct engine_node *node OVS_UNUSED,
+                     struct engine_arg *arg OVS_UNUSED)
+{
+    struct ed_type_port_binding *data = xzalloc(sizeof *data);
+    port_binding_init(data);
+    return data;
+}
+
+void
+en_port_binding_cleanup(void *data)
+{
+    port_binding_destroy(data);
+}
+
+static void
+port_binding_init(struct ed_type_port_binding *data)
+{
+    hmap_init(&data->pb_tnlids);
+    shash_init(&data->switch_all_local_pbs);
+    shash_init(&data->router_all_local_pbs);
+}
+
+static void
+port_binding_destroy(struct ed_type_port_binding *data)
+{
+    port_binding_clear(data);
+    ovn_destroy_tnlids(&data->pb_tnlids);
+
+    shash_destroy(&data->switch_all_local_pbs);
+    shash_destroy(&data->router_all_local_pbs);
+}
+
+static void
+port_binding_clear(struct ed_type_port_binding *data)
+{
+    ovn_destroy_tnlids(&data->pb_tnlids);
+    hmap_init(&data->pb_tnlids);
+
+    shash_clear(&data->switch_all_local_pbs);
+    shash_clear(&data->router_all_local_pbs);
+}
+
+static void
+port_binding_run(const struct engine_context *eng_ctx,
+                 struct pb_input *pb_input,
+                 struct ed_type_port_binding *pb_data,
+                 const struct icnbrec_transit_switch_table *icnb_ts_table,
+                 const struct icnbrec_transit_router_table *icnb_tr_table)
+{
+    if (!eng_ctx->ovnisb_idl_txn || !eng_ctx->ovnnb_idl_txn
+        || !eng_ctx->ovnsb_idl_txn) {
+        return;
+    }
+
+    struct shash_node *node;
+    const struct icsbrec_port_binding *isb_pb;
+    const struct icsbrec_port_binding *isb_pb_key =
+        icsbrec_port_binding_index_init_row(
+            pb_input->icsbrec_port_binding_by_az);
+    icsbrec_port_binding_index_set_availability_zone(isb_pb_key,
+                                                     pb_input->runned_az);
+
+    ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
+        pb_input->icsbrec_port_binding_by_az) {
+        ic_pb_get_type(isb_pb) != IC_ROUTER_PORT
+            ? shash_add(&pb_data->switch_all_local_pbs, isb_pb->logical_port,
+                        isb_pb)
+            : shash_add(&pb_data->router_all_local_pbs, isb_pb->logical_port,
+                        isb_pb);
+
+        ovn_add_tnlid(&pb_data->pb_tnlids, isb_pb->tunnel_key);
+    }
+    icsbrec_port_binding_index_destroy_row(isb_pb_key);
+
+    const struct sbrec_port_binding *sb_pb;
+    const struct icnbrec_transit_switch *ts;
+    ICNBREC_TRANSIT_SWITCH_TABLE_FOR_EACH (ts, icnb_ts_table) {
+        const struct nbrec_logical_switch *ls =
+            find_ts_in_nb(pb_input->nbrec_ls_by_name,
+                          ts->name);
+        if (!ls) {
+            VLOG_DBG("Transit switch %s not found in NB.", ts->name);
+            continue;
+        }
+        struct shash local_pbs = SHASH_INITIALIZER(&local_pbs);
+        struct shash remote_pbs = SHASH_INITIALIZER(&remote_pbs);
+
+        isb_pb_key = icsbrec_port_binding_index_init_row(
+            pb_input->icsbrec_port_binding_by_ts);
+        icsbrec_port_binding_index_set_transit_switch(isb_pb_key, ts->name);
+
+        ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
+            pb_input->icsbrec_port_binding_by_ts) {
+            if (isb_pb->availability_zone == pb_input->runned_az) {
+                shash_add(&local_pbs, isb_pb->logical_port, isb_pb);
+                shash_find_and_delete(&pb_data->switch_all_local_pbs,
+                                      isb_pb->logical_port);
+            } else {
+                shash_add(&remote_pbs, isb_pb->logical_port, isb_pb);
+            }
+        }
+        icsbrec_port_binding_index_destroy_row(isb_pb_key);
+
+        const struct nbrec_logical_switch_port *lsp;
+        for (int i = 0; i < ls->n_ports; i++) {
+            lsp = ls->ports[i];
+
+            if (!strcmp(lsp->type, "router")
+                || !strcmp(lsp->type, "switch")) {
+                /* The port is local. */
+                sb_pb = find_lsp_in_sb(pb_input, lsp);
+                if (!sb_pb) {
+                    continue;
+                }
+                isb_pb = shash_find_and_delete(&local_pbs, lsp->name);
+                if (!isb_pb) {
+                    isb_pb = create_isb_pb(
+                        eng_ctx, sb_pb->logical_port, pb_input->runned_az,
+                        ts->name, &ts->header_.uuid, "transit-switch-port",
+                        &pb_data->pb_tnlids);
+                    sync_ts_isb_pb(pb_input, sb_pb, isb_pb);
+                } else {
+                    sync_local_port(pb_input, isb_pb, sb_pb, lsp);
+                }
+
+                if (isb_pb->type) {
+                    icsbrec_port_binding_set_type(isb_pb,
+                                                  "transit-switch-port");
+                }
+
+                if (isb_pb->nb_ic_uuid) {
+                    icsbrec_port_binding_set_nb_ic_uuid(isb_pb,
+                                                        &ts->header_.uuid, 1);
+                }
+            } else if (!strcmp(lsp->type, "remote")) {
+                /* The port is remote. */
+                isb_pb = shash_find_and_delete(&remote_pbs, lsp->name);
+                if (!isb_pb) {
+                    nbrec_logical_switch_update_ports_delvalue(ls, lsp);
+                } else {
+                    sb_pb = find_lsp_in_sb(pb_input, lsp);
+                    if (!sb_pb) {
+                        continue;
+                    }
+                    sync_remote_port(pb_input, isb_pb, lsp, sb_pb);
+                }
+            } else {
+                VLOG_DBG("Ignore lsp %s on ts %s with type %s.",
+                         lsp->name, ts->name, lsp->type);
+            }
+        }
+
+        /* Delete extra port-binding from ISB */
+        SHASH_FOR_EACH (node, &local_pbs) {
+            icsbrec_port_binding_delete(node->data);
+        }
+
+        /* Create lsp in NB for remote ports */
+        SHASH_FOR_EACH (node, &remote_pbs) {
+            create_nb_lsp(eng_ctx, node->data, ls);
+        }
+
+        shash_destroy(&local_pbs);
+        shash_destroy(&remote_pbs);
+    }
+
+    SHASH_FOR_EACH (node, &pb_data->switch_all_local_pbs) {
+        icsbrec_port_binding_delete(node->data);
+    }
+
+    const struct icnbrec_transit_router *tr;
+    ICNBREC_TRANSIT_ROUTER_TABLE_FOR_EACH (tr, icnb_tr_table) {
+        const struct nbrec_logical_router *lr = find_tr_in_nb(pb_input,
+                                                              tr->name);
+        if (!lr) {
+            VLOG_DBG("Transit router %s not found in NB.", tr->name);
+            continue;
+        }
+
+        struct shash nb_ports = SHASH_INITIALIZER(&nb_ports);
+        struct shash local_pbs = SHASH_INITIALIZER(&local_pbs);
+        struct shash remote_pbs = SHASH_INITIALIZER(&remote_pbs);
+
+        for (size_t i = 0; i < lr->n_ports; i++) {
+            const struct nbrec_logical_router_port *lrp = lr->ports[i];
+            if (smap_get_def(&lrp->options, "interconn-tr", NULL)) {
+                shash_add(&nb_ports, lrp->name, lrp);
+            }
+        }
+
+        isb_pb_key = icsbrec_port_binding_index_init_row(
+            pb_input->icsbrec_port_binding_by_ts);
+        icsbrec_port_binding_index_set_transit_switch(isb_pb_key, tr->name);
+
+        ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
+            pb_input->icsbrec_port_binding_by_ts) {
+            if (isb_pb->availability_zone == pb_input->runned_az) {
+                shash_add(&local_pbs, isb_pb->logical_port, isb_pb);
+                shash_find_and_delete(&pb_data->router_all_local_pbs,
+                                      isb_pb->logical_port);
+            } else {
+                shash_add(&remote_pbs, isb_pb->logical_port, isb_pb);
+            }
+        }
+        icsbrec_port_binding_index_destroy_row(isb_pb_key);
+
+        for (size_t i = 0; i < tr->n_ports; i++) {
+            const struct icnbrec_transit_router_port *trp = tr->ports[i];
+
+            if (trp_is_remote(pb_input, trp->chassis)) {
+                isb_pb = shash_find_and_delete(&remote_pbs, trp->name);
+            } else {
+                isb_pb = shash_find_and_delete(&local_pbs, trp->name);
+                if (!isb_pb) {
+                    isb_pb = create_isb_pb(eng_ctx, trp->name,
+                                           pb_input->runned_az, tr->name,
+                                           &tr->header_.uuid,
+                                           "transit-router-port",
+                                           &pb_data->pb_tnlids);
+                    icsbrec_port_binding_set_address(isb_pb, trp->mac);
+                }
+            }
+
+            /* Don't allow remote ports to create NB LRP until ICSB entry is
+             * created in the appropriate AZ. */
+            if (isb_pb) {
+                const struct nbrec_logical_router_port *lrp =
+                    shash_find_and_delete(&nb_ports, trp->name);
+                if (!lrp) {
+                    lrp = lrp_create(eng_ctx, lr, trp);
+                }
+
+                sync_router_port(isb_pb, trp, lrp);
+            }
+        }
+
+        SHASH_FOR_EACH (node, &nb_ports) {
+            nbrec_logical_router_port_delete(node->data);
+            nbrec_logical_router_update_ports_delvalue(lr, node->data);
+        }
+
+        shash_destroy(&nb_ports);
+        shash_destroy(&local_pbs);
+        shash_destroy(&remote_pbs);
+    }
+
+    SHASH_FOR_EACH (node, &pb_data->router_all_local_pbs) {
+        icsbrec_port_binding_delete(node->data);
+    }
+}
+
+static const struct nbrec_logical_router *
+find_tr_in_nb(struct pb_input *pb, char *tr_name)
+{
+    const struct nbrec_logical_router *key =
+        nbrec_logical_router_index_init_row(pb->nbrec_lr_by_name);
+    nbrec_logical_router_index_set_name(key, tr_name);
+
+    const struct nbrec_logical_router *lr;
+    bool found = false;
+    NBREC_LOGICAL_ROUTER_FOR_EACH_EQUAL (lr, key, pb->nbrec_lr_by_name) {
+        if (smap_get(&lr->options, "interconn-tr")) {
+            found = true;
+            break;
+        }
+    }
+
+    nbrec_logical_router_index_destroy_row(key);
+    if (found) {
+        return lr;
+    }
+
+    return NULL;
+}
+
+static const struct sbrec_port_binding *
+find_peer_port(struct pb_input *pb,
+               const struct sbrec_port_binding *sb_pb)
+{
+    const char *peer_name = smap_get(&sb_pb->options, "peer");
+    if (!peer_name) {
+        return NULL;
+    }
+
+    return find_sb_pb_by_name(pb->sbrec_port_binding_by_name, peer_name);
+}
+
+static const struct sbrec_port_binding *
+find_crp_from_lrp(struct pb_input *pb,
+                  const struct sbrec_port_binding *lrp_pb)
+{
+    char *crp_name = ovn_chassis_redirect_name(lrp_pb->logical_port);
+
+    const struct sbrec_port_binding *sb_pb =
+        find_sb_pb_by_name(pb->sbrec_port_binding_by_name, crp_name);
+
+    free(crp_name);
+    return sb_pb;
+}
+
+static const struct sbrec_port_binding *
+find_crp_for_sb_pb(struct pb_input *pb,
+                   const struct sbrec_port_binding *sb_pb)
+{
+    const struct sbrec_port_binding *peer = find_peer_port(pb, sb_pb);
+    if (!peer) {
+        return NULL;
+    }
+
+    return find_crp_from_lrp(pb, peer);
+}
+
+static const char *
+get_lp_address_for_sb_pb(struct pb_input *pb,
+                         const struct sbrec_port_binding *sb_pb)
+{
+    const struct nbrec_logical_switch_port *nb_lsp;
+
+    nb_lsp = get_lsp_by_ts_port_name(pb->nbrec_port_by_name,
+                                     sb_pb->logical_port);
+    if (!strcmp(nb_lsp->type, "switch")) {
+        /* Switches always have implicit "unknown" address, and IC-SB port
+         * binding can only have one address specified. */
+        return "unknown";
+    }
+
+    const struct sbrec_port_binding *peer = find_peer_port(pb, sb_pb);
+    if (!peer) {
+        return NULL;
+    }
+
+    return peer->n_mac ? *peer->mac : NULL;
+}
+
+static const struct sbrec_chassis *
+find_sb_chassis(struct pb_input *pb, const char *name)
+{
+    const struct sbrec_chassis *key =
+        sbrec_chassis_index_init_row(pb->sbrec_chassis_by_name);
+    sbrec_chassis_index_set_name(key, name);
+
+    const struct sbrec_chassis *chassis =
+        sbrec_chassis_index_find(pb->sbrec_chassis_by_name, key);
+    sbrec_chassis_index_destroy_row(key);
+
+    return chassis;
+}
+
+static void
+sync_lsp_tnl_key(const struct nbrec_logical_switch_port *lsp,
+                 int64_t isb_tnl_key)
+{
+    int64_t tnl_key = smap_get_int(&lsp->options, "requested-tnl-key", 0);
+    if (tnl_key != isb_tnl_key) {
+        VLOG_DBG("Set options:requested-tnl-key %"PRId64
+                 " for lsp %s in NB.", isb_tnl_key, lsp->name);
+        char *tnl_key_str = xasprintf("%"PRId64, isb_tnl_key);
+        nbrec_logical_switch_port_update_options_setkey(lsp,
+                                                        "requested-tnl-key",
+                                                        tnl_key_str);
+        free(tnl_key_str);
+    }
+}
+
+static inline void
+sync_lrp_tnl_key(const struct nbrec_logical_router_port *lrp,
+                 int64_t isb_tnl_key)
+{
+    int64_t tnl_key = smap_get_int(&lrp->options, "requested-tnl-key", 0);
+    if (tnl_key != isb_tnl_key) {
+        VLOG_DBG("Set options:requested-tnl-key %" PRId64 " for lrp %s in NB.",
+                 isb_tnl_key, lrp->name);
+        char *tnl_key_str = xasprintf("%"PRId64, isb_tnl_key);
+        nbrec_logical_router_port_update_options_setkey(
+            lrp, "requested-tnl-key", tnl_key_str);
+        free(tnl_key_str);
+    }
+}
+
+static bool
+get_router_uuid_by_sb_pb(struct pb_input *pb,
+                         const struct sbrec_port_binding *sb_pb,
+                         struct uuid *router_uuid)
+{
+    const struct sbrec_port_binding *router_pb = find_peer_port(pb, sb_pb);
+    if (!router_pb || !router_pb->datapath) {
+        return NULL;
+    }
+
+    return datapath_get_nb_uuid(router_pb->datapath, router_uuid);
+}
+
+static void
+update_isb_pb_external_ids(struct pb_input *pb,
+                           const struct sbrec_port_binding *sb_pb,
+                           const struct icsbrec_port_binding *isb_pb)
+{
+    struct uuid lr_uuid;
+    if (!get_router_uuid_by_sb_pb(pb, sb_pb, &lr_uuid)) {
+        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+        VLOG_WARN_RL(&rl, "Can't get router uuid for transit switch port %s.",
+                     isb_pb->logical_port);
+        return;
+    }
+
+    struct uuid current_lr_uuid;
+    if (smap_get_uuid(&isb_pb->external_ids, "router-id", &current_lr_uuid) &&
+        uuid_equals(&lr_uuid, &current_lr_uuid)) {
+        return;
+    }
+
+    char *uuid_s = xasprintf(UUID_FMT, UUID_ARGS(&lr_uuid));
+    icsbrec_port_binding_update_external_ids_setkey(isb_pb, "router-id",
+                                                    uuid_s);
+    free(uuid_s);
+}
+
+/* For each local port:
+ *   - Sync from NB to ISB.
+ *   - Sync gateway from SB to ISB.
+ *   - Sync tunnel key from ISB to NB.
+ */
+static void
+sync_local_port(struct pb_input *pb,
+                const struct icsbrec_port_binding *isb_pb,
+                const struct sbrec_port_binding *sb_pb,
+                const struct nbrec_logical_switch_port *lsp)
+{
+    /* Sync address from NB to ISB */
+    const char *address = get_lp_address_for_sb_pb(pb, sb_pb);
+    if (!address) {
+        VLOG_DBG("Can't get router/switch port address for logical"
+                 " switch port %s", sb_pb->logical_port);
+        if (isb_pb->address[0]) {
+            icsbrec_port_binding_set_address(isb_pb, "");
+        }
+    } else {
+        if (strcmp(address, isb_pb->address)) {
+            icsbrec_port_binding_set_address(isb_pb, address);
+        }
+    }
+
+    /* Sync gateway from SB to ISB */
+    const struct sbrec_port_binding *crp = find_crp_for_sb_pb(pb, sb_pb);
+    if (crp && crp->chassis) {
+        if (strcmp(crp->chassis->name, isb_pb->gateway)) {
+            icsbrec_port_binding_set_gateway(isb_pb, crp->chassis->name);
+        }
+    } else if (!strcmp(lsp->type, "switch") && sb_pb->chassis) {
+        if (strcmp(sb_pb->chassis->name, isb_pb->gateway)) {
+            icsbrec_port_binding_set_gateway(isb_pb, sb_pb->chassis->name);
+        }
+    } else {
+        if (isb_pb->gateway[0]) {
+            icsbrec_port_binding_set_gateway(isb_pb, "");
+        }
+    }
+
+    /* Sync external_ids:router-id to ISB */
+    update_isb_pb_external_ids(pb, sb_pb, isb_pb);
+
+    /* Sync back tunnel key from ISB to NB */
+    sync_lsp_tnl_key(lsp, isb_pb->tunnel_key);
+}
+
+/* For each remote port:
+ *   - Sync from ISB to NB
+ *   - Sync gateway from ISB to SB
+ */
+static void
+sync_remote_port(struct pb_input *pb,
+                 const struct icsbrec_port_binding *isb_pb,
+                 const struct nbrec_logical_switch_port *lsp,
+                 const struct sbrec_port_binding *sb_pb)
+{
+    /* Sync address from ISB to NB */
+    if (isb_pb->address[0]) {
+        if (lsp->n_addresses != 1 ||
+            strcmp(isb_pb->address, lsp->addresses[0])) {
+            nbrec_logical_switch_port_set_addresses(
+                lsp, (const char **)&isb_pb->address, 1);
+        }
+    } else {
+        if (lsp->n_addresses != 0) {
+            nbrec_logical_switch_port_set_addresses(lsp, NULL, 0);
+        }
+    }
+
+    /* Sync tunnel key from ISB to NB */
+    sync_lsp_tnl_key(lsp, isb_pb->tunnel_key);
+
+    /* Skip port binding if it is already requested by the CMS. */
+    if (smap_get(&lsp->options, "requested-chassis")) {
+        return;
+    }
+
+    /* Sync gateway from ISB to SB */
+    if (isb_pb->gateway[0]) {
+        if (!sb_pb->chassis || strcmp(sb_pb->chassis->name, isb_pb->gateway)) {
+            const struct sbrec_chassis *chassis =
+                find_sb_chassis(pb, isb_pb->gateway);
+            if (!chassis) {
+                VLOG_DBG("Chassis %s is not found in SB, syncing from ISB "
+                         "to SB skipped for logical port %s.",
+                         isb_pb->gateway, lsp->name);
+                return;
+            }
+            sbrec_port_binding_set_chassis(sb_pb, chassis);
+        }
+    } else {
+        if (sb_pb->chassis) {
+            sbrec_port_binding_set_chassis(sb_pb, NULL);
+        }
+    }
+}
+
+/* For each remote port:
+ *   - Sync from ISB to NB
+ */
+static void
+sync_router_port(const struct icsbrec_port_binding *isb_pb,
+                 const struct icnbrec_transit_router_port *trp,
+                 const struct nbrec_logical_router_port *lrp)
+{
+    /* Sync from ICNB to NB */
+    if (trp->chassis[0]) {
+        const char *chassis_name =
+            smap_get_def(&lrp->options, "requested-chassis", "");
+        if (strcmp(trp->chassis, chassis_name)) {
+            nbrec_logical_router_port_update_options_setkey(
+                lrp, "requested-chassis", trp->chassis);
+        }
+    } else {
+        nbrec_logical_router_port_update_options_delkey(
+            lrp, "requested-chassis");
+    }
+
+    if (strcmp(trp->mac, lrp->mac)) {
+        nbrec_logical_router_port_set_mac(lrp, trp->mac);
+    }
+
+    bool sync_networks = false;
+    if (trp->n_networks != lrp->n_networks) {
+        sync_networks = true;
+    } else {
+        for (size_t i = 0; i < trp->n_networks; i++) {
+            if (strcmp(trp->networks[i], lrp->networks[i])) {
+                sync_networks |= true;
+                break;
+            }
+        }
+    }
+
+    if (sync_networks) {
+        nbrec_logical_router_port_set_networks(
+            lrp, (const char **) trp->networks, trp->n_networks);
+    }
+
+    /* Sync tunnel key from ISB to NB */
+    sync_lrp_tnl_key(lrp, isb_pb->tunnel_key);
+}
+
+static void
+create_nb_lsp(const struct engine_context *ctx,
+              const struct icsbrec_port_binding *isb_pb,
+              const struct nbrec_logical_switch *ls)
+{
+    const struct nbrec_logical_switch_port *lsp =
+        nbrec_logical_switch_port_insert(ctx->ovnnb_idl_txn);
+    nbrec_logical_switch_port_set_name(lsp, isb_pb->logical_port);
+    nbrec_logical_switch_port_set_type(lsp, "remote");
+
+    bool up = true;
+    nbrec_logical_switch_port_set_up(lsp, &up, 1);
+
+    if (isb_pb->address[0]) {
+        nbrec_logical_switch_port_set_addresses(
+            lsp, (const char **)&isb_pb->address, 1);
+    }
+    sync_lsp_tnl_key(lsp, isb_pb->tunnel_key);
+    nbrec_logical_switch_update_ports_addvalue(ls, lsp);
+}
+
+static uint32_t
+allocate_port_key(struct hmap *pb_tnlids)
+{
+    static uint32_t hint;
+    return ovn_allocate_tnlid(pb_tnlids, "transit port",
+                              1, (1u << 15) - 1, &hint);
+}
+
+static const struct icsbrec_port_binding *
+create_isb_pb(const struct engine_context *ctx, const char *logical_port,
+              const struct icsbrec_availability_zone *az, const char *ts_name,
+              const struct uuid *nb_ic_uuid, const char *type,
+              struct hmap *pb_tnlids)
+{
+    uint32_t pb_tnl_key = allocate_port_key(pb_tnlids);
+    if (!pb_tnl_key) {
+        return NULL;
+    }
+
+    const struct icsbrec_port_binding *isb_pb =
+        icsbrec_port_binding_insert(ctx->ovnisb_idl_txn);
+    icsbrec_port_binding_set_availability_zone(isb_pb, az);
+    icsbrec_port_binding_set_transit_switch(isb_pb, ts_name);
+    icsbrec_port_binding_set_logical_port(isb_pb, logical_port);
+    icsbrec_port_binding_set_tunnel_key(isb_pb, pb_tnl_key);
+    icsbrec_port_binding_set_nb_ic_uuid(isb_pb, nb_ic_uuid, 1);
+    icsbrec_port_binding_set_type(isb_pb, type);
+    return isb_pb;
+}
+
+static bool
+trp_is_remote(struct pb_input *pb, const char *chassis_name)
+{
+    if (chassis_name) {
+        const struct sbrec_chassis *chassis =
+            find_sb_chassis(pb, chassis_name);
+        if (chassis) {
+            return smap_get_bool(&chassis->other_config, "is-remote", false);
+        } else {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+static struct nbrec_logical_router_port *
+lrp_create(const struct engine_context *ctx,
+           const struct nbrec_logical_router *lr,
+           const struct icnbrec_transit_router_port *trp)
+{
+    struct nbrec_logical_router_port *lrp =
+        nbrec_logical_router_port_insert(ctx->ovnnb_idl_txn);
+    nbrec_logical_router_port_set_name(lrp, trp->name);
+
+    nbrec_logical_router_port_update_options_setkey(lrp, "interconn-tr",
+                                                    trp->name);
+    nbrec_logical_router_update_ports_addvalue(lr, lrp);
+    return lrp;
+}
+
+static void
+sync_ts_isb_pb(struct pb_input *pb, const struct sbrec_port_binding *sb_pb,
+               const struct icsbrec_port_binding *isb_pb)
+{
+    const char *address = get_lp_address_for_sb_pb(pb, sb_pb);
+    if (address) {
+        icsbrec_port_binding_set_address(isb_pb, address);
+    }
+
+    const struct sbrec_port_binding *crp = find_crp_for_sb_pb(pb, sb_pb);
+    if (crp && crp->chassis) {
+        icsbrec_port_binding_set_gateway(isb_pb, crp->chassis->name);
+    }
+
+    update_isb_pb_external_ids(pb, sb_pb, isb_pb);
+
+    /* Sync encap so that multiple encaps can be used for the same
+     * gateway.  However, it is not needed for now, since we don't yet
+     * support specifying encap type/ip for gateway chassis or ha-chassis
+     * for logical router port in NB DB, and now encap should always be
+     * empty.  The sync can be added if we add such support for gateway
+     * chassis/ha-chassis in NB DB. */
+}
+
+static const struct sbrec_port_binding *
+find_lsp_in_sb(struct pb_input *pb,
+               const struct nbrec_logical_switch_port *lsp)
+{
+    return find_sb_pb_by_name(pb->sbrec_port_binding_by_name, lsp->name);
+}
diff --git a/ic/en-port-binding.h b/ic/en-port-binding.h
new file mode 100644
index 000000000..e5f10dced
--- /dev/null
+++ b/ic/en-port-binding.h
@@ -0,0 +1,36 @@
+#ifndef EN_IC_PORT_BINDING_H
+#define EN_IC_PORT_BINDING_H 1
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* OVN includes. */
+#include "lib/inc-proc-eng.h"
+
+struct ed_type_port_binding {
+    struct hmap pb_tnlids;
+    struct shash switch_all_local_pbs;
+    struct shash router_all_local_pbs;
+};
+
+struct pb_input {
+    /* Indexes */
+    const struct icsbrec_availability_zone *runned_az;
+    struct ovsdb_idl_index *nbrec_ls_by_name;
+    struct ovsdb_idl_index *nbrec_port_by_name;
+    struct ovsdb_idl_index *nbrec_lr_by_name;
+    struct ovsdb_idl_index *sbrec_port_binding_by_name;
+    struct ovsdb_idl_index *sbrec_chassis_by_name;
+    struct ovsdb_idl_index *icsbrec_port_binding_by_az;
+    struct ovsdb_idl_index *icsbrec_port_binding_by_ts;
+};
+
+void *en_port_binding_init(struct engine_node *, struct engine_arg *);
+enum engine_node_state en_port_binding_run(struct engine_node *, void *data);
+void en_port_binding_cleanup(void *data);
+
+#endif
diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c
index e907a902a..ac360fb9f 100644
--- a/ic/inc-proc-ic.c
+++ b/ic/inc-proc-ic.c
@@ -28,6 +28,7 @@
 #include "inc-proc-ic.h"
 #include "en-ic.h"
 #include "en-enum-datapaths.h"
+#include "en-port-binding.h"
 #include "unixctl.h"
 #include "util.h"
 
@@ -160,6 +161,7 @@ VLOG_DEFINE_THIS_MODULE(inc_proc_ic);
  * avoid sparse errors. */
 static ENGINE_NODE(ic, SB_WRITE);
 static ENGINE_NODE(enum_datapaths);
+static ENGINE_NODE(port_binding, SB_WRITE);
 
 void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
                       struct ovsdb_idl_loop *sb,
@@ -171,7 +173,16 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
     engine_add_input(&en_enum_datapaths, &en_icnb_transit_switch, NULL);
     engine_add_input(&en_enum_datapaths, &en_icsb_datapath_binding, NULL);
 
+    engine_add_input(&en_port_binding, &en_icnb_transit_switch, NULL);
+    engine_add_input(&en_port_binding, &en_icnb_transit_router, NULL);
+    engine_add_input(&en_port_binding, &en_icsb_port_binding, NULL);
+    engine_add_input(&en_port_binding, &en_nb_logical_switch, NULL);
+    engine_add_input(&en_port_binding, &en_sb_port_binding, NULL);
+    engine_add_input(&en_port_binding, &en_nb_logical_router, NULL);
+    engine_add_input(&en_port_binding, &en_sb_chassis, NULL);
+
     engine_add_input(&en_ic, &en_enum_datapaths, NULL);
+    engine_add_input(&en_ic, &en_port_binding, NULL);
     engine_add_input(&en_ic, &en_nb_nb_global, NULL);
     engine_add_input(&en_ic, &en_nb_logical_router_static_route, NULL);
     engine_add_input(&en_ic, &en_nb_logical_router, NULL);
@@ -193,11 +204,11 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
     engine_add_input(&en_ic, &en_icnb_transit_router, NULL);
     engine_add_input(&en_ic, &en_icnb_transit_router_port, NULL);
 
+    engine_add_input(&en_ic, &en_icsb_port_binding, NULL);
     engine_add_input(&en_ic, &en_icsb_ic_sb_global, NULL);
     engine_add_input(&en_ic, &en_icsb_availability_zone, NULL);
     engine_add_input(&en_ic, &en_icsb_encap, NULL);
     engine_add_input(&en_ic, &en_icsb_service_monitor, NULL);
-    engine_add_input(&en_ic, &en_icsb_port_binding, NULL);
     engine_add_input(&en_ic, &en_icsb_gateway, NULL);
     engine_add_input(&en_ic, &en_icsb_route, NULL);
     engine_add_input(&en_ic, &en_icsb_datapath_binding, NULL);
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index 3ad40583e..7bde85854 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -70,9 +70,6 @@ static const char *ssl_private_key_file;
 static const char *ssl_certificate_file;
 static const char *ssl_ca_cert_file;
 
-static const struct sbrec_port_binding * find_sb_pb_by_name(
-    struct ovsdb_idl_index *sbrec_port_binding_by_name, const char *name);
-
 
 static void
 usage(void)
@@ -172,7 +169,7 @@ allocate_dp_key(struct hmap *dp_tnlids, bool vxlan_mode, 
const char *name)
             &hint);
 }
 
-static enum ic_port_binding_type
+enum ic_port_binding_type
 ic_pb_get_type(const struct icsbrec_port_binding *isb_pb)
 {
     if (isb_pb->type && !strcmp(isb_pb->type, "transit-router-port")) {
@@ -579,16 +576,30 @@ gateway_run(struct engine_context *ctx,
     shash_destroy(&remote_gws);
 }
 
-static const struct nbrec_logical_switch *
-find_ts_in_nb(struct ic_input *ic, char *ts_name)
+const struct nbrec_logical_router_port *
+get_lrp_by_lrp_name(struct ic_input *ic, const char *lrp_name)
+{
+    const struct nbrec_logical_router_port *lrp;
+    const struct nbrec_logical_router_port *lrp_key =
+        nbrec_logical_router_port_index_init_row(ic->nbrec_lrp_by_name);
+    nbrec_logical_router_port_index_set_name(lrp_key, lrp_name);
+    lrp =
+        nbrec_logical_router_port_index_find(ic->nbrec_lrp_by_name, lrp_key);
+    nbrec_logical_router_port_index_destroy_row(lrp_key);
+
+    return lrp;
+}
+
+const struct nbrec_logical_switch *
+find_ts_in_nb(struct ovsdb_idl_index *nbrec_ls_by_name, char *ts_name)
 {
     const struct nbrec_logical_switch *key =
-        nbrec_logical_switch_index_init_row(ic->nbrec_ls_by_name);
+        nbrec_logical_switch_index_init_row(nbrec_ls_by_name);
     nbrec_logical_switch_index_set_name(key, ts_name);
 
     const struct nbrec_logical_switch *ls;
     bool found = false;
-    NBREC_LOGICAL_SWITCH_FOR_EACH_EQUAL (ls, key, ic->nbrec_ls_by_name) {
+    NBREC_LOGICAL_SWITCH_FOR_EACH_EQUAL (ls, key, nbrec_ls_by_name) {
         const char *ls_ts_name = smap_get(&ls->other_config, "interconn-ts");
         if (ls_ts_name && !strcmp(ts_name, ls_ts_name)) {
             found = true;
@@ -603,31 +614,21 @@ find_ts_in_nb(struct ic_input *ic, char *ts_name)
     return NULL;
 }
 
-static const struct nbrec_logical_router *
-find_tr_in_nb(struct ic_input *ic, char *tr_name)
+const struct nbrec_logical_switch_port *
+get_lsp_by_ts_port_name(struct ovsdb_idl_index *nbrec_port_by_name,
+                        const char *ts_port_name)
 {
-    const struct nbrec_logical_router *key =
-        nbrec_logical_router_index_init_row(ic->nbrec_lr_by_name);
-    nbrec_logical_router_index_set_name(key, tr_name);
-
-    const struct nbrec_logical_router *lr;
-    bool found = false;
-    NBREC_LOGICAL_ROUTER_FOR_EACH_EQUAL (lr, key, ic->nbrec_lr_by_name) {
-        if (smap_get(&lr->options, "interconn-tr")) {
-            found = true;
-            break;
-        }
-    }
+    const struct nbrec_logical_switch_port *lsp, *key;
 
-    nbrec_logical_router_index_destroy_row(key);
-    if (found) {
-        return lr;
-    }
+    key = nbrec_logical_switch_port_index_init_row(nbrec_port_by_name);
+    nbrec_logical_switch_port_index_set_name(key, ts_port_name);
+    lsp = nbrec_logical_switch_port_index_find(nbrec_port_by_name, key);
+    nbrec_logical_switch_port_index_destroy_row(key);
 
-    return NULL;
+    return lsp;
 }
 
-static const struct sbrec_port_binding *
+const struct sbrec_port_binding *
 find_sb_pb_by_name(struct ovsdb_idl_index *sbrec_port_binding_by_name,
                    const char *name)
 {
@@ -642,641 +643,6 @@ find_sb_pb_by_name(struct ovsdb_idl_index 
*sbrec_port_binding_by_name,
     return pb;
 }
 
-static const struct sbrec_port_binding *
-find_peer_port(struct ic_input *ic,
-               const struct sbrec_port_binding *sb_pb)
-{
-    const char *peer_name = smap_get(&sb_pb->options, "peer");
-    if (!peer_name) {
-        return NULL;
-    }
-
-    return find_sb_pb_by_name(ic->sbrec_port_binding_by_name, peer_name);
-}
-
-static const struct sbrec_port_binding *
-find_crp_from_lrp(struct ic_input *ic,
-                  const struct sbrec_port_binding *lrp_pb)
-{
-    char *crp_name = ovn_chassis_redirect_name(lrp_pb->logical_port);
-
-    const struct sbrec_port_binding *pb =
-        find_sb_pb_by_name(ic->sbrec_port_binding_by_name, crp_name);
-
-    free(crp_name);
-    return pb;
-}
-
-static const struct sbrec_port_binding *
-find_crp_for_sb_pb(struct ic_input *ic,
-                   const struct sbrec_port_binding *sb_pb)
-{
-    const struct sbrec_port_binding *peer = find_peer_port(ic, sb_pb);
-    if (!peer) {
-        return NULL;
-    }
-
-    return find_crp_from_lrp(ic, peer);
-}
-
-static const struct nbrec_logical_switch_port *
-get_lsp_by_ts_port_name(struct ic_input *ic, const char *ts_port_name)
-{
-    const struct nbrec_logical_switch_port *lsp, *key;
-
-    key = nbrec_logical_switch_port_index_init_row(ic->nbrec_port_by_name);
-    nbrec_logical_switch_port_index_set_name(key, ts_port_name);
-    lsp = nbrec_logical_switch_port_index_find(ic->nbrec_port_by_name, key);
-    nbrec_logical_switch_port_index_destroy_row(key);
-
-    return lsp;
-}
-
-static const char *
-get_lp_address_for_sb_pb(struct ic_input *ic,
-                         const struct sbrec_port_binding *sb_pb)
-{
-    const struct nbrec_logical_switch_port *nb_lsp;
-
-    nb_lsp = get_lsp_by_ts_port_name(ic, sb_pb->logical_port);
-    if (!strcmp(nb_lsp->type, "switch")) {
-        /* Switches always have implicit "unknown" address, and IC-SB port
-         * binding can only have one address specified. */
-        return "unknown";
-    }
-
-    const struct sbrec_port_binding *peer = find_peer_port(ic, sb_pb);
-    if (!peer) {
-        return NULL;
-    }
-
-    return peer->n_mac ? *peer->mac : NULL;
-}
-
-static const struct sbrec_chassis *
-find_sb_chassis(struct ic_input *ic, const char *name)
-{
-    const struct sbrec_chassis *key =
-        sbrec_chassis_index_init_row(ic->sbrec_chassis_by_name);
-    sbrec_chassis_index_set_name(key, name);
-
-    const struct sbrec_chassis *chassis =
-        sbrec_chassis_index_find(ic->sbrec_chassis_by_name, key);
-    sbrec_chassis_index_destroy_row(key);
-
-    return chassis;
-}
-
-static void
-sync_lsp_tnl_key(const struct nbrec_logical_switch_port *lsp,
-                 int64_t isb_tnl_key)
-{
-    int64_t tnl_key = smap_get_int(&lsp->options, "requested-tnl-key", 0);
-    if (tnl_key != isb_tnl_key) {
-        VLOG_DBG("Set options:requested-tnl-key %"PRId64
-                 " for lsp %s in NB.", isb_tnl_key, lsp->name);
-        char *tnl_key_str = xasprintf("%"PRId64, isb_tnl_key);
-        nbrec_logical_switch_port_update_options_setkey(lsp,
-                                                        "requested-tnl-key",
-                                                        tnl_key_str);
-        free(tnl_key_str);
-    }
-
-}
-
-static inline void
-sync_lrp_tnl_key(const struct nbrec_logical_router_port *lrp,
-                 int64_t isb_tnl_key)
-{
-    int64_t tnl_key = smap_get_int(&lrp->options, "requested-tnl-key", 0);
-    if (tnl_key != isb_tnl_key) {
-        VLOG_DBG("Set options:requested-tnl-key %" PRId64 " for lrp %s in NB.",
-                 isb_tnl_key, lrp->name);
-        char *tnl_key_str = xasprintf("%"PRId64, isb_tnl_key);
-        nbrec_logical_router_port_update_options_setkey(
-            lrp, "requested-tnl-key", tnl_key_str);
-        free(tnl_key_str);
-    }
-}
-
-static bool
-get_router_uuid_by_sb_pb(struct ic_input *ic,
-                         const struct sbrec_port_binding *sb_pb,
-                         struct uuid *router_uuid)
-{
-    const struct sbrec_port_binding *router_pb = find_peer_port(ic, sb_pb);
-    if (!router_pb || !router_pb->datapath) {
-        return NULL;
-    }
-
-    return datapath_get_nb_uuid(router_pb->datapath, router_uuid);
-}
-
-static void
-update_isb_pb_external_ids(struct ic_input *ic,
-                           const struct sbrec_port_binding *sb_pb,
-                           const struct icsbrec_port_binding *isb_pb)
-{
-    struct uuid lr_uuid;
-    if (!get_router_uuid_by_sb_pb(ic, sb_pb, &lr_uuid)) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
-        VLOG_WARN_RL(&rl, "Can't get router uuid for transit switch port %s.",
-                     isb_pb->logical_port);
-        return;
-    }
-
-    struct uuid current_lr_uuid;
-    if (smap_get_uuid(&isb_pb->external_ids, "router-id", &current_lr_uuid) &&
-        uuid_equals(&lr_uuid, &current_lr_uuid)) {
-        return;
-    }
-
-    char *uuid_s = xasprintf(UUID_FMT, UUID_ARGS(&lr_uuid));
-    icsbrec_port_binding_update_external_ids_setkey(isb_pb, "router-id",
-                                                    uuid_s);
-    free(uuid_s);
-}
-
-/* For each local port:
- *   - Sync from NB to ISB.
- *   - Sync gateway from SB to ISB.
- *   - Sync tunnel key from ISB to NB.
- */
-static void
-sync_local_port(struct ic_input *ic,
-                const struct icsbrec_port_binding *isb_pb,
-                const struct sbrec_port_binding *sb_pb,
-                const struct nbrec_logical_switch_port *lsp)
-{
-    /* Sync address from NB to ISB */
-    const char *address = get_lp_address_for_sb_pb(ic, sb_pb);
-    if (!address) {
-        VLOG_DBG("Can't get router/switch port address for logical"
-                 " switch port %s", sb_pb->logical_port);
-        if (isb_pb->address[0]) {
-            icsbrec_port_binding_set_address(isb_pb, "");
-        }
-    } else {
-        if (strcmp(address, isb_pb->address)) {
-            icsbrec_port_binding_set_address(isb_pb, address);
-        }
-    }
-
-    /* Sync gateway from SB to ISB */
-    const struct sbrec_port_binding *crp = find_crp_for_sb_pb(ic, sb_pb);
-    if (crp && crp->chassis) {
-        if (strcmp(crp->chassis->name, isb_pb->gateway)) {
-            icsbrec_port_binding_set_gateway(isb_pb, crp->chassis->name);
-        }
-    } else if (!strcmp(lsp->type, "switch") && sb_pb->chassis) {
-        if (strcmp(sb_pb->chassis->name, isb_pb->gateway)) {
-            icsbrec_port_binding_set_gateway(isb_pb, sb_pb->chassis->name);
-        }
-    } else {
-        if (isb_pb->gateway[0]) {
-            icsbrec_port_binding_set_gateway(isb_pb, "");
-        }
-    }
-
-    /* Sync external_ids:router-id to ISB */
-    update_isb_pb_external_ids(ic, sb_pb, isb_pb);
-
-    /* Sync back tunnel key from ISB to NB */
-    sync_lsp_tnl_key(lsp, isb_pb->tunnel_key);
-}
-
-/* For each remote port:
- *   - Sync from ISB to NB
- *   - Sync gateway from ISB to SB
- */
-static void
-sync_remote_port(struct ic_input *ic,
-                 const struct icsbrec_port_binding *isb_pb,
-                 const struct nbrec_logical_switch_port *lsp,
-                 const struct sbrec_port_binding *sb_pb)
-{
-    /* Sync address from ISB to NB */
-    if (isb_pb->address[0]) {
-        if (lsp->n_addresses != 1 ||
-            strcmp(isb_pb->address, lsp->addresses[0])) {
-            nbrec_logical_switch_port_set_addresses(
-                lsp, (const char **)&isb_pb->address, 1);
-        }
-    } else {
-        if (lsp->n_addresses != 0) {
-            nbrec_logical_switch_port_set_addresses(lsp, NULL, 0);
-        }
-    }
-
-    /* Sync tunnel key from ISB to NB */
-    sync_lsp_tnl_key(lsp, isb_pb->tunnel_key);
-
-    /* Skip port binding if it is already requested by the CMS. */
-    if (smap_get(&lsp->options, "requested-chassis")) {
-        return;
-    }
-
-    /* Sync gateway from ISB to SB */
-    if (isb_pb->gateway[0]) {
-        if (!sb_pb->chassis || strcmp(sb_pb->chassis->name, isb_pb->gateway)) {
-            const struct sbrec_chassis *chassis =
-                find_sb_chassis(ic, isb_pb->gateway);
-            if (!chassis) {
-                VLOG_DBG("Chassis %s is not found in SB, syncing from ISB "
-                         "to SB skipped for logical port %s.",
-                         isb_pb->gateway, lsp->name);
-                return;
-            }
-            sbrec_port_binding_set_chassis(sb_pb, chassis);
-        }
-    } else {
-        if (sb_pb->chassis) {
-            sbrec_port_binding_set_chassis(sb_pb, NULL);
-        }
-    }
-}
-
-/* For each remote port:
- *   - Sync from ISB to NB
- */
-static void
-sync_router_port(const struct icsbrec_port_binding *isb_pb,
-                 const struct icnbrec_transit_router_port *trp,
-                 const struct nbrec_logical_router_port *lrp)
-{
-    /* Sync from ICNB to NB */
-    if (trp->chassis[0]) {
-        const char *chassis_name =
-            smap_get_def(&lrp->options, "requested-chassis", "");
-        if (strcmp(trp->chassis, chassis_name)) {
-            nbrec_logical_router_port_update_options_setkey(
-                lrp, "requested-chassis", trp->chassis);
-        }
-    } else {
-        nbrec_logical_router_port_update_options_delkey(
-            lrp, "requested-chassis");
-    }
-
-    if (strcmp(trp->mac, lrp->mac)) {
-        nbrec_logical_router_port_set_mac(lrp, trp->mac);
-    }
-
-    bool sync_networks = false;
-    if (trp->n_networks != lrp->n_networks) {
-        sync_networks = true;
-    } else {
-        for (size_t i = 0; i < trp->n_networks; i++) {
-            if (strcmp(trp->networks[i], lrp->networks[i])) {
-                sync_networks |= true;
-                break;
-            }
-        }
-    }
-
-    if (sync_networks) {
-        nbrec_logical_router_port_set_networks(
-            lrp, (const char **) trp->networks, trp->n_networks);
-    }
-
-    /* Sync tunnel key from ISB to NB */
-    sync_lrp_tnl_key(lrp, isb_pb->tunnel_key);
-}
-
-static void
-create_nb_lsp(struct engine_context *ctx,
-              const struct icsbrec_port_binding *isb_pb,
-              const struct nbrec_logical_switch *ls)
-{
-    const struct nbrec_logical_switch_port *lsp =
-        nbrec_logical_switch_port_insert(ctx->ovnnb_idl_txn);
-    nbrec_logical_switch_port_set_name(lsp, isb_pb->logical_port);
-    nbrec_logical_switch_port_set_type(lsp, "remote");
-
-    bool up = true;
-    nbrec_logical_switch_port_set_up(lsp, &up, 1);
-
-    if (isb_pb->address[0]) {
-        nbrec_logical_switch_port_set_addresses(
-            lsp, (const char **)&isb_pb->address, 1);
-    }
-    sync_lsp_tnl_key(lsp, isb_pb->tunnel_key);
-    nbrec_logical_switch_update_ports_addvalue(ls, lsp);
-}
-
-static uint32_t
-allocate_port_key(struct hmap *pb_tnlids)
-{
-    static uint32_t hint;
-    return ovn_allocate_tnlid(pb_tnlids, "transit port",
-                              1, (1u << 15) - 1, &hint);
-}
-
-static const struct icsbrec_port_binding *
-create_isb_pb(struct engine_context *ctx, const char *logical_port,
-              const struct icsbrec_availability_zone *az, const char *ts_name,
-              const struct uuid *nb_ic_uuid, const char *type,
-              struct hmap *pb_tnlids)
-{
-    uint32_t pb_tnl_key = allocate_port_key(pb_tnlids);
-    if (!pb_tnl_key) {
-        return NULL;
-    }
-
-    const struct icsbrec_port_binding *isb_pb =
-        icsbrec_port_binding_insert(ctx->ovnisb_idl_txn);
-    icsbrec_port_binding_set_availability_zone(isb_pb, az);
-    icsbrec_port_binding_set_transit_switch(isb_pb, ts_name);
-    icsbrec_port_binding_set_logical_port(isb_pb, logical_port);
-    icsbrec_port_binding_set_tunnel_key(isb_pb, pb_tnl_key);
-    icsbrec_port_binding_set_nb_ic_uuid(isb_pb, nb_ic_uuid, 1);
-    icsbrec_port_binding_set_type(isb_pb, type);
-    return isb_pb;
-}
-
-static const struct nbrec_logical_router_port *
-get_lrp_by_lrp_name(struct ic_input *ic, const char *lrp_name)
-{
-    const struct nbrec_logical_router_port *lrp;
-    const struct nbrec_logical_router_port *lrp_key =
-        nbrec_logical_router_port_index_init_row(ic->nbrec_lrp_by_name);
-    nbrec_logical_router_port_index_set_name(lrp_key, lrp_name);
-    lrp =
-        nbrec_logical_router_port_index_find(ic->nbrec_lrp_by_name, lrp_key);
-    nbrec_logical_router_port_index_destroy_row(lrp_key);
-
-    return lrp;
-}
-
-static bool
-trp_is_remote(struct ic_input *ic, const char *chassis_name)
-{
-    if (chassis_name) {
-        const struct sbrec_chassis *chassis =
-            find_sb_chassis(ic, chassis_name);
-        if (chassis) {
-            return smap_get_bool(&chassis->other_config, "is-remote", false);
-        } else {
-            return true;
-        }
-    }
-
-    return false;
-}
-
-static struct nbrec_logical_router_port *
-lrp_create(struct engine_context *ctx, const struct nbrec_logical_router *lr,
-           const struct icnbrec_transit_router_port *trp)
-{
-    struct nbrec_logical_router_port *lrp =
-        nbrec_logical_router_port_insert(ctx->ovnnb_idl_txn);
-    nbrec_logical_router_port_set_name(lrp, trp->name);
-
-    nbrec_logical_router_port_update_options_setkey(lrp, "interconn-tr",
-                                                    trp->name);
-    nbrec_logical_router_update_ports_addvalue(lr, lrp);
-    return lrp;
-}
-
-static void
-sync_ts_isb_pb(struct ic_input *ic, const struct sbrec_port_binding *sb_pb,
-               const struct icsbrec_port_binding *isb_pb)
-{
-    const char *address = get_lp_address_for_sb_pb(ic, sb_pb);
-    if (address) {
-        icsbrec_port_binding_set_address(isb_pb, address);
-    }
-
-    const struct sbrec_port_binding *crp = find_crp_for_sb_pb(ic, sb_pb);
-    if (crp && crp->chassis) {
-        icsbrec_port_binding_set_gateway(isb_pb, crp->chassis->name);
-    }
-
-    update_isb_pb_external_ids(ic, sb_pb, isb_pb);
-
-    /* XXX: Sync encap so that multiple encaps can be used for the same
-     * gateway.  However, it is not needed for now, since we don't yet
-     * support specifying encap type/ip for gateway chassis or ha-chassis
-     * for logical router port in NB DB, and now encap should always be
-     * empty.  The sync can be added if we add such support for gateway
-     * chassis/ha-chassis in NB DB. */
-}
-
-static const struct sbrec_port_binding *
-find_lsp_in_sb(struct ic_input *ic,
-               const struct nbrec_logical_switch_port *lsp)
-{
-    return find_sb_pb_by_name(ic->sbrec_port_binding_by_name, lsp->name);
-}
-
-static void
-port_binding_run(struct engine_context *ctx,
-                 struct ic_input *ic)
-{
-    if (!ctx->ovnisb_idl_txn || !ctx->ovnnb_idl_txn
-        || !ctx->ovnsb_idl_txn) {
-        return;
-    }
-
-    struct shash switch_all_local_pbs =
-        SHASH_INITIALIZER(&switch_all_local_pbs);
-    struct shash router_all_local_pbs =
-        SHASH_INITIALIZER(&router_all_local_pbs);
-    struct hmap pb_tnlids = HMAP_INITIALIZER(&pb_tnlids);
-    struct shash_node *node;
-
-    const struct icsbrec_port_binding *isb_pb;
-    const struct icsbrec_port_binding *isb_pb_key =
-        icsbrec_port_binding_index_init_row(ic->icsbrec_port_binding_by_az);
-    icsbrec_port_binding_index_set_availability_zone(isb_pb_key,
-                                                     ic->runned_az);
-
-    ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
-                                         ic->icsbrec_port_binding_by_az) {
-        ic_pb_get_type(isb_pb) != IC_ROUTER_PORT
-            ? shash_add(&switch_all_local_pbs, isb_pb->logical_port, isb_pb)
-            : shash_add(&router_all_local_pbs, isb_pb->logical_port, isb_pb);
-
-        ovn_add_tnlid(&pb_tnlids, isb_pb->tunnel_key);
-    }
-    icsbrec_port_binding_index_destroy_row(isb_pb_key);
-
-    const struct sbrec_port_binding *sb_pb;
-    const struct icnbrec_transit_switch *ts;
-    ICNBREC_TRANSIT_SWITCH_TABLE_FOR_EACH (ts,
-                                           ic->icnbrec_transit_switch_table) {
-        const struct nbrec_logical_switch *ls = find_ts_in_nb(ic, ts->name);
-        if (!ls) {
-            VLOG_DBG("Transit switch %s not found in NB.", ts->name);
-            continue;
-        }
-        struct shash local_pbs = SHASH_INITIALIZER(&local_pbs);
-        struct shash remote_pbs = SHASH_INITIALIZER(&remote_pbs);
-
-        isb_pb_key = icsbrec_port_binding_index_init_row(
-            ic->icsbrec_port_binding_by_ts);
-        icsbrec_port_binding_index_set_transit_switch(isb_pb_key, ts->name);
-
-        ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
-                                             ic->icsbrec_port_binding_by_ts) {
-            if (isb_pb->availability_zone == ic->runned_az) {
-                shash_add(&local_pbs, isb_pb->logical_port, isb_pb);
-                shash_find_and_delete(&switch_all_local_pbs,
-                                      isb_pb->logical_port);
-            } else {
-                shash_add(&remote_pbs, isb_pb->logical_port, isb_pb);
-            }
-        }
-        icsbrec_port_binding_index_destroy_row(isb_pb_key);
-
-        const struct nbrec_logical_switch_port *lsp;
-        for (int i = 0; i < ls->n_ports; i++) {
-            lsp = ls->ports[i];
-
-            if (!strcmp(lsp->type, "router")
-                || !strcmp(lsp->type, "switch")) {
-                /* The port is local. */
-                sb_pb = find_lsp_in_sb(ic, lsp);
-                if (!sb_pb) {
-                    continue;
-                }
-                isb_pb = shash_find_and_delete(&local_pbs, lsp->name);
-                if (!isb_pb) {
-                    isb_pb = create_isb_pb(
-                        ctx, sb_pb->logical_port, ic->runned_az, ts->name,
-                        &ts->header_.uuid, "transit-switch-port", &pb_tnlids);
-                    sync_ts_isb_pb(ic, sb_pb, isb_pb);
-                } else {
-                    sync_local_port(ic, isb_pb, sb_pb, lsp);
-                }
-
-                if (isb_pb->type) {
-                    icsbrec_port_binding_set_type(isb_pb,
-                                                  "transit-switch-port");
-                }
-
-                if (isb_pb->nb_ic_uuid) {
-                    icsbrec_port_binding_set_nb_ic_uuid(isb_pb,
-                                                        &ts->header_.uuid, 1);
-                }
-            } else if (!strcmp(lsp->type, "remote")) {
-                /* The port is remote. */
-                isb_pb = shash_find_and_delete(&remote_pbs, lsp->name);
-                if (!isb_pb) {
-                    nbrec_logical_switch_update_ports_delvalue(ls, lsp);
-                } else {
-                    sb_pb = find_lsp_in_sb(ic, lsp);
-                    if (!sb_pb) {
-                        continue;
-                    }
-                    sync_remote_port(ic, isb_pb, lsp, sb_pb);
-                }
-            } else {
-                VLOG_DBG("Ignore lsp %s on ts %s with type %s.",
-                         lsp->name, ts->name, lsp->type);
-            }
-        }
-
-        /* Delete extra port-binding from ISB */
-        SHASH_FOR_EACH (node, &local_pbs) {
-            icsbrec_port_binding_delete(node->data);
-        }
-
-        /* Create lsp in NB for remote ports */
-        SHASH_FOR_EACH (node, &remote_pbs) {
-            create_nb_lsp(ctx, node->data, ls);
-        }
-
-        shash_destroy(&local_pbs);
-        shash_destroy(&remote_pbs);
-    }
-
-    SHASH_FOR_EACH (node, &switch_all_local_pbs) {
-        icsbrec_port_binding_delete(node->data);
-    }
-    shash_destroy(&switch_all_local_pbs);
-
-    const struct icnbrec_transit_router *tr;
-    ICNBREC_TRANSIT_ROUTER_TABLE_FOR_EACH (tr,
-                                           ic->icnbrec_transit_router_table) {
-        const struct nbrec_logical_router *lr = find_tr_in_nb(ic, tr->name);
-        if (!lr) {
-            VLOG_DBG("Transit router %s not found in NB.", tr->name);
-            continue;
-        }
-
-        struct shash nb_ports = SHASH_INITIALIZER(&nb_ports);
-        struct shash local_pbs = SHASH_INITIALIZER(&local_pbs);
-        struct shash remote_pbs = SHASH_INITIALIZER(&remote_pbs);
-
-        for (size_t i = 0; i < lr->n_ports; i++) {
-            const struct nbrec_logical_router_port *lrp = lr->ports[i];
-            if (smap_get_def(&lrp->options, "interconn-tr", NULL)) {
-                shash_add(&nb_ports, lrp->name, lrp);
-            }
-        }
-
-        isb_pb_key = icsbrec_port_binding_index_init_row(
-            ic->icsbrec_port_binding_by_ts);
-        icsbrec_port_binding_index_set_transit_switch(isb_pb_key, tr->name);
-
-        ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key,
-                                             ic->icsbrec_port_binding_by_ts) {
-            if (isb_pb->availability_zone == ic->runned_az) {
-                shash_add(&local_pbs, isb_pb->logical_port, isb_pb);
-                shash_find_and_delete(&router_all_local_pbs,
-                                      isb_pb->logical_port);
-            } else {
-                shash_add(&remote_pbs, isb_pb->logical_port, isb_pb);
-            }
-        }
-        icsbrec_port_binding_index_destroy_row(isb_pb_key);
-
-        for (size_t i = 0; i < tr->n_ports; i++) {
-            const struct icnbrec_transit_router_port *trp = tr->ports[i];
-
-            if (trp_is_remote(ic, trp->chassis)) {
-                isb_pb = shash_find_and_delete(&remote_pbs, trp->name);
-            } else {
-                isb_pb = shash_find_and_delete(&local_pbs, trp->name);
-                if (!isb_pb) {
-                    isb_pb = create_isb_pb(ctx, trp->name, ic->runned_az,
-                                           tr->name, &tr->header_.uuid,
-                                           "transit-router-port", &pb_tnlids);
-                    icsbrec_port_binding_set_address(isb_pb, trp->mac);
-                }
-            }
-
-            /* Don't allow remote ports to create NB LRP until ICSB entry is
-             * created in the appropriate AZ. */
-            if (isb_pb) {
-                const struct nbrec_logical_router_port *lrp =
-                    shash_find_and_delete(&nb_ports, trp->name);
-                if (!lrp) {
-                    lrp = lrp_create(ctx, lr, trp);
-                }
-
-                sync_router_port(isb_pb, trp, lrp);
-            }
-        }
-
-        SHASH_FOR_EACH(node, &nb_ports) {
-            nbrec_logical_router_port_delete(node->data);
-            nbrec_logical_router_update_ports_delvalue(lr, node->data);
-        }
-
-        shash_destroy(&nb_ports);
-        shash_destroy(&local_pbs);
-        shash_destroy(&remote_pbs);
-    }
-
-    SHASH_FOR_EACH (node, &router_all_local_pbs) {
-        icsbrec_port_binding_delete(node->data);
-    }
-
-    ovn_destroy_tnlids(&pb_tnlids);
-    shash_destroy(&router_all_local_pbs);
-}
-
 struct ic_router_info {
     struct hmap_node node;
     const struct nbrec_logical_router *lr; /* key of hmap */
@@ -1948,7 +1314,7 @@ get_lrp_name_by_ts_port_name(struct ic_input *ic, const 
char *ts_port_name)
 {
     const struct nbrec_logical_switch_port *nb_lsp;
 
-    nb_lsp = get_lsp_by_ts_port_name(ic, ts_port_name);
+    nb_lsp = get_lsp_by_ts_port_name(ic->nbrec_port_by_name, ts_port_name);
     if (!nb_lsp) {
         return NULL;
     }
@@ -1962,7 +1328,7 @@ find_lrp_of_nexthop(struct ic_input *ic,
 {
     const struct nbrec_logical_router_port *lrp;
     const struct nbrec_logical_switch *ls;
-    ls = find_ts_in_nb(ic, isb_route->transit_switch);
+    ls = find_ts_in_nb(ic->nbrec_ls_by_name, isb_route->transit_switch);
     if (!ls) {
         return NULL;
     }
@@ -2502,7 +1868,8 @@ route_run(struct engine_context *ctx,
         }
         const struct nbrec_logical_switch_port *nb_lsp;
 
-        nb_lsp = get_lsp_by_ts_port_name(ic, isb_pb->logical_port);
+        nb_lsp = get_lsp_by_ts_port_name(ic->nbrec_port_by_name,
+                                         isb_pb->logical_port);
         if (!strcmp(nb_lsp->type, "switch")) {
             VLOG_DBG("IC-SB Port_Binding '%s' on ts '%s' corresponds to a "
                      "switch port, not considering for route collection.",
@@ -3118,7 +2485,6 @@ ovn_db_run(struct ic_input *input_data,
     gateway_run(eng_ctx, input_data);
     ts_run(eng_ctx, input_data, ic_data->dp_tnlids, ic_data->isb_ts_dps);
     tr_run(eng_ctx, input_data, ic_data->dp_tnlids, ic_data->isb_tr_dps);
-    port_binding_run(eng_ctx, input_data);
     route_run(eng_ctx, input_data);
     sync_service_monitor(eng_ctx, input_data);
 }
@@ -3524,6 +2890,7 @@ main(int argc, char *argv[])
     stopwatch_create(OVN_IC_LOOP_STOPWATCH_NAME, SW_MS);
     stopwatch_create(IC_OVN_DB_RUN_STOPWATCH_NAME, SW_MS);
     stopwatch_create(OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME, SW_MS);
+    stopwatch_create(OVN_IC_PORT_BINDING_RUN_STOPWATCH_NAME, SW_MS);
 
     /* Initialize incremental processing engine for ovn-northd */
     inc_proc_ic_init(&ovnnb_idl_loop, &ovnsb_idl_loop,
diff --git a/ic/ovn-ic.h b/ic/ovn-ic.h
index 9b0009274..ff6317786 100644
--- a/ic/ovn-ic.h
+++ b/ic/ovn-ic.h
@@ -55,8 +55,6 @@ struct ic_input {
     struct ovsdb_idl_index *sbrec_service_monitor_by_remote_type_logical_port;
     struct ovsdb_idl_index *icnbrec_transit_switch_by_name;
     struct ovsdb_idl_index *icsbrec_port_binding_by_az;
-    struct ovsdb_idl_index *icsbrec_port_binding_by_ts;
-    struct ovsdb_idl_index *icsbrec_port_binding_by_ts_az;
     struct ovsdb_idl_index *icsbrec_route_by_az;
     struct ovsdb_idl_index *icsbrec_route_by_ts;
     struct ovsdb_idl_index *icsbrec_route_by_ts_az;
@@ -76,16 +74,29 @@ struct ic_state {
     bool paused;
 };
 
+struct icsbrec_port_binding;
+
 enum ic_datapath_type { IC_SWITCH, IC_ROUTER, IC_DATAPATH_MAX };
 enum ic_port_binding_type { IC_SWITCH_PORT, IC_ROUTER_PORT, IC_PORT_MAX };
 
+const struct nbrec_logical_router_port *
+    get_lrp_by_lrp_name(struct ic_input *ic, const char *lrp_name);
+const struct sbrec_port_binding * find_sb_pb_by_name(
+    struct ovsdb_idl_index *sbrec_port_binding_by_name, const char *name);
+const struct nbrec_logical_switch *
+    find_ts_in_nb(struct ovsdb_idl_index *nbrec_ls_by_name, char *ts_name);
+const struct nbrec_logical_switch_port *
+    get_lsp_by_ts_port_name(struct ovsdb_idl_index *nbrec_port_by_name,
+                            const char *ts_port_name);
+const struct sbrec_port_binding *
+    find_sb_pb_by_name(struct ovsdb_idl_index *sbrec_port_binding_by_name,
+                       const char *name);
+enum ic_port_binding_type
+    ic_pb_get_type(const struct icsbrec_port_binding *isb_pb);
 const struct icsbrec_availability_zone *
-    az_run(struct ovsdb_idl *ovnnb_idl,
-           struct ovsdb_idl *ovnisb_idl,
+    az_run(struct ovsdb_idl *ovnnb_idl, struct ovsdb_idl *ovnisb_idl,
            struct ovsdb_idl_txn *ovnisb_idl_txn);
-
-void ovn_db_run(struct ic_input *input_data,
-                struct ic_data *ic_data,
+void ovn_db_run(struct ic_input *input_data, struct ic_data *ic_data,
                 struct engine_context *eng_ctx);
 
 #endif /* OVN_IC_H */
diff --git a/lib/stopwatch-names.h b/lib/stopwatch-names.h
index 4eef534ed..bf5da699c 100644
--- a/lib/stopwatch-names.h
+++ b/lib/stopwatch-names.h
@@ -43,5 +43,6 @@
 #define OVN_IC_LOOP_STOPWATCH_NAME "ovn-ic-loop"
 #define IC_OVN_DB_RUN_STOPWATCH_NAME "ovn_db_run"
 #define OVN_IC_ENUM_DATAPATHS_RUN_STOPWATCH_NAME "enum_datapaths_run"
+#define OVN_IC_PORT_BINDING_RUN_STOPWATCH_NAME "port_binding_run"
 
 #endif
-- 
2.34.1


-- 




_'Esta mensagem é direcionada apenas para os endereços constantes no 
cabeçalho inicial. Se você não está listado nos endereços constantes no 
cabeçalho, pedimos-lhe que desconsidere completamente o conteúdo dessa 
mensagem e cuja cópia, encaminhamento e/ou execução das ações citadas estão 
imediatamente anuladas e proibidas'._


* **'Apesar do Magazine Luiza tomar 
todas as precauções razoáveis para assegurar que nenhum vírus esteja 
presente nesse e-mail, a empresa não poderá aceitar a responsabilidade por 
quaisquer perdas ou danos causados por esse e-mail ou por seus anexos'.*



_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to