Hi Alexandra,

I reviewed the test here more than I did the ovn-ic changes. I have a few problems with the test you added:

1. It appears to enable monitoring for all load balancer backends. The test should likely leave some load balancer backends unmonitored and ensure correct behavior is used for those. 2. The test should ensure that garbage input is handled properly. Examples would include:
   * ip port mappings with non-existent lports.
   * ip port mappings with non-existent or zero-length azs.

I have one more small comment in-line in the test below.

On 7/31/25 8:01 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>
---
  ic/ovn-ic.c         | 503 ++++++++++++++++++++++++++++++++++++++++++++
  ovn-ic-sb.ovsschema |  32 ++-
  ovn-ic-sb.xml       |  56 +++++
  tests/ovn-ic.at     | 380 +++++++++++++++++++++++++++++++++
  4 files changed, 968 insertions(+), 3 deletions(-)

diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index 0d36b0bf5..52c4c8435 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -70,6 +70,9 @@ struct ic_context {
      struct ovsdb_idl_index *nbrec_port_by_name;
      struct ovsdb_idl_index *sbrec_chassis_by_name;
      struct ovsdb_idl_index *sbrec_port_binding_by_name;
+    struct ovsdb_idl_index *sbrec_service_monitor_by_local_type;
+    struct ovsdb_idl_index *sbrec_service_monitor_by_ic_learned;
+    struct ovsdb_idl_index *sbrec_service_monitor_by_local_type_logical_port;
      struct ovsdb_idl_index *icnbrec_transit_switch_by_name;
      struct ovsdb_idl_index *icsbrec_port_binding_by_az;
      struct ovsdb_idl_index *icsbrec_port_binding_by_ts;
@@ -77,6 +80,9 @@ struct ic_context {
      struct ovsdb_idl_index *icsbrec_route_by_az;
      struct ovsdb_idl_index *icsbrec_route_by_ts;
      struct ovsdb_idl_index *icsbrec_route_by_ts_az;
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_source_az;
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az;
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az_logical_port;
  };
struct ic_state {
@@ -95,6 +101,9 @@ static const char *ssl_private_key_file;
  static const char *ssl_certificate_file;
  static const char *ssl_ca_cert_file;
+static const struct sbrec_port_binding * find_sb_pb_by_name(
+    struct ovsdb_idl_index *sbrec_port_binding_by_name, const char *name);
+
  
  static void
  usage(void)
@@ -2182,6 +2191,428 @@ route_run(struct ic_context *ctx)
      hmap_destroy(&ic_lrs);
  }
+/*
+ * 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,
+                       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;
+        }
+        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", "");
+
+    if (svc_monitor_mac) {
+        sync_data->prpg_svc_monitor_mac = xstrdup(svc_monitor_mac);
+    }
+
+    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);
+}
+
+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)
+{
+    if (!ctx->ovnisb_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, &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_txn);
+            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_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_local(sb_rec, true);
+            sbrec_service_monitor_set_ic_learned(sb_rec, true);
+        }
+
+        /* 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
@@ -2274,6 +2705,7 @@ ovn_db_run(struct ic_context *ctx)
      ts_run(ctx);
      port_binding_run(ctx);
      route_run(ctx);
+    sync_service_monitor(ctx);
  }
  
  static void
@@ -2570,6 +3002,9 @@ main(int argc, char *argv[])
      struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
          ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true));
+ ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_sb_global);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_sb_global_col_options);
+
      ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis);
      ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_encaps);
      ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name);
@@ -2599,6 +3034,35 @@ main(int argc, char *argv[])
                           &sbrec_port_binding_col_external_ids);
      ovsdb_idl_add_column(ovnsb_idl_loop.idl,
                           &sbrec_port_binding_col_chassis);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_port_binding_col_up);
+
+    ovsdb_idl_add_table(ovnsb_idl_loop.idl,
+                        &sbrec_table_service_monitor);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_chassis_name);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_external_ids);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_ip);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_logical_port);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_port);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_protocol);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_src_ip);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_src_mac);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_local);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_ic_learned);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_status);
+    ovsdb_idl_add_column(ovnsb_idl_loop.idl,
+                         &sbrec_service_monitor_col_options);
/* Create IDL indexes */
      struct ovsdb_idl_index *nbrec_ls_by_name
@@ -2617,6 +3081,19 @@ main(int argc, char *argv[])
          = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
                                    &sbrec_chassis_col_name);
