Hi Paulo, Like with the other patches in this series, I only have minor comments.
This patch introduces the ic-backoff-interval-ms. However, comments in the ic code reference northd-backoff-interval-ms, and so those should be updated to be the new configuration value. On Wed, Aug 12, 2026 at 10:56 PM Paulo Guilherme Silva <[email protected]> wrote: > > Introduce the en_az engine node: move the availability-zone computation > (previously done inline in ovn_db_run) into a dedicated node that resolves > ctx->runned_az, which the downstream subsystem nodes gate on. > > Also wire the ic-backoff-interval-ms option to throttle the engine loop > (IC_NB_Global:options:ic-backoff-interval-ms), so a busy IC-SB does not > spin ovn-ic at full speed. > > Assisted-by: Claude Opus 4.8, Claude Code > Signed-off-by: Paulo Guilherme Silva <[email protected]> > --- > ic/automake.mk | 2 + > ic/en-address-set.c | 17 ++++- > ic/en-az.c | 127 +++++++++++++++++++++++++++++++ > ic/en-az.h | 26 +++++++ > ic/en-gateway.c | 10 ++- > ic/en-port-binding.c | 10 ++- > ic/en-route.c | 10 ++- > ic/en-service-monitor.c | 10 ++- > ic/en-tr.c | 8 ++ > ic/en-ts.c | 8 ++ > ic/inc-proc-ic.c | 24 +++++- > ic/inc-proc-ic.h | 7 ++ > ic/ovn-ic.c | 163 +++++++++++++++------------------------- > ic/ovn-ic.h | 5 +- > ovn-ic-nb.xml | 23 ++++++ > 15 files changed, 338 insertions(+), 112 deletions(-) > create mode 100644 ic/en-az.c > create mode 100644 ic/en-az.h > > diff --git a/ic/automake.mk b/ic/automake.mk > index fd888d60c..b730fc578 100644 > --- a/ic/automake.mk > +++ b/ic/automake.mk > @@ -4,6 +4,8 @@ ic_ovn_ic_SOURCES = ic/ovn-ic.c \ > ic/ovn-ic.h \ > ic/en-ic.c \ > ic/en-ic.h \ > + ic/en-az.c \ > + ic/en-az.h \ > ic/en-dp-enum.c \ > ic/en-dp-enum.h \ > ic/en-gateway.c \ > diff --git a/ic/en-address-set.c b/ic/en-address-set.c > index 764dd71d2..5a29f8201 100644 > --- a/ic/en-address-set.c > +++ b/ic/en-address-set.c > @@ -15,6 +15,7 @@ > #include <config.h> > > #include "en-address-set.h" > +#include "en-az.h" > #include "lib/inc-proc-eng.h" > #include "openvswitch/vlog.h" > #include "ovn-ic.h" > @@ -22,12 +23,22 @@ > VLOG_DEFINE_THIS_MODULE(en_ic_address_set); > > enum engine_node_state > -en_address_set_run(struct engine_node *node OVS_UNUSED, void *data > OVS_UNUSED) > +en_address_set_run(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; > - > - address_set_run(ctx); > + const struct ed_type_az *az = engine_get_input_data("az", node); > + > + /* runned_az is resolved by the upstream en_az node. Without an AZ there > + * is nothing to sync; this also mirrors the previous main-loop gating > and > + * avoids running address_set_run() before the NB Global row exists > (en_az > + * leaves runned_az NULL until then, and address_set_run() asserts on a > + * NULL NB Global). */ > + if (!az->runned_az) { > + return EN_UNCHANGED; > + } > + > + address_set_run(ctx, az->runned_az); > > return EN_UPDATED; > } > diff --git a/ic/en-az.c b/ic/en-az.c > new file mode 100644 > index 000000000..4d3c9bc71 > --- /dev/null > +++ b/ic/en-az.c > @@ -0,0 +1,127 @@ > +/* > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > + > +#include "en-az.h" > +#include "lib/inc-proc-eng.h" > +#include "lib/ovn-ic-sb-idl.h" > +#include "lib/ovn-nb-idl.h" > +#include "openvswitch/vlog.h" > +#include "ovn-ic.h" > +#include "ovsdb-idl.h" > +#include "util.h" > + > +VLOG_DEFINE_THIS_MODULE(en_ic_az); > + > +/* Resolves (and, if needed, registers) the availability zone for this ovn-ic > + * instance. This node has no engine inputs: like the former az_run() helper > + * it runs on every engine iteration and reads the NB Global and IC-SB > + * Availability_Zone tables directly. The resolved AZ is stored in this > node's > + * own data (struct ed_type_az): dependent nodes declare en_az as an input > and > + * read it with engine_get_input_data("az", node), and the main loop reads it > + * with inc_proc_ic_get_runned_az() after inc_proc_ic_run(). It reports > + * EN_UPDATED only when the resolved AZ identity changes so dependent nodes > do > + * not recompute on every iteration. */ > +enum engine_node_state > +en_az_run(struct engine_node *node OVS_UNUSED, void *data_) > +{ > + const struct engine_context *eng_ctx = engine_get_context(); > + struct ic_context *ctx = eng_ctx->client_ctx; > + struct ed_type_az *data = data_; > + const struct icsbrec_availability_zone *old_az = data->runned_az; > + const struct icsbrec_availability_zone *az; > + > + data->runned_az = NULL; > + > + const struct nbrec_nb_global *nb_global = > + nbrec_nb_global_first(ctx->ovnnb_idl); > + if (!nb_global) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > + VLOG_WARN_RL(&rl, "NB Global does not exist."); > + goto out; > + } > + > + /* Update old AZ if name changes. Note: if name changed when ovn-ic > + * is not running, one has to manually delete/update the old AZ with: > + * "ovn-ic-sbctl destroy avail <az>". */ > + if (ctx->ovnisb_unlocked_txn && data->az_name > + && strcmp(data->az_name, nb_global->name)) { > + ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_unlocked_idl) { > + /* AZ name update locally need to update az in ISB. */ > + if (nb_global->name[0] && !strcmp(az->name, data->az_name)) { > + icsbrec_availability_zone_set_name(az, nb_global->name); > + break; > + } else if (!nb_global->name[0] > + && !strcmp(az->name, data->az_name)) { > + icsbrec_availability_zone_delete(az); > + break; > + } > + } > + free(data->az_name); > + data->az_name = NULL; > + } > + > + if (!nb_global->name[0]) { > + goto out; > + } > + > + if (!data->az_name) { > + data->az_name = xstrdup(nb_global->name); > + } > + > + if (ctx->ovnisb_unlocked_txn) { > + ovsdb_idl_txn_add_comment(ctx->ovnisb_unlocked_txn, "AZ %s", > + data->az_name); > + } > + > + ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_unlocked_idl) { > + if (!strcmp(az->name, data->az_name)) { > + data->runned_az = az; > + goto out; > + } > + } > + > + /* Create AZ in ISB */ > + if (ctx->ovnisb_unlocked_txn) { > + VLOG_INFO("Register AZ %s to interconnection DB.", data->az_name); > + az = icsbrec_availability_zone_insert(ctx->ovnisb_unlocked_txn); > + icsbrec_availability_zone_set_name(az, data->az_name); > + data->runned_az = az; > + } > + > +out: { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > + VLOG_DBG_RL(&rl, "Availability zone: %s", > + data->runned_az ? data->runned_az->name : "not created > yet."); > + > + return data->runned_az == old_az ? EN_UNCHANGED : EN_UPDATED; > +} > +} > + > +void * > +en_az_init(struct engine_node *node OVS_UNUSED, > + struct engine_arg *arg OVS_UNUSED) > +{ > + return xzalloc(sizeof(struct ed_type_az)); > +} > + > +void > +en_az_cleanup(void *data_) > +{ > + struct ed_type_az *data = data_; > + > + free(data->az_name); > + data->az_name = NULL; > +} > diff --git a/ic/en-az.h b/ic/en-az.h > new file mode 100644 > index 000000000..ea9b1a81c > --- /dev/null > +++ b/ic/en-az.h > @@ -0,0 +1,26 @@ > +#ifndef EN_IC_AZ_H > +#define EN_IC_AZ_H 1 > + > +#include <config.h> > + > +#include "lib/inc-proc-eng.h" > + > +struct icsbrec_availability_zone; > + > +/* Data maintained by the "az" engine node: the availability zone this ovn-ic > + * instance runs for. This replaces the former az_run() helper and its file > + * scope 'az_name' static variable. */ > +struct ed_type_az { > + /* The availability zone record for this instance, or NULL if it is not > + * known/registered yet. Owned by the IDL. */ > + const struct icsbrec_availability_zone *runned_az; > + /* The name this instance registered as, persisted across iterations so a > + * later rename can update the existing IC-SB record. */ > + char *az_name; > +}; > + > +enum engine_node_state en_az_run(struct engine_node *node, void *data); > +void *en_az_init(struct engine_node *node, struct engine_arg *arg); > +void en_az_cleanup(void *data); > + > +#endif /* EN_IC_AZ_H */ > diff --git a/ic/en-gateway.c b/ic/en-gateway.c > index f41166018..8a8755673 100644 > --- a/ic/en-gateway.c > +++ b/ic/en-gateway.c > @@ -15,6 +15,7 @@ > #include <config.h> > > #include "en-gateway.h" > +#include "en-az.h" > #include "lib/inc-proc-eng.h" > #include "openvswitch/vlog.h" > #include "ovn-ic.h" > @@ -22,10 +23,17 @@ > VLOG_DEFINE_THIS_MODULE(en_ic_gateway); > > enum engine_node_state > -en_gateway_run(struct engine_node *node OVS_UNUSED, void *data OVS_UNUSED) > +en_gateway_run(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); > + > + /* runned_az is resolved by the upstream en_az node. Without an AZ there > + * is nothing to sync (mirrors the previous main-loop gating). */ > + if (!az->runned_az) { > + return EN_UNCHANGED; > + } > > gateway_run(ctx); > > diff --git a/ic/en-port-binding.c b/ic/en-port-binding.c > index 8843d6cef..3c0f67be8 100644 > --- a/ic/en-port-binding.c > +++ b/ic/en-port-binding.c > @@ -15,6 +15,7 @@ > #include <config.h> > > #include "en-port-binding.h" > +#include "en-az.h" > #include "lib/inc-proc-eng.h" > #include "openvswitch/vlog.h" > #include "ovn-ic.h" > @@ -22,10 +23,17 @@ > VLOG_DEFINE_THIS_MODULE(en_ic_port_binding); > > enum engine_node_state > -en_port_binding_run(struct engine_node *node OVS_UNUSED, void *data > OVS_UNUSED) > +en_port_binding_run(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); > + > + /* runned_az is resolved by the upstream en_az node. Without an AZ there > + * is nothing to sync (mirrors the previous main-loop gating). */ > + if (!az->runned_az) { > + return EN_UNCHANGED; > + } > > port_binding_run(ctx); > > diff --git a/ic/en-route.c b/ic/en-route.c > index ec39d89d9..e1edce910 100644 > --- a/ic/en-route.c > +++ b/ic/en-route.c > @@ -15,6 +15,7 @@ > #include <config.h> > > #include "en-route.h" > +#include "en-az.h" > #include "lib/inc-proc-eng.h" > #include "openvswitch/vlog.h" > #include "ovn-ic.h" > @@ -22,10 +23,17 @@ > VLOG_DEFINE_THIS_MODULE(en_ic_route); > > enum engine_node_state > -en_route_run(struct engine_node *node OVS_UNUSED, void *data OVS_UNUSED) > +en_route_run(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); > + > + /* runned_az is resolved by the upstream en_az node. Without an AZ there > + * is nothing to sync (mirrors the previous main-loop gating). */ > + if (!az->runned_az) { > + return EN_UNCHANGED; > + } > > route_run(ctx); > > diff --git a/ic/en-service-monitor.c b/ic/en-service-monitor.c > index b85a36dc7..feb0630c3 100644 > --- a/ic/en-service-monitor.c > +++ b/ic/en-service-monitor.c > @@ -15,6 +15,7 @@ > #include <config.h> > > #include "en-service-monitor.h" > +#include "en-az.h" > #include "lib/inc-proc-eng.h" > #include "openvswitch/vlog.h" > #include "ovn-ic.h" > @@ -22,11 +23,18 @@ > VLOG_DEFINE_THIS_MODULE(en_ic_service_monitor); > > enum engine_node_state > -en_service_monitor_run(struct engine_node *node OVS_UNUSED, > +en_service_monitor_run(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); > + > + /* runned_az is resolved by the upstream en_az node. Without an AZ there > + * is nothing to sync (mirrors the previous main-loop gating). */ > + if (!az->runned_az) { > + return EN_UNCHANGED; > + } > > sync_service_monitor(ctx); > > diff --git a/ic/en-tr.c b/ic/en-tr.c > index 4f05a4325..c3b1b60c6 100644 > --- a/ic/en-tr.c > +++ b/ic/en-tr.c > @@ -16,6 +16,7 @@ > > #include "en-dp-enum.h" > #include "en-tr.h" > +#include "en-az.h" > #include "lib/inc-proc-eng.h" > #include "openvswitch/vlog.h" > #include "ovn-ic.h" > @@ -28,6 +29,13 @@ en_tr_run(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; > struct ed_type_dp_enum *dp = engine_get_input_data("dp_enum", node); > + const struct ed_type_az *az = engine_get_input_data("az", node); > + > + /* runned_az is resolved by the upstream en_az node. Without an AZ there > + * is nothing to sync (mirrors the previous main-loop gating). */ > + if (!az->runned_az) { > + return EN_UNCHANGED; > + } > > tr_run(ctx, &dp->dp_tnlids, &dp->isb_tr_dps); > > diff --git a/ic/en-ts.c b/ic/en-ts.c > index e8df1888a..e4ec2a0b7 100644 > --- a/ic/en-ts.c > +++ b/ic/en-ts.c > @@ -16,6 +16,7 @@ > > #include "en-dp-enum.h" > #include "en-ts.h" > +#include "en-az.h" > #include "lib/inc-proc-eng.h" > #include "openvswitch/vlog.h" > #include "ovn-ic.h" > @@ -28,6 +29,13 @@ en_ts_run(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; > struct ed_type_dp_enum *dp = engine_get_input_data("dp_enum", node); > + const struct ed_type_az *az = engine_get_input_data("az", node); > + > + /* runned_az is resolved by the upstream en_az node. Without an AZ there > + * is nothing to sync (mirrors the previous main-loop gating). */ > + if (!az->runned_az) { > + return EN_UNCHANGED; > + } > > ts_run(ctx, &dp->dp_tnlids, &dp->isb_ts_dps); > > diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c > index 8721c5673..8d48b86a2 100644 > --- a/ic/inc-proc-ic.c > +++ b/ic/inc-proc-ic.c > @@ -27,6 +27,7 @@ > #include "openvswitch/vlog.h" > #include "inc-proc-ic.h" > #include "en-ic.h" > +#include "en-az.h" > #include "en-dp-enum.h" > #include "en-gateway.h" > #include "en-ts.h" > @@ -173,6 +174,7 @@ VLOG_DEFINE_THIS_MODULE(inc_proc_ic); > > /* Define engine nodes for other nodes. They should be defined as static to > * avoid sparse errors. */ > +static ENGINE_NODE(az); > static ENGINE_NODE(dp_enum); > static ENGINE_NODE(gateway); > static ENGINE_NODE(ts); > @@ -215,6 +217,7 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_dp_enum, &en_icnb_ic_nb_global, NULL); > > /* en_gateway: sync gateways/chassis between SB and IC-SB. */ > + 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_encap, NULL); > @@ -222,6 +225,7 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_gateway, &en_sb_encap, NULL); > > /* en_ts: sync transit switches to NB and IC-SB datapath bindings. */ > + engine_add_input(&en_ts, &en_az, NULL); > engine_add_input(&en_ts, &en_dp_enum, NULL); > engine_add_input(&en_ts, &en_icnb_ic_nb_global, NULL); > engine_add_input(&en_ts, &en_icnb_transit_switch, NULL); > @@ -229,11 +233,13 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_ts, &en_icsb_encap, NULL); > > /* en_tr: sync transit routers to NB and IC-SB datapath bindings. */ > + engine_add_input(&en_tr, &en_az, NULL); > engine_add_input(&en_tr, &en_dp_enum, NULL); > engine_add_input(&en_tr, &en_icnb_transit_router, NULL); > engine_add_input(&en_tr, &en_nb_logical_router, NULL); > > /* en_port_binding: sync cross-AZ port bindings. */ > + engine_add_input(&en_port_binding, &en_az, NULL); > engine_add_input(&en_port_binding, &en_icsb_availability_zone, NULL); > engine_add_input(&en_port_binding, &en_icsb_port_binding, NULL); > engine_add_input(&en_port_binding, &en_icnb_transit_switch, NULL); > @@ -247,6 +253,7 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_port_binding, &en_sb_chassis, NULL); > > /* en_route: advertise/learn cross-AZ routes. */ > + engine_add_input(&en_route, &en_az, NULL); > engine_add_input(&en_route, &en_icsb_availability_zone, NULL); > engine_add_input(&en_route, &en_icsb_port_binding, NULL); > engine_add_input(&en_route, &en_icsb_route, NULL); > @@ -262,13 +269,21 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb, > engine_add_input(&en_route, &en_sb_learned_route, NULL); > > /* en_service_monitor: sync load-balancer health checks across AZs. */ > + engine_add_input(&en_service_monitor, &en_az, NULL); > engine_add_input(&en_service_monitor, &en_icsb_availability_zone, NULL); > engine_add_input(&en_service_monitor, &en_icsb_service_monitor, NULL); > engine_add_input(&en_service_monitor, &en_sb_sb_global, NULL); > engine_add_input(&en_service_monitor, &en_sb_service_monitor, NULL); > engine_add_input(&en_service_monitor, &en_sb_port_binding, NULL); > > - /* en_address_set: advertise/learn address sets across AZs. */ > + /* en_address_set: advertise/learn address sets across AZs. > + * > + * Like the other AZ-scoped nodes, address_set_run() partitions IC-SB > + * address sets into local/remote by comparing their availability_zone > + * against this instance's AZ, so it depends on en_az (which reports > + * EN_UPDATED only when the AZ identity changes) to be re-run when the > + * resolved AZ changes. */ > + engine_add_input(&en_address_set, &en_az, NULL); > engine_add_input(&en_address_set, &en_nb_nb_global, NULL); > engine_add_input(&en_address_set, &en_nb_address_set, NULL); > engine_add_input(&en_address_set, &en_sb_address_set, NULL); > @@ -343,6 +358,13 @@ inc_proc_ic_cleanup(void) > engine_set_context(NULL); > } > > +const struct icsbrec_availability_zone * > +inc_proc_ic_get_runned_az(void) > +{ > + const struct ed_type_az *az = engine_get_data(&en_az); > + return az ? az->runned_az : NULL; > +} > + > bool > inc_proc_ic_can_run(struct ic_engine_context *ctx) > { > diff --git a/ic/inc-proc-ic.h b/ic/inc-proc-ic.h > index 36464564d..1fc3a0ca1 100644 > --- a/ic/inc-proc-ic.h > +++ b/ic/inc-proc-ic.h > @@ -28,6 +28,13 @@ bool inc_proc_ic_run(struct ic_context *ctx, > void inc_proc_ic_cleanup(void); > bool inc_proc_ic_can_run(struct ic_engine_context *ctx); > > +struct icsbrec_availability_zone; > + > +/* Returns the availability zone resolved by the en_az engine node during the > + * last inc_proc_ic_run(), or NULL if none is resolved yet. Used by the main > + * loop, which runs the AZ sequence-number bookkeeping outside the engine. */ > +const struct icsbrec_availability_zone *inc_proc_ic_get_runned_az(void); > + > static inline void > inc_proc_ic_force_recompute(void) > { > diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c > index 9f3e7cafd..77a52f246 100644 > --- a/ic/ovn-ic.c > +++ b/ic/ovn-ic.c > @@ -99,68 +99,6 @@ Options:\n\ > stream_usage("database", true, true, false); > } > > -static const struct icsbrec_availability_zone * > -az_run(struct ic_context *ctx) > -{ > - const struct nbrec_nb_global *nb_global = > - nbrec_nb_global_first(ctx->ovnnb_idl); > - > - if (!nb_global) { > - VLOG_INFO("NB Global not exist."); > - return NULL; > - } > - > - /* Update old AZ if name changes. Note: if name changed when ovn-ic > - * is not running, one has to manually delete/update the old AZ with: > - * "ovn-ic-sbctl destroy avail <az>". */ > - static char *az_name; > - const struct icsbrec_availability_zone *az; > - if (ctx->ovnisb_unlocked_txn && az_name > - && strcmp(az_name, nb_global->name)) { > - ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_unlocked_idl) { > - /* AZ name update locally need to update az in ISB. */ > - if (nb_global->name[0] && !strcmp(az->name, az_name)) { > - icsbrec_availability_zone_set_name(az, nb_global->name); > - break; > - } else if (!nb_global->name[0] && !strcmp(az->name, az_name)) { > - icsbrec_availability_zone_delete(az); > - break; > - } > - } > - free(az_name); > - az_name = NULL; > - } > - > - if (!nb_global->name[0]) { > - return NULL; > - } > - > - if (!az_name) { > - az_name = xstrdup(nb_global->name); > - } > - > - if (ctx->ovnisb_unlocked_txn) { > - ovsdb_idl_txn_add_comment(ctx->ovnisb_unlocked_txn, "AZ %s", > az_name); > - } > - > - ICSBREC_AVAILABILITY_ZONE_FOR_EACH (az, ctx->ovnisb_unlocked_idl) { > - if (!strcmp(az->name, az_name)) { > - ctx->runned_az = az; > - return az; > - } > - } > - > - /* Create AZ in ISB */ > - if (ctx->ovnisb_unlocked_txn) { > - VLOG_INFO("Register AZ %s to interconnection DB.", az_name); > - az = icsbrec_availability_zone_insert(ctx->ovnisb_unlocked_txn); > - icsbrec_availability_zone_set_name(az, az_name); > - ctx->runned_az = az; > - return az; > - } > - return NULL; > -} > - > static uint32_t > allocate_dp_key(struct hmap *dp_tnlids, bool vxlan_mode, const char *name) > { > @@ -611,7 +549,8 @@ sync_addr_set_from_icsb(struct ovsdb_idl_txn *ovnnb_txn, > } > > void > -address_set_run(struct ic_context *ctx) > +address_set_run(struct ic_context *ctx, > + const struct icsbrec_availability_zone *runned_az) The other _run() functions take the ic_context as a sole parameter, but address_set_run() also takes the runned_az as a parameter. The other _run() functions call inc_proc_ic_get_runned_az() to get the runned_az within the function. I believe in every case, the runned_az is checked for NULLity before calling the _run() function, so it makes sense to pass the runned_az as a parameter to the function, like is done here. Although if you'd rather just change address_set_run() to be consistent with the others, that's fine too. > { > if (!ctx->ovnisb_unlocked_txn || !ctx->ovnnb_txn || !ctx->ovnsb_txn) { > return; > @@ -621,7 +560,7 @@ address_set_run(struct ic_context *ctx) > struct shash ic_remote_as = SHASH_INITIALIZER(&ic_remote_as); > const struct icsbrec_address_set *ic_as; > ICSBREC_ADDRESS_SET_FOR_EACH (ic_as, ctx->ovnisb_unlocked_idl) { > - if (ic_as->availability_zone == ctx->runned_az) { > + if (ic_as->availability_zone == runned_az) { > shash_add(&ic_local_as, ic_as->name, ic_as); > } else { > /* Merge addresses from all remote AZs that share the same > @@ -659,7 +598,7 @@ address_set_run(struct ic_context *ctx) > const struct icsbrec_address_set *icsb_as; > icsb_as = shash_find_and_delete(&ic_local_as, sb_as->name); > sync_addr_set_to_icsb(ctx->ovnisb_unlocked_txn, sb_as, > icsb_as, > - ctx->runned_az); > + runned_az); > } > } > } > @@ -721,7 +660,7 @@ gateway_run(struct ic_context *ctx) > 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) { > + if (gw->availability_zone == inc_proc_ic_get_runned_az()) { > shash_add(&local_gws, gw->name, gw); > } else { > shash_add(&remote_gws, gw->name, gw); > @@ -734,7 +673,8 @@ gateway_run(struct ic_context *ctx) > 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_availability_zone(gw, > + inc_proc_ic_get_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)) { > @@ -1417,7 +1357,7 @@ port_binding_run(struct ic_context *ctx) > const struct icsbrec_port_binding *isb_pb_key = > icsbrec_port_binding_index_init_row(ctx->icsbrec_port_binding_by_az); > icsbrec_port_binding_index_set_availability_zone(isb_pb_key, > - ctx->runned_az); > + inc_proc_ic_get_runned_az()); > > ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key, > ctx->icsbrec_port_binding_by_az) { > @@ -1456,7 +1396,7 @@ port_binding_run(struct ic_context *ctx) > > ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key, > > ctx->icsbrec_port_binding_by_ts) { > - if (isb_pb->availability_zone == ctx->runned_az) { > + if (isb_pb->availability_zone == inc_proc_ic_get_runned_az()) { > shash_add(&local_pbs, isb_pb->logical_port, isb_pb); > shash_find_and_delete(&switch_all_local_pbs, > isb_pb->logical_port); > @@ -1478,8 +1418,9 @@ port_binding_run(struct ic_context *ctx) > if (ctx->ovnisb_txn && is_az_leader(ctx->ovnisb_txn)) { > if (!isb_pb) { > isb_pb = create_isb_pb( > - ctx->ovnisb_txn, tsp->name, ctx->runned_az, > - ts->name, &ts->header_.uuid, > "transit-switch-port", > + ctx->ovnisb_txn, tsp->name, > + inc_proc_ic_get_runned_az(), ts->name, > + &ts->header_.uuid, "transit-switch-port", > &pb_tnlids); > } > sync_tsp_pb(tsp, isb_pb); > @@ -1489,7 +1430,7 @@ port_binding_run(struct ic_context *ctx) > isb_pb = shash_find_and_delete(&local_pbs, tsp->name); > if (!isb_pb) { > isb_pb = create_isb_pb(ctx->ovnisb_unlocked_txn, > tsp->name, > - ctx->runned_az, > + inc_proc_ic_get_runned_az(), > ts->name, &ts->header_.uuid, > "transit-switch-port", > &pb_tnlids); > } > @@ -1532,8 +1473,8 @@ port_binding_run(struct ic_context *ctx) > if (!isb_pb) { > isb_pb = create_isb_pb( > ctx->ovnisb_unlocked_txn, sb_pb->logical_port, > - ctx->runned_az, ts->name, &ts->header_.uuid, > - "transit-switch-port", &pb_tnlids); > + inc_proc_ic_get_runned_az(), ts->name, > + &ts->header_.uuid, "transit-switch-port", > &pb_tnlids); > sync_ts_isb_pb(ctx, sb_pb, isb_pb); > } else { > sync_local_port(ctx, isb_pb, sb_pb, lsp); > @@ -1617,7 +1558,7 @@ port_binding_run(struct ic_context *ctx) > > ICSBREC_PORT_BINDING_FOR_EACH_EQUAL (isb_pb, isb_pb_key, > > ctx->icsbrec_port_binding_by_ts) { > - if (isb_pb->availability_zone == ctx->runned_az) { > + if (isb_pb->availability_zone == inc_proc_ic_get_runned_az()) { > shash_add(&local_pbs, isb_pb->logical_port, isb_pb); > shash_find_and_delete(&router_all_local_pbs, > isb_pb->logical_port); > @@ -1636,7 +1577,7 @@ port_binding_run(struct ic_context *ctx) > isb_pb = shash_find_and_delete(&local_pbs, trp->name); > if (!isb_pb) { > isb_pb = create_isb_pb(ctx->ovnisb_unlocked_txn, > trp->name, > - ctx->runned_az, > + inc_proc_ic_get_runned_az(), > tr->name, &tr->header_.uuid, > "transit-router-port", > &pb_tnlids); > icsbrec_port_binding_set_address(isb_pb, trp->mac); > @@ -2572,7 +2513,8 @@ sync_learned_routes(struct ic_context *ctx, > || uuid_equals(&ic_lr->lr->header_.uuid, &lr_uuid)) { > continue; > } > - } else if (isb_route->availability_zone == ctx->runned_az) { > + } else if (isb_route->availability_zone == > + inc_proc_ic_get_runned_az()) { > continue; > } > > @@ -3026,14 +2968,14 @@ route_run(struct ic_context *ctx) > return; > } > > - delete_orphan_ic_routes(ctx, ctx->runned_az); > + delete_orphan_ic_routes(ctx, inc_proc_ic_get_runned_az()); > > struct hmap ic_lrs = HMAP_INITIALIZER(&ic_lrs); > const struct icsbrec_port_binding *isb_pb; > const struct icsbrec_port_binding *isb_pb_key = > icsbrec_port_binding_index_init_row(ctx->icsbrec_port_binding_by_az); > icsbrec_port_binding_index_set_availability_zone(isb_pb_key, > - ctx->runned_az); > + inc_proc_ic_get_runned_az()); > > /* Each port on TS maps to a logical router, which is stored in the > * external_ids:router-id of the IC SB port_binding record. > @@ -3118,7 +3060,8 @@ route_run(struct ic_context *ctx) > } > struct shash_node *node; > SHASH_FOR_EACH (node, &routes_ad_by_ts) { > - advertise_routes(ctx, ctx->runned_az, node->name, node->data); > + advertise_routes(ctx, inc_proc_ic_get_runned_az(), node->name, > + node->data); > hmap_destroy(node->data); > } > shash_destroy_free_data(&routes_ad_by_ts); > @@ -3271,8 +3214,8 @@ create_pushed_svcs_mon(struct ic_context *ctx, > } > create_service_monitor_info(pushed_svcs_map, sb_rec, > &sb_rec->header_.uuid, > - ctx->runned_az->name, target_az_name, > - NULL, false); > + inc_proc_ic_get_runned_az()->name, > + target_az_name, NULL, false); > } > > sbrec_service_monitor_index_destroy_row(key); > @@ -3287,7 +3230,7 @@ create_synced_svcs_mon(struct ic_context *ctx, > ctx->icsbrec_service_monitor_by_target_az); > > icsbrec_service_monitor_index_set_target_availability_zone( > - key, ctx->runned_az->name); > + key, inc_proc_ic_get_runned_az()->name); > > const struct icsbrec_service_monitor *ic_rec; > ICSBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (ic_rec, key, > @@ -3304,7 +3247,7 @@ create_synced_svcs_mon(struct ic_context *ctx, > const char *chassis_name = pb->chassis ? pb->chassis->name : NULL; > create_service_monitor_info(synced_svcs_map, ic_rec, > &ic_rec->header_.uuid, > - ctx->runned_az->name, > + inc_proc_ic_get_runned_az()->name, > NULL, chassis_name, true); > } > > @@ -3320,14 +3263,14 @@ create_local_ic_svcs_map(struct ic_context *ctx, > ctx->icsbrec_service_monitor_by_source_az); > > icsbrec_service_monitor_index_set_source_availability_zone( > - key, ctx->runned_az->name); > + key, inc_proc_ic_get_runned_az()->name); > > const struct icsbrec_service_monitor *ic_rec; > ICSBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (ic_rec, key, > ctx->icsbrec_service_monitor_by_source_az) { > create_service_monitor_info(owned_svc_map, ic_rec, > &ic_rec->header_.uuid, > - ctx->runned_az->name, NULL, > + inc_proc_ic_get_runned_az()->name, NULL, > NULL, true); > } > > @@ -3350,7 +3293,7 @@ create_local_sb_svcs_map(struct ic_context *ctx, > ctx->sbrec_service_monitor_by_ic_learned) { > create_service_monitor_info(owned_svc_map, sb_rec, > &sb_rec->header_.uuid, > - ctx->runned_az->name, NULL, > + inc_proc_ic_get_runned_az()->name, NULL, > NULL, false); > } > > @@ -3593,6 +3536,7 @@ sync_service_monitor(struct ic_context *ctx) > */ > static void > update_sequence_numbers(struct ic_context *ctx, > + const struct icsbrec_availability_zone *runned_az, > struct ovsdb_idl_loop *ic_sb_loop) > { > if (!ctx->ovnisb_unlocked_txn || !ctx->ovninb_txn) { > @@ -3611,14 +3555,14 @@ update_sequence_numbers(struct ic_context *ctx, > } > > if ((ic_nb->nb_ic_cfg != ic_sb->nb_ic_cfg) && > - (ic_nb->nb_ic_cfg != ctx->runned_az->nb_ic_cfg)) { > + (ic_nb->nb_ic_cfg != runned_az->nb_ic_cfg)) { > /* Deal with potential overflows. */ > - if (ctx->runned_az->nb_ic_cfg == INT64_MAX) { > - icsbrec_availability_zone_set_nb_ic_cfg(ctx->runned_az, 0); > + if (runned_az->nb_ic_cfg == INT64_MAX) { > + icsbrec_availability_zone_set_nb_ic_cfg(runned_az, 0); > } > ic_sb_loop->next_cfg = ic_nb->nb_ic_cfg; > ovsdb_idl_txn_increment(ctx->ovnisb_unlocked_txn, > - &ctx->runned_az->header_, > + &runned_az->header_, > &icsbrec_availability_zone_col_nb_ic_cfg, true); > return; > } > @@ -3626,22 +3570,22 @@ update_sequence_numbers(struct ic_context *ctx, > /* handle cases where accidentally AZ:ic_nb_cfg exceeds > * the INB:ic_nb_cfg. > */ > - if (ctx->runned_az->nb_ic_cfg != ic_sb_loop->cur_cfg) { > - icsbrec_availability_zone_set_nb_ic_cfg(ctx->runned_az, > + if (runned_az->nb_ic_cfg != ic_sb_loop->cur_cfg) { > + icsbrec_availability_zone_set_nb_ic_cfg(runned_az, > ic_sb_loop->cur_cfg); > return; > } > > const struct icsbrec_availability_zone *other_az; > ICSBREC_AVAILABILITY_ZONE_FOR_EACH (other_az, ctx->ovnisb_unlocked_idl) { > - if (other_az->nb_ic_cfg != ctx->runned_az->nb_ic_cfg) { > + if (other_az->nb_ic_cfg != runned_az->nb_ic_cfg) { > return; > } > } > /* All the AZs are updated successfully, update SB/NB counter. */ > if (ic_nb->nb_ic_cfg != ic_sb->nb_ic_cfg) { > - icsbrec_ic_sb_global_set_nb_ic_cfg(ic_sb, ctx->runned_az->nb_ic_cfg); > - icnbrec_ic_nb_global_set_sb_ic_cfg(ic_nb, ctx->runned_az->nb_ic_cfg); > + icsbrec_ic_sb_global_set_nb_ic_cfg(ic_sb, runned_az->nb_ic_cfg); > + icnbrec_ic_nb_global_set_sb_ic_cfg(ic_nb, runned_az->nb_ic_cfg); > } > } > > @@ -4219,6 +4163,17 @@ main(int argc, char *argv[]) > ovnisb_idl_loop.idl, > ovnisb_unlocked_idl_loop.idl, > ovninb_idl_loop.idl); > + > + /* Postpone the next engine run by the length of the previous one, up > + * to this interval, to coalesce bursts of change-driven runs. A > + * forced recompute (set_force_recompute) still runs immediately, so > + * this only throttles the natural, incremental path. */ > + const struct icnbrec_ic_nb_global *ic_nb_global = > + icnbrec_ic_nb_global_first(ovninb_idl_loop.idl); > + eng_ctx.backoff_ms = ic_nb_global > + ? smap_get_uint(&ic_nb_global->options, > + "ic-backoff-interval-ms", 0) : 0; > + > memory_run(); > if (memory_should_report()) { > struct simap usage = SIMAP_INITIALIZER(&usage); > @@ -4389,12 +4344,16 @@ main(int argc, char *argv[]) > ovsdb_idl_has_ever_connected(ctx.ovnisb_unlocked_idl)) { > if (ctx.ovnnb_txn && ctx.ovnsb_txn && ctx.ovninb_txn && > ctx.ovnisb_unlocked_txn && > inc_proc_ic_can_run(&eng_ctx)) { > - ctx.runned_az = az_run(&ctx); > - VLOG_DBG("Availability zone: %s", ctx.runned_az ? > - ctx.runned_az->name : "not created yet."); > - if (ctx.runned_az) { > - (void) inc_proc_ic_run(&ctx, &eng_ctx); > - update_sequence_numbers(&ctx, > + /* The availability zone is now resolved by the en_az > + * engine node. The subsystem nodes skip their work when > + * there is no AZ; the sequence-number bookkeeping below > + * runs outside the engine, so it reads the resolved AZ > via > + * inc_proc_ic_get_runned_az(). */ > + (void) inc_proc_ic_run(&ctx, &eng_ctx); > + const struct icsbrec_availability_zone *runned_az = > + inc_proc_ic_get_runned_az(); > + if (runned_az) { > + update_sequence_numbers(&ctx, runned_az, > &ovnisb_unlocked_idl_loop); > } > } else if (!inc_proc_ic_get_force_recompute()) { > diff --git a/ic/ovn-ic.h b/ic/ovn-ic.h > index b06725373..194eba397 100644 > --- a/ic/ovn-ic.h > +++ b/ic/ovn-ic.h > @@ -28,7 +28,6 @@ struct ic_context { > struct ovsdb_idl_txn *ovninb_txn; > struct ovsdb_idl_txn *ovnisb_txn; > struct ovsdb_idl_txn *ovnisb_unlocked_txn; > - const struct icsbrec_availability_zone *runned_az; > struct ovsdb_idl_index *nbrec_ls_by_name; > struct ovsdb_idl_index *nbrec_lr_by_name; > struct ovsdb_idl_index *nbrec_lrp_by_name; > @@ -63,6 +62,7 @@ enum ic_port_binding_type { IC_SWITCH_PORT, IC_ROUTER_PORT, > IC_PORT_MAX }; > > struct hmap; > struct shash; > +struct icsbrec_availability_zone; > > /* Per-subsystem entry points, invoked by the incremental-processing engine > * nodes (see ic/en-*.c). Each performs a full recompute of its subsystem > and > @@ -70,7 +70,8 @@ struct shash; > void enumerate_datapaths(struct ic_context *ctx, struct hmap *dp_tnlids, > struct shash *isb_ts_dps, struct shash *isb_tr_dps); > void gateway_run(struct ic_context *ctx); > -void address_set_run(struct ic_context *ctx); > +void address_set_run(struct ic_context *ctx, > + const struct icsbrec_availability_zone *runned_az); > void ts_run(struct ic_context *ctx, struct hmap *dp_tnlids, > struct shash *isb_ts_dps); > void tr_run(struct ic_context *ctx, struct hmap *dp_tnlids, > diff --git a/ovn-ic-nb.xml b/ovn-ic-nb.xml > index f6110324c..408b44558 100644 > --- a/ovn-ic-nb.xml > +++ b/ovn-ic-nb.xml > @@ -65,6 +65,29 @@ > options are described individually below. > </column> > > + <column name="options" key="ic-backoff-interval-ms"> > + <p> > + Upper bound, in milliseconds, on how long <code>ovn-ic</code> > + postpones the next run of its incremental-processing engine. > + After each engine run, the next run is delayed by the duration of > + the run that just finished, capped by this value. This coalesces > + bursts of change-driven runs into fewer, larger runs, trading a > + small amount of latency for reduced CPU usage when the databases > + are changing rapidly. > + </p> > + > + <p> > + This throttling only applies to the natural, change-driven > + incremental path. A forced full recompute is never delayed and > + always runs immediately. > + </p> > + > + <p> > + The default value is <code>0</code>, which disables the backoff so > + each run is scheduled as soon as there is work to do. > + </p> > + </column> > + > <column name="options" key="ic_probe_interval"> > <p> > The inactivity probe interval of the connection to the OVN IC > -- > 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
