Acked-by: Lucas Vargas Dias <[email protected]>

Em qua., 2 de set. de 2026 às 18:20, Paulo Guilherme Silva
<[email protected]> escreveu:

> Move the load-balancer health-check sync out of ovn-ic.c into the
> en_service_monitor node and give the node a change handler for its
> busiest input.
>
> The sync reads an SB Port_Binding only through create_synced_svcs_mon(),
> which - for each IC-SB Service_Monitor targeting this AZ - looks up the
> backing port by 'logical_port' and reads its 'up' and 'chassis'.  SB
> Port_Binding is the busiest table in an availability zone, so answering
> every change on it with a full recompute charges the whole health-check
> sync to churn that cannot affect it.
>
> Add a handler that falls back only when the change can matter: the row is
> new or deleted, or its 'up'/'chassis' column changed, and the port backs
> a Service_Monitor targeting this AZ.  The second test resolves through
> the existing by-target-AZ/logical-port index, so it costs one lookup per
> changed row.  Every other port-binding change is answered as handled and
> unchanged.
>
> Drop the en_icsb_availability_zone input from en_service_monitor and
> en_address_set, and stop modelling the Availability_Zone table as an
> engine input altogether: these were its last two consumers.  Both nodes
> need only the AZ identity that en_az reports and neither reads the table,
> so the input only exposed them to the nb_ic_cfg sequence number bumped on
> its rows.  en_gateway, en_port_binding and en_route already avoid it for
> the same reason; this completes the pattern.
>
> Add tests/ovn-ic.at tests for the port-binding handler scoping and for
> the sequence-number churn no longer recomputing the node.
>
> Assisted-by: Claude Opus 4.8, Claude Code
> Signed-off-by: Paulo Guilherme Silva <[email protected]>
> ---
>  NEWS                    |   7 +
>  ic/en-service-monitor.c | 500 +++++++++++++++++++++++++++++++++++++++-
>  ic/en-service-monitor.h |   4 +
>  ic/inc-proc-ic.c        |  34 ++-
>  ic/ovn-ic.c             | 441 -----------------------------------
>  ic/ovn-ic.h             |   2 -
>  tests/ovn-ic.at         |  78 +++++++
>  7 files changed, 612 insertions(+), 454 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 819e81a79..4d2c73bbc 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -133,6 +133,13 @@ OVN v26.09.0 - xxx xx xxxx
>       coalescing bursts of change-driven runs into fewer, larger runs.  It
>       defaults to 0, which keeps running as soon as there is work to do.  A
>       forced full recompute is never delayed.
> +   - ovn-ic now processes database changes incrementally.  Its processing
> +     engine is split into one node per subsystem - availability zone,
> +     gateways, transit switches and routers, datapath tunnel keys, port
> +     bindings, routes, service monitors and address sets - and each node
> has
> +     change handlers, so a change is reconciled in place instead of
> re-running
> +     the whole ovn-ic computation.  The "inc-engine/show-stats" command
> +     reports the per-node recompute counters.
>
>  OVN v26.03.0 - xxx xx xxxx
>  --------------------------
> diff --git a/ic/en-service-monitor.c b/ic/en-service-monitor.c
> index d0aab60bb..bd903e709 100644
> --- a/ic/en-service-monitor.c
> +++ b/ic/en-service-monitor.c
> @@ -14,14 +14,452 @@
>
>  #include <config.h>
>
> -#include "en-service-monitor.h"
>  #include "en-az.h"
> +#include "en-service-monitor.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"
> +#include "ovsdb-idl.h"
>
>  VLOG_DEFINE_THIS_MODULE(en_ic_service_monitor);
>
> +struct service_monitor_info {
> +    struct hmap_node hmap_node;
> +    union {
> +        const struct sbrec_service_monitor *sb_rec;
> +        const struct icsbrec_service_monitor *ic_rec;
> +    } db_rec;
> +    /* Destination availability zone name. */
> +    char *dst_az_name;
> +    /* Source availability zone name. */
> +    char *src_az_name;
> +    /* Chassis name associated with monitor logical port. */
> +    char *chassis_name;
> +};
> +
> +struct sync_service_monitor_data {
> +    /* Map of service monitors to be pushed to other AZs. */
> +    struct hmap pushed_svcs_map;
> +    /* Map of service monitors synced from other AZs to our. */
> +    struct hmap synced_svcs_map;
> +    /* Map of local service monitors in the ICSBDB. */
> +    struct hmap local_ic_svcs_map;
> +    /* Map of local service monitors in SBDB. */
> +    struct hmap local_sb_svcs_map;
> +    /* MAC address used for service monitor.  */
> +    char *prpg_svc_monitor_mac;
> +};
> +
> +static void
> +create_service_monitor_info(struct hmap *svc_map,
> +                            const void *db_rec,
> +                            const struct uuid *uuid,
> +                            const char *src_az_name,
> +                            const char *target_az_name,
> +                            const char *chassis_name,
> +                            bool ic_rec)
> +{
> +    struct service_monitor_info *svc_mon = xzalloc(sizeof(*svc_mon));
> +    size_t hash = uuid_hash(uuid);
> +
> +    if (ic_rec) {
> +        svc_mon->db_rec.ic_rec =
> +            (const struct icsbrec_service_monitor *) db_rec;
> +    } else {
> +        svc_mon->db_rec.sb_rec =
> +            (const struct sbrec_service_monitor *) db_rec;
> +    }
> +
> +    svc_mon->dst_az_name = target_az_name ? xstrdup(target_az_name) :
> NULL;
> +    svc_mon->chassis_name = chassis_name ? xstrdup(chassis_name) : NULL;
> +    svc_mon->src_az_name = xstrdup(src_az_name);
> +
> +    hmap_insert(svc_map, &svc_mon->hmap_node, hash);
> +}
> +
> +static void
> +destroy_service_monitor_info(struct service_monitor_info *svc_mon)
> +{
> +    free(svc_mon->src_az_name);
> +    free(svc_mon->dst_az_name);
> +    free(svc_mon->chassis_name);
> +    free(svc_mon);
> +}
> +
> +static void
> +refresh_sb_record_cache(struct hmap *svc_mon_map,
> +                        const struct sbrec_service_monitor *lookup_rec)
> +{
> +    size_t hash = uuid_hash(&lookup_rec->header_.uuid);
> +    struct service_monitor_info *svc_mon;
> +
> +    HMAP_FOR_EACH_WITH_HASH (svc_mon, hmap_node, hash, svc_mon_map) {
> +        ovs_assert(svc_mon->db_rec.sb_rec);
> +        if (svc_mon->db_rec.sb_rec == lookup_rec) {
> +            hmap_remove(svc_mon_map, &svc_mon->hmap_node);
> +            destroy_service_monitor_info(svc_mon);
> +            return;
> +        }
> +    }
> +}
> +
> +static void
> +refresh_ic_record_cache(struct hmap *svc_mon_map,
> +                        const struct icsbrec_service_monitor *lookup_rec)
> +{
> +    size_t hash = uuid_hash(&lookup_rec->header_.uuid);
> +    struct service_monitor_info *svc_mon;
> +
> +    HMAP_FOR_EACH_WITH_HASH (svc_mon, hmap_node, hash, svc_mon_map) {
> +        ovs_assert(svc_mon->db_rec.ic_rec);
> +        if (svc_mon->db_rec.ic_rec == lookup_rec) {
> +            hmap_remove(svc_mon_map, &svc_mon->hmap_node);
> +            destroy_service_monitor_info(svc_mon);
> +            return;
> +        }
> +    }
> +}
> +
> +static void
> +remove_unused_ic_records(struct hmap *local_ic_svcs_map)
> +{
> +    struct service_monitor_info *svc_mon;
> +    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, local_ic_svcs_map) {
> +        icsbrec_service_monitor_delete(svc_mon->db_rec.ic_rec);
> +        destroy_service_monitor_info(svc_mon);
> +    }
> +
> +    hmap_destroy(local_ic_svcs_map);
> +}
> +
> +static void
> +remove_unused_sb_records(struct hmap *local_sb_svcs_map)
> +{
> +    struct service_monitor_info *svc_mon;
> +    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, local_sb_svcs_map) {
> +        sbrec_service_monitor_delete(svc_mon->db_rec.sb_rec);
> +        destroy_service_monitor_info(svc_mon);
> +    }
> +
> +    hmap_destroy(local_sb_svcs_map);
> +}
> +
> +static void
> +create_pushed_svcs_mon(struct ic_context *ctx,
> +                       const struct icsbrec_availability_zone *runned_az,
> +                       struct hmap *pushed_svcs_map)
> +{
> +    struct sbrec_service_monitor *key =
> +        sbrec_service_monitor_index_init_row(
> +            ctx->sbrec_service_monitor_by_remote_type);
> +
> +    sbrec_service_monitor_index_set_remote(key, true);
> +
> +    const struct sbrec_service_monitor *sb_rec;
> +    SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sb_rec, key,
> +        ctx->sbrec_service_monitor_by_remote_type) {
> +        const char *target_az_name = smap_get(&sb_rec->options,
> +                                              "az-name");
> +        if (!target_az_name) {
> +            continue;
> +        }
> +        create_service_monitor_info(pushed_svcs_map, sb_rec,
> +                                    &sb_rec->header_.uuid,
> +                                    runned_az->name, target_az_name,
> +                                    NULL, false);
> +    }
> +
> +    sbrec_service_monitor_index_destroy_row(key);
> +}
> +
> +static void
> +create_synced_svcs_mon(struct ic_context *ctx,
> +                       const struct icsbrec_availability_zone *runned_az,
> +                       struct hmap *synced_svcs_map)
> +{
> +    struct icsbrec_service_monitor *key =
> +        icsbrec_service_monitor_index_init_row(
> +          ctx->icsbrec_service_monitor_by_target_az);
> +
> +    icsbrec_service_monitor_index_set_target_availability_zone(
> +        key, runned_az->name);
> +
> +    const struct icsbrec_service_monitor *ic_rec;
> +    ICSBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (ic_rec, key,
> +        ctx->icsbrec_service_monitor_by_target_az) {
> +
> +        const struct sbrec_port_binding *pb =
> +            find_sb_pb_by_name(ctx->sbrec_port_binding_by_name,
> +                               ic_rec->logical_port);
> +
> +        if (!pb || !pb->up) {
> +            continue;
> +        }
> +
> +        const char *chassis_name = pb->chassis ? pb->chassis->name : NULL;
> +        create_service_monitor_info(synced_svcs_map, ic_rec,
> +                                    &ic_rec->header_.uuid,
> +                                    runned_az->name,
> +                                    NULL, chassis_name, true);
> +    }
> +
> +    icsbrec_service_monitor_index_destroy_row(key);
> +}
> +
> +static void
> +create_local_ic_svcs_map(struct ic_context *ctx,
> +                         const struct icsbrec_availability_zone
> *runned_az,
> +                         struct hmap *owned_svc_map)
> +{
> +    struct icsbrec_service_monitor *key =
> +        icsbrec_service_monitor_index_init_row(
> +          ctx->icsbrec_service_monitor_by_source_az);
> +
> +    icsbrec_service_monitor_index_set_source_availability_zone(
> +        key, 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,
> +                                    runned_az->name, NULL,
> +                                    NULL, true);
> +    }
> +
> +    icsbrec_service_monitor_index_destroy_row(key);
> +}
> +
> +static void
> +create_local_sb_svcs_map(struct ic_context *ctx,
> +                         const struct icsbrec_availability_zone
> *runned_az,
> +                         struct hmap *owned_svc_map)
> +{
> +    struct sbrec_service_monitor *key =
> +        sbrec_service_monitor_index_init_row(
> +          ctx->sbrec_service_monitor_by_ic_learned);
> +
> +    sbrec_service_monitor_index_set_ic_learned(
> +        key, true);
> +
> +    const struct sbrec_service_monitor *sb_rec;
> +    SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sb_rec, key,
> +        ctx->sbrec_service_monitor_by_ic_learned) {
> +        create_service_monitor_info(owned_svc_map, sb_rec,
> +                                    &sb_rec->header_.uuid,
> +                                    runned_az->name, NULL,
> +                                    NULL, false);
> +    }
> +
> +    sbrec_service_monitor_index_destroy_row(key);
> +}
> +
> +static const struct sbrec_service_monitor *
> +lookup_sb_svc_rec(struct ic_context *ctx,
> +                  const struct service_monitor_info *svc_mon)
> +{
> +    const struct icsbrec_service_monitor *db_rec =
> +        svc_mon->db_rec.ic_rec;
> +    struct sbrec_service_monitor *key =
> +        sbrec_service_monitor_index_init_row(
> +            ctx->sbrec_service_monitor_by_remote_type_logical_port);
> +
> +    sbrec_service_monitor_index_set_remote(key, false);
> +    sbrec_service_monitor_index_set_logical_port(key,
> db_rec->logical_port);
> +
> +    const struct sbrec_service_monitor *sb_rec;
> +    SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sb_rec, key,
> +        ctx->sbrec_service_monitor_by_remote_type_logical_port) {
> +        if (db_rec->port == sb_rec->port &&
> +            ((db_rec->type && sb_rec->type &&
> +              !strcmp(db_rec->type, sb_rec->type)) ||
> +             (!db_rec->type && !sb_rec->type)) &&
> +            !strcmp(db_rec->ip, sb_rec->ip) &&
> +            !strcmp(db_rec->src_ip, sb_rec->src_ip) &&
> +            !strcmp(db_rec->protocol, sb_rec->protocol)) {
> +            sbrec_service_monitor_index_destroy_row(key);
> +            return sb_rec;
> +        }
> +    }
> +
> +    sbrec_service_monitor_index_destroy_row(key);
> +
> +    return NULL;
> +}
> +
> +static const struct icsbrec_service_monitor *
> +lookup_icsb_svc_rec(struct ic_context *ctx,
> +                    const struct service_monitor_info *svc_mon)
> +{
> +    const struct sbrec_service_monitor *db_rec =
> +       svc_mon->db_rec.sb_rec;
> +    struct icsbrec_service_monitor *key =
> +        icsbrec_service_monitor_index_init_row(
> +        ctx->icsbrec_service_monitor_by_target_az_logical_port);
> +
> +    ovs_assert(svc_mon->dst_az_name);
> +    icsbrec_service_monitor_index_set_target_availability_zone(
> +        key, svc_mon->dst_az_name);
> +
> +    icsbrec_service_monitor_index_set_logical_port(
> +        key, db_rec->logical_port);
> +
> +    const struct icsbrec_service_monitor *ic_rec;
> +    ICSBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (ic_rec, key,
> +        ctx->icsbrec_service_monitor_by_target_az_logical_port) {
> +        if (db_rec->port == ic_rec->port &&
> +            ((db_rec->type && ic_rec->type &&
> +              !strcmp(db_rec->type, ic_rec->type)) ||
> +             (!db_rec->type && !ic_rec->type)) &&
> +            !strcmp(db_rec->ip, ic_rec->ip) &&
> +            !strcmp(db_rec->src_ip, ic_rec->src_ip) &&
> +            !strcmp(db_rec->protocol, ic_rec->protocol) &&
> +            !strcmp(db_rec->logical_port, ic_rec->logical_port)) {
> +            icsbrec_service_monitor_index_destroy_row(key);
> +            return ic_rec;
> +        }
> +    }
> +
> +    icsbrec_service_monitor_index_destroy_row(key);
> +
> +    return NULL;
> +}
> +
> +static void
> +create_service_monitor_data(struct ic_context *ctx,
> +                            const struct icsbrec_availability_zone
> *runned_az,
> +                            struct sync_service_monitor_data *sync_data)
> +{
> +    const struct sbrec_sb_global *ic_sb = sbrec_sb_global_first(
> +                                                ctx->ovnsb_idl);
> +    const char *svc_monitor_mac = smap_get(&ic_sb->options,
> +                                           "svc_monitor_mac");
> +
> +    if (!svc_monitor_mac) {
> +        return;
> +    }
> +
> +    sync_data->prpg_svc_monitor_mac = xstrdup(svc_monitor_mac);
> +    create_pushed_svcs_mon(ctx, runned_az, &sync_data->pushed_svcs_map);
> +    create_synced_svcs_mon(ctx, runned_az, &sync_data->synced_svcs_map);
> +    create_local_ic_svcs_map(ctx, runned_az,
> &sync_data->local_ic_svcs_map);
> +    create_local_sb_svcs_map(ctx, runned_az,
> &sync_data->local_sb_svcs_map);
> +}
> +
> +static void
> +destroy_service_monitor_data(struct sync_service_monitor_data *sync_data)
> +{
> +    struct service_monitor_info *svc_mon;
> +    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data->pushed_svcs_map) {
> +        destroy_service_monitor_info(svc_mon);
> +    }
> +
> +    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data->synced_svcs_map) {
> +        destroy_service_monitor_info(svc_mon);
> +    }
> +
> +    hmap_destroy(&sync_data->pushed_svcs_map);
> +    hmap_destroy(&sync_data->synced_svcs_map);
> +    free(sync_data->prpg_svc_monitor_mac);
> +}
> +
> +static void
> +sync_service_monitor(struct ic_context *ctx,
> +                     const struct icsbrec_availability_zone *runned_az)
> +{
> +    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {
> +        return;
> +    }
> +
> +    struct sync_service_monitor_data sync_data;
> +    memset(&sync_data, 0, sizeof(sync_data));
> +    hmap_init(&sync_data.pushed_svcs_map);
> +    hmap_init(&sync_data.synced_svcs_map);
> +    hmap_init(&sync_data.local_ic_svcs_map);
> +    hmap_init(&sync_data.local_sb_svcs_map);
> +
> +    create_service_monitor_data(ctx, runned_az, &sync_data);
> +
> +    struct service_monitor_info *svc_mon;
> +    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data.pushed_svcs_map) {
> +        const struct sbrec_service_monitor *db_rec =
> svc_mon->db_rec.sb_rec;
> +        const struct icsbrec_service_monitor *ic_rec =
> +            lookup_icsb_svc_rec(ctx, svc_mon);
> +
> +        if (ic_rec) {
> +            sbrec_service_monitor_set_status(db_rec, ic_rec->status);
> +        } else {
> +            ic_rec =
> icsbrec_service_monitor_insert(ctx->ovnisb_unlocked_txn);
> +            icsbrec_service_monitor_set_type(ic_rec, db_rec->type);
> +            icsbrec_service_monitor_set_ip(ic_rec, db_rec->ip);
> +            icsbrec_service_monitor_set_port(ic_rec, db_rec->port);
> +            icsbrec_service_monitor_set_src_ip(ic_rec, db_rec->src_ip);
> +            icsbrec_service_monitor_set_src_mac(ic_rec,
> +                sync_data.prpg_svc_monitor_mac);
> +            icsbrec_service_monitor_set_protocol(ic_rec,
> db_rec->protocol);
> +            icsbrec_service_monitor_set_logical_port(ic_rec,
> +                db_rec->logical_port);
> +            icsbrec_service_monitor_set_target_availability_zone(ic_rec,
> +                svc_mon->dst_az_name);
> +            icsbrec_service_monitor_set_source_availability_zone(ic_rec,
> +                svc_mon->src_az_name);
> +        }
> +
> +        /* Always update options because they change from NB. */
> +        icsbrec_service_monitor_set_options(ic_rec, &db_rec->options);
> +        refresh_ic_record_cache(&sync_data.local_ic_svcs_map, ic_rec);
> +    }
> +
> +    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data.synced_svcs_map) {
> +        const struct icsbrec_service_monitor *db_rec =
> +            svc_mon->db_rec.ic_rec;
> +        const struct sbrec_service_monitor *sb_rec =
> +            lookup_sb_svc_rec(ctx, svc_mon);
> +
> +        if (sb_rec) {
> +            icsbrec_service_monitor_set_status(svc_mon->db_rec.ic_rec,
> +                                               sb_rec->status);
> +        } else {
> +            sb_rec = sbrec_service_monitor_insert(ctx->ovnsb_txn);
> +            sbrec_service_monitor_set_type(sb_rec, db_rec->type);
> +            sbrec_service_monitor_set_ip(sb_rec, db_rec->ip);
> +            sbrec_service_monitor_set_port(sb_rec, db_rec->port);
> +            sbrec_service_monitor_set_src_ip(sb_rec, db_rec->src_ip);
> +            /* Set svc_monitor_mac from local SBDB. */
> +            sbrec_service_monitor_set_src_mac(sb_rec,
> +                sync_data.prpg_svc_monitor_mac);
> +            sbrec_service_monitor_set_protocol(sb_rec,
> +                db_rec->protocol);
> +            sbrec_service_monitor_set_logical_port(sb_rec,
> +                db_rec->logical_port);
> +            sbrec_service_monitor_set_remote(sb_rec, false);
> +            sbrec_service_monitor_set_ic_learned(sb_rec, true);
> +        }
> +
> +        /* Only update if ic owns it */
> +        if (sb_rec->ic_learned) {
> +            /* Always update options since they may change via
> +             * NB configuration. Also update chassis_name if
> +             * the port has been reassigned to a different chassis.
> +             */
> +            if (svc_mon->chassis_name) {
> +                sbrec_service_monitor_set_chassis_name(sb_rec,
> +                    svc_mon->chassis_name);
> +            }
> +            sbrec_service_monitor_set_options(sb_rec, &db_rec->options);
> +            refresh_sb_record_cache(&sync_data.local_sb_svcs_map, sb_rec);
> +        }
> +    }
> +
> +    /* Delete local created records that are no longer used. */
> +    remove_unused_ic_records(&sync_data.local_ic_svcs_map);
> +    remove_unused_sb_records(&sync_data.local_sb_svcs_map);
> +
> +    destroy_service_monitor_data(&sync_data);
> +}
> +
>  enum engine_node_state
>  en_service_monitor_run(struct engine_node *node,
>                         void *data OVS_UNUSED)
> @@ -41,6 +479,66 @@ en_service_monitor_run(struct engine_node *node,
>      return EN_UPDATED;
>  }
>
> +/* True if 'logical_port' backs a service monitor targeting this AZ -
> i.e. a
> + * port whose 'up'/'chassis' state create_synced_svcs_mon() reads. */
> +static bool
> +svc_monitor_target_lport(struct ic_context *ctx,
> +                         const struct icsbrec_availability_zone
> *runned_az,
> +                         const char *logical_port)
> +{
> +    struct icsbrec_service_monitor *key =
> +        icsbrec_service_monitor_index_init_row(
> +            ctx->icsbrec_service_monitor_by_target_az_logical_port);
> +    icsbrec_service_monitor_index_set_target_availability_zone(
> +        key, runned_az->name);
> +    icsbrec_service_monitor_index_set_logical_port(key, logical_port);
> +    const struct icsbrec_service_monitor *ic_rec =
> +        icsbrec_service_monitor_index_find(
> +            ctx->icsbrec_service_monitor_by_target_az_logical_port, key);
> +    icsbrec_service_monitor_index_destroy_row(key);
> +    return ic_rec != NULL;
> +}
> +
> +/* SB Port_Binding: sync_service_monitor() reads a port binding only
> through
> + * create_synced_svcs_mon(), which - for each IC-SB service monitor
> targeting
> + * this AZ - looks up the backing SB port binding by logical_port and
> reads its
> + * 'up' and 'chassis'.  So a port-binding change matters only when it is
> + * new/deleted or its 'up'/'chassis' changed AND the port backs such a
> service
> + * monitor.  Every other SB port-binding change (other columns, or ports
> that
> + * are not service-monitor backends - the vast majority of SB churn) is a
> + * no-op, instead of forcing a full recompute of this node. */
> +enum engine_input_handler_result
> +en_service_monitor_sb_port_binding_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_port_binding_table *tbl =
> +        EN_OVSDB_GET(engine_get_input("SB_port_binding", node));
> +    const struct sbrec_port_binding *pb;
> +    SBREC_PORT_BINDING_TABLE_FOR_EACH_TRACKED (pb, tbl) {
> +        if (!sbrec_port_binding_is_new(pb) &&
> +            !sbrec_port_binding_is_deleted(pb) &&
> +            !ovsdb_idl_track_is_updated(&pb->header_,
> +                                        &sbrec_port_binding_col_up) &&
> +            !ovsdb_idl_track_is_updated(&pb->header_,
> +                                        &sbrec_port_binding_col_chassis))
> {
> +            continue;
> +        }
> +        if (svc_monitor_target_lport(ctx, az->runned_az,
> pb->logical_port)) {
> +            return EN_UNHANDLED;
> +        }
> +    }
> +
> +    return EN_HANDLED_UNCHANGED;
> +}
> +
>  void *
>  en_service_monitor_init(struct engine_node *node OVS_UNUSED,
>                          struct engine_arg *arg OVS_UNUSED)
> diff --git a/ic/en-service-monitor.h b/ic/en-service-monitor.h
> index c0d6f0f0b..8b57d995f 100644
> --- a/ic/en-service-monitor.h
> +++ b/ic/en-service-monitor.h
> @@ -23,4 +23,8 @@ void *en_service_monitor_init(struct engine_node *node,
>                                struct engine_arg *arg);
>  void en_service_monitor_cleanup(void *data);
>
> +enum engine_input_handler_result
> +en_service_monitor_sb_port_binding_handler(struct engine_node *node,
> +                                           void *data);
> +
>  #endif /* EN_IC_SERVICE_MONITOR_H */
> diff --git a/ic/inc-proc-ic.c b/ic/inc-proc-ic.c
> index 92b368153..af0060ae5 100644
> --- a/ic/inc-proc-ic.c
> +++ b/ic/inc-proc-ic.c
> @@ -118,12 +118,14 @@ VLOG_DEFINE_THIS_MODULE(inc_proc_ic);
>      ICNB_NODES
>  #undef ICNB_NODE
>
> -/* Note: the ic_sb_global table is intentionally not modeled as an engine
> input
> - * node.  It only carries IC-SB sequence numbers, which are written by
> - * update_sequence_numbers() in the main loop (outside the engine) and
> are not
> - * read by any subsystem node. */
> +/* Note: the ic_sb_global and availability_zone tables are intentionally
> not
> + * modeled as engine input nodes.  ic_sb_global only carries IC-SB
> sequence
> + * numbers, written by update_sequence_numbers() in the main loop
> (outside the
> + * engine).  availability_zone is consumed by the en_az node, which reads
> it
> + * directly every iteration; the subsystem nodes depend on en_az for the
> AZ
> + * identity rather than on the (sequence-number-bumped) Availability_Zone
> + * table. */
>  #define ICSB_NODES \
> -    ICSB_NODE(availability_zone, "availability_zone") \
>      ICSB_NODE(service_monitor, "service_monitor") \
>      ICSB_NODE(route, "route") \
>      ICSB_NODE(datapath_binding, "datapath_binding") \
> @@ -351,13 +353,23 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
>      engine_add_input(&en_route, &en_sb_learned_route,
>                       route_sb_learned_route_handler);
>
> -    /* en_service_monitor: sync load-balancer health checks across AZs. */
> +    /* en_service_monitor: sync load-balancer health checks across AZs.
> +     *
> +     * Like the other AZ-scoped nodes it uses only the AZ identity
> +     * (en_az's resolved AZ name and the by-source/target-AZ indexes)
> +     * and does not read the Availability_Zone table, so it does not
> depend on
> +     * en_icsb_availability_zone and is not churned by its nb_ic_cfg
> sequence
> +     * number. */
>      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);
> +    /* SB port bindings are the busiest table in the AZ, but the sync
> reads
> +     * only the 'up'/'chassis' of ports backing a service monitor
> targeting
> +     * this AZ, so a dedicated handler scopes that churn out instead of
> forcing
> +     * a full recompute on every port-binding change. */
> +    engine_add_input(&en_service_monitor, &en_sb_port_binding,
> +                     en_service_monitor_sb_port_binding_handler);
>
>      /* en_address_set: advertise/learn address sets across AZs.
>       *
> @@ -365,9 +377,11 @@ void inc_proc_ic_init(struct ovsdb_idl_loop *nb,
>       * 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. */
> +     * resolved AZ changes.  It uses only that AZ identity and does not
> read
> +     * the Availability_Zone table, so it does not depend on
> +     * en_icsb_availability_zone and is not churned by its nb_ic_cfg
> sequence
> +     * number. */
>      engine_add_input(&en_address_set, &en_az, NULL);
> -    engine_add_input(&en_address_set, &en_icsb_availability_zone, 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);
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index a73a30723..6730c4c79 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -595,447 +595,6 @@ port_binding_collect_lsp_ts(const struct shash
> *lsp_ts_map,
>      }
>  }
>
> -/*
> - * Data structures and functions related to
> - * synchronize health checks for load balancers
> - * between availability zones.
> - */
> -struct sync_service_monitor_data {
> -    /* Map of service monitors to be pushed to other AZs. */
> -    struct hmap pushed_svcs_map;
> -    /* Map of service monitors synced from other AZs to our. */
> -    struct hmap synced_svcs_map;
> -    /* Map of local service monitors in the ICSBDB. */
> -    struct hmap local_ic_svcs_map;
> -    /* Map of local service monitors in SBDB. */
> -    struct hmap local_sb_svcs_map;
> -    /* MAC address used for service monitor.  */
> -    char *prpg_svc_monitor_mac;
> -};
> -
> -struct service_monitor_info {
> -    struct hmap_node hmap_node;
> -    union {
> -        const struct sbrec_service_monitor *sb_rec;
> -        const struct icsbrec_service_monitor *ic_rec;
> -    } db_rec;
> -    /* Destination availability zone name. */
> -    char *dst_az_name;
> -    /* Source availability zone name. */
> -    char *src_az_name;
> -    /* Chassis name associated with monitor logical port. */
> -    char *chassis_name;
> -};
> -
> -static void
> -create_service_monitor_info(struct hmap *svc_map,
> -                            const void *db_rec,
> -                            const struct uuid *uuid,
> -                            const char *src_az_name,
> -                            const char *target_az_name,
> -                            const char *chassis_name,
> -                            bool ic_rec)
> -{
> -    struct service_monitor_info *svc_mon = xzalloc(sizeof(*svc_mon));
> -    size_t hash = uuid_hash(uuid);
> -
> -    if (ic_rec) {
> -        svc_mon->db_rec.ic_rec =
> -            (const struct icsbrec_service_monitor *) db_rec;
> -    } else {
> -        svc_mon->db_rec.sb_rec =
> -            (const struct sbrec_service_monitor *) db_rec;
> -    }
> -
> -    svc_mon->dst_az_name = target_az_name ? xstrdup(target_az_name) :
> NULL;
> -    svc_mon->chassis_name = chassis_name ? xstrdup(chassis_name) : NULL;
> -    svc_mon->src_az_name = xstrdup(src_az_name);
> -
> -    hmap_insert(svc_map, &svc_mon->hmap_node, hash);
> -}
> -
> -static void
> -destroy_service_monitor_info(struct service_monitor_info *svc_mon)
> -{
> -    free(svc_mon->src_az_name);
> -    free(svc_mon->dst_az_name);
> -    free(svc_mon->chassis_name);
> -    free(svc_mon);
> -}
> -
> -static void
> -refresh_sb_record_cache(struct hmap *svc_mon_map,
> -                        const struct sbrec_service_monitor *lookup_rec)
> -{
> -    size_t hash = uuid_hash(&lookup_rec->header_.uuid);
> -    struct service_monitor_info *svc_mon;
> -
> -    HMAP_FOR_EACH_WITH_HASH (svc_mon, hmap_node, hash, svc_mon_map) {
> -        ovs_assert(svc_mon->db_rec.sb_rec);
> -        if (svc_mon->db_rec.sb_rec == lookup_rec) {
> -            hmap_remove(svc_mon_map, &svc_mon->hmap_node);
> -            destroy_service_monitor_info(svc_mon);
> -            return;
> -        }
> -    }
> -}
> -
> -static void
> -refresh_ic_record_cache(struct hmap *svc_mon_map,
> -                        const struct icsbrec_service_monitor *lookup_rec)
> -{
> -    size_t hash = uuid_hash(&lookup_rec->header_.uuid);
> -    struct service_monitor_info *svc_mon;
> -
> -    HMAP_FOR_EACH_WITH_HASH (svc_mon, hmap_node, hash, svc_mon_map) {
> -        ovs_assert(svc_mon->db_rec.ic_rec);
> -        if (svc_mon->db_rec.ic_rec == lookup_rec) {
> -            hmap_remove(svc_mon_map, &svc_mon->hmap_node);
> -            destroy_service_monitor_info(svc_mon);
> -            return;
> -        }
> -    }
> -}
> -
> -static void
> -remove_unused_ic_records(struct hmap *local_ic_svcs_map)
> -{
> -    struct service_monitor_info *svc_mon;
> -    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, local_ic_svcs_map) {
> -        icsbrec_service_monitor_delete(svc_mon->db_rec.ic_rec);
> -        destroy_service_monitor_info(svc_mon);
> -    }
> -
> -    hmap_destroy(local_ic_svcs_map);
> -}
> -
> -static void
> -remove_unused_sb_records(struct hmap *local_sb_svcs_map)
> -{
> -    struct service_monitor_info *svc_mon;
> -    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, local_sb_svcs_map) {
> -        sbrec_service_monitor_delete(svc_mon->db_rec.sb_rec);
> -        destroy_service_monitor_info(svc_mon);
> -    }
> -
> -    hmap_destroy(local_sb_svcs_map);
> -}
> -
> -static void
> -create_pushed_svcs_mon(struct ic_context *ctx,
> -                       const struct icsbrec_availability_zone *runned_az,
> -                       struct hmap *pushed_svcs_map)
> -{
> -    struct sbrec_service_monitor *key =
> -        sbrec_service_monitor_index_init_row(
> -            ctx->sbrec_service_monitor_by_remote_type);
> -
> -    sbrec_service_monitor_index_set_remote(key, true);
> -
> -    const struct sbrec_service_monitor *sb_rec;
> -    SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sb_rec, key,
> -        ctx->sbrec_service_monitor_by_remote_type) {
> -        const char *target_az_name = smap_get(&sb_rec->options,
> -                                              "az-name");
> -        if (!target_az_name) {
> -            continue;
> -        }
> -        create_service_monitor_info(pushed_svcs_map, sb_rec,
> -                                    &sb_rec->header_.uuid,
> -                                    runned_az->name,
> -                                    target_az_name, NULL, false);
> -    }
> -
> -    sbrec_service_monitor_index_destroy_row(key);
> -}
> -
> -static void
> -create_synced_svcs_mon(struct ic_context *ctx,
> -                       const struct icsbrec_availability_zone *runned_az,
> -                       struct hmap *synced_svcs_map)
> -{
> -    struct icsbrec_service_monitor *key =
> -        icsbrec_service_monitor_index_init_row(
> -          ctx->icsbrec_service_monitor_by_target_az);
> -
> -    icsbrec_service_monitor_index_set_target_availability_zone(
> -        key, runned_az->name);
> -
> -    const struct icsbrec_service_monitor *ic_rec;
> -    ICSBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (ic_rec, key,
> -        ctx->icsbrec_service_monitor_by_target_az) {
> -
> -        const struct sbrec_port_binding *pb =
> -            find_sb_pb_by_name(ctx->sbrec_port_binding_by_name,
> -                               ic_rec->logical_port);
> -
> -        if (!pb || !pb->up) {
> -            continue;
> -        }
> -
> -        const char *chassis_name = pb->chassis ? pb->chassis->name : NULL;
> -        create_service_monitor_info(synced_svcs_map, ic_rec,
> -                                    &ic_rec->header_.uuid,
> -                                    runned_az->name,
> -                                    NULL, chassis_name, true);
> -    }
> -
> -    icsbrec_service_monitor_index_destroy_row(key);
> -}
> -
> -static void
> -create_local_ic_svcs_map(struct ic_context *ctx,
> -                         const struct icsbrec_availability_zone
> *runned_az,
> -                         struct hmap *owned_svc_map)
> -{
> -    struct icsbrec_service_monitor *key =
> -        icsbrec_service_monitor_index_init_row(
> -          ctx->icsbrec_service_monitor_by_source_az);
> -
> -    icsbrec_service_monitor_index_set_source_availability_zone(
> -        key, 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,
> -                                    runned_az->name, NULL,
> -                                    NULL, true);
> -    }
> -
> -    icsbrec_service_monitor_index_destroy_row(key);
> -}
> -
> -static void
> -create_local_sb_svcs_map(struct ic_context *ctx,
> -                         const struct icsbrec_availability_zone
> *runned_az,
> -                         struct hmap *owned_svc_map)
> -{
> -    struct sbrec_service_monitor *key =
> -        sbrec_service_monitor_index_init_row(
> -          ctx->sbrec_service_monitor_by_ic_learned);
> -
> -    sbrec_service_monitor_index_set_ic_learned(
> -        key, true);
> -
> -    const struct sbrec_service_monitor *sb_rec;
> -    SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sb_rec, key,
> -        ctx->sbrec_service_monitor_by_ic_learned) {
> -        create_service_monitor_info(owned_svc_map, sb_rec,
> -                                    &sb_rec->header_.uuid,
> -                                    runned_az->name, NULL,
> -                                    NULL, false);
> -    }
> -
> -    sbrec_service_monitor_index_destroy_row(key);
> -}
> -
> -static const struct sbrec_service_monitor *
> -lookup_sb_svc_rec(struct ic_context *ctx,
> -                  const struct service_monitor_info *svc_mon)
> -{
> -    const struct icsbrec_service_monitor *db_rec =
> -        svc_mon->db_rec.ic_rec;
> -    struct sbrec_service_monitor *key =
> -        sbrec_service_monitor_index_init_row(
> -            ctx->sbrec_service_monitor_by_remote_type_logical_port);
> -
> -    sbrec_service_monitor_index_set_remote(key, false);
> -    sbrec_service_monitor_index_set_logical_port(key,
> db_rec->logical_port);
> -
> -    const struct sbrec_service_monitor *sb_rec;
> -    SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sb_rec, key,
> -        ctx->sbrec_service_monitor_by_remote_type_logical_port) {
> -        if (db_rec->port == sb_rec->port &&
> -            ((db_rec->type && sb_rec->type &&
> -              !strcmp(db_rec->type, sb_rec->type)) ||
> -             (!db_rec->type && !sb_rec->type)) &&
> -            !strcmp(db_rec->ip, sb_rec->ip) &&
> -            !strcmp(db_rec->src_ip, sb_rec->src_ip) &&
> -            !strcmp(db_rec->protocol, sb_rec->protocol)) {
> -            sbrec_service_monitor_index_destroy_row(key);
> -            return sb_rec;
> -        }
> -    }
> -
> -    sbrec_service_monitor_index_destroy_row(key);
> -
> -    return NULL;
> -}
> -
> -static const struct icsbrec_service_monitor *
> -lookup_icsb_svc_rec(struct ic_context *ctx,
> -                    const struct service_monitor_info *svc_mon)
> -{
> -    const struct sbrec_service_monitor *db_rec =
> -       svc_mon->db_rec.sb_rec;
> -    struct icsbrec_service_monitor *key =
> -        icsbrec_service_monitor_index_init_row(
> -        ctx->icsbrec_service_monitor_by_target_az_logical_port);
> -
> -    ovs_assert(svc_mon->dst_az_name);
> -    icsbrec_service_monitor_index_set_target_availability_zone(
> -        key, svc_mon->dst_az_name);
> -
> -    icsbrec_service_monitor_index_set_logical_port(
> -        key, db_rec->logical_port);
> -
> -    const struct icsbrec_service_monitor *ic_rec;
> -    ICSBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (ic_rec, key,
> -        ctx->icsbrec_service_monitor_by_target_az_logical_port) {
> -        if (db_rec->port == ic_rec->port &&
> -            ((db_rec->type && ic_rec->type &&
> -              !strcmp(db_rec->type, ic_rec->type)) ||
> -             (!db_rec->type && !ic_rec->type)) &&
> -            !strcmp(db_rec->ip, ic_rec->ip) &&
> -            !strcmp(db_rec->src_ip, ic_rec->src_ip) &&
> -            !strcmp(db_rec->protocol, ic_rec->protocol) &&
> -            !strcmp(db_rec->logical_port, ic_rec->logical_port)) {
> -            icsbrec_service_monitor_index_destroy_row(key);
> -            return ic_rec;
> -        }
> -    }
> -
> -    icsbrec_service_monitor_index_destroy_row(key);
> -
> -    return NULL;
> -}
> -
> -static void
> -create_service_monitor_data(struct ic_context *ctx,
> -                            const struct icsbrec_availability_zone
> *runned_az,
> -                            struct sync_service_monitor_data *sync_data)
> -{
> -    const struct sbrec_sb_global *ic_sb = sbrec_sb_global_first(
> -                                                ctx->ovnsb_idl);
> -    const char *svc_monitor_mac = smap_get(&ic_sb->options,
> -                                           "svc_monitor_mac");
> -
> -    if (!svc_monitor_mac) {
> -        return;
> -    }
> -
> -    sync_data->prpg_svc_monitor_mac = xstrdup(svc_monitor_mac);
> -    create_pushed_svcs_mon(ctx, runned_az, &sync_data->pushed_svcs_map);
> -    create_synced_svcs_mon(ctx, runned_az, &sync_data->synced_svcs_map);
> -    create_local_ic_svcs_map(ctx, runned_az,
> &sync_data->local_ic_svcs_map);
> -    create_local_sb_svcs_map(ctx, runned_az,
> -                             &sync_data->local_sb_svcs_map);
> -}
> -
> -static void
> -destroy_service_monitor_data(struct sync_service_monitor_data *sync_data)
> -{
> -    struct service_monitor_info *svc_mon;
> -    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data->pushed_svcs_map) {
> -        destroy_service_monitor_info(svc_mon);
> -    }
> -
> -    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data->synced_svcs_map) {
> -        destroy_service_monitor_info(svc_mon);
> -    }
> -
> -    hmap_destroy(&sync_data->pushed_svcs_map);
> -    hmap_destroy(&sync_data->synced_svcs_map);
> -    free(sync_data->prpg_svc_monitor_mac);
> -}
> -
> -void
> -sync_service_monitor(struct ic_context *ctx,
> -                     const struct icsbrec_availability_zone *runned_az)
> -{
> -    if (!ctx->ovnisb_unlocked_txn || !ctx->ovnsb_txn) {
> -        return;
> -    }
> -
> -    struct sync_service_monitor_data sync_data;
> -    memset(&sync_data, 0, sizeof(sync_data));
> -    hmap_init(&sync_data.pushed_svcs_map);
> -    hmap_init(&sync_data.synced_svcs_map);
> -    hmap_init(&sync_data.local_ic_svcs_map);
> -    hmap_init(&sync_data.local_sb_svcs_map);
> -
> -    create_service_monitor_data(ctx, runned_az, &sync_data);
> -
> -    struct service_monitor_info *svc_mon;
> -    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data.pushed_svcs_map) {
> -        const struct sbrec_service_monitor *db_rec =
> svc_mon->db_rec.sb_rec;
> -        const struct icsbrec_service_monitor *ic_rec =
> -            lookup_icsb_svc_rec(ctx, svc_mon);
> -
> -        if (ic_rec) {
> -            sbrec_service_monitor_set_status(db_rec, ic_rec->status);
> -        } else {
> -            ic_rec =
> icsbrec_service_monitor_insert(ctx->ovnisb_unlocked_txn);
> -            icsbrec_service_monitor_set_type(ic_rec, db_rec->type);
> -            icsbrec_service_monitor_set_ip(ic_rec, db_rec->ip);
> -            icsbrec_service_monitor_set_port(ic_rec, db_rec->port);
> -            icsbrec_service_monitor_set_src_ip(ic_rec, db_rec->src_ip);
> -            icsbrec_service_monitor_set_src_mac(ic_rec,
> -                sync_data.prpg_svc_monitor_mac);
> -            icsbrec_service_monitor_set_protocol(ic_rec,
> db_rec->protocol);
> -            icsbrec_service_monitor_set_logical_port(ic_rec,
> -                db_rec->logical_port);
> -            icsbrec_service_monitor_set_target_availability_zone(ic_rec,
> -                svc_mon->dst_az_name);
> -            icsbrec_service_monitor_set_source_availability_zone(ic_rec,
> -                svc_mon->src_az_name);
> -        }
> -
> -        /* Always update options because they change from NB. */
> -        icsbrec_service_monitor_set_options(ic_rec, &db_rec->options);
> -        refresh_ic_record_cache(&sync_data.local_ic_svcs_map, ic_rec);
> -    }
> -
> -    HMAP_FOR_EACH_SAFE (svc_mon, hmap_node, &sync_data.synced_svcs_map) {
> -        const struct icsbrec_service_monitor *db_rec =
> -            svc_mon->db_rec.ic_rec;
> -        const struct sbrec_service_monitor *sb_rec =
> -            lookup_sb_svc_rec(ctx, svc_mon);
> -
> -        if (sb_rec) {
> -            icsbrec_service_monitor_set_status(svc_mon->db_rec.ic_rec,
> -                                               sb_rec->status);
> -        } else {
> -            sb_rec = sbrec_service_monitor_insert(ctx->ovnsb_txn);
> -            sbrec_service_monitor_set_type(sb_rec, db_rec->type);
> -            sbrec_service_monitor_set_ip(sb_rec, db_rec->ip);
> -            sbrec_service_monitor_set_port(sb_rec, db_rec->port);
> -            sbrec_service_monitor_set_src_ip(sb_rec, db_rec->src_ip);
> -            /* Set svc_monitor_mac from local SBDB. */
> -            sbrec_service_monitor_set_src_mac(sb_rec,
> -                sync_data.prpg_svc_monitor_mac);
> -            sbrec_service_monitor_set_protocol(sb_rec,
> -                db_rec->protocol);
> -            sbrec_service_monitor_set_logical_port(sb_rec,
> -                db_rec->logical_port);
> -            sbrec_service_monitor_set_remote(sb_rec, false);
> -            sbrec_service_monitor_set_ic_learned(sb_rec, true);
> -        }
> -
> -        /* Only update if ic owns it */
> -        if (sb_rec->ic_learned) {
> -            /* Always update options since they may change via
> -             * NB configuration. Also update chassis_name if
> -             * the port has been reassigned to a different chassis.
> -             */
> -            if (svc_mon->chassis_name) {
> -                sbrec_service_monitor_set_chassis_name(sb_rec,
> -                    svc_mon->chassis_name);
> -            }
> -            sbrec_service_monitor_set_options(sb_rec, &db_rec->options);
> -            refresh_sb_record_cache(&sync_data.local_sb_svcs_map, sb_rec);
> -        }
> -    }
> -
> -    /* Delete local created records that are no longer used. */
> -    remove_unused_ic_records(&sync_data.local_ic_svcs_map);
> -    remove_unused_sb_records(&sync_data.local_sb_svcs_map);
> -
> -    destroy_service_monitor_data(&sync_data);
> -}
> -
>  /*
>   * This function implements a sequence number protocol that can be used by
>   * the INB end user to verify that ISB is synced with all the changes that
> diff --git a/ic/ovn-ic.h b/ic/ovn-ic.h
> index 69ffa34d4..8adb17ad7 100644
> --- a/ic/ovn-ic.h
> +++ b/ic/ovn-ic.h
> @@ -101,8 +101,6 @@ void port_binding_lsp_ts_map_init(struct ic_context
> *ctx, struct shash *map);
>  void port_binding_collect_lsp_ts(const struct shash *lsp_ts_map,
>                                   const struct nbrec_logical_switch_port
> *lsp,
>                                   struct sset *ts_scope);
> -void sync_service_monitor(struct ic_context *ctx,
> -                          const struct icsbrec_availability_zone
> *runned_az);
>
>  /* Shared IC helpers used by more than one engine node. */
>  uint32_t
> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
> index 7f557f171..6d0734b1a 100644
> --- a/tests/ovn-ic.at
> +++ b/tests/ovn-ic.at
> @@ -1012,6 +1012,84 @@ OVN_CLEANUP_IC([az1])
>  AT_CLEANUP
>  ])
>
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([ovn-ic -- incremental processing - port binding, route, svc
> monitor])
> +
> +# The en_port_binding, en_route and en_service_monitor nodes use only the
> AZ
> +# identity, not the Availability_Zone table, so a change to IC-NB Global
> +# options and the resulting nb_ic_cfg sequence-number bump must not
> recompute
> +# them.
> +
> +ovn_init_ic_db
> +net_add n1
> +ovn_start az1
> +as az1
> +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
> +check ovn-appctl -t ic/ovn-ic inc-engine/recompute
> +check ovn-ic-nbctl --wait=sb sync
> +check ovn-appctl -t ic/ovn-ic inc-engine/clear-stats
> +
> +check ovn-ic-nbctl --wait=sb set IC_NB_Global . options:foo=bar
> +check ovn-ic-nbctl --wait=sb sync
> +
> +AT_CHECK([test "$(ovn-appctl -t ic/ovn-ic \
> +                      inc-engine/show-stats port_binding recompute)" = 0])
> +AT_CHECK([test "$(ovn-appctl -t ic/ovn-ic \
> +                      inc-engine/show-stats route recompute)" = 0])
> +AT_CHECK([test "$(ovn-appctl -t ic/ovn-ic \
> +                      inc-engine/show-stats service_monitor recompute)" =
> 0])
> +
> +OVN_CLEANUP_IC([az1])
> +AT_CLEANUP
> +])
> +
> +OVN_FOR_EACH_NORTHD([
> +AT_SETUP([ovn-ic -- incremental processing - service monitor SB port
> binding scoping])
> +
> +# SB Port_Binding is the busiest table in the AZ, but the
> en_service_monitor
> +# sync reads only the 'up'/'chassis' of the port backing a service monitor
> +# targeting this AZ.  A port binding that backs no such service monitor
> must be
> +# handled by the en_service_monitor SB Port_Binding handler without a full
> +# recompute of the node.
> +
> +ovn_init_ic_db
> +net_add n1
> +ovn_start az1
> +as az1
> +check ovn-ic-nbctl --wait=sb ts-add ts1
> +check ovn-nbctl ls-add sw0
> +check ovn-nbctl --wait=sb lsp-add sw0 sp0
> +OVS_WAIT_UNTIL([test -n "$(ovn-sbctl --bare --columns=_uuid \
> +                            find port_binding logical_port=sp0)"])
> +
> +# Quiesce the engine and reset stats so only the change under test counts.
> +check ovn-ic-nbctl --wait=sb sync
> +check ovn-appctl -t ic/ovn-ic inc-engine/recompute
> +check ovn-ic-nbctl --wait=sb sync
> +check ovn-appctl -t ic/ovn-ic inc-engine/clear-stats
> +
> +# Flip the SB port binding 'up' of a port that backs no service monitor,
> +# directly in the SB (so SB_Global is not bumped).  This is a watched
> column,
> +# but the port is not a service-monitor target, so en_service_monitor
> must not
> +# recompute.
> +check ovn-sbctl set port_binding sp0 up=true
> +OVS_WAIT_UNTIL([test "$(ovn-sbctl --bare --columns=up \
> +                            find port_binding logical_port=sp0)" = true])
> +check ovn-ic-nbctl --wait=sb sync
> +
> +AT_CHECK([test "$(ovn-appctl -t ic/ovn-ic \
> +                      inc-engine/show-stats service_monitor compute)" -gt
> 0])
> +AT_CHECK([test "$(ovn-appctl -t ic/ovn-ic \
> +                      inc-engine/show-stats service_monitor recompute)" =
> 0])
> +
> +OVN_CLEANUP_IC([az1])
> +AT_CLEANUP
> +])
> +
>  OVN_FOR_EACH_NORTHD([
>  AT_SETUP([ovn-ic -- incremental processing - route handlers])
>
> --
> 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
>

-- 




_‘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

Reply via email to