[ovs-dev] [PATCH ovn v2] northd: Fix the missing force_snat_for_lb flows when router_ip is configured.

numans at ovn.org numans at ovn.org
Fri Mar 5 09:23:47 UTC 2021


From: Numan Siddique <numans at ovn.org>

The commit c6e21a23bd8 which supported the option 'lb_force_snat_ip=router_ip'
on a gateway router, missed out on
  - updating the flows in 'lr_in_dnat' to set 'flags.force_snat_for_lb = 1'.
  - removing the flow to drop if ip.dst == router port IP in 'lr_in_ip_input'
    stage.

This patch fixes these issue and adds a system test to cover the
hairpin load balancer traffic for the gateway routers.

Fixes: c6e21a23bd8("northd: Provide the Gateway router option 'lb_force_snat_ip' to take router port ips.")

CC: Ben Pfaff <blp at ovn.org>
Signed-off-by: Numan Siddique <numans at ovn.org>
---
v1 -> v2
-------
  * Patch 1 of v1 is merged now.
  * Addressed the review comments from Ben in p2 of v1.
      - Added the missing lflow in northd-ddlog
      - Added the missing lflow for IPv6 scenarion which I missed in v1.
      - Changed to '.force_lb_snat = false'.

 northd/lrouter.dl       |  13 +++-
 northd/ovn-northd.8.xml |  10 +++
 northd/ovn-northd.c     |  36 +++++++---
 northd/ovn_northd.dl    |  24 +++++--
 tests/ovn-northd.at     |  54 +++++++++++++++
 tests/system-ovn.at     | 141 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 263 insertions(+), 15 deletions(-)

diff --git a/northd/lrouter.dl b/northd/lrouter.dl
index 8b8005b0c..1a7cb2d23 100644
--- a/northd/lrouter.dl
+++ b/northd/lrouter.dl
@@ -353,6 +353,10 @@ function lb_force_snat_router_ip(lr_options: Map<string, string>): bool {
     lr_options.contains_key("chassis")
 }
 
