Initial implementation adds a single node (ic). This single
node executes the ovn-ic processing pipeline but does not do so
incrementally.

In order to develop incremental processing for ovn-ic, the code
will be organised with a .c/.h file for each I-P node following
the naming convention en-<node name>.c/.h. These files will
contain definition of the node data, the main node processing
functions and change handlers (if any). The purpose of these nodes
will be coordination of the nodes work and implemention of the
relevant interfaces to plug into the I-P framework. The actual
work that will be executed by the node will be organised into
a companion file or files. Ideally this file will follow the
naming convention of the node: e.g. en-<node name>.c is
associated with <node name>.c.

Initial node topology sees the ic node dependent on all DB
nodes. This structure and approach was heavily influenced
by the way I+P was developed and evolved in the northd daemon.

Signed-off-by: Paulo Guilherme Silva <[email protected]>
---
 ic/automake.mk     |   7 +-
 ic/en-ic.c         |  50 +++++
 ic/en-ic.h         |  18 ++
 ic/inc-proc-ic.c   | 269 +++++++++++++++++++++++++
 ic/inc-proc-ic.h   |  48 +++++
 ic/ovn-ic.c        | 481 ++++++++++++++++++++++++++-------------------
 ic/ovn-ic.h        |  61 ++++++
 lib/inc-proc-eng.h |  21 ++
 8 files changed, 754 insertions(+), 201 deletions(-)
 create mode 100644 ic/en-ic.c
 create mode 100644 ic/en-ic.h
 create mode 100644 ic/inc-proc-ic.c
 create mode 100644 ic/inc-proc-ic.h
 create mode 100644 ic/ovn-ic.h

diff --git a/ic/automake.mk b/ic/automake.mk
index 8e71bc334..a69b1030d 100644
--- a/ic/automake.mk
+++ b/ic/automake.mk
@@ -1,6 +1,11 @@
 # ovn-ic
 bin_PROGRAMS += ic/ovn-ic
-ic_ovn_ic_SOURCES = ic/ovn-ic.c
+ic_ovn_ic_SOURCES = ic/ovn-ic.c \
+       ic/ovn-ic.h \
+       ic/en-ic.c \
+       ic/en-ic.h \
+       ic/inc-proc-ic.c \
+       ic/inc-proc-ic.h
 ic_ovn_ic_LDADD = \
        lib/libovn.la \
        $(OVSDB_LIBDIR)/libovsdb.la \
