On 8/15/25 10:06 AM, Alexandra Rukomoinikova wrote: > This commit adds support for synchronizing load balancer health checks > across interconnected availability zones via OVN-IC. Key features include: > > 1. Added new Service_Monitor table to ICSB database > - Tracks service monitors across AZs with source/target zone info > - Supports status propagation between zones > > 2. Implemented synchronization logic in ovn-ic: > - Pushes local service monitors to remote AZs via ICSB > - Pulls remote monitors into local SBDB as IC-learned > - Handles status updates in both directions > - Maintains consistency during configuration changes > > 3. Added comprehensive test casesю > > 4. Extended OVSDB indexes for efficient lookups. > > Signed-off-by: Alexandra Rukomoinikova <arukomoinikova@k2.cloud> > --- > v1 --> v2: 1) added test for parsing ip_port_mapping for ipv4 > 2) corrected comments regarding tests > ---
Hi Alexandra, I know the patch was merged but I think we might need some small follow ups, please see below. > ic/ovn-ic.c | 503 ++++++++++++++++++++++++++++++++++++++++++++ > ovn-ic-sb.ovsschema | 32 ++- > ovn-ic-sb.xml | 56 +++++ > tests/ovn-ic.at | 404 +++++++++++++++++++++++++++++++++++ > tests/ovn-northd.at | 105 +++++---- > 5 files changed, 1058 insertions(+), 42 deletions(-) > > diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c > index ac245a8ed..cfdbd4b40 100644 > --- a/ic/ovn-ic.c > +++ b/ic/ovn-ic.c [...] > +static void > +create_pushed_svcs_mon(struct ic_context *ctx, > + struct hmap *pushed_svcs_map) > +{ > + struct sbrec_service_monitor *key = > + sbrec_service_monitor_index_init_row( > + ctx->sbrec_service_monitor_by_local_type); > + > + sbrec_service_monitor_index_set_local(key, false); > + > + const struct sbrec_service_monitor *sb_rec; > + SBREC_SERVICE_MONITOR_FOR_EACH_EQUAL (sb_rec, key, > + ctx->sbrec_service_monitor_by_local_type) { > + const char *target_az_name = smap_get_def(&sb_rec->options, > + "az-name", ""); > + if (!target_az_name) { > + continue; > + } smap_get_def() never returns NULL and, as far as I can tell, the actual goal here is to really skip SB.service_monitor records that don't have az-name set. That doesn't happen with this code, we'd just create a "pushed_svc" with target_az_name = "". Do we need to change this to something like below? const char *target_az_name = smap_get(&sb_rec->options, "az-name"); if (!target_az_name) { continue; } If so, do you mind posting a follow up patch? We might also need a test for this scenario. > + create_service_monitor_info(pushed_svcs_map, sb_rec, > + &sb_rec->header_.uuid, > + ctx->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, > + 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, ctx->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, > + ctx->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, > + 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, ctx->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, > + NULL, true); > + } > + > + icsbrec_service_monitor_index_destroy_row(key); > +} > + > +static void > +create_local_sb_svcs_map(struct ic_context *ctx, > + 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, > + ctx->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_local_type_logical_port); > + > + sbrec_service_monitor_index_set_local(key, true); > + 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_local_type_logical_port) { > + if (db_rec->port == sb_rec->port && > + !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 && > + !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, > + 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_def(&ic_sb->options, > + "svc_monitor_mac", ""); > + Here too, smap_get_def() can never return NULL. > + if (svc_monitor_mac) { > + sync_data->prpg_svc_monitor_mac = xstrdup(svc_monitor_mac); So, if SB.Options:svc_monitor_mac is not present sync_data->prpg_svc_monitor_mac will be "". I know in practice this should be at most transient (because ovn-northd will probably reconcile the SB.Options:svc_monitor_mac to an actual MAC address value) but should we just return early here if the mac is not currently set? Or do we need to something else? > + } > + > + create_pushed_svcs_mon(ctx, &sync_data->pushed_svcs_map); > + create_synced_svcs_mon(ctx, &sync_data->synced_svcs_map); > + create_local_ic_svcs_map(ctx, &sync_data->local_ic_svcs_map); > + create_local_sb_svcs_map(ctx, &sync_data->local_sb_svcs_map); > +} > + Regards, Dumitru _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev