Signed-off-by: Dumitru Ceara <[email protected]>
---
TODO:
- No support for LB health check if the LB is templated.
- No support for VIP ARP responder if the LB is templated.
- No support for routed VIPs if the LB is templated.
- No 'ovn-nbctl lb-*' commands support for templated LBs.

Signed-off-by: Dumitru Ceara <[email protected]>
---
 controller/lflow.c |   18 +++--
 lib/lb.c           |  200 +++++++++++++++++++++++++++++++++++++++++++++-------
 lib/lb.h           |   35 +++++++--
 northd/northd.c    |   64 +++++++++--------
 4 files changed, 245 insertions(+), 72 deletions(-)

diff --git a/controller/lflow.c b/controller/lflow.c
index 6e60728f0..fe887d3cb 100644
--- a/controller/lflow.c
+++ b/controller/lflow.c
@@ -2343,7 +2343,9 @@ add_lb_ct_snat_hairpin_flows(struct ovn_controller_lb *lb,
 
 static void
 consider_lb_hairpin_flows(const struct sbrec_load_balancer *sbrec_lb,
-                          const struct hmap *local_datapaths, bool use_ct_mark,
+                          const struct hmap *local_datapaths,
+                          const struct smap *template_vars,
+                          bool use_ct_mark,
                           struct ovn_desired_flow_table *flow_table,
                           struct simap *ids)
 {
@@ -2366,7 +2368,8 @@ consider_lb_hairpin_flows(const struct 
sbrec_load_balancer *sbrec_lb,
         return;
     }
 
-    struct ovn_controller_lb *lb = ovn_controller_lb_create(sbrec_lb);
+    struct ovn_controller_lb *lb = ovn_controller_lb_create(sbrec_lb,
+                                                            template_vars);
     uint8_t lb_proto = IPPROTO_TCP;
     if (lb->slb->protocol && lb->slb->protocol[0]) {
         if (!strcmp(lb->slb->protocol, "udp")) {
@@ -2396,7 +2399,9 @@ consider_lb_hairpin_flows(const struct 
sbrec_load_balancer *sbrec_lb,
  * backends to handle the load balanced hairpin traffic. */
 static void
 add_lb_hairpin_flows(const struct sbrec_load_balancer_table *lb_table,
-                     const struct hmap *local_datapaths, bool use_ct_mark,
+                     const struct hmap *local_datapaths,
+                     const struct smap *template_vars,
+                     bool use_ct_mark,
                      struct ovn_desired_flow_table *flow_table,
                      struct simap *ids,
                      struct id_pool *pool)
@@ -2419,8 +2424,8 @@ add_lb_hairpin_flows(const struct 
sbrec_load_balancer_table *lb_table,
             ovs_assert(id_pool_alloc_id(pool, &id));
             simap_put(ids, lb->name, id);
         }
-        consider_lb_hairpin_flows(lb, local_datapaths, use_ct_mark, flow_table,
-                                  ids);
+        consider_lb_hairpin_flows(lb, local_datapaths, template_vars,
+                                  use_ct_mark, flow_table, ids);
     }
 }
 
@@ -2557,6 +2562,7 @@ lflow_run(struct lflow_ctx_in *l_ctx_in, struct 
lflow_ctx_out *l_ctx_out)
                        l_ctx_in->local_datapaths,
                        l_ctx_out->flow_table);
     add_lb_hairpin_flows(l_ctx_in->lb_table, l_ctx_in->local_datapaths,
+                         l_ctx_in->template_vars,
                          l_ctx_in->lb_hairpin_use_ct_mark,
                          l_ctx_out->flow_table,
                          l_ctx_out->hairpin_lb_ids,
@@ -2721,6 +2727,7 @@ lflow_add_flows_for_datapath(const struct 
sbrec_datapath_binding *dp,
      * associated. */
     for (size_t i = 0; i < n_dp_lbs; i++) {
         consider_lb_hairpin_flows(dp_lbs[i], l_ctx_in->local_datapaths,
+                                  l_ctx_in->template_vars,
                                   l_ctx_in->lb_hairpin_use_ct_mark,
                                   l_ctx_out->flow_table,
                                   l_ctx_out->hairpin_lb_ids);
@@ -2852,6 +2859,7 @@ lflow_handle_changed_lbs(struct lflow_ctx_in *l_ctx_in,
         VLOG_DBG("Add load balancer hairpin flows for "UUID_FMT,
                  UUID_ARGS(&lb->header_.uuid));
         consider_lb_hairpin_flows(lb, l_ctx_in->local_datapaths,
+                                  l_ctx_in->template_vars,
                                   l_ctx_in->lb_hairpin_use_ct_mark,
                                   l_ctx_out->flow_table,
                                   l_ctx_out->hairpin_lb_ids);
diff --git a/lib/lb.c b/lib/lb.c
index 7b0ed1abe..56944ace8 100644
--- a/lib/lb.c
+++ b/lib/lb.c
@@ -19,6 +19,7 @@
 #include "lib/ovn-nb-idl.h"
 #include "lib/ovn-sb-idl.h"
 #include "lib/ovn-util.h"
+#include "ovn/lex.h"
 
 /* OpenvSwitch lib includes. */
 #include "openvswitch/vlog.h"
@@ -26,29 +27,13 @@
 
 VLOG_DEFINE_THIS_MODULE(lb);
 
-static
-bool ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key,
-                     const char *lb_value)
+/* Format for backend ips: "IP1:port1,IP2:port2,...". */
+static size_t
+ovn_lb_backends_init_explicit(struct ovn_lb_vip *lb_vip, const char *value)
 {
-    int addr_family;
-
-    if (!ip_address_and_port_from_lb_key(lb_key, &lb_vip->vip_str,
-                                         &lb_vip->vip_port, &addr_family)) {
-        return false;
-    }
-
-    if (addr_family == AF_INET) {
-        ovs_be32 vip4;
-        ip_parse(lb_vip->vip_str, &vip4);
-        in6_addr_set_mapped_ipv4(&lb_vip->vip, vip4);
-    } else {
-        ipv6_parse(lb_vip->vip_str, &lb_vip->vip);
-    }
-
-    /* Format for backend ips: "IP1:port1,IP2:port2,...". */
     size_t n_backends = 0;
     size_t n_allocated_backends = 0;
-    char *tokstr = xstrdup(lb_value);
+    char *tokstr = xstrdup(value);
     char *save_ptr = NULL;
     for (char *token = strtok_r(tokstr, ",", &save_ptr);
         token != NULL;
@@ -68,12 +53,15 @@ bool ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char 
*lb_key,
             continue;
         }
 
-        if (addr_family != backend_addr_family) {
+        if (lb_vip->address_family != backend_addr_family) {
             free(backend->ip_str);
             continue;
         }
 
-        if (addr_family == AF_INET) {
+        backend->port_str =
+            backend->port ? xasprintf("%"PRIu16, backend->port) : NULL;
+
+        if (lb_vip->address_family == AF_INET) {
             ovs_be32 ip4;
             ip_parse(backend->ip_str, &ip4);
             in6_addr_set_mapped_ipv4(&backend->ip, ip4);
@@ -83,16 +71,156 @@ bool ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char 
*lb_key,
         n_backends++;
     }
     free(tokstr);
-    lb_vip->n_backends = n_backends;
+    return n_backends;
+}
+
+static
+bool ovn_lb_vip_init_explicit(struct ovn_lb_vip *lb_vip, const char *lb_key,
+                              const char *lb_value)
+{
+    if (!ip_address_and_port_from_lb_key(lb_key, &lb_vip->vip_str,
+                                         &lb_vip->vip_port,
+                                         &lb_vip->address_family)) {
+        return false;
+    }
+
+    lb_vip->port_str = lb_vip->vip_port
+                       ? xasprintf("%"PRIu16, lb_vip->vip_port)
+                       : NULL;
+
+    if (lb_vip->address_family == AF_INET) {
+        ovs_be32 vip4;
+        ip_parse(lb_vip->vip_str, &vip4);
+        in6_addr_set_mapped_ipv4(&lb_vip->vip, vip4);
+    } else {
+        ipv6_parse(lb_vip->vip_str, &lb_vip->vip);
+    }
+    lb_vip->n_backends = ovn_lb_backends_init_explicit(lb_vip, lb_value);
     return true;
 }
 
+/* Parses backends of a templated LB VIP.
+ * For now only the following template forms are supported:
+ * A.
+ *   ^backendip_variable1[:^port_variable1|:port],
+ *   ^backendip_variable2[:^port_variable2|:port]
+ *
+ * B.
+ *   ^backends_variable1,^backends_variable2 is also a thing
+ *      where 'backends_variable1' may expand to IP1_1:PORT1_1 on chassis-1
+ *                                               IP1_2:PORT1_2 on chassis-2
+ *        and 'backends_variable2' may expand to IP2_1:PORT2_1 on chassis-1
+ *                                               IP2_2:PORT2_2 on chassis-2
+ *
+ * Returns the number of successfully parsed backends.
+ */
+static size_t
+ovn_lb_backends_init_template(struct ovn_lb_vip *lb_vip, const char *value_)
+{
+    char *value = xstrdup(value_);
+    char *save_ptr = NULL;
+    size_t n_allocated_backends = 0;
+    size_t n_backends = 0;
+
+    for (char *backend = strtok_r(value, ",", &save_ptr); backend;
+         backend = strtok_r(NULL, ",", &save_ptr)) {
+
+        char *atom = xstrdup(backend);
+        char *save_ptr2 = NULL;
+        bool success = false;
+        char *backend_ip = NULL;
+        char *backend_port = NULL;
+
+        for (char *subatom = strtok_r(atom, ":", &save_ptr2); subatom;
+             subatom = strtok_r(NULL, ":", &save_ptr2)) {
+            if (backend_ip && backend_port) {
+                /* XXX: Log when there are more than two tokens? */
+                success = false;
+                break;
+            }
+            success = true;
+            if (!backend_ip) {
+                backend_ip = xstrdup(subatom);
+            } else {
+                backend_port = xstrdup(subatom);
+            }
+        }
+
+        if (success) {
+            if (n_backends == n_allocated_backends) {
+                lb_vip->backends = x2nrealloc(lb_vip->backends,
+                                              &n_allocated_backends,
+                                              sizeof *lb_vip->backends);
+            }
+            lb_vip->backends[n_backends].ip_str = backend_ip;
+            lb_vip->backends[n_backends].port_str = backend_port;
+            lb_vip->backends[n_backends].port = 0;
+            n_backends++;
+        }
+        free(atom);
+    }
+
+    free(value);
+    return n_backends;
+}
+
+/* Parses a VIP of a templated LB.
+ * For now only the following template forms are supported:
+ *   ^vip_variable[:^port_variable|:port]
+ */
+static bool
+ovn_lb_vip_init_template(struct ovn_lb_vip *lb_vip, const char *lb_key_,
+                         const char *lb_value, int address_family)
+{
+    char *save_ptr = NULL;
+    char *lb_key = xstrdup(lb_key_);
+    bool success = false;
+
+    for (char *atom = strtok_r(lb_key, ":", &save_ptr); atom;
+         atom = strtok_r(NULL, ":", &save_ptr)) {
+        if (lb_vip->vip_str && lb_vip->port_str) {
+            /* XXX: Log when there are more than two tokens? */
+            success = false;
+            break;
+        }
+        success = true;
+        if (!lb_vip->vip_str) {
+            lb_vip->vip_str = xstrdup(atom);
+        } else {
+            lb_vip->port_str = xstrdup(atom);
+        }
+    }
+
+    free(lb_key);
+
+    lb_vip->address_family = address_family;
+    if (success) {
+        lb_vip->n_backends = ovn_lb_backends_init_template(lb_vip, lb_value);
+    }
+    return success;
+}
+
+static
+bool ovn_lb_vip_init(struct ovn_lb_vip *lb_vip, const char *lb_key,
+                     const char *lb_value, bool is_template,
+                     int address_family)
+{
+    if (!is_template) {
+        return ovn_lb_vip_init_explicit(lb_vip, lb_key, lb_value);
+    } else {
+        return ovn_lb_vip_init_template(lb_vip, lb_key, lb_value,
+                                        address_family);
+    }
+}
+
 static
 void ovn_lb_vip_destroy(struct ovn_lb_vip *vip)
 {
     free(vip->vip_str);
+    free(vip->port_str);
     for (size_t i = 0; i < vip->n_backends; i++) {
         free(vip->backends[i].ip_str);
+        free(vip->backends[i].port_str);
     }
     free(vip->backends);
 }
@@ -167,12 +295,19 @@ ovn_northd_lb_create(const struct nbrec_load_balancer 
*nbrec_lb)
     bool is_udp = nullable_string_is_equal(nbrec_lb->protocol, "udp");
     bool is_sctp = nullable_string_is_equal(nbrec_lb->protocol, "sctp");
     struct ovn_northd_lb *lb = xzalloc(sizeof *lb);
+    int address_family = !strcmp(smap_get_def(&nbrec_lb->options,
+                                              "address-family", "ipv4"),
+                                 "ipv4")
+                         ? AF_INET
+                         : AF_INET6;
 
     lb->nlb = nbrec_lb;
     lb->proto = is_udp ? "udp" : is_sctp ? "sctp" : "tcp";
     lb->n_vips = smap_count(&nbrec_lb->vips);
     lb->vips = xcalloc(lb->n_vips, sizeof *lb->vips);
     lb->vips_nb = xcalloc(lb->n_vips, sizeof *lb->vips_nb);
+    lb->is_template = smap_get_bool(&nbrec_lb->options, "template", false);
+
     sset_init(&lb->ips_v4);
     sset_init(&lb->ips_v6);
     struct smap_node *node;
@@ -184,7 +319,8 @@ ovn_northd_lb_create(const struct nbrec_load_balancer 
*nbrec_lb)
 
         lb_vip->empty_backend_rej = smap_get_bool(&nbrec_lb->options,
                                                   "reject", false);
-        if (!ovn_lb_vip_init(lb_vip, node->key, node->value)) {
+        if (!ovn_lb_vip_init(lb_vip, node->key, node->value, lb->is_template,
+                             address_family)) {
             continue;
         }
         ovn_northd_lb_vip_init(lb_vip_nb, lb_vip, nbrec_lb,
@@ -276,7 +412,8 @@ ovn_northd_lb_destroy(struct ovn_northd_lb *lb)
 }
 
 struct ovn_controller_lb *
-ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb)
+ovn_controller_lb_create(const struct sbrec_load_balancer *sbrec_lb,
+                         const struct smap *template_vars)
 {
     struct ovn_controller_lb *lb = xzalloc(sizeof *lb);
 
@@ -290,10 +427,17 @@ ovn_controller_lb_create(const struct sbrec_load_balancer 
*sbrec_lb)
     SMAP_FOR_EACH (node, &sbrec_lb->vips) {
         struct ovn_lb_vip *lb_vip = &lb->vips[n_vips];
 
-        if (!ovn_lb_vip_init(lb_vip, node->key, node->value)) {
-            continue;
+        char *key_s = lexer_parse_template_string(xstrdup(node->key),
+                                                  template_vars,
+                                                  NULL);
+        char *value_s = lexer_parse_template_string(xstrdup(node->value),
+                                                    template_vars,
+                                                    NULL);
+        if (ovn_lb_vip_init_explicit(lb_vip, key_s, value_s)) {
+            n_vips++;
         }
-        n_vips++;
+        free(key_s);
+        free(value_s);
     }
 
     /* It's possible that parsing VIPs fails.  Update the lb->n_vips to the
diff --git a/lib/lb.h b/lib/lb.h
index 832ed31fb..192ec7ed2 100644
--- a/lib/lb.h
+++ b/lib/lb.h
@@ -50,27 +50,43 @@ struct ovn_northd_lb {
     size_t n_nb_lr;
     size_t n_allocated_nb_lr;
     struct ovn_datapath **nb_lr;
+
+    bool is_template;
 };
 
 struct ovn_lb_vip {
-    struct in6_addr vip;
-    char *vip_str;
-    uint16_t vip_port;
-
+    struct in6_addr vip; /* Only used in ovn-controller. */
+    char *vip_str;       /* Actual VIP string representation (without port).
+                          * To be used in ovn-northd.
+                          */
+    uint16_t vip_port;   /* Only used in ovn-controller. */
+    char *port_str;      /* Actual port string representation.  To be used
+                          * in ovn-controller.
+                          */
     struct ovn_lb_backend *backends;
     size_t n_backends;
     bool empty_backend_rej;
+    int address_family;
 };
 
 struct ovn_lb_backend {
-    struct in6_addr ip;
-    char *ip_str;
-    uint16_t port;
+    struct in6_addr ip;  /* Only used in ovn-controller. */
+    char *ip_str;        /* Actual IP string representation. To be used in
+                          * ovn-northd.
+                          */
+    uint16_t port;       /* Mostly used in ovn-controller but also for
+                          * healthcheck in ovn-northd.
+                          */
+    char *port_str;      /* Actual port string representation. To be used
+                          * in ovn-northd.
+                          */
 };
 
 /* ovn-northd specific backend information. */
 struct ovn_northd_lb_vip {
-    char *vip_port_str;
+    char *vip_port_str;  /* VIP string representation of the form:
+                          * "VIP[:port]"
+                          */
     char *backend_ips;
     struct ovn_northd_lb_backend *backends_nb;
     size_t n_backends;
@@ -109,7 +125,8 @@ struct ovn_controller_lb {
 };
 
 struct ovn_controller_lb *ovn_controller_lb_create(
-    const struct sbrec_load_balancer *);
+    const struct sbrec_load_balancer *,
+    const struct smap *template_vars);
 void ovn_controller_lb_destroy(struct ovn_controller_lb *);
 
 #endif /* OVN_LIB_LB_H 1 */
diff --git a/northd/northd.c b/northd/northd.c
index c4769ea07..e9a6dad38 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -3821,6 +3821,10 @@ static void
 ovn_lb_svc_create(struct ovsdb_idl_txn *ovnsb_txn, struct ovn_northd_lb *lb,
                   struct hmap *monitor_map, struct hmap *ports)
 {
+    if (lb->is_template) {
+        return;
+    }
+
     for (size_t i = 0; i < lb->n_vips; i++) {
         struct ovn_lb_vip *lb_vip = &lb->vips[i];
         struct ovn_northd_lb_vip *lb_vip_nb = &lb->vips_nb[i];
@@ -4097,7 +4101,7 @@ build_lrouter_lb_reachable_ips(struct ovn_datapath *od,
      */
     if (!strcmp(neighbor_responder_mode, "all")) {
         for (size_t i = 0; i < lb->n_vips; i++) {
-            if (IN6_IS_ADDR_V4MAPPED(&lb->vips[i].vip)) {
+            if (lb->vips[i].address_family == AF_INET) {
                 sset_add(&od->lb_ips_v4_reachable, lb->vips[i].vip_str);
             } else {
                 sset_add(&od->lb_ips_v6_reachable, lb->vips[i].vip_str);
@@ -4110,7 +4114,7 @@ build_lrouter_lb_reachable_ips(struct ovn_datapath *od,
      * subnet that includes it.
      */
     for (size_t i = 0; i < lb->n_vips; i++) {
-        if (IN6_IS_ADDR_V4MAPPED(&lb->vips[i].vip)) {
+        if (lb->vips[i].address_family == AF_INET) {
             ovs_be32 vip_ip4 = in6_addr_get_mapped_ipv4(&lb->vips[i].vip);
             struct ovn_port *op;
 
@@ -5782,17 +5786,17 @@ build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
     ds_clear(action);
     ds_clear(match);
 
-    bool ipv4 = IN6_IS_ADDR_V4MAPPED(&lb_vip->vip);
+    bool ipv4 = lb_vip->address_family == AF_INET;
 
     ds_put_format(match, "ip%s.dst == %s && %s",
                   ipv4 ? "4": "6", lb_vip->vip_str, lb->protocol);
 
     char *vip = lb_vip->vip_str;
-    if (lb_vip->vip_port) {
-        ds_put_format(match, " && %s.dst == %u", lb->protocol,
-                      lb_vip->vip_port);
-        vip = xasprintf("%s%s%s:%u", ipv4 ? "" : "[", lb_vip->vip_str,
-                        ipv4 ? "" : "]", lb_vip->vip_port);
+    if (lb_vip->port_str) {
+        ds_put_format(match, " && %s.dst == %s", lb->protocol,
+                      lb_vip->port_str);
+        vip = xasprintf("%s%s%s:%s", ipv4 ? "" : "[", lb_vip->vip_str,
+                        ipv4 ? "" : "]", lb_vip->port_str);
     }
 
     ds_put_format(action,
@@ -5803,7 +5807,7 @@ build_empty_lb_event_flow(struct ovn_lb_vip *lb_vip,
                   event_to_string(OVN_EVENT_EMPTY_LB_BACKENDS),
                   vip, lb->protocol,
                   UUID_ARGS(&lb->header_.uuid));
-    if (lb_vip->vip_port) {
+    if (lb_vip->port_str) {
         free(vip);
     }
     return true;
@@ -6893,7 +6897,7 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb 
*lb, bool ct_lb_mark,
         /* Store the original destination IP to be used when generating
          * hairpin flows.
          */
-        if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
+        if (lb->vips[i].address_family == AF_INET) {
             ip_match = "ip4";
             ds_put_format(action, REG_ORIG_DIP_IPV4 " = %s; ",
                           lb_vip->vip_str);
@@ -6904,7 +6908,7 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb 
*lb, bool ct_lb_mark,
         }
 
         const char *proto = NULL;
-        if (lb_vip->vip_port) {
+        if (lb_vip->port_str) {
             proto = "tcp";
             if (lb->nlb->protocol) {
                 if (!strcmp(lb->nlb->protocol, "udp")) {
@@ -6917,8 +6921,8 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb 
*lb, bool ct_lb_mark,
             /* Store the original destination port to be used when generating
              * hairpin flows.
              */
-            ds_put_format(action, REG_ORIG_TP_DPORT " = %"PRIu16"; ",
-                          lb_vip->vip_port);
+            ds_put_format(action, REG_ORIG_TP_DPORT " = %s; ",
+                          lb_vip->port_str);
         }
 
         /* New connections in Ingress table. */
@@ -6930,8 +6934,8 @@ build_lb_rules(struct hmap *lflows, struct ovn_northd_lb 
*lb, bool ct_lb_mark,
         ds_put_format(match, "ct.new && %s.dst == %s", ip_match,
                       lb_vip->vip_str);
         int priority = 110;
-        if (lb_vip->vip_port) {
-            ds_put_format(match, " && %s.dst == %d", proto, lb_vip->vip_port);
+        if (lb_vip->port_str) {
+            ds_put_format(match, " && %s.dst == %s", proto, lb_vip->port_str);
             priority = 120;
         }
 
@@ -9848,7 +9852,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
      * of "ct_lb_mark($targets);". The other flow is for ct.est with
      * an action of "next;".
      */
-    if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
+    if (lb_vip->address_family == AF_INET) {
         ds_put_format(match, "ip4 && "REG_NEXT_HOP_IPV4" == %s",
                       lb_vip->vip_str);
     } else {
@@ -9865,14 +9869,14 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip 
*lb_vip,
     }
 
     int prio = 110;
-    if (lb_vip->vip_port) {
+    if (lb_vip->port_str) {
         prio = 120;
         new_match = xasprintf("ct.new && %s && %s && "
-                              REG_ORIG_TP_DPORT_ROUTER" == %d",
-                              ds_cstr(match), lb->proto, lb_vip->vip_port);
+                              REG_ORIG_TP_DPORT_ROUTER" == %s",
+                              ds_cstr(match), lb->proto, lb_vip->port_str);
         est_match = xasprintf("ct.est && %s && %s && "
-                              REG_ORIG_TP_DPORT_ROUTER" == %d && %s == 1",
-                              ds_cstr(match), lb->proto, lb_vip->vip_port,
+                              REG_ORIG_TP_DPORT_ROUTER" == %s && %s == 1",
+                              ds_cstr(match), lb->proto, lb_vip->port_str,
                               ct_natted);
     } else {
         new_match = xasprintf("ct.new && %s", ds_cstr(match));
@@ -9881,7 +9885,7 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
     }
 
     const char *ip_match = NULL;
-    if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
+    if (lb_vip->address_family == AF_INET) {
         ip_match = "ip4";
     } else {
         ip_match = "ip6";
@@ -9899,9 +9903,9 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
         ds_put_format(&undnat_match, "(%s.src == %s", ip_match,
                       backend->ip_str);
 
-        if (backend->port) {
-            ds_put_format(&undnat_match, " && %s.src == %d) || ",
-                          lb->proto, backend->port);
+        if (backend->port_str) {
+            ds_put_format(&undnat_match, " && %s.src == %s) || ",
+                          lb->proto, backend->port_str);
         } else {
             ds_put_cstr(&undnat_match, ") || ");
         }
@@ -9914,9 +9918,9 @@ build_lrouter_nat_flows_for_lb(struct ovn_lb_vip *lb_vip,
     struct ds unsnat_match = DS_EMPTY_INITIALIZER;
     ds_put_format(&unsnat_match, "%s && %s.dst == %s && %s",
                   ip_match, ip_match, lb_vip->vip_str, lb->proto);
-    if (lb_vip->vip_port) {
-        ds_put_format(&unsnat_match, " && %s.dst == %d", lb->proto,
-                      lb_vip->vip_port);
+    if (lb_vip->port_str) {
+        ds_put_format(&unsnat_match, " && %s.dst == %s", lb->proto,
+                      lb_vip->port_str);
     }
 
     struct ovn_datapath **gw_router_skip_snat =
@@ -10154,7 +10158,7 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb 
*lb,
         ds_clear(&defrag_actions);
         ds_clear(match);
 
-        if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
+        if (lb_vip->address_family == AF_INET) {
             ds_put_format(match, "ip && ip4.dst == %s", lb_vip->vip_str);
             ds_put_format(&defrag_actions, REG_NEXT_HOP_IPV4" = %s; ",
                           lb_vip->vip_str);
@@ -10164,7 +10168,7 @@ build_lrouter_defrag_flows_for_lb(struct ovn_northd_lb 
*lb,
                           lb_vip->vip_str);
         }
 
-        if (lb_vip->vip_port) {
+        if (lb_vip->port_str) {
             ds_put_format(match, " && %s", lb->proto);
             prio = 110;
 

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to