diff --git a/ic/en-ic.c b/ic/en-ic.c
new file mode 100644
index 000000000..2db9d3b84
--- /dev/null
+++ b/ic/en-ic.c
@@ -0,0 +1,50 @@
+/*
+ * 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>
+
+#include "en-ic.h"
+#include "lib/inc-proc-eng.h"
+#include "lib/stopwatch-names.h"
+#include "ovn-ic.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(en_ic);
+
+enum engine_node_state
+en_ic_run(struct engine_node *node OVS_UNUSED, void *data OVS_UNUSED)
+{
+    const struct engine_context *eng_ctx = engine_get_context();
+    struct ic_context *ctx = eng_ctx->client_ctx;
+
+    ovn_db_run(ctx);
+
+    return EN_UPDATED;
+}
+
+void *
+en_ic_init(struct engine_node *node OVS_UNUSED,
+            struct engine_arg *arg OVS_UNUSED)
+{
+    return NULL;
+}
+
+void
+en_ic_cleanup(void *data OVS_UNUSED)
+{
+}
diff --git a/ic/en-ic.h b/ic/en-ic.h
new file mode 100644
index 000000000..a4b75bb0e
--- /dev/null
+++ b/ic/en-ic.h
@@ -0,0 +1,18 @@
+#ifndef EN_IC_H
+#define EN_IC_H 1
+
+#include <config.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "lib/inc-proc-eng.h"
+
+enum engine_node_state en_ic_run(struct engine_node *node OVS_UNUSED,
+                                 void *data OVS_UNUSED);
+void *en_ic_init(struct engine_node *node OVS_UNUSED,
+                 struct engine_arg *arg);
+void en_ic_cleanup(void *data);
+
+#endif /* EN_IC_H */
diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c
new file mode 100644
index 000000000..ba9fdeb9e
--- /dev/null
+++ b/ic/inc-proc-ic.c
@@ -0,0 +1,269 @@
+/*
+ * 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>
+
+#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 "openvswitch/poll-loop.h"
+#include "openvswitch/vlog.h"
+#include "inc-proc-ic.h"
+#include "en-ic.h"
+#include "unixctl.h"
+#include "util.h"
+
+VLOG_DEFINE_THIS_MODULE(inc_proc_ic);
+
+#define NB_NODES \
+    NB_NODE(nb_global, "nb_global") \
+    NB_NODE(logical_router_static_route, "logical_router_static_route") \
+    NB_NODE(logical_router, "logical_router") \
+    NB_NODE(logical_router_port, "logical_router_port") \
+    NB_NODE(logical_switch, "logical_switch") \
+    NB_NODE(logical_switch_port, "logical_switch_port") \
+    NB_NODE(load_balancer, "load_balancer") \
+    NB_NODE(load_balancer_group, "load_balancer_group")
+
+    enum nb_engine_node {
+#define NB_NODE(NAME, NAME_STR) NB_##NAME,
+    NB_NODES
+#undef NB_NODE
+    };
+
+/* Define engine node functions for nodes that represent NB tables
+ *
+ * en_nb_<TABLE_NAME>_run()
+ * en_nb_<TABLE_NAME>_init()
+ * en_nb_<TABLE_NAME>_cleanup()
+ */
+#define NB_NODE(NAME, NAME_STR) ENGINE_FUNC_NB(NAME);
+    NB_NODES
+#undef NB_NODE
+
+#define SB_NODES \
+    SB_NODE(sb_global, "sb_global") \
+    SB_NODE(chassis, "chassis") \
+    SB_NODE(encap, "encap") \
+    SB_NODE(datapath_binding, "datapath_binding") \
+    SB_NODE(port_binding, "port_binding") \
+    SB_NODE(service_monitor, "service_monitor")
+
+    enum sb_engine_node {
+#define SB_NODE(NAME, NAME_STR) SB_##NAME,
+    SB_NODES
+#undef SB_NODE
+};
+
+/* Define engine node functions for nodes that represent SB tables
+ *
+ * en_sb_<TABLE_NAME>_run()
+ * en_sb_<TABLE_NAME>_init()
+ * en_sb_<TABLE_NAME>_cleanup()
+ */
+#define SB_NODE(NAME, NAME_STR) ENGINE_FUNC_SB(NAME);
+    SB_NODES
+#undef SB_NODE
+
+#define ICNB_NODES \
+    ICNB_NODE(ic_nb_global, "ic_nb_global") \
+    ICNB_NODE(transit_switch, "transit_switch") \
+    ICNB_NODE(transit_router, "transit_router") \
+    ICNB_NODE(transit_router_port, "transit_router_port")
+
+    enum icnb_engine_node {
+#define ICNB_NODE(NAME, NAME_STR) ICNB_##NAME,
+    ICNB_NODES
+#undef ICNB_NODE
+    };
+
+/* Define engine node functions for nodes that represent ICNB tables
+ *
+ * en_icnb_<TABLE_NAME>_run()
+ * en_icnb_<TABLE_NAME>_init()
+ * en_icnb_<TABLE_NAME>_cleanup()
+ */
+#define ICNB_NODE(NAME, NAME_STR) ENGINE_FUNC_ICNB(NAME);
+    ICNB_NODES
+#undef ICNB_NODE
+
+#define ICSB_NODES \
+    ICSB_NODE(ic_sb_global, "ic_sb_global") \
+    ICSB_NODE(availability_zone, "availability_zone") \
+    ICSB_NODE(service_monitor, "service_monitor") \
+    ICSB_NODE(route, "route") \
+    ICSB_NODE(datapath_binding, "datapath_binding") \
+    ICSB_NODE(encap, "encap") \
+    ICSB_NODE(gateway, "gateway") \
+    ICSB_NODE(port_binding, "port_binding")
+
+    enum icsb_engine_node {
+#define ICSB_NODE(NAME, NAME_STR) ICSB_##NAME,
+    ICSB_NODES
+#undef ICSB_NODE
+    };
+
+/* Define engine node functions for nodes that represent ICSB tables
+ *
+ * en_icsb_<TABLE_NAME>_run()
+ * en_icsb_<TABLE_NAME>_init()
+ * en_icsb_<TABLE_NAME>_cleanup()
+ */
+#define ICSB_NODE(NAME, NAME_STR) ENGINE_FUNC_ICSB(NAME);
+    ICSB_NODES
+#undef ICSB_NODE
+
+/* Define engine nodes for NB, SB, ICNB and ICSB tables
+ *
+ * struct engine_node en_nb_<TABLE_NAME>
+ * struct engine_node en_sb_<TABLE_NAME>
+ * struct engine_node en_icnb_<TABLE_NAME>
+ * struct engine_node en_icsb_<TABLE_NAME>
+ *
+ * Define nodes as static to avoid sparse errors.
+ */
+#define NB_NODE(NAME, NAME_STR) static ENGINE_NODE_NB(NAME);
+    NB_NODES
+#undef NB_NODE
+
+#define SB_NODE(NAME, NAME_STR) static ENGINE_NODE_SB(NAME);
+    SB_NODES
+#undef SB_NODE
+
+#define ICNB_NODE(NAME, NAME_STR) static ENGINE_NODE_ICNB(NAME);
+    ICNB_NODES
+#undef ICNB_NODE
+
+#define ICSB_NODE(NAME, NAME_STR) static ENGINE_NODE_ICSB(NAME);
+    ICSB_NODES
+#undef ICSB_NODE
+
+/* Define engine nodes for other nodes. They should be defined as static to
+ * avoid sparse errors. */
+static ENGINE_NODE(ic);
+
+void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
+                      struct ovsdb_idl_loop *sb,
+                      struct ovsdb_idl_loop *icnb,
+                      struct ovsdb_idl_loop *icsb)
+{
+    /* Define relationships between nodes where first argument is dependent
+     * on the second argument */
+    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);
+    engine_add_input(&en_ic, &en_nb_logical_router_port, NULL);
+    engine_add_input(&en_ic, &en_nb_logical_switch, NULL);
+    engine_add_input(&en_ic, &en_nb_logical_switch_port, NULL);
+    engine_add_input(&en_ic, &en_nb_load_balancer, NULL);
+    engine_add_input(&en_ic, &en_nb_load_balancer_group, NULL);
+
+    engine_add_input(&en_ic, &en_sb_sb_global, NULL);
+    engine_add_input(&en_ic, &en_sb_chassis, NULL);
+    engine_add_input(&en_ic, &en_sb_encap, NULL);
+    engine_add_input(&en_ic, &en_sb_datapath_binding, NULL);
+    engine_add_input(&en_ic, &en_sb_port_binding, NULL);
+    engine_add_input(&en_ic, &en_sb_service_monitor, NULL);
+
+    engine_add_input(&en_ic, &en_icnb_ic_nb_global, NULL);
+    engine_add_input(&en_ic, &en_icnb_transit_switch, NULL);
+    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_encap, NULL);
+    engine_add_input(&en_ic, &en_icsb_service_monitor, NULL);
+    engine_add_input(&en_ic, &en_icsb_ic_sb_global, NULL);
+    engine_add_input(&en_ic, &en_icsb_port_binding, NULL);
+    engine_add_input(&en_ic, &en_icsb_availability_zone, 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);
+
+    struct engine_arg engine_arg = {
+        .nb_idl = nb->idl,
+        .sb_idl = sb->idl,
+        .icnb_idl = icnb->idl,
+        .icsb_idl = icsb->idl,
+    };
+
+    engine_init(&en_ic, &engine_arg);
+}
+
+/* Returns true if the incremental processing ended up updating nodes. */
+bool
+inc_proc_ic_run(struct ic_context *ctx,
+                struct ic_engine_context *ic_eng_ctx)
+{
+    ovs_assert(ctx->ovnnb_txn && ctx->ovnsb_txn &&
+               ctx->ovninb_txn && ctx->ovnisb_txn);
+
+    int64_t start = time_msec();
+    engine_init_run();
+
+    struct engine_context eng_ctx = {
+        .client_ctx = ctx,
+    };
+
+    engine_set_context(&eng_ctx);
+    engine_run(true);
+
+    if (!engine_has_run()) {
+        if (engine_need_run()) {
+            VLOG_DBG("engine did not run, force recompute next time.");
+            engine_set_force_recompute_immediate();
+        } else {
+            VLOG_DBG("engine did not run, and it was not needed");
+        }
+    } else if (engine_canceled()) {
+        VLOG_DBG("engine was canceled, force recompute next time.");
+        engine_set_force_recompute_immediate();
+    } else {
+        engine_clear_force_recompute();
+    }
+
+    int64_t now = time_msec();
+    /* Postpone the next run by length of current run with maximum capped
+     * by "northd-backoff-interval-ms" interval. */
+    ic_eng_ctx->next_run_ms = now + MIN(now - start, ic_eng_ctx->backoff_ms);
+
+    return engine_has_updated();
+}
+
+void
+inc_proc_ic_cleanup(void)
+{
+    engine_cleanup();
+    engine_set_context(NULL);
+}
+
+bool
+inc_proc_ic_can_run(struct ic_engine_context *ctx)
+{
+    if (engine_get_force_recompute() || time_msec() >= ctx->next_run_ms ||
+        ctx->nb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS ||
+        ctx->sb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS ||
+        ctx->inb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS ||
+        ctx->isb_idl_duration_ms >= IDL_LOOP_MAX_DURATION_MS) {
+        return true;
+    }
+
+    poll_timer_wait_until(ctx->next_run_ms);
+    return false;
+}
diff --git a/ic/inc-proc-ic.h b/ic/inc-proc-ic.h
new file mode 100644
index 000000000..9af147fb3
--- /dev/null
+++ b/ic/inc-proc-ic.h
@@ -0,0 +1,48 @@
+#ifndef INC_PROC_IC_H
+#define INC_PROC_IC_H 1
+
+#include <config.h>
+
+#include "ovn-ic.h"
+#include "ovsdb-idl.h"
+#include "lib/inc-proc-eng.h"
+
+struct ic_engine_context {
+    int64_t next_run_ms;
+    uint64_t nb_idl_duration_ms;
+    uint64_t sb_idl_duration_ms;
+    uint64_t inb_idl_duration_ms;
+    uint64_t isb_idl_duration_ms;
+    uint32_t backoff_ms;
+};
+
+void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
+                      struct ovsdb_idl_loop *sb,
+                      struct ovsdb_idl_loop *icnb,
+                      struct ovsdb_idl_loop *icsb);
+
+bool inc_proc_ic_run(struct ic_context *ctx,
+                     struct ic_engine_context *ic_eng_ctx);
+
+void inc_proc_ic_cleanup(void);
+bool inc_proc_ic_can_run(struct ic_engine_context *ctx);
+
+static inline void
+inc_proc_ic_force_recompute(void)
+{
+    engine_set_force_recompute();
+}
+
+static inline void
+inc_proc_ic_force_recompute_immediate(void)
+{
+    engine_set_force_recompute_immediate();
+}
+
+static inline bool
+inc_proc_ic_get_force_recompute(void)
+{
+    return engine_get_force_recompute();
+}
+
+#endif /* INC_PROC_IC */
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index 0ef82f3a3..0e8c0953d 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -46,6 +46,8 @@
 #include "uuid.h"
 #include "openvswitch/vlog.h"
 #include "vec.h"
