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 +# 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
