This commit introduces the ability to configure health checks for load balancer
backends located in remote availability zones through OVN Interconnect.

Key changes include:
1. Added new 'local' field to service monitor schema.
2. Extended ip_port_mappings syntax to support remote backends:
   - Added :remote:<az-name> suffix for health check targets
3. Modified controller logic to skip non-local monitors.
4. Enhanced northd to handle remote health check configuration.

Signed-off-by: Alexandra Rukomoinikova <arukomoinikova@k2.cloud>
---
 controller/pinctrl.c |  2 +-
 northd/lb.c          | 30 +++++++++++++++++++++++-------
 northd/lb.h          |  9 +++++++--
 northd/northd.c      | 35 ++++++++++++++++++++++++++++-------
 ovn-nb.xml           |  7 +++++++
 ovn-sb.ovsschema     |  5 +++--
 ovn-sb.xml           | 10 +++++++++-
 7 files changed, 78 insertions(+), 20 deletions(-)

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index d4f4da731..fcb04eadd 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -7048,7 +7048,7 @@ sync_svc_monitors(struct ovsdb_idl_txn *ovnsb_idl_txn,
         const struct sbrec_port_binding *pb
             = lport_lookup_by_name(sbrec_port_binding_by_name,
                                    sb_svc_mon->logical_port);
-        if (!pb) {
+        if (!pb || !sb_svc_mon->local) {
             continue;
         }
 
diff --git a/northd/lb.c b/northd/lb.c
index b11896cf1..15a0b8651 100644
--- a/northd/lb.c
+++ b/northd/lb.c
@@ -120,20 +120,29 @@ ovn_lb_vip_backends_health_check_init(const struct 
ovn_northd_lb *lb,
         }
 
         char *svc_mon_src_ip = NULL;
+        char *az_name = NULL;
         char *port_name = xstrdup(s);
-        char *p = strstr(port_name, ":");
-        if (p) {
-            *p = 0;
-            p++;
+
+        char *ip_part = strstr(port_name, ":");
+        if (ip_part) {
+            *ip_part = '\0';
+            ip_part++;
+
+            char *remote_marker = strstr(ip_part, ":remote:");
+            if (remote_marker) {
+                *remote_marker = '\0';
+                az_name = remote_marker + 8;
+            }
+
             struct sockaddr_storage svc_mon_src_addr;
-            if (!inet_parse_address(p, &svc_mon_src_addr)) {
+            if (!inet_parse_address(ip_part, &svc_mon_src_addr)) {
                 static struct vlog_rate_limit rl =
                     VLOG_RATE_LIMIT_INIT(5, 1);
-                VLOG_WARN_RL(&rl, "Invalid svc mon src IP %s", p);
+                VLOG_WARN_RL(&rl, "Invalid svc mon src IP %s", ip_part);
             } else {
                 struct ds src_ip_s = DS_EMPTY_INITIALIZER;
                 ss_format_address_nobracks(&svc_mon_src_addr,
-                                            &src_ip_s);
+                                           &src_ip_s);
                 svc_mon_src_ip = ds_steal_cstr(&src_ip_s);
             }
         }
@@ -144,6 +153,12 @@ ovn_lb_vip_backends_health_check_init(const struct 
ovn_northd_lb *lb,
             backend_nb->health_check = true;
             backend_nb->logical_port = xstrdup(port_name);
             backend_nb->svc_mon_src_ip = svc_mon_src_ip;
+            if (az_name) {
+                backend_nb->local_backend = false;
+                backend_nb->az_name = xstrdup(az_name);
+            } else {
+                backend_nb->local_backend = true;
+            }
         }
         free(port_name);
     }
@@ -158,6 +173,7 @@ void ovn_northd_lb_vip_destroy(struct ovn_northd_lb_vip 
*vip)
     for (size_t i = 0; i < vip->n_backends; i++) {
         free(vip->backends_nb[i].logical_port);
         free(vip->backends_nb[i].svc_mon_src_ip);
+        free(vip->backends_nb[i].az_name);
     }
     free(vip->backends_nb);
 }
diff --git a/northd/lb.h b/northd/lb.h
index eb1942bd4..6de953cfc 100644
--- a/northd/lb.h
+++ b/northd/lb.h
@@ -88,8 +88,13 @@ struct ovn_northd_lb_vip {
 
 struct ovn_northd_lb_backend {
     bool health_check;
-    char *logical_port; /* Logical port to which the ip belong to. */
-    char *svc_mon_src_ip; /* Source IP to use for monitoring. */
+     /* Set to true if port locates in current ovn cluster. */
+    bool local_backend;
+    /* Logical port to which the ip belong to. */
+    char *logical_port;
+    char *svc_mon_src_ip;
+    /* Target az_name for service monitor. */
+    char *az_name;
 };
 
 struct ovn_northd_lb *ovn_northd_lb_create(const struct nbrec_load_balancer *);
diff --git a/northd/northd.c b/northd/northd.c
index a7be29619..c83348fe5 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -3730,13 +3730,28 @@ get_service_mon(const struct hmap *local_monitor_map,
     return NULL;
 }
 
+static void
+set_service_mon_options(const struct sbrec_service_monitor *sbrec_mon,
+                        const struct smap *nb_hc_options,
+                        const char *target_az_name)
+{
+    struct smap sb_svc_options = SMAP_INITIALIZER(&sb_svc_options);
+
+    smap_clone(&sb_svc_options, nb_hc_options);
+    if (target_az_name) {
+        smap_add(&sb_svc_options, "az-name", target_az_name);
+    }
+    sbrec_service_monitor_set_options(sbrec_mon, &sb_svc_options);
+    smap_destroy(&sb_svc_options);
+}
+
 static struct service_monitor_info *
 create_or_get_service_mon(struct ovsdb_idl_txn *ovnsb_txn,
                           struct hmap *local_monitor_map,
                           struct hmap *ic_learned_monitor_map,
                           const char *ip, const char *logical_port,
                           uint16_t service_port, const char *protocol,
-                          const char *chassis_name)
+                          const char *chassis_name, bool local_backend)
 {
     struct service_monitor_info *mon_info =
         get_service_mon(local_monitor_map, ic_learned_monitor_map,
@@ -3762,6 +3777,8 @@ create_or_get_service_mon(struct ovsdb_idl_txn *ovnsb_txn,
     sbrec_service_monitor_set_port(sbrec_mon, service_port);
     sbrec_service_monitor_set_logical_port(sbrec_mon, logical_port);
     sbrec_service_monitor_set_protocol(sbrec_mon, protocol);
+    sbrec_service_monitor_set_local(sbrec_mon, local_backend);
+    sbrec_service_monitor_set_ic_learned(sbrec_mon, false);
     if (chassis_name) {
         sbrec_service_monitor_set_chassis_name(sbrec_mon, chassis_name);
     }
@@ -3803,7 +3820,8 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
             struct ovn_port *op = ovn_port_find(ls_ports,
                                                 backend_nb->logical_port);
 
-            if (!op || !lsp_is_enabled(op->nbsp)) {
+            if (backend_nb->local_backend &&
+                (!op || !lsp_is_enabled(op->nbsp))) {
                 continue;
             }
 
@@ -3813,7 +3831,7 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
             }
 
             const char *chassis_name = NULL;
-            if (op->sb->chassis) {
+            if (backend_nb->local_backend && op->sb->chassis) {
                 chassis_name = op->sb->chassis->name;
             }
 
@@ -3825,10 +3843,12 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
                                           backend_nb->logical_port,
                                           backend->port,
                                           protocol,
-                                          chassis_name);
+                                          chassis_name,
+                                          backend_nb->local_backend);
             ovs_assert(mon_info);
-            sbrec_service_monitor_set_options(
-                mon_info->sbrec_mon, &lb_vip_nb->lb_health_check->options);
+            set_service_mon_options(mon_info->sbrec_mon,
+                                    &lb_vip_nb->lb_health_check->options,
+                                    backend_nb->az_name);
             struct eth_addr ea;
             if (!mon_info->sbrec_mon->src_mac ||
                 !eth_addr_from_string(mon_info->sbrec_mon->src_mac, &ea) ||
@@ -3845,7 +3865,8 @@ ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn,
                     backend_nb->svc_mon_src_ip);
             }
 
-            if ((!op->sb->n_up || !op->sb->up[0])
+            if (backend_nb->local_backend &&
+                (!op->sb->n_up || !op->sb->up[0])
                 && mon_info->sbrec_mon->status
                 && !strcmp(mon_info->sbrec_mon->status, "online")) {
                 sbrec_service_monitor_set_status(mon_info->sbrec_mon,
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 4a7581807..674dfdc0c 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -2231,6 +2231,9 @@
           Health checks are sent to this port with the specified source IP.
           For IPv6 square brackets must be used around IP address, e.g:
           <code><var>port_name</var>:<var>[sourc_ip]</var></code>
+          Remote endpoint:
+          Use the :remote:<code>az-name</code> syntax to create remote health
+          checks in a specific zone.
         </p>
 
         <p>
@@ -2238,11 +2241,15 @@
           defined as <code>10.0.0.4</code>=<code>sw0-p1:10.0.0.2</code> and
           <code>20.0.0.4</code>=<code>sw1-p1:20.0.0.2</code>, if the values
           given were suitable ports and IP addresses.
+          And remote endpoint:
+          <code>10.0.0.4</code>=<code>sw0-p1:10.0.0.2</code>:remote:az1, where
+          <code>sw0-p1</code> - logical port in <code>az1</code>.
         </p>
 
         <p>
           For IPv6 IP to port mappings might be defined as
           <code>[2001::1]</code>=<code>sw0-p1:[2002::1]</code>.
+          Remote endpoint: same as for IP.
         </p>
       </column>
     </group>
diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
index da1fd38e8..91763b7f8 100644
--- a/ovn-sb.ovsschema
+++ b/ovn-sb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_Southbound",
-    "version": "21.3.0",
-    "cksum": "3512532069 34910",
+    "version": "21.4.0",
+    "cksum": "1850884918 34956",
     "tables": {
         "SB_Global": {
             "columns": {
@@ -517,6 +517,7 @@
                 "src_mac": {"type": "string"},
                 "src_ip": {"type": "string"},
                 "chassis_name": {"type": "string"},
+                "local": {"type": "boolean"},
                 "ic_learned": {"type": "boolean"},
                 "status": {
                     "type": {"key": {"type": "string",
diff --git a/ovn-sb.xml b/ovn-sb.xml
index f7eafd379..08b4892f5 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -4967,6 +4967,10 @@ tcp.flags = RST;
       The service can be an IPv4 TCP or UDP
       service. <code>ovn-controller</code> periodically sends out service
       monitor packets and updates the status of the service.
+      If the service monitor is not local, then ovn-ic creates a record about
+      it in the SBDB database, after which another OVN deployment creates a
+      record about the Service Monitor in its SBDB and the status is
+      propagated back to the initial record in the original availability zone.
     </p>
 
     <p>
@@ -4981,7 +4985,7 @@ tcp.flags = RST;
       </p>
 
       <column name="ip">
-        IP of the service to be monitored. Only IPv4 is supported.
+        IP of the service to be monitored.
       </column>
 
       <column name="protocol">
@@ -5010,6 +5014,10 @@ tcp.flags = RST;
         The name of the chassis where the logical port is bound.
       </column>
 
+      <column name="local">
+        Set to true if backend locates on local ovn deployment.
+      </column>
+
       <column name="ic_learned">
         Set to true if the service monitor was propagated from another
         OVN deployment via ovn-ic management.
-- 
2.48.1

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

Reply via email to