+#include "inc-proc-ic.h"
+#include "ovn-ic.h"
 
 VLOG_DEFINE_THIS_MODULE(ovn_ic);
 
@@ -55,45 +57,6 @@ static unixctl_cb_func ovn_ic_resume;
 static unixctl_cb_func ovn_ic_is_paused;
 static unixctl_cb_func ovn_ic_status;
 
-struct ic_context {
-    struct ovsdb_idl *ovnnb_idl;
-    struct ovsdb_idl *ovnsb_idl;
-    struct ovsdb_idl *ovninb_idl;
-    struct ovsdb_idl *ovnisb_idl;
-    struct ovsdb_idl_txn *ovnnb_txn;
-    struct ovsdb_idl_txn *ovnsb_txn;
-    struct ovsdb_idl_txn *ovninb_txn;
-    struct ovsdb_idl_txn *ovnisb_txn;
-    const struct icsbrec_availability_zone *runned_az;
-    struct ovsdb_idl_index *nbrec_ls_by_name;
-    struct ovsdb_idl_index *nbrec_lr_by_name;
-    struct ovsdb_idl_index *nbrec_lrp_by_name;
-    struct ovsdb_idl_index *nbrec_port_by_name;
-    struct ovsdb_idl_index *sbrec_chassis_by_name;
-    struct ovsdb_idl_index *sbrec_port_binding_by_name;
-    struct ovsdb_idl_index *sbrec_service_monitor_by_remote_type;
-    struct ovsdb_idl_index *sbrec_service_monitor_by_ic_learned;
-    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;
-    struct ovsdb_idl_index *icsbrec_service_monitor_by_source_az;
-    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az;
-    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az_logical_port;
-};
-
-struct ic_state {
-    bool had_lock;
-    bool paused;
-};
-
-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 };
-
 static const char *ovnnb_db;
 static const char *ovnsb_db;
 static const char *ovn_ic_nb_db;
