[ovs-dev] [PATCH ovn 4/6] northd: move lb_{skip, force}_snat code in build_lrouter_snat_flows_for_lb

Lorenzo Bianconi lorenzo.bianconi at redhat.com
Fri Jun 11 10:17:34 UTC 2021


Introduce build_lrouter_snat_flows_for_lb routine to configuring
lb_{skip,force}_snat flows for each configured load_balancer

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at redhat.com>
---
 northd/ovn-northd.c | 163 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 127 insertions(+), 36 deletions(-)

diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 701cc4fbb..9a13dfcea 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -8730,41 +8730,10 @@ enum lb_snat_type {
 
 static void
 add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
-                   struct ds *match, struct ds *actions, int priority,
                    enum lb_snat_type snat_type, struct ovn_lb_vip *lb_vip,
                    const char *proto, struct nbrec_load_balancer *lb,
                    struct sset *nat_entries)
 {
-    /* A match and actions for new connections. */
-    char *new_match = xasprintf("ct.new && %s", ds_cstr(match));
-    if (snat_type == FORCE_SNAT || snat_type == SKIP_SNAT) {
-        char *new_actions = xasprintf("flags.%s_snat_for_lb = 1; %s",
-                snat_type == SKIP_SNAT ? "skip" : "force",
-                ds_cstr(actions));
-        ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority,
-                                new_match, new_actions, &lb->header_);
-        free(new_actions);
-    } else {
-        ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority,
-                                new_match, ds_cstr(actions), &lb->header_);
-    }
-
-    /* A match and actions for established connections. */
-    char *est_match = xasprintf("ct.est && %s", ds_cstr(match));
-    if (snat_type == FORCE_SNAT || snat_type == SKIP_SNAT) {
-        char *est_actions = xasprintf("flags.%s_snat_for_lb = 1; ct_dnat;",
-                snat_type == SKIP_SNAT ? "skip" : "force");
-        ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority,
-                                est_match, est_actions, &lb->header_);
-        free(est_actions);
-    } else {
-        ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority,
-                                est_match, "ct_dnat;", &lb->header_);
-    }
-
-    free(new_match);
-    free(est_match);
-
     const char *ip_match = NULL;
     if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
         ip_match = "ip4";
@@ -8845,6 +8814,126 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
     ds_destroy(&undnat_match);
 }
 