+ struct ovsdb_idl_index *sbrec_service_monitor_by_local_type
+        = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
+                                  &sbrec_service_monitor_col_local);
+
+    struct ovsdb_idl_index *sbrec_service_monitor_by_ic_learned
+        = ovsdb_idl_index_create1(ovnsb_idl_loop.idl,
+                                  &sbrec_service_monitor_col_ic_learned);
+
+    struct ovsdb_idl_index *sbrec_service_monitor_by_local_type_logical_port
+        = ovsdb_idl_index_create2(ovnsb_idl_loop.idl,
+                                  &sbrec_service_monitor_col_local,
+                                  &sbrec_service_monitor_col_logical_port);
+
      struct ovsdb_idl_index *icnbrec_transit_switch_by_name
          = ovsdb_idl_index_create1(ovninb_idl_loop.idl,
                                    &icnbrec_transit_switch_col_name);
@@ -2647,6 +3124,19 @@ main(int argc, char *argv[])
                                    &icsbrec_route_col_transit_switch,
                                    &icsbrec_route_col_availability_zone);
+ struct ovsdb_idl_index *icsbrec_service_monitor_by_source_az
+        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,
+            &icsbrec_service_monitor_col_source_availability_zone);
+
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az
+        = ovsdb_idl_index_create1(ovnisb_idl_loop.idl,
+            &icsbrec_service_monitor_col_target_availability_zone);
+
+    struct ovsdb_idl_index *icsbrec_service_monitor_by_target_az_logical_port
+        = ovsdb_idl_index_create2(ovnisb_idl_loop.idl,
+            &icsbrec_service_monitor_col_target_availability_zone,
+            &icsbrec_service_monitor_col_logical_port);
+
      unixctl_command_register("nb-connection-status", "", 0, 0,
                               ovn_conn_show, ovnnb_idl_loop.idl);
      unixctl_command_register("sb-connection-status", "", 0, 0,
@@ -2698,6 +3188,12 @@ main(int argc, char *argv[])
                  .nbrec_port_by_name = nbrec_port_by_name,
                  .sbrec_port_binding_by_name = sbrec_port_binding_by_name,
                  .sbrec_chassis_by_name = sbrec_chassis_by_name,
+                .sbrec_service_monitor_by_local_type =
+                    sbrec_service_monitor_by_local_type,
+                .sbrec_service_monitor_by_ic_learned =
+                    sbrec_service_monitor_by_ic_learned,
+                .sbrec_service_monitor_by_local_type_logical_port =
+                    sbrec_service_monitor_by_local_type_logical_port,
                  .icnbrec_transit_switch_by_name =
                      icnbrec_transit_switch_by_name,
                  .icsbrec_port_binding_by_az = icsbrec_port_binding_by_az,
@@ -2706,6 +3202,12 @@ main(int argc, char *argv[])
                  .icsbrec_route_by_az = icsbrec_route_by_az,
                  .icsbrec_route_by_ts = icsbrec_route_by_ts,
                  .icsbrec_route_by_ts_az = icsbrec_route_by_ts_az,
+                .icsbrec_service_monitor_by_source_az =
+                    icsbrec_service_monitor_by_source_az,
+                .icsbrec_service_monitor_by_target_az =
+                    icsbrec_service_monitor_by_target_az,
+                .icsbrec_service_monitor_by_target_az_logical_port =
+                    icsbrec_service_monitor_by_target_az_logical_port,
              };