@@ -3091,7 +3054,7 @@ update_sequence_numbers(struct ic_context *ctx,
     }
 }
 
-static void
+void
 ovn_db_run(struct ic_context *ctx)
 {
     struct hmap dp_tnlids = HMAP_INITIALIZER(&dp_tnlids);
@@ -3311,172 +3274,183 @@ main(int argc, char *argv[])
     /* ovn-ic-nb db. */
     struct ovsdb_idl_loop ovninb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
         ovsdb_idl_create(ovn_ic_nb_db, &icnbrec_idl_class, true, true));
+    ovsdb_idl_track_add_all(ovninb_idl_loop.idl);
 
     /* ovn-ic-sb db. */
     struct ovsdb_idl_loop ovnisb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
         ovsdb_idl_create(ovn_ic_sb_db, &icsbrec_idl_class, true, true));
+    ovsdb_idl_track_add_all(ovnisb_idl_loop.idl);
 
     /* ovn-nb db. */
     struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
         ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, false, true));
 
     ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_nb_global);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl, &nbrec_nb_global_col_name);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl, &nbrec_nb_global_col_options);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_nb_global_col_name);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_nb_global_col_options);
 
     ovsdb_idl_add_table(ovnnb_idl_loop.idl,
                         &nbrec_table_logical_router_static_route);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_static_route_col_route_table);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_static_route_col_ip_prefix);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_static_route_col_nexthop);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_static_route_col_external_ids);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_static_route_col_options);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_static_route_col_policy);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                    &nbrec_logical_router_static_route_col_route_table);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                    &nbrec_logical_router_static_route_col_ip_prefix);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                    &nbrec_logical_router_static_route_col_nexthop);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                    &nbrec_logical_router_static_route_col_external_ids);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                    &nbrec_logical_router_static_route_col_options);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                    &nbrec_logical_router_static_route_col_policy);
 
     ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_router);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_name);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_static_routes);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_ports);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_options);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_external_ids);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_enabled);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_load_balancer);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_col_load_balancer_group);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_name);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_static_routes);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_ports);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_options);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_external_ids);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_enabled);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_load_balancer);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_col_load_balancer_group);
 
     ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_router_port);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_port_col_mac);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_port_col_name);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_port_col_networks);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_port_col_external_ids);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_router_port_col_options);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_port_col_mac);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_port_col_name);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_port_col_networks);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_port_col_external_ids);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_router_port_col_options);
 
     ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_switch);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_col_name);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_col_ports);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_col_other_config);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_col_external_ids);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_col_name);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_col_ports);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_col_other_config);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_col_external_ids);
 
     ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_logical_switch_port);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_name);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_addresses);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_options);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_type);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_up);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_addresses);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_enabled);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_logical_switch_port_col_external_ids);