+static void
+build_lrouter_snat_flows_for_lb(struct ovn_lb_vip *lb_vip,
+                                struct ovn_northd_lb *lb,
+                                struct ovn_northd_lb_vip *vips_nb,
+                                struct hmap *lflows)
+{
+    char *new_match, *skip_snat_new_action = NULL;
+    char *est_match, *skip_snat_est_action = NULL;
+    struct ds action = DS_EMPTY_INITIALIZER;
+    struct ds match = DS_EMPTY_INITIALIZER;
+
+    build_lb_vip_actions(lb_vip, vips_nb, &action,
+                         lb->selection_fields, false);
+
+    /* Higher priority rules are added for load-balancing in DNAT
+     * table.  For every match (on a VIP[:port]), we add two flows.
+     * One flow is for specific matching on ct.new with an action
+     * of "ct_lb($targets);". The other flow is for ct.est with
+     * an action of "ct_dnat;".
+     */
+    if (IN6_IS_ADDR_V4MAPPED(&lb_vip->vip)) {
+        ds_put_format(&match, "ip && ip4.dst == %s", lb_vip->vip_str);
+    } else {
+        ds_put_format(&match, "ip && ip6.dst == %s", lb_vip->vip_str);
+    }
+
+    int prio = 110;
+    bool is_udp = nullable_string_is_equal(lb->nlb->protocol, "udp");
+    bool is_sctp = nullable_string_is_equal(lb->nlb->protocol,
+                                            "sctp");
+    const char *proto = is_udp ? "udp" : is_sctp ? "sctp" : "tcp";
+    if (lb_vip->vip_port) {
+        ds_put_format(&match, " && %s && %s.dst == %d", proto,
+                      proto, lb_vip->vip_port);
+        prio = 120;
+    }
+
+    enum lb_snat_type snat_type = NO_FORCE_SNAT;
+    if (smap_get_bool(&lb->nlb->options, "skip_snat", false)) {
+        snat_type = SKIP_SNAT;
+        skip_snat_new_action = xasprintf("flags.skip_snat_for_lb = 1; %s",
+                                         ds_cstr(&action));
+        skip_snat_est_action = xasprintf("flags.skip_snat_for_lb = 1; "
+                                         "ct_dnat;");
+    }
+    new_match = xasprintf("ct.new && %s", ds_cstr(&match));
+    est_match = xasprintf("ct.est && %s", ds_cstr(&match));
+
+    for (int i = 0; i < lb->n_nb_lr; i++) {
+        char *new_match_p = new_match, *est_match_p = est_match;
+        struct ovn_datapath *od = lb->nb_lr[i];
+
+        if (od->l3redirect_port &&
+            (lb_vip->n_backends || !lb_vip->empty_backend_rej)) {
+            new_match_p = xasprintf("ct.new && %s && is_chassis_resident(%s)",
+                                    ds_cstr(&match),
+                                    od->l3redirect_port->json_key);
+            est_match_p = xasprintf("ct.est && %s && is_chassis_resident(%s)",
+                                    ds_cstr(&match),
+                                    od->l3redirect_port->json_key);
+        }
+
+        if (snat_type == NO_FORCE_SNAT &&
+            (!lport_addresses_is_empty(&od->lb_force_snat_addrs) ||
+             od->lb_force_snat_router_ip)) {
+            snat_type = FORCE_SNAT;
+        }
+
+        if (snat_type == SKIP_SNAT) {
+            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
+                                    new_match_p, skip_snat_new_action,
+                                    &lb->nlb->header_);
+            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
+                                    est_match_p, skip_snat_est_action,
+                                    &lb->nlb->header_);
+        } else if (snat_type == FORCE_SNAT) {
+            char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s",
+                                          ds_cstr(&action));
+            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
+                                    new_match_p, new_actions,
+                                    &lb->nlb->header_);
+            free(new_actions);
+
+            char *est_actions = xasprintf("flags.force_snat_for_lb = 1; "
+                                          "ct_dnat;");
+            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
+                                    est_match_p, est_actions,
+                                    &lb->nlb->header_);
+            free(est_actions);
+        } else {
+            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
+                                    new_match_p, ds_cstr(&action),
+                                    &lb->nlb->header_);
+            ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, prio,
+                                    est_match_p, "ct_dnat;",
+                                    &lb->nlb->header_);
+        }
+
+        if (new_match_p != new_match) {
+            free(new_match_p);
+        }
+        if (est_match_p != est_match) {
+            free(est_match_p);
+        }
+    }
+
+    ds_destroy(&action);
+    ds_destroy(&match);
+
+    if (skip_snat_new_action) {
+        free(skip_snat_new_action);
+    }
+    if (skip_snat_est_action) {
+        free(skip_snat_est_action);
+    }
+
+    free(est_match);
+    free(new_match);
+}
+
 static void
 build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
                            struct shash *meter_groups)
@@ -8857,7 +8946,9 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
     struct ds match = DS_EMPTY_INITIALIZER;
 
     for (size_t i = 0; i < lb->n_vips; i++) {
-        if (build_empty_lb_event_flow(&lb->vips[i], lb->nlb, meter_groups,
+        struct ovn_lb_vip *lb_vip = &lb->vips[i];
+
+        if (build_empty_lb_event_flow(lb_vip, lb->nlb, meter_groups,
                                       &match, &action)) {
             for (int j = 0; j < lb->n_nb_lr; j++) {
                 ovn_lflow_add_with_hint(lflows, lb->nb_lr[j], S_ROUTER_IN_DNAT,
@@ -8866,6 +8957,9 @@ build_lrouter_flows_for_lb(struct ovn_northd_lb *lb, struct hmap *lflows,
                                         &lb->nlb->header_);
             }
         }
+
+        build_lrouter_snat_flows_for_lb(lb_vip, lb, &lb->vips_nb[i],
+                                        lflows);
     }
 
     ds_destroy(&action);
@@ -8941,7 +9035,6 @@ build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od,
                               lb_vip->vip_str);
             }
 
-            int prio = 110;
             bool is_udp = nullable_string_is_equal(nb_lb->protocol, "udp");
             bool is_sctp = nullable_string_is_equal(nb_lb->protocol,
                                                     "sctp");
@@ -8950,7 +9043,6 @@ build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od,
             if (lb_vip->vip_port) {
                 ds_put_format(match, " && %s && %s.dst == %d", proto,
                               proto, lb_vip->vip_port);
-                prio = 120;
             }
 
             if (od->l3redirect_port &&
@@ -8958,8 +9050,7 @@ build_lrouter_lb_flows(struct hmap *lflows, struct ovn_datapath *od,
                 ds_put_format(match, " && is_chassis_resident(%s)",
                               od->l3redirect_port->json_key);
             }
-            add_router_lb_flow(lflows, od, match, actions, prio,
-                               snat_type, lb_vip, proto, nb_lb,
+            add_router_lb_flow(lflows, od, snat_type, lb_vip, proto, nb_lb,
                                nat_entries);
         }
     }
-- 
2.31.1



More information about the dev mailing list