In the current codebase for distributed gw router port use-case,
it is not possible to add a load balancer that redirects the traffic
to a back-end if it is used as internal IP of a FIP NAT rule since
the reply traffic is never centralized. Fix the issue centralizing the
traffic if it is the reply packet for the load balancer.

Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2023609
Signed-off-by: Lorenzo Bianconi <lorenzo.bianc...@redhat.com>
---
Changes since v2:
- rebase on top of ovn main branch
- fix spelling
Changes since v1:
- add new system-test and unit-test
---
 northd/northd.c         |  15 ++++++
 northd/ovn-northd.8.xml |  16 +++++++
 tests/ovn-northd.at     |  48 +++++++++++++++++++
 tests/system-ovn.at     | 100 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 179 insertions(+)

diff --git a/northd/northd.c b/northd/northd.c
index a6eca916b..6317c36fd 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -10740,6 +10740,8 @@ build_distr_lrouter_nat_flows_for_lb(struct 
lrouter_nat_lb_flows_ctx *ctx,
                                      struct ovn_datapath *od)
 {
     struct ovn_port *dgp = od->l3dgw_ports[0];
+    struct ds gw_redir_match = DS_EMPTY_INITIALIZER;
+    struct ds gw_redir_action = DS_EMPTY_INITIALIZER;
 
     const char *undnat_action;
 
@@ -10784,6 +10786,17 @@ build_distr_lrouter_nat_flows_for_lb(struct 
lrouter_nat_lb_flows_ctx *ctx,
         return;
     }
 
+    /* We need to centralize the LB traffic to properly perform
+     * the undnat stage.
+     */
+    ds_put_format(&gw_redir_match, "%s) && outport == %s",
+                  ds_cstr(ctx->undnat_match), dgp->json_key);
+    ds_put_format(&gw_redir_action, "outport = %s; next;",
+                  dgp->cr_port->json_key);
+    ovn_lflow_add_with_hint(ctx->lflows, od, S_ROUTER_IN_GW_REDIRECT,
+                            200, ds_cstr(&gw_redir_match),
+                            ds_cstr(&gw_redir_action), &ctx->lb->nlb->header_);
+
     ds_put_format(ctx->undnat_match, ") && (inport == %s || outport == %s)"
                   " && is_chassis_resident(%s)", dgp->json_key, dgp->json_key,
                   dgp->cr_port->json_key);
@@ -10791,6 +10804,8 @@ build_distr_lrouter_nat_flows_for_lb(struct 
lrouter_nat_lb_flows_ctx *ctx,
                             ds_cstr(ctx->undnat_match), undnat_action,
                             &ctx->lb->nlb->header_);
     ds_truncate(ctx->undnat_match, undnat_match_len);
+    ds_destroy(&gw_redir_match);
+    ds_destroy(&gw_redir_action);
 }
 
 static void
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 540fe03bd..295f52b11 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -4578,6 +4578,22 @@ icmp6 {
     </p>
 
     <ul>
+      <li>
+        For all the configured load balancing rules that include an IPv4
+        address <var>VIP</var>, and a list of IPv4 backend addresses
+        <var>B0</var>, <var>B1</var> .. <var>Bn</var> defined for the
+        <var>VIP</var> a priority-200 flow is added that matches <code>
+        ip4 &amp;&amp; (ip4.src == <var>B0</var> || ip4.src == <var>B1</var>
+        || ... || ip4.src == <var>Bn</var>)</code> with an action <code>
+        outport = <var>CR</var>; next;</code> where <var>CR</var> is the
+        <code>chassisredirect</code> port representing the instance of the
+        logical router distributed gateway port on the gateway chassis.
+        If the backend IPv4 address <var>Bx</var> is also configured with
+        L4 port <var>PORT</var> of protocol <var>P</var>, then the match
+        also includes <code>P.src</code> == <var>PORT</var>.
+        Similar flows are addeded for IPv6.
+      </li>
+
       <li>
         For each NAT rule in the OVN Northbound database that can
         be handled in a distributed manner, a priority-100 logical
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index e3669bdf5..59f932c5f 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -9484,3 +9484,51 @@ AT_CHECK([ovn-sbctl lflow-list sw | grep ls_out_pre_lb | 
grep priority=110 | gre
 
 AT_CLEANUP
 ])
+
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([check fip and lb flows])
+AT_KEYWORDS([fip-lb-flows])
+ovn_start
+
+ovn-nbctl lr-add R1
+ovn-nbctl lrp-add R1 R1-S0 02:ac:10:01:00:01 10.0.0.1/24 1000::a/64
+ovn-nbctl lrp-add R1 R1-PUB 02:ac:20:01:01:01 172.16.0.1/24 3000::a/64
+ovn-nbctl lrp-set-gateway-chassis R1-PUB hv1 20
+
+ovn-nbctl ls-add S0
+ovn-nbctl lsp-add S0 S0-R1
+ovn-nbctl lsp-set-type S0-R1 router
+ovn-nbctl lsp-set-addresses S0-R1 02:ac:10:01:00:01
+ovn-nbctl lsp-set-options S0-R1 router-port=R1-S0
+ovn-nbctl lsp-add S0 S0-P0
+ovn-nbctl lsp-set-addresses S0-P0 "50:54:00:00:00:03 10.0.0.3 1000::3"
+
+ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.0.110 10.0.0.3 S0-P0 
30:54:00:00:00:03
+ovn-nbctl lr-nat-add R1 dnat_and_snat 3000::c 1000::3 S0-P0 40:54:00:00:00:03
+
+ovn-sbctl dump-flows R1 > R1flows
+AT_CAPTURE_FILE([R1flows])
+AT_CHECK([grep "lr_in_gw_redirect" R1flows | sort], [0], [dnl
+  table=20(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
+  table=20(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && 
outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 
30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
+  table=20(lr_in_gw_redirect  ), priority=100  , match=(ip6.src == 1000::3 && 
outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 
40:54:00:00:00:03; xxreg1 = 3000::c; next;)
+  table=20(lr_in_gw_redirect  ), priority=50   , match=(outport == "R1-PUB"), 
action=(outport = "cr-R1-PUB"; next;)
+])
+
+ovn-nbctl lb-add lb_tcp4 172.16.0.100:50001 
10.0.0.2:50001,10.0.0.3:50001,10.0.0.4:50001 tcp
+ovn-nbctl lb-add lb_tcp6 [[1000::1]]:50001 [[1000::3]]:8080
+ovn-nbctl --wait=sb lr-lb-add R1 lb_tcp4
+ovn-nbctl --wait=sb lr-lb-add R1 lb_tcp6
+ovn-sbctl dump-flows R1 > R1flows
+AT_CAPTURE_FILE([R1flows])
+AT_CHECK([grep "lr_in_gw_redirect" R1flows | sort], [0], [dnl
+  table=20(lr_in_gw_redirect  ), priority=0    , match=(1), action=(next;)
+  table=20(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && 
outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 
30:54:00:00:00:03; reg1 = 172.16.0.110; next;)
+  table=20(lr_in_gw_redirect  ), priority=100  , match=(ip6.src == 1000::3 && 
outport == "R1-PUB" && is_chassis_resident("S0-P0")), action=(eth.src = 
40:54:00:00:00:03; xxreg1 = 3000::c; next;)
+  table=20(lr_in_gw_redirect  ), priority=200  , match=(ip4 && ((ip4.src == 
10.0.0.2 && tcp.src == 50001) || (ip4.src == 10.0.0.3 && tcp.src == 50001) || 
(ip4.src == 10.0.0.4 && tcp.src == 50001)) && outport == "R1-PUB"), 
action=(outport = "cr-R1-PUB"; next;)
+  table=20(lr_in_gw_redirect  ), priority=200  , match=(ip6 && ((ip6.src == 
1000::3 && tcp.src == 8080)) && outport == "R1-PUB"), action=(outport = 
"cr-R1-PUB"; next;)
+  table=20(lr_in_gw_redirect  ), priority=50   , match=(outport == "R1-PUB"), 
action=(outport = "cr-R1-PUB"; next;)
+])
+
+AT_CLEANUP
+])
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index c2490008d..cd9bb7433 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -11546,3 +11546,103 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port 
patch-.*/d
 
 AT_CLEANUP
 ])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([DNAT_SNAT and LB traffic])