-
-    ovsdb_idl_add_table(ovnnb_idl_loop.idl,
-                        &nbrec_table_load_balancer);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_load_balancer_col_vips);
-
-    ovsdb_idl_add_table(ovnnb_idl_loop.idl,
-                        &nbrec_table_load_balancer_group);
-    ovsdb_idl_add_column(ovnnb_idl_loop.idl,
-                         &nbrec_load_balancer_group_col_load_balancer);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_name);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_addresses);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_options);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_type);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_up);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_addresses);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_enabled);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_logical_switch_port_col_external_ids);
+
+    ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_load_balancer);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_load_balancer_col_vips);
+
+    ovsdb_idl_add_table(ovnnb_idl_loop.idl, &nbrec_table_load_balancer_group);
+    ovsdb_idl_track_add_column(ovnnb_idl_loop.idl,
+                               &nbrec_load_balancer_group_col_load_balancer);
 
     /* ovn-sb db. */
     struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
         ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true));
 
     ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_sb_global);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_sb_global_col_options);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_sb_global_col_options);
 
     ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_hostname);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_other_config);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_chassis_col_encaps);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_chassis_col_name);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_chassis_col_hostname);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_chassis_col_other_config);
 
     ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_encap);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_chassis_name);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_type);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_ip);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_encap_col_options);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_encap_col_chassis_name);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_encap_col_type);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_encap_col_ip);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_encap_col_options);
 
     ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_datapath_binding_col_type);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_datapath_binding_col_external_ids);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_datapath_binding_col_nb_uuid);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_datapath_binding_col_type);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_datapath_binding_col_external_ids);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_datapath_binding_col_nb_uuid);
 
     ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_port_binding_col_datapath);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_port_binding_col_mac);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_port_binding_col_options);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_port_binding_col_logical_port);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_port_binding_col_external_ids);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_port_binding_col_chassis);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_port_binding_col_up);
-
-    ovsdb_idl_add_table(ovnsb_idl_loop.idl,
-                        &sbrec_table_service_monitor);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_chassis_name);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_external_ids);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_type);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_ip);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_logical_port);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_port);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_protocol);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_src_ip);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_src_mac);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_remote);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_ic_learned);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_status);
-    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
-                         &sbrec_service_monitor_col_options);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_port_binding_col_datapath);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_port_binding_col_mac);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_port_binding_col_options);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_port_binding_col_logical_port);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_port_binding_col_external_ids);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_port_binding_col_chassis);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_port_binding_col_up);
+
+    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_service_monitor);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_chassis_name);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_external_ids);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_type);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_ip);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_logical_port);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_port);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_protocol);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_src_ip);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_src_mac);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_remote);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_ic_learned);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_status);
+    ovsdb_idl_track_add_column(ovnsb_idl_loop.idl,
+                               &sbrec_service_monitor_col_options);
 
     /* Create IDL indexes */
     struct ovsdb_idl_index *nbrec_ls_by_name
@@ -3497,7 +3471,7 @@ main(int argc, char *argv[])
         = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
                                   &sbrec_chassis_col_name);
 
-   struct ovsdb_idl_index *sbrec_service_monitor_by_remote_type
+    struct ovsdb_idl_index *sbrec_service_monitor_by_remote_type
         = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
                                   &sbrec_service_monitor_col_remote);
 
@@ -3562,10 +3536,22 @@ main(int argc, char *argv[])
     unixctl_command_register("ic-sb-connection-status", "", 0, 0,
                              ovn_conn_show, ovnisb_idl_loop.idl);
 
+    /* Initialize incremental processing engine for ovn-northd */
+    inc_proc_ic_init(&ovnnb_idl_loop, &ovnsb_idl_loop,
+                     &ovninb_idl_loop, &ovnisb_idl_loop);
+
+    unsigned int ovnnb_cond_seqno = UINT_MAX;
+    unsigned int ovnsb_cond_seqno = UINT_MAX;
+    unsigned int ovninb_cond_seqno = UINT_MAX;
+    unsigned int ovnisb_cond_seqno = UINT_MAX;
+
     /* Main loop. */
+    struct ic_engine_context  eng_ctx = {0};
+
     exiting = false;
     state.had_lock = false;
     state.paused = false;
