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

Reply via email to