Centralized routing was introduced by commit [0] as an opt-in option and
made the default by commit [1].  Both restrict it to routers with exactly
one DGP: a chassisredirect port on the switch side is only created when
the router has a single DGP and the peer logical switch has no localnet
port.

As a result, a router with more than one DGP gets no centralized routing
on any of them.  When such a DGP is attached to a switch that has no
localnet port there is no other path to the gateway chassis, so packets
are dropped in lr_in_admission -- the flow that admits the DGP MAC is
installed on the gateway chassis only.

Drop the single-DGP condition, so that a chassisredirect port is created
for every DGP whose peer switch has no localnet port.  The localnet
condition is kept: when the switch has a localnet port, packets reach the
gateway chassis over the physical network and routing stays distributed.

Restrict the rule that disables NAT distribution for a DGP with
centralized routing to routers with a single DGP.  Without this, creating
the chassisredirect ports would also turn every distributed NAT on such a
router into a centralized one, changing both where the NAT is processed
and which port an advertised NAT route is tracked against.

[0] 
https://github.com/ovn-org/ovn/commit/8d13579bf5b390c1dcf1e737f918e05407f8692c
[1] 
https://github.com/ovn-org/ovn/commit/c71383f858cc80617d50aa8b1fcdb573f3930f4d

Fixes: 8d13579bf5b3 ("Add support for centralize routing for distributed gw 
ports.")

Signed-off-by: Alexandra Rukomoinikova <[email protected]>
---
 northd/en-lr-nat.c  |  3 ++-
 northd/northd.c     |  2 +-
 tests/ovn-northd.at | 38 ++++++++++++++++++++------------------
 3 files changed, 23 insertions(+), 20 deletions(-)

diff --git a/northd/en-lr-nat.c b/northd/en-lr-nat.c
index f0596d254..fcf8d73cb 100644
--- a/northd/en-lr-nat.c
+++ b/northd/en-lr-nat.c
@@ -354,7 +354,8 @@ lr_nat_entry_set_dgw_port(const struct ovn_datapath *od,
      * on the gateway chassis for the DGP's networks/subnets.)
      */
     struct ovn_port *l3dgw_port = nat_entry->l3dgw_port;
-    if (l3dgw_port && l3dgw_port->peer && l3dgw_port->peer->cr_port) {
+    if (l3dgw_port && l3dgw_port->peer && l3dgw_port->peer->cr_port
+        && vector_len(&od->l3dgw_ports) == 1) {
         return true;
     }
 
diff --git a/northd/northd.c b/northd/northd.c
index 88e3ece88..a352a810b 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -1835,7 +1835,7 @@ static bool
 peer_needs_cr_port_creation(struct ovn_port *op)
 {
     if ((op->nbrp->n_gateway_chassis || op->nbrp->ha_chassis_group)
-        && vector_len(&op->od->l3dgw_ports) == 1 && op->peer && op->peer->nbsp
+        && op->peer && op->peer->nbsp
         && !ls_has_localnet_port(op->peer->od)) {
         return true;
     }
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 6d191c1a0..d0fa17d08 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -5949,7 +5949,8 @@ check ovn-nbctl --wait=sb sync
 
 ovn-sbctl lflow-list sw > ls1_lflows
 AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | grep 10.0.10.100 | 
ovn_strip_lflows], [0], [dnl
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 10.0.10.100), 
action=(outport = "sw-ro2"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 10.0.10.100 && 
!is_chassis_resident("cr-sw-ro2")), action=(outport = "cr-sw-ro2"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 10.0.10.100 && 
is_chassis_resident("cr-sw-ro2")), action=(outport = "sw-ro2"; output;)
 ])
 
 OVN_CLEANUP_NORTHD
@@ -9010,9 +9011,9 @@ AT_CAPTURE_FILE([lrflows])
 
 AT_CHECK([grep lr_in_ip_input lrflows | grep arp | grep -e 172.16.1.10 -e 
10.0.0.10 -e 192.168.0.10 -e drop | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_input     ), priority=85   , match=(arp || nd), 
action=(drop;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S1" && 
arp.op == 1 && arp.tpa == 172.16.1.10 && is_chassis_resident("cr-DR-S1")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S2" && 
arp.op == 1 && arp.tpa == 10.0.0.10 && is_chassis_resident("cr-DR-S2")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S3" && 
arp.op == 1 && arp.tpa == 192.168.0.10 && is_chassis_resident("cr-DR-S3")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 10.0.0.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; 
/* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 172.16.1.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 
2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 192.168.0.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 
2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
 ])
 
 AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat | ovn_strip_lflows], [0], 
[dnl
@@ -9053,9 +9054,8 @@ AT_CAPTURE_FILE([lrflows])
 
 AT_CHECK([grep lr_in_ip_input lrflows | grep arp | grep -e 172.16.1.10 -e 
10.0.0.10 -e drop | ovn_strip_lflows], [0], [dnl
   table=??(lr_in_ip_input     ), priority=85   , match=(arp || nd), 
action=(drop;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S1" && 
arp.op == 1 && arp.tpa == 172.16.1.10 && is_chassis_resident("cr-DR-S1")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S2" && 
arp.op == 1 && arp.tpa == 10.0.0.10 && is_chassis_resident("cr-DR-S2")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S3" && 
arp.op == 1 && arp.tpa == 172.16.1.10 && is_chassis_resident("cr-DR-S3")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 10.0.0.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; 
/* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 172.16.1.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 
2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
 ])
 
 AT_CHECK([grep lr_in_dnat lrflows | grep ct_dnat | ovn_strip_lflows], [0], [dnl
@@ -9086,9 +9086,9 @@ ovn-sbctl dump-flows DR > lrflows
 AT_CAPTURE_FILE([lrflows])
 
 AT_CHECK([grep lr_in_ip_input lrflows | grep arp | grep -e 172.16.1.10 -e 
10.0.0.10 -e 192.168.0.10 | ovn_strip_lflows], [0], [dnl
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S1" && 
arp.op == 1 && arp.tpa == 172.16.1.10 && is_chassis_resident("cr-DR-S1")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S2" && 
arp.op == 1 && arp.tpa == 10.0.0.10 && is_chassis_resident("cr-DR-S2")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "DR-S3" && 
arp.op == 1 && arp.tpa == 192.168.0.10 && is_chassis_resident("cr-DR-S3")), 
action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; /* ARP reply 
*/ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = 
inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 10.0.0.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 2; 
/* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 172.16.1.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 
2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 192.168.0.10), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op = 
2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
 ])
 
 AT_CHECK([grep lr_in_unsnat lrflows | grep ct_snat | ovn_strip_lflows], [0], 
[dnl
@@ -15165,12 +15165,12 @@ check ovn-nbctl --wait=sb lsp-del ln-public
 # Check that the lflows are as expected when public has no localnet port.
 check_flows_cr_port_for_public_lr0
 
-# Create multiple gateway ports.  chassisresident port should not be
-# created for 'public-lr0' even if there is no localnet port on 'public'
-# logical switch.
+# Create multiple gateway ports. Check centralized routing is
+# supported with multiple dgp.
 check ovn-nbctl --wait=sb lrp-set-gateway-chassis lr0-sw0 gw1
 # check that there is no port binding cr-public-lr0
-check_row_count Port_Binding 0 logical_port=cr-public-lr0
+check_row_count Port_Binding 1 logical_port=cr-public-lr0
+check_row_count Port_Binding 1 logical_port=cr-sw0-lr0
 
 ovn-sbctl dump-flows lr0 > lr0flows
 ovn-sbctl dump-flows public > publicflows
@@ -15184,8 +15184,8 @@ AT_CHECK([grep -Fe "172.168.0.110" -e "172.168.0.120" 
-e "10.0.0.3" -e "20.0.0.3
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 
172.168.0.110 && inport == "lr0-public"), action=(ct_dnat(10.0.0.3);)
   table=??(lr_in_dnat         ), priority=100  , match=(ip && ip4.dst == 
172.168.0.120 && inport == "lr0-public" && 
is_chassis_resident("cr-lr0-public")), action=(ct_dnat(20.0.0.3);)
   table=??(lr_in_gw_redirect  ), priority=100  , match=(ip4.src == 10.0.0.3 && 
outport == "lr0-public" && is_chassis_resident("sw0-port1")), action=(eth.src = 
30:54:00:00:00:03; reg5 = 172.168.0.110; next;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "lr0-public" 
&& arp.op == 1 && arp.tpa == 172.168.0.110 && 
is_chassis_resident("sw0-port1")), action=(eth.dst = eth.src; eth.src = 
30:54:00:00:00:03; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 
30:54:00:00:00:03; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; 
output;)
-  table=??(lr_in_ip_input     ), priority=92   , match=(inport == "lr0-public" 
&& arp.op == 1 && arp.tpa == 172.168.0.120 && 
is_chassis_resident("cr-lr0-public")), action=(eth.dst = eth.src; eth.src = 
xreg0[[0..47]]; arp.op = 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = 
xreg0[[0..47]]; arp.tpa <-> arp.spa; outport = inport; flags.loopback = 1; 
output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 172.168.0.110), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op 
= 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
+  table=??(lr_in_ip_input     ), priority=90   , match=(arp.op == 1 && arp.tpa 
== 172.168.0.120), action=(eth.dst = eth.src; eth.src = xreg0[[0..47]]; arp.op 
= 2; /* ARP reply */ arp.tha = arp.sha; arp.sha = xreg0[[0..47]]; arp.tpa <-> 
arp.spa; outport = inport; flags.loopback = 1; output;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 
172.168.0.110 && inport == "lr0-public"), action=(ct_snat;)
   table=??(lr_in_unsnat       ), priority=100  , match=(ip && ip4.dst == 
172.168.0.120 && inport == "lr0-public" && 
is_chassis_resident("cr-lr0-public")), action=(ct_snat;)
   table=??(lr_out_egr_loop    ), priority=100  , match=(ip4.dst == 
172.168.0.110 && outport == "lr0-public" && is_chassis_resident("sw0-port1")), 
action=(clone { ct_clear; inport = outport; outport = ""; eth.dst <-> eth.src; 
flags = 0; flags.loopback = 1; reg0 = 0; reg1 = 0; reg2 = 0; reg3 = 0; reg4 = 
0; reg5 = 0; reg6 = 0; reg7 = 0; reg8 = 0; reg9 = 0; reg9[[0]] = 1; 
next(pipeline=ingress, table=??); };)
@@ -15199,8 +15199,10 @@ AT_CHECK([grep -Fe "172.168.0.110" -e "172.168.0.120" 
-e "10.0.0.3" -e "20.0.0.3
 AT_CHECK([grep -Fe "172.168.0.110" -e "172.168.0.120" -e "10.0.0.3" -e 
"20.0.0.3" -e "30:54:00:00:00:03"  -e "sw0-port1" publicflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=50   , match=(eth.dst == 
30:54:00:00:00:03 && is_chassis_resident("sw0-port1")), action=(outport = 
"public-lr0"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:ff:02, 30:54:00:00:00:03} && eth.dst == ff:ff:ff:ff:ff:ff && 
(arp.op == 1 || rarp.op == 3 || nd_ns)), action=(outport = "_MC_flood_l2"; 
output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.110), 
action=(clone {outport = "public-lr0"; output; }; outport = "_MC_unknown"; 
output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.120), 
action=(clone {outport = "public-lr0"; output; }; outport = "_MC_unknown"; 
output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.110 && 
!is_chassis_resident("cr-public-lr0")), action=(clone {outport = 
"cr-public-lr0"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.110 && 
is_chassis_resident("cr-public-lr0")), action=(clone {outport = "public-lr0"; 
output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.120 && 
!is_chassis_resident("cr-public-lr0")), action=(clone {outport = 
"cr-public-lr0"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.120 && 
is_chassis_resident("cr-public-lr0")), action=(clone {outport = "public-lr0"; 
output; }; outport = "_MC_unknown"; output;)
   table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.110 && 
arp.spa == 172.168.0.110), action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
eth.dst == ff:ff:ff:ff:ff:ff && arp.op == 1 && arp.tpa == 172.168.0.120 && 
arp.spa == 172.168.0.120), action=(outport = "_MC_flood_l2"; output;)
 ])
-- 
2.48.1

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

Reply via email to