+
     while (!exiting) {
         update_ssl_config();
         update_idl_probe_interval(ovnsb_idl_loop.idl, ovnnb_idl_loop.idl,
@@ -3579,6 +3565,7 @@ main(int argc, char *argv[])
             simap_destroy(&usage);
         }
 
+        bool clear_idl_track = true;
         if (!state.paused) {
             if (!ovsdb_idl_has_lock(ovnsb_idl_loop.idl) &&
                 !ovsdb_idl_is_lock_contended(ovnsb_idl_loop.idl))
@@ -3590,15 +3577,67 @@ main(int argc, char *argv[])
                 ovsdb_idl_set_lock(ovnsb_idl_loop.idl, "ovn_ic");
             }
 
+            struct ovsdb_idl_txn *ovnnb_txn =
+                run_idl_loop(&ovnnb_idl_loop, "OVN_Northbound",
+                             &eng_ctx.nb_idl_duration_ms);
+            unsigned int new_ovnnb_cond_seqno =
+                        ovsdb_idl_get_condition_seqno(ovnnb_idl_loop.idl);
+            if (new_ovnnb_cond_seqno != ovnnb_cond_seqno) {
+                if (!new_ovnnb_cond_seqno) {
+                    VLOG_INFO("OVN NB IDL reconnected, force recompute.");
+                    inc_proc_ic_force_recompute();
+                }
+                ovnnb_cond_seqno = new_ovnnb_cond_seqno;
+            }
+
+            struct ovsdb_idl_txn *ovnsb_txn =
+                run_idl_loop(&ovnsb_idl_loop, "OVN_Southbound",
+                             &eng_ctx.sb_idl_duration_ms);
+            unsigned int new_ovnsb_cond_seqno =
+                        ovsdb_idl_get_condition_seqno(ovnsb_idl_loop.idl);
+            if (new_ovnsb_cond_seqno != ovnsb_cond_seqno) {
+                if (!new_ovnsb_cond_seqno) {
+                    VLOG_INFO("OVN SB IDL reconnected, force recompute.");
+                    inc_proc_ic_force_recompute();
+                }
+                ovnsb_cond_seqno = new_ovnsb_cond_seqno;
+            }
+
+            struct ovsdb_idl_txn *ovninb_txn =
+                run_idl_loop(&ovninb_idl_loop, "OVN_IC_Northbound",
+                             &eng_ctx.inb_idl_duration_ms);
+            unsigned int new_ovninb_cond_seqno =
+                        ovsdb_idl_get_condition_seqno(ovninb_idl_loop.idl);
+            if (new_ovninb_cond_seqno != ovninb_cond_seqno) {
+                if (!new_ovninb_cond_seqno) {
+                    VLOG_INFO("OVN INB IDL reconnected, force recompute.");
+                    inc_proc_ic_force_recompute();
+                }
+                ovninb_cond_seqno = new_ovninb_cond_seqno;
+            }
+
+            struct ovsdb_idl_txn *ovnisb_txn =
+                run_idl_loop(&ovnisb_idl_loop, "OVN_IC_Southbound",
+                             &eng_ctx.isb_idl_duration_ms);
+            unsigned int new_ovnisb_cond_seqno =
+                        ovsdb_idl_get_condition_seqno(ovnisb_idl_loop.idl);
+            if (new_ovnisb_cond_seqno != ovnisb_cond_seqno) {
+                if (!new_ovnisb_cond_seqno) {
+                    VLOG_INFO("OVN ISB IDL reconnected, force recompute.");
+                    inc_proc_ic_force_recompute();
+                }
+                ovnisb_cond_seqno = new_ovnisb_cond_seqno;
+            }
+
             struct ic_context ctx = {
                 .ovnnb_idl = ovnnb_idl_loop.idl,
-                .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop),
+                .ovnnb_txn = ovnnb_txn,
                 .ovnsb_idl = ovnsb_idl_loop.idl,
-                .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
+                .ovnsb_txn = ovnsb_txn,
                 .ovninb_idl = ovninb_idl_loop.idl,
-                .ovninb_txn = ovsdb_idl_loop_run(&ovninb_idl_loop),
+                .ovninb_txn = ovninb_txn,
                 .ovnisb_idl = ovnisb_idl_loop.idl,
-                .ovnisb_txn = ovsdb_idl_loop_run(&ovnisb_idl_loop),
+                .ovnisb_txn = ovnisb_txn,
                 .nbrec_ls_by_name = nbrec_ls_by_name,
                 .nbrec_lr_by_name = nbrec_lr_by_name,
                 .nbrec_lrp_by_name = nbrec_lrp_by_name,
@@ -3627,44 +3666,75 @@ main(int argc, char *argv[])
                     icsbrec_service_monitor_by_target_az_logical_port,
             };
 