+function force_snat_for_lb(lr: nb::Logical_Router): bool {
+    not get_force_snat_ip(lr, "lb").is_empty() or lb_force_snat_router_ip(lr.options)
+}
+
 /* For each router, collect the set of IPv4 and IPv6 addresses used for SNAT,
  * which includes:
  *
@@ -434,7 +438,8 @@ relation &Router(
     snat_ips:           Map<v46_ip, Set<NAT>>,
     lbs:                Vec<Ref<nb::Load_Balancer>>,
     mcast_cfg:          Ref<McastRouterCfg>,
-    learn_from_arp_request: bool
+    learn_from_arp_request: bool,
+    force_lb_snat: bool,
 )
 
 &Router(.lr = lr,
@@ -449,7 +454,8 @@ relation &Router(
         .snat_ips   = snat_ips,
         .lbs        = lbs,
         .mcast_cfg  = mcast_cfg,
-        .learn_from_arp_request = learn_from_arp_request) :-
+        .learn_from_arp_request = learn_from_arp_request,
+        .force_lb_snat = force_lb_snat) :-
     lr in nb::Logical_Router(),
     lr.is_enabled(),
     LogicalRouterRedirectPort(lr._uuid, l3dgw_port),
@@ -457,7 +463,8 @@ relation &Router(
     LogicalRouterLBs(lr._uuid, lbs),
     LogicalRouterSnatIPs(lr._uuid, snat_ips),
     mcast_cfg in &McastRouterCfg(.datapath = lr._uuid),
-    var learn_from_arp_request = map_get_bool_def(lr.options, "always_learn_from_arp_request", true).
+    var learn_from_arp_request = map_get_bool_def(lr.options, "always_learn_from_arp_request", true),
+    var force_lb_snat = lb_force_snat_router_ip(lr.options).
 
 /* RouterLB: many-to-many relation between logical routers and nb::LB */
 relation RouterLB(router: Ref<Router>, lb: Ref<nb::Load_Balancer>)
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index a16937a21..c272cc922 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -2611,6 +2611,16 @@ icmp6 {
           with an action <code>ct_snat; </code>.
         </p>
 
+        <p>
+          If the Gateway router is configured with
+          <code>lb_force_snat_ip=router_ip</code> then for every logical router
+          port <var>P</var> attached to the Gateway router with the router ip
+          <var>B</var>, a priority-110 flow is added with the match
+          <code>inport == <var>P</var> && ip4.dst == <var>B</var></code> or
+          <code>inport == <var>P</var> && ip6.dst == <var>B</var></code>
+          with an action <code>ct_snat; </code>.
+        </p>
+
         <p>
           If the Gateway router has been configured to force SNAT any
           previously load-balanced packets to <var>B</var>, a priority-100 flow
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index ac872aade..33b8d70d3 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -8576,7 +8576,7 @@ get_force_snat_ip(struct ovn_datapath *od, const char *key_type,
 static void
 add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
                    struct ds *match, struct ds *actions, int priority,
-                   bool lb_force_snat_ip, struct ovn_lb_vip *lb_vip,
+                   bool force_snat_for_lb, struct ovn_lb_vip *lb_vip,
                    const char *proto, struct nbrec_load_balancer *lb,
                    struct shash *meter_groups, struct sset *nat_entries)
 {
@@ -8585,7 +8585,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
 
     /* A match and actions for new connections. */
     char *new_match = xasprintf("ct.new && %s", ds_cstr(match));
-    if (lb_force_snat_ip) {
+    if (force_snat_for_lb) {
         char *new_actions = xasprintf("flags.force_snat_for_lb = 1; %s",
                                       ds_cstr(actions));
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority,
@@ -8598,7 +8598,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
 
     /* A match and actions for established connections. */
     char *est_match = xasprintf("ct.est && %s", ds_cstr(match));
-    if (lb_force_snat_ip) {
+    if (force_snat_for_lb) {
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority,
                                 est_match,
                                 "flags.force_snat_for_lb = 1; ct_dnat;",
@@ -8675,7 +8675,7 @@ add_router_lb_flow(struct hmap *lflows, struct ovn_datapath *od,
     ds_put_format(&undnat_match, ") && outport == %s && "
                  "is_chassis_resident(%s)", od->l3dgw_port->json_key,
                  od->l3redirect_port->json_key);
-    if (lb_force_snat_ip) {
+    if (force_snat_for_lb) {
         ovn_lflow_add_with_hint(lflows, od, S_ROUTER_OUT_UNDNAT, 120,
                                 ds_cstr(&undnat_match),
                                 "flags.force_snat_for_lb = 1; ct_dnat;",
@@ -9155,6 +9155,13 @@ build_lrouter_force_snat_flows_op(struct ovn_port *op,
         ds_clear(match);
         ds_clear(actions);
 
+        ds_put_format(match, "inport == %s && ip4.dst == %s",
+                      op->json_key, op->lrp_networks.ipv4_addrs[0].addr_s);
+        ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110,
+                      ds_cstr(match), "ct_snat;");
+
+        ds_clear(match);
+
         /* Higher priority rules to force SNAT with the router port ip.
          * This only takes effect when the packet has already been
          * load balanced once. */
@@ -9180,6 +9187,13 @@ build_lrouter_force_snat_flows_op(struct ovn_port *op,
         ds_clear(match);
         ds_clear(actions);
 
+        ds_put_format(match, "inport == %s && ip6.dst == %s",
+                      op->json_key, op->lrp_networks.ipv6_addrs[0].addr_s);
+        ovn_lflow_add(lflows, op->od, S_ROUTER_IN_UNSNAT, 110,
+                      ds_cstr(match), "ct_snat;");
+
+        ds_clear(match);
+
         /* Higher priority rules to force SNAT with the router port ip.
          * This only takes effect when the packet has already been
          * load balanced once. */
@@ -10932,11 +10946,15 @@ build_lrouter_ipv4_ip_input(struct ovn_port *op,
          * also a SNAT IP. Those are dropped later, in stage
          * "lr_in_arp_resolve", if unSNAT was unsuccessful.
          *
+         * If op->pd->lb_force_snat_router_ip is true, it means the IP of the
+         * router port is also SNAT IP.
+         *
          * Priority 60.
          */
-        build_lrouter_drop_own_dest(op, S_ROUTER_IN_IP_INPUT, 60, false,
-                                    lflows);
-
+        if (!op->od->lb_force_snat_router_ip) {
+            build_lrouter_drop_own_dest(op, S_ROUTER_IN_IP_INPUT, 60, false,
+                                        lflows);
+        }
         /* ARP / ND handling for external IP addresses.
          *
          * DNAT and SNAT IP addresses are external IP addresses that need ARP
@@ -11636,8 +11654,10 @@ build_lrouter_nat_defrag_and_lb(struct ovn_datapath *od,
                     ds_put_format(match, " && is_chassis_resident(%s)",
                                   od->l3redirect_port->json_key);
                 }
+                bool force_snat_for_lb =
+                    lb_force_snat_ip || od->lb_force_snat_router_ip;
                 add_router_lb_flow(lflows, od, match, actions, prio,
-                                   lb_force_snat_ip, lb_vip, proto,
+                                   force_snat_for_lb, lb_vip, proto,
                                    nb_lb, meter_groups, &nat_entries);
             }
         }
diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
index 8fc24dfcb..8d0d55682 100644
--- a/northd/ovn_northd.dl
+++ b/northd/ovn_northd.dl
@@ -5142,6 +5142,7 @@ Flow(.logical_datapath = lr_uuid,
      .external_ids = stage_hint(lrp_uuid)) :-
     &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid},
                 .router = &Router{.snat_ips = snat_ips,
+                                  .force_lb_snat = false,
                                   .lr = nb::Logical_Router{._uuid = lr_uuid}},
                 .networks = networks),
     var addr = FlatMap(networks.ipv4_addrs),
@@ -5155,6 +5156,7 @@ Flow(.logical_datapath = lr_uuid,
      .external_ids = stage_hint(lrp_uuid)) :-
     &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid},
                 .router = &Router{.snat_ips = snat_ips,
+                                  .force_lb_snat = false,
                                   .lr = nb::Logical_Router{._uuid = lr_uuid}},
                 .networks = networks),
     var addr = FlatMap(networks.ipv6_addrs),
@@ -5502,6 +5504,13 @@ Flow(.logical_datapath = logical_router,
 for (rp in &RouterPort(.router = &Router{.lr = lr}, .lrp = lrp)) {
     if (lb_force_snat_router_ip(lr.options) and rp.peer != PeerNone) {
         Some{var ipv4} = rp.networks.ipv4_addrs.nth(0) in {
+            Flow(.logical_datapath = lr._uuid,
+                 .stage = router_stage(IN, UNSNAT),
+                 .priority = 110,
+                 .__match = "inport == ${rp.json_name} && ip4.dst == ${ipv4.addr}",
+                 .actions = "ct_snat;",
+                 .external_ids = map_empty());
+
             Flow(.logical_datapath = lr._uuid,
                  .stage = router_stage(OUT, SNAT),
                  .priority = 110,
@@ -5520,6 +5529,13 @@ for (rp in &RouterPort(.router = &Router{.lr = lr}, .lrp = lrp)) {
          * last in the list. So add the flows only if n_ipv6_addrs > 1. */
         if (rp.networks.ipv6_addrs.len() > 1) {
             Some{var ipv6} = rp.networks.ipv6_addrs.nth(0) in {
+                Flow(.logical_datapath = lr._uuid,
+                     .stage = router_stage(IN, UNSNAT),
+                     .priority = 110,
+                     .__match = "inport == ${rp.json_name} && ip6.dst == ${ipv6.addr}",
+                     .actions = "ct_snat;",
+                     .external_ids = map_empty());
+
                 Flow(.logical_datapath = lr._uuid,
                      .stage = router_stage(OUT, SNAT),
                      .priority = 110,
@@ -6035,12 +6051,12 @@ for (RouterLBVIP(
                 (Some{gwport}, true) -> " && is_chassis_resident(${redirect_port_name})",
                 _ -> ""
             } in
-        var has_force_snat_ip = has_force_snat_ip(lr, "lb") in
+        var force_snat_for_lb = force_snat_for_lb(lr) in
         {
             /* A match and actions for established connections. */
             var est_match = "ct.est && " ++ __match in
             var actions =
-                match (has_force_snat_ip) {
+                match (force_snat_for_lb) {
                     true -> "flags.force_snat_for_lb = 1; ct_dnat;",
                     false -> "ct_dnat;"
                 } in
@@ -6101,7 +6117,7 @@ for (RouterLBVIP(
                 ") && outport == ${json_string_escape(gwport.name)} && "
                 "is_chassis_resident(${redirect_port_name})" in
             var action =
-                match (has_force_snat_ip) {
+                match (force_snat_for_lb) {
                     true -> "flags.force_snat_for_lb = 1; ct_dnat;",
                     false -> "ct_dnat;"
                 } in
@@ -6138,7 +6154,7 @@ Flow(.logical_datapath = r.lr._uuid,
               _ -> ""
           },
     var priority = if (lbvip.vip_port != 0) 120 else 110,
-    var force_snat = if (has_force_snat_ip(r.lr, "lb")) "flags.force_snat_for_lb = 1; " else "",
+    var force_snat = if (force_snat_for_lb(r.lr)) "flags.force_snat_for_lb = 1; " else "",
     var actions = build_lb_vip_actions(lbvip, stage_id(router_stage(OUT, SNAT)).0, force_snat).
 
 
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index b9ae63cfa..02f6ede84 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2727,11 +2727,21 @@ check ovn-nbctl lsp-set-type public-lr0 router
 check ovn-nbctl lsp-set-addresses public-lr0 router
 check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public
 
+check ovn-nbctl lb-add lb1 10.0.0.10:80 10.0.0.4:8080
+check ovn-nbctl lr-lb-add lr0 lb1
 check ovn-nbctl set logical_router lr0 options:chassis=ch1
 
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CAPTURE_FILE([lr0flows])
 
+AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+])
+
+AT_CHECK([grep "lr_in_dnat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
+])
+
+
 AT_CHECK([grep "lr_out_snat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
 ])
 
@@ -2740,6 +2750,18 @@ check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="20.0.
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CAPTURE_FILE([lr0flows])
 
+
+AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(ip4 && ip4.dst == 20.0.0.4), action=(ct_snat;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(ip6 && ip6.dst == aef0::4), action=(ct_snat;)
+])
+
+AT_CHECK([grep "lr_in_dnat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
+  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
+  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
+])
+
 AT_CHECK([grep "lr_out_snat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
   table=1 (lr_out_snat        ), priority=100  , match=(flags.force_snat_for_lb == 1 && ip4), action=(ct_snat(20.0.0.4);)
   table=1 (lr_out_snat        ), priority=100  , match=(flags.force_snat_for_lb == 1 && ip6), action=(ct_snat(aef0::4);)
@@ -2750,6 +2772,21 @@ check ovn-nbctl --wait=sb set logical_router lr0 options:lb_force_snat_ip="route
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CAPTURE_FILE([lr0flows])
 
+AT_CHECK([grep "lr_in_ip_input" lr0flows | grep "priority=60" | sort], [0], [dnl
+])
+
+AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
+])
+
+AT_CHECK([grep "lr_in_dnat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
+  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
+  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
+])
+
 AT_CHECK([grep "lr_out_snat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
   table=1 (lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.100);)
   table=1 (lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
@@ -2761,6 +2798,10 @@ check ovn-nbctl --wait=sb remove logical_router lr0 options chassis
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CAPTURE_FILE([lr0flows])
 
+AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+])
+
 AT_CHECK([grep "lr_out_snat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
 ])
 
@@ -2770,6 +2811,19 @@ check ovn-nbctl --wait=sb add logical_router_port lr0-sw1 networks "bef0\:\:1/64
 ovn-sbctl dump-flows lr0 > lr0flows
 AT_CAPTURE_FILE([lr0flows])
 
+AT_CHECK([grep "lr_in_unsnat" lr0flows | sort], [0], [dnl
+  table=5 (lr_in_unsnat       ), priority=0    , match=(1), action=(next;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-public" && ip4.dst == 172.168.0.100), action=(ct_snat;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw0" && ip4.dst == 10.0.0.1), action=(ct_snat;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip4.dst == 20.0.0.1), action=(ct_snat;)
+  table=5 (lr_in_unsnat       ), priority=110  , match=(inport == "lr0-sw1" && ip6.dst == bef0::1), action=(ct_snat;)
+])
+
+AT_CHECK([grep "lr_in_dnat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
+  table=6 (lr_in_dnat         ), priority=120  , match=(ct.est && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_dnat;)
+  table=6 (lr_in_dnat         ), priority=120  , match=(ct.new && ip && ip4.dst == 10.0.0.10 && tcp && tcp.dst == 80), action=(flags.force_snat_for_lb = 1; ct_lb(backends=10.0.0.4:8080);)
+])
+
 AT_CHECK([grep "lr_out_snat" lr0flows | grep force_snat_for_lb | sort], [0], [dnl
   table=1 (lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-public"), action=(ct_snat(172.168.0.100);)
   table=1 (lr_out_snat        ), priority=110  , match=(flags.force_snat_for_lb == 1 && ip4 && outport == "lr0-sw0"), action=(ct_snat(10.0.0.1);)
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index f466dcc09..4885303d1 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -2246,6 +2246,146 @@ tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=
 
 OVS_WAIT_UNTIL([check_est_flows], [check established flows])
 
+ovn-nbctl set logical_router R2 options:lb_force_snat_ip=router_ip
+
+# Destroy the load balancer and create again. ovn-controller will
+# clear the OF flows and re add again and clears the n_packets
+# for these flows.
+ovn-nbctl destroy load_balancer $uuid
+uuid=`ovn-nbctl  create load_balancer vips:30.0.0.1="192.168.1.2,192.168.2.2"`
+ovn-nbctl set logical_router R2 load_balancer=$uuid
+
+# Config OVN load-balancer with another VIP (this time with ports).
+ovn-nbctl set load_balancer $uuid vips:'"30.0.0.2:8000"'='"192.168.1.2:80,192.168.2.2:80"'
+
+ovn-nbctl list load_balancer
+ovn-sbctl dump-flows R2
+OVS_WAIT_UNTIL([ovs-ofctl -O OpenFlow13 dump-flows br-int table=41 | \
+grep 'nat(src=20.0.0.2)'])
+
+rm -f wget*.log
+
+dnl Test load-balancing that includes L4 ports in NAT.
+for i in `seq 1 20`; do
+    echo Request $i
+    NS_CHECK_EXEC([alice1], [wget 30.0.0.2:8000 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+dnl Each server should have at least one connection.
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.2) |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,labels=0x2,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.2,dst=30.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=172.16.1.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,labels=0x2,protoinfo=(state=<cleared>)
+])
+
+AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(20.0.0.2) |
+sed -e 's/zone=[[0-9]]*/zone=<cleared>/'], [0], [dnl
+tcp,orig=(src=172.16.1.2,dst=192.168.1.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.1.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+tcp,orig=(src=172.16.1.2,dst=192.168.2.2,sport=<cleared>,dport=<cleared>),reply=(src=192.168.2.2,dst=20.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,protoinfo=(state=<cleared>)
+])
+
+OVS_WAIT_UNTIL([check_est_flows], [check established flows])
+
+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
+])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn -- load balancing in gateway router hairpin scenario])
+AT_KEYWORDS([ovnlb])
+
+CHECK_CONNTRACK()
+CHECK_CONNTRACK_NAT()
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+check ovs-vsctl add-br br-ext
+
+
+# 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
+
+check ovn-nbctl lr-add R1
+
+check ovn-nbctl ls-add sw0
+check ovn-nbctl ls-add public
+
+check ovn-nbctl lrp-add R1 rp-sw0 00:00:01:01:02:03 192.168.1.1/24
+check ovn-nbctl lrp-add R1 rp-public 00:00:02:01:02:03 172.16.1.1/24
+
+check ovn-nbctl set logical_router R1 options:chassis=hv1
+
+check ovn-nbctl lsp-add sw0 sw0-rp -- set Logical_Switch_Port sw0-rp \
+    type=router options:router-port=rp-sw0 \
+    -- lsp-set-addresses sw0-rp router
+
+check ovn-nbctl lsp-add public public-rp -- set Logical_Switch_Port public-rp \
+    type=router options:router-port=rp-public \
+    -- lsp-set-addresses public-rp router
+
+check ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext
+
+check ovn-nbctl lsp-add public public1 \
+        -- lsp-set-addresses public1 unknown \
+        -- lsp-set-type public1 localnet \
+        -- lsp-set-options public1 network_name=phynet
+
+ADD_NAMESPACES(server)
+ADD_VETH(s1, server, br-ext, "172.16.1.100/24", "1a:00:00:00:00:01", \
+         "172.16.1.1")
+
+OVS_WAIT_UNTIL([test "$(ip netns exec server ip a | grep fe80 | grep tentative)" = ""])
+
+ADD_NAMESPACES(client)
+ADD_VETH(c1, client, br-ext, "172.16.1.110/24", "1a:00:00:00:00:02", \
+         "172.16.1.1")
+
+OVS_WAIT_UNTIL([test "$(ip netns exec client ip a | grep fe80 | grep tentative)" = ""])
+
+# Start webservers in 'server'.
+OVS_START_L7([server], [http])
+
+# Create a load balancer and associate to R1
+check ovn-nbctl lb-add lb1 172.16.1.150:80 172.16.1.100:80
+check ovn-nbctl lr-lb-add R1 lb1
+
+check ovn-nbctl --wait=hv sync
+
+for i in $(seq 1 5); do
+    echo Request $i
+    NS_CHECK_EXEC([client], [wget 172.16.1.100 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
+# Now send the traffic from client to the VIP - 172.16.1.150
+check ovn-nbctl set logical_router R1 options:lb_force_snat_ip=router_ip
+check ovn-nbctl --wait=hv sync
+
+for i in $(seq 1 5); do
+    echo Request $i
+    NS_CHECK_EXEC([client], [wget 172.16.1.150 -t 5 -T 1 --retry-connrefused -v -o wget$i.log])
+done
+
 OVS_APP_EXIT_AND_WAIT([ovn-controller])
 
 as ovn-sb
@@ -2259,6 +2399,7 @@ OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
 
 as
 OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+/Failed to acquire.*/d
 /connection dropped.*/d"])
 AT_CLEANUP
 ])
-- 
2.29.2



More information about the dev mailing list