if (!state.had_lock && ovsdb_idl_has_lock(ovnsb_idl_loop.idl)) {
@@ -2731,6 +3233,7 @@ main(int argc, char *argv[])
                      ovn_db_run(&ctx);
                      update_sequence_numbers(&ctx, &ovnisb_idl_loop);
                  }
+
              }
int rc1 = ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);
diff --git a/ovn-ic-sb.ovsschema b/ovn-ic-sb.ovsschema
index 22f75b06c..34b5457bb 100644
--- a/ovn-ic-sb.ovsschema
+++ b/ovn-ic-sb.ovsschema
@@ -1,7 +1,7 @@
  {
      "name": "OVN_IC_Southbound",
-    "version": "2.1.0",
-    "cksum": "1466425967 7126",
+    "version": "2.2.0",
+    "cksum": "2294868959 8438",
      "tables": {
          "IC_SB_Global": {
              "columns": {
@@ -145,6 +145,32 @@
                                            "value": "string",
                                            "min": 0,
                                            "max": "unlimited"}}},
-            "maxRows": 1}
+            "maxRows": 1},
+        "Service_Monitor": {
+            "columns": {
+                "ip": {"type": "string"},
+                "protocol": {
+                    "type": {"key": {"type": "string",
+                             "enum": ["set", ["tcp", "udp"]]},
+                             "min": 0, "max": 1}},
+                "port": {"type": {"key": {"type": "integer",
+                                          "minInteger": 0,
+                                          "maxInteger": 65535}}},
+                "logical_port": {"type": "string"},
+                "src_ip": {"type": "string"},
+                "src_mac": {"type": "string"},
+                "status": {
+                    "type": {"key": {"type": "string",
+                             "enum": ["set", ["online", "offline", "error"]]},
+                             "min": 0, "max": 1}},
+                "target_availability_zone": {"type": "string"},
+                "source_availability_zone": {"type": "string"},
+                "options": {
+                    "type": {"key": "string", "value": "string",
+                             "min": 0, "max": "unlimited"}},
+                "external_ids": {
+                    "type": {"key": "string", "value": "string",
+                             "min": 0, "max": "unlimited"}}},
+            "isRoot": true}
      }
  }
diff --git a/ovn-ic-sb.xml b/ovn-ic-sb.xml
index 8f98c7ebb..35dc1f509 100644
--- a/ovn-ic-sb.xml
+++ b/ovn-ic-sb.xml
@@ -691,4 +691,60 @@
      </group>
    </table>
+ <table name="Service_Monitor">
+    <column name="ip">
+      IP of the service to be monitored. Copy from SBDB record.
+    </column>
+
+    <column name="protocol">
+      The protocol of the service.
+      Copy from source Southbound Database record.
+    </column>
+
+    <column name="port">
+      The TCP or UDP port of the service.
+      Copy from source Southbound Database record.
+    </column>
+
+    <column name="logical_port">
+      The VIF of the logical port on which the service is running. The
+      <code>ovn-controller</code> that binds this <code>logical_port</code>
+      monitors the service by sending periodic monitor packets.
+      Copy from source Southbound Database record.
+    </column>
+
+    <column name="src_ip">
+      Source IPv4 or IPv6 address to use in the service monitor packet.
+      Copy from source Southbound Database record.
+    </column>
+
+    <column name="src_mac">
+      Source Ethernet address to use in the service monitor packet.
+      Copy from Southbound Database record.
+    </column>
+
+    <column name="status">
+      The health status of the service monitor, synchronized from target
+      Southbound Database.
+    </column>
+
+    <column name="target_availability_zone">
+      The Availability Zone where the monitored service endpoint is located.
+    </column>
+
+    <column name="source_availability_zone">
+      Availability Zone that initiated this monitor entry in ICSB and retains
+      ownership for lifecycle management.
+    </column>
+
+    <column name="options">
+      Same as in Table Service_Monitor in SBDB.
+      Copy from source SBDB record.
+    </column>
+
+    <column name="external_ids">
+      Same as in Table Service_Monitor in SBDB.
+      Copy from source SBDB record.
+    </column>
+  </table>
  </database>
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 49a409015..817efd090 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -3643,3 +3643,383 @@ OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list 
lr11 | grep 2001 |
  OVN_CLEANUP_IC([az1], [az2])
  AT_CLEANUP
  ])
