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