Hi Paulo, I have a couple of notes below.

On Tue, Jul 21, 2026 at 1:45 PM Paulo Guilherme Silva
<[email protected]> wrote:
>
> Add the incremental change handlers for the en_gateway node so SB/IC-SB
> gateway and chassis changes are reconciled in place instead of forcing a
> full recompute.
>
> Add a tests/ovn-ic.at test exercising the en_dp_enum and en_gateway
> incremental handlers (the change handler of the node that reads a changed
> table fires, and a forced recompute produces no diff).
>
> Assisted-by: Claude Opus 4.8, Claude Code
> Signed-off-by: Paulo Guilherme Silva <[email protected]>
> ---
>  ic/en-gateway.c  | 333 +++++++++++++++++++++++++++++++++++++++++++++++
>  ic/en-gateway.h  |   5 +
>  ic/inc-proc-ic.c |  16 ++-
>  ic/ovn-ic.c      | 155 +---------------------
>  ic/ovn-ic.h      |   8 +-
>  tests/ovn-ic.at  |  64 +++++++++
>  6 files changed, 422 insertions(+), 159 deletions(-)
>
> diff --git a/ic/en-gateway.c b/ic/en-gateway.c
> index 570bfea8d..b10e9ec9d 100644
> --- a/ic/en-gateway.c
> +++ b/ic/en-gateway.c
> @@ -16,11 +16,305 @@
>
>  #include "en-gateway.h"
>  #include "lib/inc-proc-eng.h"
> +#include "lib/ovn-ic-sb-idl.h"
> +#include "lib/ovn-sb-idl.h"
>  #include "openvswitch/vlog.h"
>  #include "ovn-ic.h"
>
>  VLOG_DEFINE_THIS_MODULE(en_ic_gateway);
>
> +/* Returns true if any information in gw and chassis is different. */
> +static bool
> +is_gateway_data_changed(const struct icsbrec_gateway *gw,
> +                   const struct sbrec_chassis *chassis)
> +{
> +    if (strcmp(gw->hostname, chassis->hostname)) {
> +        return true;
> +    }
> +
> +    if (gw->n_encaps != chassis->n_encaps) {
> +        return true;
> +    }
> +
> +    for (int g = 0; g < gw->n_encaps; g++) {
> +

two nits here:
* Use a size_t for g instead of int.
* Remove the extra blank line between the for loop header and body.

I realize that this is a copy-paste from an existing function, but we
may as well get it right since we're touching it :)

> +        bool found = false;
> +        const struct icsbrec_encap *gw_encap = gw->encaps[g];
> +        for (int s = 0; s < chassis->n_encaps; s++) {

nit: Use size_t for s instead of int.

> +            const struct sbrec_encap *chassis_encap = chassis->encaps[s];
> +            if (!strcmp(gw_encap->type, chassis_encap->type) &&
> +                !strcmp(gw_encap->ip, chassis_encap->ip)) {
> +                found = true;
> +                if (!smap_equal(&gw_encap->options, 
> &chassis_encap->options)) {
> +                    return true;
> +                }
> +                break;
> +            }
> +        }
> +        if (!found) {
> +            return true;
> +        }
> +    }
> +
> +    return false;
> +}
> +
> +static void
> +sync_isb_gw_to_sb(struct ic_context *ctx,
> +                  const struct icsbrec_gateway *gw,
> +                  const struct sbrec_chassis *chassis)
> +{
> +    struct smap temp_map;
> +    sbrec_chassis_set_hostname(chassis, gw->hostname);
> +    smap_clone(&temp_map, &chassis->other_config);
> +    smap_replace(&temp_map, "is-remote", "true");
> +    /* Use sbrec_chassis_set_other_config instead of
> +     * sbrec_chassis_update_other_config_setkey so the in-memory datum is
> +     * updated for reads in the same loop iteration. */
> +    sbrec_chassis_set_other_config(chassis, &temp_map);
> +    smap_destroy(&temp_map);
> +
> +    /* Sync encaps used by this gateway. */
> +    ovs_assert(gw->n_encaps);
> +    struct sbrec_encap *sb_encap;
> +    struct sbrec_encap **sb_encaps =
> +        xmalloc(gw->n_encaps * sizeof *sb_encaps);
> +    for (int i = 0; i < gw->n_encaps; i++) {

nit: size_t instead of int.

> +        sb_encap = sbrec_encap_insert(ctx->ovnsb_txn);
> +        sbrec_encap_set_chassis_name(sb_encap, gw->name);
> +        sbrec_encap_set_ip(sb_encap, gw->encaps[i]->ip);
> +        sbrec_encap_set_type(sb_encap, gw->encaps[i]->type);
> +        sbrec_encap_set_options(sb_encap, &gw->encaps[i]->options);
> +        sb_encaps[i] = sb_encap;
> +    }
> +    sbrec_chassis_set_encaps(chassis, sb_encaps, gw->n_encaps);
> +    free(sb_encaps);
> +}
> +
> +static void
> +sync_sb_gw_to_isb(struct ic_context *ctx,
> +                  const struct sbrec_chassis *chassis,
> +                  const struct icsbrec_gateway *gw)
> +{
> +    icsbrec_gateway_set_hostname(gw, chassis->hostname);
> +
> +    /* Sync encaps used by this chassis. */
> +    ovs_assert(chassis->n_encaps);
> +    struct icsbrec_encap *isb_encap;
> +    struct icsbrec_encap **isb_encaps =
> +        xmalloc(chassis->n_encaps * sizeof *isb_encaps);
> +    for (int i = 0; i < chassis->n_encaps; i++) {

Another place where we should use size_t.

> +        isb_encap = icsbrec_encap_insert(ctx->ovnisb_unlocked_txn);
> +        icsbrec_encap_set_gateway_name(isb_encap,
> +                                      chassis->name);
> +        icsbrec_encap_set_ip(isb_encap, chassis->encaps[i]->ip);
> +        icsbrec_encap_set_type(isb_encap,
> +                              chassis->encaps[i]->type);
> +        icsbrec_encap_set_options(isb_encap,
> +                                 &chassis->encaps[i]->options);
> +        isb_encaps[i] = isb_encap;
> +    }
> +    icsbrec_gateway_set_encaps(gw, isb_encaps,
> +                              chassis->n_encaps);
> +    free(isb_encaps);
> +}
> +
> +static void
> +gateway_run(struct ic_context *ctx)
> +{
> +    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {
> +        return;
> +    }

gateway_run() has this section at the top where it might not actually
do anything since the transaction pointers are NULL. I think that
gateway_run() should be changed to no longer return void. It should
have a return value that indicates whether it was able to properly run
or not. You could use a boolean for this potentially. When
en_gateway_run() calls gateway_run(), it should use the return value
to determine what value it returns. If gateway_run() couldn't actually
do anything, then en_gateway_run() should return either EN_UNCHANGED
or EN_STALE. If gateway_run() was able to run to completion, then
en_gateway_run() should return EN_UPDATED.

(I probably could have noted this in patch 3, but I didn't notice it
until now, sorry)


> +
> +    struct shash local_gws = SHASH_INITIALIZER(&local_gws);
> +    struct shash remote_gws = SHASH_INITIALIZER(&remote_gws);
> +    const struct icsbrec_gateway *gw;
> +    ICSBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_unlocked_idl) {
> +        if (gw->availability_zone == ctx->runned_az) {
> +            shash_add(&local_gws, gw->name, gw);
> +        } else {
> +            shash_add(&remote_gws, gw->name, gw);
> +        }
> +    }
> +
> +    const struct sbrec_chassis *chassis;
> +    SBREC_CHASSIS_FOR_EACH (chassis, ctx->ovnsb_idl) {
> +        if (smap_get_bool(&chassis->other_config, "is-interconn", false)) {
> +            gw = shash_find_and_delete(&local_gws, chassis->name);
> +            if (!gw) {
> +                gw = icsbrec_gateway_insert(ctx->ovnisb_unlocked_txn);
> +                icsbrec_gateway_set_availability_zone(gw, ctx->runned_az);
> +                icsbrec_gateway_set_name(gw, chassis->name);
> +                sync_sb_gw_to_isb(ctx, chassis, gw);
> +            } else if (is_gateway_data_changed(gw, chassis)) {
> +                sync_sb_gw_to_isb(ctx, chassis, gw);
> +            }
> +        } else if (smap_get_bool(&chassis->other_config, "is-remote", 
> false)) {
> +            gw = shash_find_and_delete(&remote_gws, chassis->name);
> +            if (!gw) {
> +                sbrec_chassis_delete(chassis);
> +            } else if (is_gateway_data_changed(gw, chassis)) {
> +                sync_isb_gw_to_sb(ctx, gw, chassis);
> +            }
> +        }
> +    }
> +
> +    /* Delete extra gateways from ISB for the local AZ */
> +    struct shash_node *node;
> +    SHASH_FOR_EACH (node, &local_gws) {
> +        icsbrec_gateway_delete(node->data);
> +    }
> +    shash_destroy(&local_gws);
> +
> +    /* Create SB chassis for remote gateways in ISB */
> +    SHASH_FOR_EACH (node, &remote_gws) {
> +        gw = node->data;
> +        chassis = sbrec_chassis_insert(ctx->ovnsb_txn);
> +        sbrec_chassis_set_name(chassis, gw->name);
> +        sync_isb_gw_to_sb(ctx, gw, chassis);
> +    }
> +    shash_destroy(&remote_gws);
> +}
> +
> +/* Returns the IC-SB gateway named 'name' whose availability zone is (when
> + * 'local') or is not (otherwise) this instance's AZ, or NULL.  There is no
> + * index on Gateway by name, but the number of gateways is small. */
> +static const struct icsbrec_gateway *
> +find_gw_by_name(struct ic_context *ctx, const char *name, bool local)
> +{
> +    const struct icsbrec_gateway *gw;
> +    ICSBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_unlocked_idl) {
> +        if ((gw->availability_zone == ctx->runned_az) == local
> +            && !strcmp(gw->name, name)) {
> +            return gw;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +/* Incremental handler for en_gateway's SB Chassis input.  Mirrors the
> + * SB-Chassis-driven half of gateway_run() for the tracked chassis only:
> + * an is-interconn chassis maintains its local IC-SB gateway, while an
> + * is-remote chassis (one we created from a remote gateway) is re-synced or
> + * deleted.  Returns false to fall back to a full recompute for cases that
> + * cannot be handled incrementally. */
> +static bool
> +sync_gateway_handle_sb_chassis(struct ic_context *ctx,
> +                               const struct sbrec_chassis_table *tbl)
> +{
> +    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {
> +        return false;
> +    }
> +
> +    const struct sbrec_chassis *chassis;
> +    SBREC_CHASSIS_TABLE_FOR_EACH_TRACKED (chassis, tbl) {
> +        const struct icsbrec_gateway *local_gw =
> +            find_gw_by_name(ctx, chassis->name, true);
> +
> +        if (sbrec_chassis_is_deleted(chassis)) {
> +            /* The local gateway derived from this chassis (if any) is now
> +             * orphaned. */
> +            if (local_gw) {
> +                icsbrec_gateway_delete(local_gw);

If I've read the schema information for SB Gateways properly, the
"name" field is indexed, so it's only possible for a single gateway
with a given name to exist. If we have already found the gateway and
have determined that it is local, we should skip trying to find a
remote gateway since it shouldn't exist. I think it's safe to add a
"continue;" after deleting the local_gw.


> +            }
> +            /* If this was a remote chassis we created and the remote gateway
> +             * still exists, it must be recreated: leave that to a full
> +             * recompute. */
> +            if (find_gw_by_name(ctx, chassis->name, false)) {
> +                return false;
> +            }
> +            continue;
> +        }
> +
> +        if (smap_get_bool(&chassis->other_config, "is-interconn", false)) {
> +            if (!local_gw) {
> +                local_gw = icsbrec_gateway_insert(ctx->ovnisb_unlocked_txn);
> +                icsbrec_gateway_set_availability_zone(local_gw,
> +                                                      ctx->runned_az);
> +                icsbrec_gateway_set_name(local_gw, chassis->name);
> +                sync_sb_gw_to_isb(ctx, chassis, local_gw);
> +            } else if (is_gateway_data_changed(local_gw, chassis)) {
> +                sync_sb_gw_to_isb(ctx, chassis, local_gw);
> +            }
> +        } else {
> +            /* No longer an interconn chassis: drop any local gateway derived
> +             * from it. */
> +            if (local_gw) {
> +                icsbrec_gateway_delete(local_gw);
> +            }
> +            if (smap_get_bool(&chassis->other_config, "is-remote", false)) {
> +                const struct icsbrec_gateway *remote_gw =
> +                    find_gw_by_name(ctx, chassis->name, false);
> +                if (!remote_gw) {
> +                    sbrec_chassis_delete(chassis);
> +                } else if (is_gateway_data_changed(remote_gw, chassis)) {
> +                    sync_isb_gw_to_sb(ctx, remote_gw, chassis);
> +                }
> +            }
> +        }
> +    }
> +
> +    return true;
> +}
> +
> +/* Incremental handler for en_gateway's IC-SB Gateway input.  Mirrors the
> + * remote-gateway-driven half of gateway_run() for the tracked gateways only:
> + * a remote gateway maintains its SB chassis mirror.  Returns false to fall
> + * back to a full recompute for cases that cannot be handled incrementally. 
> */
> +static bool
> +sync_gateway_handle_icsb_gateway(struct ic_context *ctx,
> +                                 const struct icsbrec_gateway_table *tbl)
> +{
> +    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {
> +        return false;
> +    }
> +
> +    const struct icsbrec_gateway *gw;
> +    ICSBREC_GATEWAY_TABLE_FOR_EACH_TRACKED (gw, tbl) {
> +        bool local = gw->availability_zone == ctx->runned_az;
> +        const struct sbrec_chassis *chassis = find_sb_chassis(ctx, gw->name);
> +
> +        if (icsbrec_gateway_is_deleted(gw)) {
> +            if (!local && chassis &&
> +                smap_get_bool(&chassis->other_config, "is-remote", false)) {
> +                sbrec_chassis_delete(chassis);
> +            }
> +            /* A local gateway disappearing while its interconn chassis still
> +             * exists needs the chassis-driven recreate path:
> +             * full recompute. */
> +            if (local && chassis &&
> +                smap_get_bool(&chassis->other_config, "is-interconn", 
> false)) {
> +                return false;
> +            }
> +            continue;
> +        }
> +
> +        if (local) {
> +            /* Local gateways are produced from SB chassis (handled by the
> +             * SB Chassis handler); a create/update here is our own write. */
> +            continue;
> +        }
> +
> +        /* Remote gateway: ensure a matching SB chassis exists and is synced.
> +         * If the only chassis with this name is a local interconn chassis,
> +         * this is an unexpected name collision; fall back. */
> +        if (chassis &&
> +            smap_get_bool(&chassis->other_config, "is-interconn", false)) {
> +            return false;
> +        }
> +        if (!chassis) {
> +            chassis = sbrec_chassis_insert(ctx->ovnsb_txn);
> +            sbrec_chassis_set_name(chassis, gw->name);
> +            sync_isb_gw_to_sb(ctx, gw, chassis);
> +        } else if (is_gateway_data_changed(gw, chassis)) {
> +            sync_isb_gw_to_sb(ctx, gw, chassis);
> +        }
> +    }
> +
> +    return true;
> +}
> +
> +
>  enum engine_node_state
>  en_gateway_run(struct engine_node *node OVS_UNUSED, void *data OVS_UNUSED)
>  {
> @@ -38,6 +332,45 @@ en_gateway_run(struct engine_node *node OVS_UNUSED, void 
> *data OVS_UNUSED)
>      return EN_UPDATED;
>  }
>
> +enum engine_input_handler_result
> +en_gateway_sb_chassis_handler(struct engine_node *node, void *data 
> OVS_UNUSED)
> +{
> +    const struct engine_context *eng_ctx = engine_get_context();
> +    struct ic_context *ctx = eng_ctx->client_ctx;
> +
> +    if (!ctx->runned_az) {
> +        return EN_HANDLED_UNCHANGED;
> +    }
> +
> +    const struct sbrec_chassis_table *tbl =
> +        EN_OVSDB_GET(engine_get_input("SB_chassis", node));
> +    if (!sync_gateway_handle_sb_chassis(ctx, tbl)) {
> +        return EN_UNHANDLED;
> +    }
> +
> +    return EN_HANDLED_UPDATED;
> +}
> +
> +enum engine_input_handler_result
> +en_gateway_icsb_gateway_handler(struct engine_node *node,
> +                                void *data OVS_UNUSED)
> +{
> +    const struct engine_context *eng_ctx = engine_get_context();
> +    struct ic_context *ctx = eng_ctx->client_ctx;
> +
> +    if (!ctx->runned_az) {
> +        return EN_HANDLED_UNCHANGED;
> +    }
> +
> +    const struct icsbrec_gateway_table *tbl =
> +        EN_OVSDB_GET(engine_get_input("ICSB_gateway", node));
> +    if (!sync_gateway_handle_icsb_gateway(ctx, tbl)) {
> +        return EN_UNHANDLED;
> +    }
> +
> +    return EN_HANDLED_UPDATED;
> +}
> +
>  void *
>  en_gateway_init(struct engine_node *node OVS_UNUSED,
>                  struct engine_arg *arg OVS_UNUSED)
> diff --git a/ic/en-gateway.h b/ic/en-gateway.h
> index 76d0b08a9..365c29b83 100644
> --- a/ic/en-gateway.h
> +++ b/ic/en-gateway.h
> @@ -9,4 +9,9 @@ enum engine_node_state en_gateway_run(struct engine_node 
> *node, void *data);
>  void *en_gateway_init(struct engine_node *node, struct engine_arg *arg);
>  void en_gateway_cleanup(void *data);
>
> +enum engine_input_handler_result
> +en_gateway_sb_chassis_handler(struct engine_node *node, void *data);
> +enum engine_input_handler_result
> +en_gateway_icsb_gateway_handler(struct engine_node *node, void *data);
> +
>  #endif /* EN_IC_GATEWAY_H */
> diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c
> index 3528542a6..7b87ee0fc 100644
> --- a/ic/inc-proc-ic.c
> +++ b/ic/inc-proc-ic.c
> @@ -233,12 +233,20 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
>      engine_add_input(&en_dp_enum, &en_icnb_ic_nb_global,
>                       en_ic_nb_global_handler);
>
> -    /* en_gateway: sync gateways/chassis between SB and IC-SB. */
> +    /* en_gateway: sync gateways/chassis between SB and IC-SB.
> +     *
> +     * The availability zone is provided by en_az (which reports EN_UPDATED
> +     * only when the AZ identity changes).  en_gateway does not read the
> +     * Availability_Zone table itself - only gateway rows' availability_zone
> +     * reference and ctx->runned_az - so it deliberately does not depend on
> +     * en_icsb_availability_zone, whose rows also carry the frequently-bumped
> +     * nb_ic_cfg sequence number. */
>      engine_add_input(&en_gateway, &en_az, NULL);
> -    engine_add_input(&en_gateway, &en_icsb_availability_zone, NULL);
> -    engine_add_input(&en_gateway, &en_icsb_gateway, NULL);
> +    engine_add_input(&en_gateway, &en_icsb_gateway,
> +                     en_gateway_icsb_gateway_handler);
>      engine_add_input(&en_gateway, &en_icsb_encap, NULL);
> -    engine_add_input(&en_gateway, &en_sb_chassis, NULL);
> +    engine_add_input(&en_gateway, &en_sb_chassis,
> +                     en_gateway_sb_chassis_handler);
>      engine_add_input(&en_gateway, &en_sb_encap, NULL);
>
>      /* en_ts: sync transit switches to NB and IC-SB datapath bindings. */
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index 428fe7cab..887c4c30f 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -356,102 +356,6 @@ tr_run(struct ic_context *ctx, struct hmap *dp_tnlids,
>      }
>  }
>
> -/* Returns true if any information in gw and chassis is different. */
> -static bool
> -is_gateway_data_changed(const struct icsbrec_gateway *gw,
> -                   const struct sbrec_chassis *chassis)
> -{
> -    if (strcmp(gw->hostname, chassis->hostname)) {
> -        return true;
> -    }
> -
> -    if (gw->n_encaps != chassis->n_encaps) {
> -        return true;
> -    }
> -
> -    for (int g = 0; g < gw->n_encaps; g++) {
> -
> -        bool found = false;
> -        const struct icsbrec_encap *gw_encap = gw->encaps[g];
> -        for (int s = 0; s < chassis->n_encaps; s++) {
> -            const struct sbrec_encap *chassis_encap = chassis->encaps[s];
> -            if (!strcmp(gw_encap->type, chassis_encap->type) &&
> -                !strcmp(gw_encap->ip, chassis_encap->ip)) {
> -                found = true;
> -                if (!smap_equal(&gw_encap->options, 
> &chassis_encap->options)) {
> -                    return true;
> -                }
> -                break;
> -            }
> -        }
> -        if (!found) {
> -            return true;
> -        }
> -    }
> -
> -    return false;
> -}
> -
> -static void
> -sync_isb_gw_to_sb(struct ic_context *ctx,
> -                  const struct icsbrec_gateway *gw,
> -                  const struct sbrec_chassis *chassis)
> -{
> -    struct smap temp_map;
> -    sbrec_chassis_set_hostname(chassis, gw->hostname);
> -    smap_clone(&temp_map, &chassis->other_config);
> -    smap_replace(&temp_map, "is-remote", "true");
> -    /* Use sbrec_chassis_set_other_config instead of
> -     * sbrec_chassis_update_other_config_setkey so the in-memory datum is
> -     * updated for reads in the same loop iteration. */
> -    sbrec_chassis_set_other_config(chassis, &temp_map);
> -    smap_destroy(&temp_map);
> -
> -    /* Sync encaps used by this gateway. */
> -    ovs_assert(gw->n_encaps);
> -    struct sbrec_encap *sb_encap;
> -    struct sbrec_encap **sb_encaps =
> -        xmalloc(gw->n_encaps * sizeof *sb_encaps);
> -    for (int i = 0; i < gw->n_encaps; i++) {
> -        sb_encap = sbrec_encap_insert(ctx->ovnsb_txn);
> -        sbrec_encap_set_chassis_name(sb_encap, gw->name);
> -        sbrec_encap_set_ip(sb_encap, gw->encaps[i]->ip);
> -        sbrec_encap_set_type(sb_encap, gw->encaps[i]->type);
> -        sbrec_encap_set_options(sb_encap, &gw->encaps[i]->options);
> -        sb_encaps[i] = sb_encap;
> -    }
> -    sbrec_chassis_set_encaps(chassis, sb_encaps, gw->n_encaps);
> -    free(sb_encaps);
> -}
> -
> -static void
> -sync_sb_gw_to_isb(struct ic_context *ctx,
> -                  const struct sbrec_chassis *chassis,
> -                  const struct icsbrec_gateway *gw)
> -{
> -    icsbrec_gateway_set_hostname(gw, chassis->hostname);
> -
> -    /* Sync encaps used by this chassis. */
> -    ovs_assert(chassis->n_encaps);
> -    struct icsbrec_encap *isb_encap;
> -    struct icsbrec_encap **isb_encaps =
> -        xmalloc(chassis->n_encaps * sizeof *isb_encaps);
> -    for (int i = 0; i < chassis->n_encaps; i++) {
> -        isb_encap = icsbrec_encap_insert(ctx->ovnisb_unlocked_txn);
> -        icsbrec_encap_set_gateway_name(isb_encap,
> -                                      chassis->name);
> -        icsbrec_encap_set_ip(isb_encap, chassis->encaps[i]->ip);
> -        icsbrec_encap_set_type(isb_encap,
> -                              chassis->encaps[i]->type);
> -        icsbrec_encap_set_options(isb_encap,
> -                                 &chassis->encaps[i]->options);
> -        isb_encaps[i] = isb_encap;
> -    }
> -    icsbrec_gateway_set_encaps(gw, isb_encaps,
> -                              chassis->n_encaps);
> -    free(isb_encaps);
> -}
> -
>  static void
>  nb_addr_set_apply_diff(const void *arg, const char *item, bool add)
>  {
> @@ -629,63 +533,6 @@ address_set_run(struct ic_context *ctx)
>      shash_destroy(&ic_remote_as);
>  }
>
> -void
> -gateway_run(struct ic_context *ctx)
> -{
> -    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {
> -        return;
> -    }
> -
> -    struct shash local_gws = SHASH_INITIALIZER(&local_gws);
> -    struct shash remote_gws = SHASH_INITIALIZER(&remote_gws);
> -    const struct icsbrec_gateway *gw;
> -    ICSBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_unlocked_idl) {
> -        if (gw->availability_zone == ctx->runned_az) {
> -            shash_add(&local_gws, gw->name, gw);
> -        } else {
> -            shash_add(&remote_gws, gw->name, gw);
> -        }
> -    }
> -
> -    const struct sbrec_chassis *chassis;
> -    SBREC_CHASSIS_FOR_EACH (chassis, ctx->ovnsb_idl) {
> -        if (smap_get_bool(&chassis->other_config, "is-interconn", false)) {
> -            gw = shash_find_and_delete(&local_gws, chassis->name);
> -            if (!gw) {
> -                gw = icsbrec_gateway_insert(ctx->ovnisb_unlocked_txn);
> -                icsbrec_gateway_set_availability_zone(gw, ctx->runned_az);
> -                icsbrec_gateway_set_name(gw, chassis->name);
> -                sync_sb_gw_to_isb(ctx, chassis, gw);
> -            } else if (is_gateway_data_changed(gw, chassis)) {
> -                sync_sb_gw_to_isb(ctx, chassis, gw);
> -            }
> -        } else if (smap_get_bool(&chassis->other_config, "is-remote", 
> false)) {
> -            gw = shash_find_and_delete(&remote_gws, chassis->name);
> -            if (!gw) {
> -                sbrec_chassis_delete(chassis);
> -            } else if (is_gateway_data_changed(gw, chassis)) {
> -                sync_isb_gw_to_sb(ctx, gw, chassis);
> -            }
> -        }
> -    }
> -
> -    /* Delete extra gateways from ISB for the local AZ */
> -    struct shash_node *node;
> -    SHASH_FOR_EACH (node, &local_gws) {
> -        icsbrec_gateway_delete(node->data);
> -    }
> -    shash_destroy(&local_gws);
> -
> -    /* Create SB chassis for remote gateways in ISB */
> -    SHASH_FOR_EACH (node, &remote_gws) {
> -        gw = node->data;
> -        chassis = sbrec_chassis_insert(ctx->ovnsb_txn);
> -        sbrec_chassis_set_name(chassis, gw->name);
> -        sync_isb_gw_to_sb(ctx, gw, chassis);
> -    }
> -    shash_destroy(&remote_gws);
> -}
> -
>  static const struct nbrec_logical_switch *
>  find_ts_in_nb(struct ic_context *ctx, char *ts_name)
>  {
> @@ -836,7 +683,7 @@ get_lp_address_for_sb_pb(struct ic_context *ctx,
>      return peer->n_mac ? *peer->mac : NULL;
>  }
>
> -static const struct sbrec_chassis *
> +const struct sbrec_chassis *
>  find_sb_chassis(struct ic_context *ctx, const char *name)
>  {
>      const struct sbrec_chassis *key =
> diff --git a/ic/ovn-ic.h b/ic/ovn-ic.h
> index 202f160c0..b4b95b3ba 100644
> --- a/ic/ovn-ic.h
> +++ b/ic/ovn-ic.h
> @@ -64,11 +64,12 @@ enum ic_port_binding_type { IC_SWITCH_PORT, 
> IC_ROUTER_PORT, IC_PORT_MAX };
>  struct hmap;
>  struct shash;
>  struct icsbrec_datapath_binding;
> +struct sbrec_chassis_table;
> +struct icsbrec_gateway_table;
>
>  enum ic_datapath_type ic_dp_get_type(
>      const struct icsbrec_datapath_binding *isb_dp);
>
> -void gateway_run(struct ic_context *ctx);
>  void address_set_run(struct ic_context *ctx);
>  void ts_run(struct ic_context *ctx, struct hmap *dp_tnlids,
>              struct shash *isb_ts_dps);
> @@ -78,4 +79,9 @@ void port_binding_run(struct ic_context *ctx);
>  void route_run(struct ic_context *ctx);
>  void sync_service_monitor(struct ic_context *ctx);
>
> +
> +/* Shared IC helpers used by more than one engine node. */
> +const struct sbrec_chassis *
> +find_sb_chassis(struct ic_context *ctx, const char *name);
> +
>  #endif /* OVN_IC_H */
> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
> index d884de282..2cf63c2c3 100644
> --- a/tests/ovn-ic.at
> +++ b/tests/ovn-ic.at
> @@ -817,6 +817,70 @@ OVN_CLEANUP_IC([az1], [az2])
>  AT_CLEANUP
>  ])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([ovn-ic -- incremental processing - dp_enum and gateway])
> +
> +# Validates the incremental-processing change handlers of the en_dp_enum and
> +# en_gateway engine nodes in two ways:
> +#  - the change handler of the node that reads the affected table fires
> +#    (its compute stat is non-zero), and
> +#  - forcing a full recompute afterwards leaves the databases unchanged,
> +#    i.e. the incremental result matches a full recompute.
> +
> +ovn_init_ic_db
> +net_add n1
> +ovn_start az1
> +sim_add gw1
> +as gw1
> +check ovs-vsctl add-br br-phys
> +ovn_az_attach az1 n1 br-phys 192.168.0.1
> +check ovs-vsctl set open . external-ids:ovn-is-interconn=true \
> +                          external-ids:hostname=gw1
> +as az1
> +
> +# Wait until the local gateway is registered in IC-SB.
> +OVS_WAIT_UNTIL([test "$(ovn-ic-sbctl --bare --columns=hostname \
> +                            find gateway name=gw1)" = gw1])
> +check ovn-ic-nbctl --wait=sb sync
> +
> +# A targeted SB Chassis change is handled by the gateway node's change
> +# handler: its compute stat becomes non-zero.
> +check ovn-appctl -t ic/ovn-ic inc-engine/clear-stats
> +as gw1
> +check ovs-vsctl set open . external-ids:hostname=gw1-new
> +as az1
> +OVS_WAIT_UNTIL([test "$(ovn-ic-sbctl --bare --columns=hostname \
> +                            find gateway name=gw1)" = gw1-new])
> +AT_CHECK([test "$(ovn-appctl -t ic/ovn-ic \
> +                      inc-engine/show-stats gateway compute)" -gt 0])
> +
> +# Exercise the dp_enum handler too: a transit switch creates an IC-SB
> +# datapath binding, and adding a port binding drives further IC-SB updates.
> +check ovn-ic-nbctl --wait=sb ts-add ts1
> +OVS_WAIT_UNTIL([test "$(ovn-nbctl --bare --columns=name \
> +                            find logical_switch name=ts1)" = ts1])
> +check ovn-ic-nbctl --wait=sb sync
> +
> +# After all the incremental updates above, a forced full recompute must not
> +# change any IC-managed table: incremental processing produced the same 
> result.
> +m4_define([_IC_DUMP], [
> +    ovn-ic-sbctl --columns=name,hostname,availability_zone list gateway \
> +        | sort > $1
> +    ovn-ic-sbctl --columns=transit_switch,type,tunnel_key \
> +        list datapath_binding | sort >> $1
> +    ovn-nbctl --columns=name,other_config list logical_switch | sort >> $1
> +    ovn-sbctl --columns=name,hostname,other_config list chassis | sort >> $1
> +])
> +_IC_DUMP([ic_before])
> +check ovn-appctl -t ic/ovn-ic inc-engine/recompute
> +check ovn-ic-nbctl --wait=sb sync
> +_IC_DUMP([ic_after])
> +AT_CHECK([diff ic_before ic_after])
> +
> +OVN_CLEANUP_IC([az1])
> +AT_CLEANUP
> +])
> +
>  OVN_FOR_EACH_NORTHD([
>  AT_SETUP([ovn-ic -- port sync])
>
> --
> 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