+
+AT_BANNER([OVN Interconnection Service Monitor synchronization])
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-ic -- Service Monitor synchronization])
+
+ovn_init_ic_db
+ovn_start az1
+ovn_start az2
+ovn_start az3
+
+#  
┌─────────────────────────────────────────────────────────────────────────────┐
+#  │               Service Monitor Sync Check (Cross-AZ LB Setup)              
  │
+#  
├───────────────┬───────────────┬────────────────────────────────────────────-┤
+#  │     AZ1       │     AZ2       │      AZ3 (Backends only)                  
  │
+#  
├───────────────┼───────────────┼────────────────────────────────────────────-┤
+#  │  ┌─────────┐  │  ┌─────────┐  │  ┌─────────┐  ┌─────────┐  ┌─────────┐    
  │
+#  │  │  LB1    │  │  │  LB2    │  │  │ lport5  │  │ lport6  │  │ lport7  │    
  │
+#  │  ├─────────┤  │  ├─────────┤  │  │ (AZ3)   │  │ (AZ3)   │  │ (AZ3)   │    
  │
+#  │  │ - lport1├──┼──┤ - lport3│  │  └─────────┘  └─────────┘  └─────────┘    
  │
+#  │  │   (AZ1) │  │  │   (AZ2) │  │                                           
  │
+#  │  │ - lport3│  │  │ - lport1├──┼───────────────────┐                       
  │
+#  │  │   (AZ2) │  │  │   (AZ3) │  │                   │                       
  │
+#  │  │ - lport5│  │  └─────────┘  │                   │                       
  │
+#  │  │   (AZ3) │  │               │                   │                       
  │
+#  │  └─────────┘  │  ┌─────────┐  │                   │                       
  │
+#  │               │  │  LB3    │  │                   │                       
  │
+#  │               │  ├─────────┤  │                   │                       
  │
+#  │               │  │ - lport5├──┼───────────────────┘                       
  │
+#  │               │  │   (AZ3) │  │                                           
  │
+#  │               │  │ - lport6│  │                                           
  │
+#  │               │  │   (AZ3) │  │                                           
  │
+#  │               │  │ - lport2├──┘                                           
  │
+#  │               │  │   (AZ1) │                                              
  │
+#  │               │  └─────────┘                                              
  │
+#  
└───────────────┴───────────────┴────────────────────────────────────────────-┘

nit: The diagram does not show lport4 as a backend for LB1.

