Wow Paulo, this is fantastic! I think this provides a great
jumping-off point for developing further incremental processing in
ovn-ic.

Acked-by: Mark Michelson <[email protected]>

On Wed, Dec 10, 2025 at 7:28 AM Paulo Guilherme Silva via dev
<[email protected]> wrote:
>
> 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
>

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

Reply via email to