-            if (!state.had_lock && ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {
+            if (!state.had_lock && ovsdb_idl_has_lock(ctx.ovnsb_idl)) {
                 VLOG_INFO("ovn-ic lock acquired. "
-                        "This ovn-ic instance is now active.");
+                            "This ovn-ic instance is now active.");
                 state.had_lock = true;
             } else if (state.had_lock &&
-                       !ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {
+                       !ovsdb_idl_has_lock(ctx.ovnsb_idl)) {
                 VLOG_INFO("ovn-ic lock lost. "
-                        "This ovn-ic instance is now on standby.");
+                            "This ovn-ic instance is now on standby.");
                 state.had_lock = false;
             }
 
-            if (ovsdb_idl_has_lock(ovnsb_idl_loop.idl) &&
+            if (ovsdb_idl_has_lock(ctx.ovnsb_idl) &&
                 ovsdb_idl_has_ever_connected(ctx.ovnnb_idl) &&
                 ovsdb_idl_has_ever_connected(ctx.ovnsb_idl) &&
                 ovsdb_idl_has_ever_connected(ctx.ovninb_idl) &&
                 ovsdb_idl_has_ever_connected(ctx.ovnisb_idl)) {
-                const struct icsbrec_availability_zone *az = az_run(&ctx);
-                VLOG_DBG("Availability zone: %s", az ? az->name :
-                                               "not created yet.");
-                if (az) {
-                    ovn_db_run(&ctx);
-                    update_sequence_numbers(&ctx, &ovnisb_idl_loop);
+                if (ctx.ovnnb_txn && ctx.ovnsb_txn && ctx.ovninb_txn &&
+                    ctx.ovnisb_txn && inc_proc_ic_can_run(&eng_ctx)) {
+                    ctx.runned_az = az_run(&ctx);
+                    VLOG_DBG("Availability zone: %s", ctx.runned_az ?
+                             ctx.runned_az->name : "not created yet.");
+                    if (ctx.runned_az) {
+                        (void) inc_proc_ic_run(&ctx, &eng_ctx);
+                        update_sequence_numbers(&ctx, &ovnisb_idl_loop);
+                    }
+                } else if (!inc_proc_ic_get_force_recompute()) {
+                    clear_idl_track = false;
+                }
+                /* If there are any errors, we force a full recompute in order
+                 * to ensure we handle all changes. */
+                if (!ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop)) {
+                    VLOG_INFO("OVNNB commit failed, "
+                                "force recompute next time.");
+                    inc_proc_ic_force_recompute_immediate();
                 }
 
-            }
+                if (!ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop)) {
+                    VLOG_INFO("OVNSB commit failed, "
+                                "force recompute next time.");
+                    inc_proc_ic_force_recompute_immediate();
+                }
+
+                if (!ovsdb_idl_loop_commit_and_wait(&ovninb_idl_loop)) {
+                    VLOG_INFO("OVNINB commit failed, "
+                                "force recompute next time.");
+                    inc_proc_ic_force_recompute_immediate();
+                }
 
-            int rc1 = ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);
-            int rc2 = ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
-            int rc3 = ovsdb_idl_loop_commit_and_wait(&ovninb_idl_loop);
-            int rc4 = ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop);
-            if (!rc1 || !rc2 || !rc3 || !rc4) {
-                VLOG_DBG(" a transaction failed in: %s %s %s %s",
-                         !rc1 ? "nb" : "", !rc2 ? "sb" : "",
-                         !rc3 ? "ic_nb" : "", !rc4 ? "ic_sb" : "");
-                /* A transaction failed. Wake up immediately to give
-                 * opportunity to send the proper transaction
-                 */
-                poll_immediate_wake();
+                if (!ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop)) {
+                    VLOG_INFO("OVNISB commit failed, "
+                                "force recompute next time.");
+                    inc_proc_ic_force_recompute_immediate();
+                }
+            } else {
+                /* Make sure we send any pending requests, e.g., lock. */
+                int rc1 = ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);
+                int rc2 = ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
+                int rc3 = ovsdb_idl_loop_commit_and_wait(&ovninb_idl_loop);
+                int rc4 = ovsdb_idl_loop_commit_and_wait(&ovnisb_idl_loop);
+                if (!rc1 || !rc2 || !rc3 || !rc4) {
+                    VLOG_DBG(" a transaction failed in: %s %s %s %s",
+                            !rc1 ? "nb" : "", !rc2 ? "sb" : "",
+                            !rc3 ? "ic_nb" : "", !rc4 ? "ic_sb" : "");
+                    /* A transaction failed. Wake up immediately to give
+                    * opportunity to send the proper transaction
+                    */
+                }
+                /* Force a full recompute next time we become active. */
+                inc_proc_ic_force_recompute();
             }
         } else {
             /* ovn-ic is paused
@@ -3690,6 +3760,16 @@ main(int argc, char *argv[])
             ovsdb_idl_wait(ovnsb_idl_loop.idl);
             ovsdb_idl_wait(ovninb_idl_loop.idl);
             ovsdb_idl_wait(ovnisb_idl_loop.idl);
+
+            /* Force a full recompute next time we become active. */
+            inc_proc_ic_force_recompute_immediate();
+        }
+
+        if (clear_idl_track) {
+            ovsdb_idl_track_clear(ovnnb_idl_loop.idl);
+            ovsdb_idl_track_clear(ovnsb_idl_loop.idl);
+            ovsdb_idl_track_clear(ovninb_idl_loop.idl);
+            ovsdb_idl_track_clear(ovnisb_idl_loop.idl);
         }
 
         unixctl_server_run(unixctl);
@@ -3704,6 +3784,7 @@ main(int argc, char *argv[])
             exiting = true;
         }
     }