+AT_SKIP_IF([test $HAVE_NC = no])
+AT_SKIP_IF([test $HAVE_TCPDUMP = no])
+AT_KEYWORDS([dnat-snat-lb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+# Set external-ids in br-int needed for ovn-controller
+ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . 
external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+ovn-nbctl lr-add R1
+
+ovn-nbctl ls-add foo
+ovn-nbctl ls-add alice
+
+ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24
+ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 172.16.1.1/24 \
+    -- lrp-set-gateway-chassis alice hv1
+
+ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \
+    type=router options:router-port=foo \
+    -- lsp-set-addresses rp-foo router
+
+ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \
+    type=router options:router-port=alice \
+    -- lsp-set-addresses rp-alice router
+
+ADD_NAMESPACES(foo1)
+ADD_VETH(foo1, foo1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
+         "192.168.1.1")
+ovn-nbctl lsp-add foo foo1 \
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
+
+# Logical port 'alice1' in switch 'alice'.
+ADD_NAMESPACES(alice1)
+ADD_VETH(alice1, alice1, br-int, "172.16.1.2/24", "f0:00:00:01:02:05", \
+         "172.16.1.1")
+ovn-nbctl lsp-add alice alice1 \
+-- lsp-set-addresses alice1 "f0:00:00:01:02:05 172.16.1.2"
+
+AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat 172.16.1.3 192.168.1.2 foo1 
00:00:02:02:03:04])
+AT_CHECK([ovn-nbctl lr-nat-add R1 snat 172.16.1.1 192.168.1.0/24])
+
+OVS_START_L7([foo1], [http])
+
+NS_CHECK_EXEC([alice1], [tcpdump -l -c 6 -neei alice1 host 172.16.1.3 and tcp 
> dna_snat.pcap 2>dna_snat_err &])
+OVS_WAIT_UNTIL([grep "listening" dna_snat_err])
+
+ovn-nbctl --wait=hv sync
+
+NS_CHECK_EXEC([alice1], [nc 172.16.1.3 80 -z], [0], [ignore], [ignore])
+
+OVS_WAIT_UNTIL([
+    n_pkt=$(cat dna_snat.pcap | wc -l)
+    test "${n_pkt}" = "6"
+])
+
+ovn-nbctl lb-add lb0 172.16.1.100:80 192.168.1.2:80 tcp
+ovn-nbctl --wait=hv lr-lb-add R1 lb0
+
+NS_CHECK_EXEC([alice1], [tcpdump -l -c 6 -neei alice1 host 172.16.1.100 and 
tcp > lb.pcap 2>lb_err &])
+OVS_WAIT_UNTIL([grep "listening" lb_err])
+
+NS_CHECK_EXEC([alice1], [nc 172.16.1.100 80 -z], [0], [ignore], [ignore])
+
+OVS_WAIT_UNTIL([
+    n_pkt=$(cat lb.pcap | wc -l)
+    test "${n_pkt}" = "6"
+])
+
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+as ovn-sb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as ovn-nb
+OVS_APP_EXIT_AND_WAIT([ovsdb-server])
+
+as northd
+OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
+
+as
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+/connection dropped.*/d"])
+AT_CLEANUP
+])
-- 
2.40.1

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

Reply via email to