I have a bit of a nit on this one. On Fri, Aug 14, 2026 at 9:55 AM 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. > > The handlers report EN_HANDLED_UNCHANGED when the tracked rows required no > write at all (an unchanged interconn chassis, a gateway update we made > ourselves, a deleted chassis with no gateway to clean up), so a tracked > change that turns out to be a no-op does not mark the node as updated. > > 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 | 364 ++++++++++++++++++++++++++++++++++++++++++++++- > ic/en-gateway.h | 5 + > ic/inc-proc-ic.c | 16 ++- > ic/ovn-ic.c | 157 +------------------- > ic/ovn-ic.h | 6 +- > tests/ovn-ic.at | 64 +++++++++ > 6 files changed, 448 insertions(+), 164 deletions(-) > > diff --git a/ic/en-gateway.c b/ic/en-gateway.c > index 3fb00ced9..e3013e6ae 100644 > --- a/ic/en-gateway.c > +++ b/ic/en-gateway.c > @@ -14,14 +14,335 @@ > > #include <config.h> > > -#include "en-gateway.h" > #include "en-az.h" > +#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 (size_t g = 0; g < gw->n_encaps; g++) { > + bool found = false; > + const struct icsbrec_encap *gw_encap = gw->encaps[g]; > + for (size_t 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 (size_t 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 (size_t 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); > +} > + > +/* Returns true if it ran to completion, false if the IC-SB/SB transactions > + * needed to sync were not available (in which case the caller should report > + * that the node is still stale). */ > +static bool > +gateway_run(struct ic_context *ctx, > + const struct icsbrec_availability_zone *runned_az) > +{ > + if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) { > + return false; > + } > + > + 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 == 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, 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); > + > + return true; > +} > + > +/* 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 struct icsbrec_availability_zone *runned_az, > + const char *name, bool local) > +{ > + const struct icsbrec_gateway *gw; > + ICSBREC_GATEWAY_FOR_EACH (gw, ctx->ovnisb_unlocked_idl) { > + if ((gw->availability_zone == 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 EN_UNHANDLED to fall back to a full recompute for cases > + * that cannot be handled incrementally, and EN_HANDLED_UNCHANGED when the > + * tracked chassis required no write at all. */ > +static enum engine_input_handler_result > +sync_gateway_handle_sb_chassis( > + struct ic_context *ctx, > + const struct icsbrec_availability_zone *runned_az, > + const struct sbrec_chassis_table *tbl) > +{ > + if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) { > + return EN_UNHANDLED; > + } > + > + bool changed = 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, runned_az, chassis->name, true); > + > + if (sbrec_chassis_is_deleted(chassis)) { > + /* The local gateway derived from this chassis (if any) is now > + * orphaned. IC-SB Gateway is indexed uniquely by name, so a > local > + * gateway with this name rules out a remote one: nothing more to > + * do for this chassis. */ > + if (local_gw) { > + icsbrec_gateway_delete(local_gw); > + changed = true; > + continue; > + } > + /* 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, runned_az, chassis->name, false)) { > + return EN_UNHANDLED; > + } > + 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, > + runned_az); > + icsbrec_gateway_set_name(local_gw, chassis->name); > + sync_sb_gw_to_isb(ctx, chassis, local_gw); > + changed = true; > + } else if (is_gateway_data_changed(local_gw, chassis)) { > + sync_sb_gw_to_isb(ctx, chassis, local_gw); > + changed = true; > + } > + } else { > + /* No longer an interconn chassis: drop any local gateway derived > + * from it. */ > + if (local_gw) { > + icsbrec_gateway_delete(local_gw); > + changed = true; > + } > + if (smap_get_bool(&chassis->other_config, "is-remote", false)) { > + const struct icsbrec_gateway *remote_gw = > + find_gw_by_name(ctx, runned_az, chassis->name, false); > + if (!remote_gw) { > + sbrec_chassis_delete(chassis); > + changed = true; > + } else if (is_gateway_data_changed(remote_gw, chassis)) { > + sync_isb_gw_to_sb(ctx, remote_gw, chassis); > + changed = true; > + } > + } > + } > + } > + > + return changed ? EN_HANDLED_UPDATED : EN_HANDLED_UNCHANGED; > +} > + > +/* 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 EN_UNHANDLED to > + * fall back to a full recompute for cases that cannot be handled > + * incrementally, and EN_HANDLED_UNCHANGED when the tracked gateways required > + * no write at all. */ > +static enum engine_input_handler_result > +sync_gateway_handle_icsb_gateway( > + struct ic_context *ctx, > + const struct icsbrec_availability_zone *runned_az, > + const struct icsbrec_gateway_table *tbl) > +{ > + if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) { > + return EN_UNHANDLED; > + } > + > + bool changed = false; > + const struct icsbrec_gateway *gw; > + ICSBREC_GATEWAY_TABLE_FOR_EACH_TRACKED (gw, tbl) { > + bool local = gw->availability_zone == 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); > + changed = true; > + } > + /* 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 EN_UNHANDLED; > + } > + 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 EN_UNHANDLED; > + } > + if (!chassis) { > + chassis = sbrec_chassis_insert(ctx->ovnsb_txn); > + sbrec_chassis_set_name(chassis, gw->name); > + sync_isb_gw_to_sb(ctx, gw, chassis); > + changed = true; > + } else if (is_gateway_data_changed(gw, chassis)) { > + sync_isb_gw_to_sb(ctx, gw, chassis); > + changed = true; > + } > + } > + > + return changed ? EN_HANDLED_UPDATED : EN_HANDLED_UNCHANGED; > +} > + > enum engine_node_state > en_gateway_run(struct engine_node *node, void *data OVS_UNUSED) > { > @@ -35,11 +356,50 @@ en_gateway_run(struct engine_node *node, void *data > OVS_UNUSED) > return EN_UNCHANGED; > } > > - gateway_run(ctx, az->runned_az); > + /* If the transactions needed to sync were not available, the node could > + * not be brought up to date; report it as stale so the engine retries. > */ > + if (!gateway_run(ctx, az->runned_az)) { > + return EN_STALE; > + } > > 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; > + const struct ed_type_az *az = engine_get_input_data("az", node); > + > + if (!az->runned_az) { > + return EN_HANDLED_UNCHANGED; > + } > + > + const struct sbrec_chassis_table *tbl = > + EN_OVSDB_GET(engine_get_input("SB_chassis", node)); > + > + return sync_gateway_handle_sb_chassis(ctx, az->runned_az, tbl); > +} > + > +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; > + const struct ed_type_az *az = engine_get_input_data("az", node); > + > + if (!az->runned_az) { > + return EN_HANDLED_UNCHANGED; > + } > + > + const struct icsbrec_gateway_table *tbl = > + EN_OVSDB_GET(engine_get_input("ICSB_gateway", node)); > + > + return sync_gateway_handle_icsb_gateway(ctx, az->runned_az, tbl); > +} > + > 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 d804d114f..e6b8591a4 100644 > --- a/ic/en-gateway.h > +++ b/ic/en-gateway.h > @@ -7,4 +7,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 64aef2c82..a30ddf367 100644 > --- a/ic/inc-proc-ic.c > +++ b/ic/inc-proc-ic.c > @@ -201,12 +201,20 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb, > * splitting the monolithic ovn_db_run() into independently-gated nodes. > * Change handlers are added incrementally in a later step. */ > > - /* 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 en_az's resolved 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 their AZ NB Logical_Switch mirrors. > diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c > index e49ef6a17..8b2cd7c1c 100644 > --- a/ic/ovn-ic.c > +++ b/ic/ovn-ic.c > @@ -302,102 +302,6 @@ ts_sync_scope(struct ic_context *ctx, struct shash > *isb_ts_dps, > shash_destroy(&nb_ts_mirrors); > } > > -/* 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) > { > @@ -576,65 +480,6 @@ address_set_run(struct ic_context *ctx, > shash_destroy(&ic_remote_as); > } > > -void > -gateway_run(struct ic_context *ctx, > - const struct icsbrec_availability_zone *runned_az) > -{ > - 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 == 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, > - 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); > -} > - > const struct nbrec_logical_switch * > find_ts_in_nb(struct ic_context *ctx, char *ts_name) > { > @@ -785,7 +630,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 be6bb9f6c..8f1609b41 100644 > --- a/ic/ovn-ic.h > +++ b/ic/ovn-ic.h > @@ -65,12 +65,12 @@ struct shash; > struct sset; > struct icsbrec_availability_zone; > 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, > - const struct icsbrec_availability_zone *runned_az); > void address_set_run(struct ic_context *ctx, > const struct icsbrec_availability_zone *runned_az); > > @@ -97,6 +97,8 @@ void sync_service_monitor(struct ic_context *ctx, > /* Shared IC helpers used by more than one engine node. */ > uint32_t > allocate_dp_key(struct hmap *dp_tnlids, bool vxlan_mode, const char *name); > +const struct sbrec_chassis * > +find_sb_chassis(struct ic_context *ctx, const char *name); > const struct nbrec_logical_switch * > find_ts_in_nb(struct ic_context *ctx, char *ts_name); > bool > diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at > index 1435a19a3..49172951c 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
This test refers to dp_enum, which no longer exists. This gets corrected in patch 9, but it should be corrected here instead. > +# 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