+    inc_proc_ic_cleanup();
 
     unixctl_server_destroy(unixctl);
     ovsdb_idl_loop_destroy(&ovnnb_idl_loop);
diff --git a/ic/ovn-ic.h b/ic/ovn-ic.h
new file mode 100644
index 000000000..e8d7a970f
--- /dev/null
+++ b/ic/ovn-ic.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+#ifndef OVN_IC_H
+#define OVN_IC_H 1
+
+#include "ovsdb-idl.h"
+#include "unixctl.h"
+
+struct ic_context {
+    struct ovsdb_idl *ovnnb_idl;
+    struct ovsdb_idl *ovnsb_idl;
+    struct ovsdb_idl *ovninb_idl;
+    struct ovsdb_idl *ovnisb_idl;
+    struct ovsdb_idl_txn *ovnnb_txn;
+    struct ovsdb_idl_txn *ovnsb_txn;
+    struct ovsdb_idl_txn *ovninb_txn;
+    struct ovsdb_idl_txn *ovnisb_txn;
+    const struct icsbrec_availability_zone *runned_az;
+    struct ovsdb_idl_index *nbrec_ls_by_name;
+    struct ovsdb_idl_index *nbrec_lr_by_name;
+    struct ovsdb_idl_index *nbrec_lrp_by_name;
+    struct ovsdb_idl_index *nbrec_port_by_name;
+    struct ovsdb_idl_index *sbrec_chassis_by_name;
+    struct ovsdb_idl_index *sbrec_port_binding_by_name;
+    struct ovsdb_idl_index *sbrec_service_monitor_by_remote_type;
+    struct ovsdb_idl_index *sbrec_service_monitor_by_ic_learned;
+    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;
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_source_az;
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az;
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az_logical_port;
+};
+
+struct ic_state {
+    bool had_lock;
+    bool paused;
+};
+
+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 };
+
+void ovn_db_run(struct ic_context *ctx);
+
+#endif /* OVN_IC_H */
diff --git a/lib/inc-proc-eng.h b/lib/inc-proc-eng.h
index 02eeb46fe..1cb2466b2 100644
--- a/lib/inc-proc-eng.h
+++ b/lib/inc-proc-eng.h
@@ -158,6 +158,8 @@ struct engine_context {
     struct ovsdb_idl_txn *ovnsb_idl_txn;
     struct ovsdb_idl_txn *ovnnb_idl_txn;
     struct ovsdb_idl_txn *ovnbr_idl_txn;
+    struct ovsdb_idl_txn *ovnisb_idl_txn;
+    struct ovsdb_idl_txn *ovninb_idl_txn;
 
     void *client_ctx;
 };
@@ -167,6 +169,8 @@ struct engine_arg {
     struct ovsdb_idl *sb_idl;
     struct ovsdb_idl *nb_idl;
     struct ovsdb_idl *ovnbr_idl;
+    struct ovsdb_idl *icsb_idl;
+    struct ovsdb_idl *icnb_idl;
     struct ovsdb_idl *ovs_idl;
 };
 
@@ -547,6 +551,16 @@ en_##DB_NAME##_##TBL_NAME##_compute_failure_info(struct 
engine_node *node)  \
 #define ENGINE_FUNC_BR(TBL_NAME) \
     ENGINE_FUNC_OVSDB(ovnbr, TBL_NAME)
 
+/* Macro to define member functions of an engine node which represents
+ * a table of OVN ISB DB */
+#define ENGINE_FUNC_ICSB(TBL_NAME) \
+    ENGINE_FUNC_OVSDB(icsb, TBL_NAME)
+
+/* Macro to define member functions of an engine node which represents
+ * a table of OVN INB DB */
+#define ENGINE_FUNC_ICNB(TBL_NAME) \
+    ENGINE_FUNC_OVSDB(icnb, TBL_NAME)
+
 /* Macro to define member functions of an engine node which represents
  * a table of open_vswitch DB */
 #define ENGINE_FUNC_OVS(TBL_NAME) \
@@ -569,6 +583,13 @@ en_##DB_NAME##_##TBL_NAME##_compute_failure_info(struct 
engine_node *node)  \
 /* Macro to define an engine node which represents a table of OVN BR DB */
 #define ENGINE_NODE_BR(TBL_NAME) \
     ENGINE_NODE_OVSDB(ovnbr, "BR", TBL_NAME, #TBL_NAME);
+/* Macro to define an engine node which represents a table of OVN ISB DB */
+#define ENGINE_NODE_ICSB(TBL_NAME) \
+    ENGINE_NODE_OVSDB(icsb, "ICSB", TBL_NAME, #TBL_NAME);
+
+/* Macro to define an engine node which represents a table of OVN INB DB */
+#define ENGINE_NODE_ICNB(TBL_NAME) \
+    ENGINE_NODE_OVSDB(icnb, "ICNB", TBL_NAME, #TBL_NAME);
 
 /* Macro to define an engine node which represents a table of open_vswitch
  * DB */
-- 
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