+#
+#  Physical Backend Locations:
+#  - AZ1: lport1, lport2
+#  - AZ2: lport3, lport4
+#  - AZ3: lport5, lport6 , lport7
+#
+#  Load Balancer Configurations:
+#  - LB1 (AZ1): lport1(AZ1), lport3(AZ2), lport5(AZ3), lport4(az2)
+#  - LB2 (AZ2): lport3(AZ2), lport1(AZ3)
+#  - LB3 (AZ2): lport5(AZ3), lport6(AZ3), lport2(AZ1)
+
+
+# AZ1 Configuration
+ovn_as az1
+check ovn-nbctl ls-add az1_ls1
+check ovn-nbctl lsp-add az1_ls1 lport1_az1
+check ovn-nbctl lsp-add az1_ls1 lport2_az1
+
+check ovn-nbctl lb-add az1_lb1 10.10.10.1:80 
1.1.1.1:10880,5.5.5.1:10880,3.3.3.1:10880,4.4.4.1:10880
+check ovn-nbctl ls-lb-add az1_ls1 az1_lb1
+AT_CHECK([ovn-nbctl --wait=sb \
+          -- --id=@hc create Load_Balancer_Health_Check vip="10.10.10.1\:80" \
+             options:failure_count=100 \
+          -- add Load_Balancer . health_check @hc | uuidfilt], [0], [<0>
+])
+
+check ovn-nbctl set load_balancer az1_lb1 
ip_port_mappings:1.1.1.1=lport1_az1:1.1.1.9
+check ovn-nbctl set load_balancer az1_lb1 
ip_port_mappings:3.3.3.1=lport3_az2:3.3.3.9:remote:az2
+check ovn-nbctl set load_balancer az1_lb1 
ip_port_mappings:5.5.5.1=lport5_az3:5.5.5.9:remote:az3
+check ovn-nbctl set load_balancer az1_lb1 
ip_port_mappings:4.4.4.1=lport4_az2:4.4.4.9:remote:az2
+
+check_row_count sb:Service_Monitor 4
+check_row_count ic-sb:Service_Monitor 3
+
+AT_CHECK([ovn-sbctl lflow-list az1_ls1 | grep arp | grep -c "1.1.1.9"], [0], 
[dnl
+1
+])
+
+AT_CHECK([ovn-sbctl lflow-list az1_ls1 | grep arp | grep -c "3.3.3.9"], [1], 
[dnl
+0
+])
+
+# AZ2 Configuration
+ovn_as az2
+check ovn-nbctl ls-add az2_ls1
+check ovn-nbctl lsp-add az2_ls1 lport3_az2
+check ovn-nbctl lsp-add az2_ls1 lport4_az2
+
+check ovn-nbctl lb-add az2_lb1 20.20.20.1:80 3.3.3.1:10880,1.1.1.1:10880
+check ovn-nbctl ls-lb-add az2_ls1 az2_lb1
+-nbctl ls-lb-add az2_ls1 az2_lb1
+AT_CHECK([ovn-nbctl --wait=sb \
+          -- --id=@hc create Load_Balancer_Health_Check vip="20.20.20.1\:80" \
+             options:failure_count=100 \
+          -- add Load_Balancer . health_check @hc | uuidfilt], [0], [<0>
+])
+
+check ovn-nbctl set load_balancer az2_lb1 
ip_port_mappings:3.3.3.1=lport3_az2:3.3.3.9
+check ovn-nbctl set load_balancer az2_lb1 
ip_port_mappings:1.1.1.1=lport1_az1:1.1.1.9:remote:az1
+
+check_row_count sb:Service_Monitor 3
+check_row_count ic-sb:Service_Monitor 4
+
+ovn_as az1
+check_row_count sb:Service_Monitor 4
+check_column false sb:Service_Monitor ic_learned logical_port=lport1_az1
+check_column true sb:Service_Monitor local logical_port=lport1_az1
+
+ovn_as az2
+check_column "3.3.3.1" sb:Service_Monitor ip logical_port=lport3_az2
+check_column 10880 sb:Service_Monitor port logical_port=lport3_az2
+check_column tcp sb:Service_Monitor protocol logical_port=lport3_az2
+check_column "3.3.3.9" sb:Service_Monitor src_ip logical_port=lport3_az2
+check_column true sb:Service_Monitor ic_learned logical_port=lport3_az2
+check_column true sb:Service_Monitor local logical_port=lport3_az2
+
+check_column false sb:Service_Monitor ic_learned logical_port=lport1_az1
+check_column false sb:Service_Monitor local logical_port=lport1_az1
+
+check_column true sb:Service_Monitor ic_learned logical_port=lport4_az2
+check_column true sb:Service_Monitor local logical_port=lport4_az2
+
+# Check ICSB records
+check_column "4.4.4.1" ic-sb:Service_Monitor ip logical_port=lport4_az2
+check_column 10880 ic-sb:Service_Monitor port logical_port=lport4_az2
+check_column tcp ic-sb:Service_Monitor protocol logical_port=lport4_az2
+check_column "4.4.4.9" ic-sb:Service_Monitor src_ip logical_port=lport4_az2
+check_column az2 ic-sb:Service_Monitor target_availability_zone 
logical_port=lport4_az2
+check_column az1 ic-sb:Service_Monitor source_availability_zone 
logical_port=lport4_az2
+
+check_column az2 ic-sb:Service_Monitor target_availability_zone 
logical_port=lport3_az2
+check_column az1 ic-sb:Service_Monitor source_availability_zone 
logical_port=lport3_az2
+
+check_column az1 ic-sb:Service_Monitor target_availability_zone 
logical_port=lport1_az1
+check_column az2 ic-sb:Service_Monitor source_availability_zone 
logical_port=lport1_az1
+
+check_column az3 ic-sb:Service_Monitor target_availability_zone 
logical_port=lport5_az3
+check_column az1 ic-sb:Service_Monitor source_availability_zone 
logical_port=lport5_az3
+
+# AZ3 Configuration
+ovn_as az3
+check ovn-nbctl ls-add az3_ls1
+
+# Check there no Service_Monitor when we have no ports.
+check_row_count sb:Service_Monitor 0
+check_row_count nb:Load_Balancer 0
+
+check ovn-nbctl lsp-add az3_ls1 lport5_az3
+check ovn-nbctl lsp-add az3_ls1 lport6_az3
+check ovn-nbctl lsp-add az3_ls1 lport7_az3
+
+# Check there is one Service Monitor learned from az1.
+check_row_count sb:Service_Monitor 1
+
+check_column "5.5.5.1" sb:Service_Monitor ip logical_port=lport5_az3
+check_column 10880 sb:Service_Monitor port logical_port=lport5_az3
+check_column tcp sb:Service_Monitor protocol logical_port=lport5_az3
+check_column "5.5.5.9" sb:Service_Monitor src_ip logical_port=lport5_az3
+check_column true sb:Service_Monitor ic_learned logical_port=lport5_az3
+check_column true sb:Service_Monitor local logical_port=lport5_az3
+
+AT_CHECK([ovn-sbctl lflow-list az3_ls1 | grep arp | grep -c "5.5.5.9"], [0], 
[dnl
+1
+])
+
+# Add more lb in AZ2, change port for one backend, check we will have one more
+# records for this Service_Monitor
+ovn_as az2
+check ovn-nbctl lb-add az2_lb2 20.20.20.2:80 
2.2.2.1:10880,5.5.5.1:10881,6.6.6.1:10880
+check ovn-nbctl ls-lb-add az2_ls1 az2_lb2
+-nbctl ls-lb-add az2_ls1 az2_lb2
+AT_CHECK([ovn-nbctl --wait=sb \
+          -- --id=@hc create Load_Balancer_Health_Check vip="20.20.20.2\:80" \
+             options:failure_count=100 \
+          -- add Load_Balancer az2_lb2 health_check @hc | uuidfilt], [0], [<0>
+])
+
+check ovn-nbctl set load_balancer az2_lb2 
ip_port_mappings:2.2.2.1=lport2_az1:2.2.2.9:remote:az1
+check ovn-nbctl set load_balancer az2_lb2 
ip_port_mappings:5.5.5.1=lport5_az3:5.5.5.9:remote:az3
+check ovn-nbctl set load_balancer az2_lb2 
ip_port_mappings:6.6.6.1=lport6_az3:6.6.6.9:remote:az3
+
+check_row_count sb:Service_Monitor 6
+
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep arp | grep -c "6.6.6.9"], [1], 
[dnl
+0
+])
+
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep arp | grep -c "5.5.5.9"], [1], 
[dnl
+0
+])
+
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep arp | grep -c "2.2.2.9"], [1], 
[dnl
+0
+])
+
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep arp | grep -c "3.3.3.9"], [0], 
[dnl
+1
+])
+
+ovn_as az1
+
+check_row_count sb:Service_Monitor 5
+
+check_column true sb:Service_Monitor ic_learned logical_port=lport2_az1
+check_column true sb:Service_Monitor local logical_port=lport2_az1
+
+ovn_as az3
+
+check_row_count sb:Service_Monitor 3
+
+AT_CHECK([ovn-sbctl lflow-list az3_ls1 | grep arp | wc -l], [0], [dnl
+3
+])
+
+AT_CHECK([ovn-sbctl lflow-list az3_ls1 | grep arp | grep -c "6.6.6.9"], [0], 
[dnl
+1
+])
+
+AT_CHECK([ovn-sbctl lflow-list az3_ls1 | grep arp | grep -c "5.5.5.9"], [0], 
[dnl
+1
+])
+
+# Check status propogation.
+
+ovn_as az1
+AT_CHECK([ovn-sbctl lflow-list az1_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.10.10.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 10.10.10.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=1.1.1.1:10880,5.5.5.1:10880,3.3.3.1:10880,4.4.4.1:10880);)
+])
+
+ovn_as az2
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=3.3.3.1:10880,1.1.1.1:10880);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.2 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.2; 
reg2[[0..15]] = 80; ct_lb_mark(backends=2.2.2.1:10880,5.5.5.1:10881,6.6.6.1:10880);)
+])
+
+ovn_as az1
+svc_lport1_uuid=$(ovn-sbctl -d bare --no-headings --columns _uuid find 
Service_Monitor logical_port=lport1_az1)
+
+check ovn-sbctl set Service_Monitor $svc_lport1_uuid status="offline"
+
+check_column offline ic-sb:Service_Monitor status logical_port=lport1_az1
+
+ovn_as az1
+AT_CHECK([ovn-sbctl lflow-list az1_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.10.10.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 10.10.10.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=5.5.5.1:10880,3.3.3.1:10880,4.4.4.1:10880);)
+])
+
+ovn_as az2
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=3.3.3.1:10880);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.2 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.2; 
reg2[[0..15]] = 80; ct_lb_mark(backends=2.2.2.1:10880,5.5.5.1:10881,6.6.6.1:10880);)
+])
+
+ovn_as az3
+svc_lport6_uuid=$(ovn-sbctl -d bare --no-headings --columns _uuid find 
Service_Monitor logical_port=lport6_az3)
+
+check ovn-sbctl set Service_Monitor $svc_lport6_uuid status="offline"
+
+check_column offline ic-sb:Service_Monitor status logical_port=lport6_az3
+
+ovn_as az2
+check_column offline sb:Service_Monitor status logical_port=lport6_az3
+
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=3.3.3.1:10880);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.2 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.2; 
reg2[[0..15]] = 80; ct_lb_mark(backends=2.2.2.1:10880,5.5.5.1:10881);)
+])
+
+ovn_as az1
+svc_lport2_uuid=$(ovn-sbctl -d bare --no-headings --columns _uuid find 
Service_Monitor logical_port=lport2_az1)
+
+check ovn-sbctl set Service_Monitor $svc_lport2_uuid status="offline"
+
+check_column offline ic-sb:Service_Monitor status logical_port=lport2_az1
+
+ovn_as az2
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=3.3.3.1:10880);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.2 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.2; 
reg2[[0..15]] = 80; ct_lb_mark(backends=5.5.5.1:10881);)
+])
+
+svc_lport4_uuid=$(ovn-sbctl -d bare --no-headings --columns _uuid find 
Service_Monitor logical_port=lport4_az2)
+
+check ovn-sbctl set Service_Monitor $svc_lport4_uuid status="offline"
+
+check_column offline ic-sb:Service_Monitor status logical_port=lport4_az2
+
+ovn_as az1
+AT_CHECK([ovn-sbctl lflow-list az1_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.10.10.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 10.10.10.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=5.5.5.1:10880,3.3.3.1:10880);)
+])
+
+ovn_as az2
+check_row_count sb:Service_Monitor 1 logical_port=lport4_az2
+
+ovn_as az1
+az1_lb1_uuid=$(ovn-nbctl --bare --no-headings --columns=_uuid find 
Load_Balancer name=az1_lb1)
+
+check_row_count sb:Service_Monitor 5
+
+check_row_count sb:Service_Monitor 1 logical_port=lport4_az2
+
+check ovn-nbctl set Load_Balancer $az1_lb1_uuid 
vip='"10.10.10.1:80"="1.1.1.1:10880,5.5.5.1:10880,3.3.3.1:10880,2.2.2.1:10880"'
+check ovn-nbctl set load_balancer az1_lb1 
ip_port_mappings:2.2.2.1=lport2_az1:2.2.2.9
+
+check_row_count sb:Service_Monitor 4
+
+check_row_count sb:Service_Monitor 0 logical_port=lport4_az2
+
+check_row_count ic-sb:Service_Monitor 0 logical_port=lport4_az2
+
+ovn_as az3
+svc_lport6_uuid=$(ovn-sbctl -d bare --no-headings --columns _uuid find 
Service_Monitor logical_port=lport6_az3)
+
+check ovn-sbctl set Service_Monitor $svc_lport6_uuid status="online"
+
+check_column online ic-sb:Service_Monitor status logical_port=lport6_az3
+
+ovn_as az2
+check_column online sb:Service_Monitor status logical_port=lport6_az3
+
+ovn_as az2
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=3.3.3.1:10880);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.2 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.2; 
reg2[[0..15]] = 80; ct_lb_mark(backends=5.5.5.1:10881,6.6.6.1:10880);)
+])
+
+ovn_as az1
+svc_lport1_uuid=$(ovn-sbctl -d bare --no-headings --columns _uuid find 
Service_Monitor logical_port=lport1_az1)
+lport1_uuid=$(ovn-sbctl -d bare --no-headings --columns _uuid find 
Port_Binding logical_port=lport1_az1)
+
+check ovn-sbctl set Port_Binding $lport1_uuid up=true
+
+check ovn-sbctl set Service_Monitor $svc_lport1_uuid status="online"
+
+check_column online ic-sb:Service_Monitor status logical_port=lport1_az1
+
+ovn_as az2
+AT_CHECK([ovn-sbctl lflow-list az2_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=3.3.3.1:10880,1.1.1.1:10880);)
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 20.20.20.2 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 20.20.20.2; 
reg2[[0..15]] = 80; ct_lb_mark(backends=5.5.5.1:10881,6.6.6.1:10880);)
+])
+
+ovn_as az1
+AT_CHECK([ovn-sbctl lflow-list az1_ls1 | grep ls_in_lb | grep backends | 
ovn_strip_lflows], [0], [dnl
+  table=??(ls_in_lb           ), priority=120  , match=(ct.new && ip4.dst == 10.10.10.1 
&& reg1[[16..23]] == 6 && reg1[[0..15]] == 80), action=(reg4 = 10.10.10.1; 
reg2[[0..15]] = 80; ct_lb_mark(backends=1.1.1.1:10880,5.5.5.1:10880,3.3.3.1:10880);)
+])
+
+check ovn-nbctl lb-del az1_lb1
+
+/* check ic_learned not deleted */
+
+check_row_count sb:Service_Monitor 2
+check_row_count sb:Service_Monitor 1 logical_port=lport1_az1
+check_row_count sb:Service_Monitor 1 logical_port=lport2_az1
+
+ovn_as az2
+
+check_row_count sb:Service_Monitor 0 logical_port=lport4_az2
+
+ovn-nbctl list load_balancer az2_lb2
+
+check ovn-nbctl lb-del az2_lb2
+check_row_count sb:Service_Monitor 2
+
+ovn_as az1
+check_row_count sb:Service_Monitor 1
+
+ovn_as az3
+check_row_count sb:Service_Monitor 0
+
+ovn_as az1
+check_row_count ic-sb:Service_Monitor 1
+
+ovn_as az2
+check ovn-nbctl lb-del az2_lb1
+check_row_count sb:Service_Monitor 0
+
+ovn_as az1
+check_row_count sb:Service_Monitor 0
+check_row_count ic-sb:Service_Monitor 0
+
+OVN_CLEANUP_IC([az1], [az2], [az3])
+AT_CLEANUP
+])

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to