The flows in ls_in_l2_lkup, generated by
build_lswitch_rport_arp_req_flow(), matched ARP requests and
ND_NS for router-owned IPs without restricting eth.dst to
broadcast/multicast.  This caused unicast ARP requests
(eth.dst == router_MAC) to be intercepted and flooded into the
L2 domain.

On switches with 200+ ports this flooding can exceed the OVS
4096 resubmit limit, dropping the packet.

Fix arp_nd_ns_match() to add "eth.dst == ff:ff:ff:ff:ff:ff"
for IPv4 ARP and "eth.mcast" for IPv6 ND_NS.  This follows
the precedent set by commit c05c565548 which added the same
eth.dst restriction to the priority 75 self-originated ARP
flood flow in the same pipeline stage.

After this fix, unicast ARP and ND requests for router-owned
IPs fall through to the L2_LKUP stage flows for direct L2
delivery.

Reported-at: https://issues.redhat.com/browse/FDP-3885
Assisted-by: Claude Opus 4.6, Claude Code
Signed-off-by: Dumitru Ceara <[email protected]>
---
NOTE: this depends on 1872d61e34aa ("northd: Use MC_UNKNOWN for
broadcast ARP requests.") which is only present on the main branch.
For backporting this fix to 26.03 we'd have to backport its dependency
too.
---
 northd/northd.c     |   7 +-
 tests/ovn-northd.at | 265 ++++++++++++++++++++++++--------------------
 tests/ovn.at        | 206 ++++++++++++++++++++++++++++++++++
 3 files changed, 358 insertions(+), 120 deletions(-)

diff --git a/northd/northd.c b/northd/northd.c
index 70033bda0c..cd613f690e 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -9571,9 +9571,12 @@ arp_nd_ns_match(const char *ips, int addr_family, struct 
ds *match)
     ds_put_cstr(match, FLAGBIT_NOT_VXLAN " && ");
 
     if (addr_family == AF_INET) {
-        ds_put_format(match, "arp.op == 1 && arp.tpa == %s", ips);
+        ds_put_format(match,
+                      "eth.dst == ff:ff:ff:ff:ff:ff && "
+                      "arp.op == 1 && arp.tpa == %s", ips);
     } else {
-        ds_put_format(match, "nd_ns && nd.target == %s", ips);
+        ds_put_format(match,
+                      "eth.mcast && nd_ns && nd.target == %s", ips);
     }
 }
 
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 0c98eb7fb5..0c3d5ecfd8 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -5964,9 +5964,9 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:01:01} && 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 && 
arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = 
"ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1 && arp.spa == 192.168.1.1), 
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 == 192.168.1.1), 
action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone 
{outport = "ls1-ro1"; 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 == 192.168.1.1 && 
arp.spa == 192.168.1.1), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 ovn-sbctl lflow-list ls2 > ls2_lflows
@@ -5981,9 +5981,9 @@ AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:02:01} && 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 && 
arp.op == 1 && arp.tpa == 192.168.2.1), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone {outport = 
"ls2-ro2"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.2.1 && arp.spa == 192.168.2.1), 
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 == 192.168.2.1), 
action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone 
{outport = "ls2-ro2"; 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 == 192.168.2.1 && 
arp.spa == 192.168.2.1), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 AS_BOX([Adding some reachable NAT addresses])
@@ -6006,13 +6006,13 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:01:01} && 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 && 
arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = 
"ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.100 && arp.spa == 10.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200 && arp.spa == 10.0.0.200), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1 && arp.spa == 192.168.1.1), 
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 == 10.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 10.0.0.200), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.1), 
action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone 
{outport = "ls1-ro1"; 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 == 10.0.0.100 && arp.spa 
== 10.0.0.100), 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 == 10.0.0.200 && arp.spa 
== 10.0.0.200), 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 == 192.168.1.1 && 
arp.spa == 192.168.1.1), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 ovn-sbctl lflow-list ls2 > ls2_lflows
@@ -6027,13 +6027,13 @@ AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:02:01} && 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 && 
arp.op == 1 && arp.tpa == 192.168.2.1), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.100), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.200), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone {outport = 
"ls2-ro2"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.2.1 && arp.spa == 192.168.2.1), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.100 && arp.spa == 20.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.200 && arp.spa == 20.0.0.200), 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 == 192.168.2.1), 
action=(clone {outport = "ls2-ro2"; 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 == 20.0.0.100), 
action=(clone {outport = "ls2-ro2"; 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 == 20.0.0.200), 
action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone 
{outport = "ls2-ro2"; 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 == 192.168.2.1 && 
arp.spa == 192.168.2.1), 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 == 20.0.0.100 && arp.spa 
== 20.0.0.100), 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 == 20.0.0.200 && arp.spa 
== 20.0.0.200), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 AS_BOX([Adding some unreachable NAT addresses])
@@ -6056,17 +6056,17 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:01:01} && 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 && 
arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = 
"ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.100 && arp.spa == 10.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200 && arp.spa == 10.0.0.200), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1 && arp.spa == 192.168.1.1), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100 && arp.spa == 30.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200 && arp.spa == 30.0.0.200), 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 == 10.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 10.0.0.200), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.1), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.200), 
action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone 
{outport = "ls1-ro1"; 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 == 10.0.0.100 && arp.spa 
== 10.0.0.100), 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 == 10.0.0.200 && arp.spa 
== 10.0.0.200), 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 == 192.168.1.1 && 
arp.spa == 192.168.1.1), 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 == 30.0.0.100 && arp.spa 
== 30.0.0.100), 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 == 30.0.0.200 && arp.spa 
== 30.0.0.200), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 ovn-sbctl lflow-list ls2 > ls2_lflows
@@ -6081,17 +6081,17 @@ AT_CHECK([grep "ls_in_l2_lkup" ls2_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:02:01} && 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 && 
arp.op == 1 && arp.tpa == 192.168.2.1), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.100), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.200), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 40.0.0.100), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 40.0.0.200), action=(clone {outport = "ls2-ro2"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone {outport = 
"ls2-ro2"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.2.1 && arp.spa == 192.168.2.1), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.100 && arp.spa == 20.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 20.0.0.200 && arp.spa == 20.0.0.200), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 40.0.0.100 && arp.spa == 40.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 40.0.0.200 && arp.spa == 40.0.0.200), 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 == 192.168.2.1), 
action=(clone {outport = "ls2-ro2"; 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 == 20.0.0.100), 
action=(clone {outport = "ls2-ro2"; 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 == 20.0.0.200), 
action=(clone {outport = "ls2-ro2"; 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 == 40.0.0.100), 
action=(clone {outport = "ls2-ro2"; 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 == 40.0.0.200), 
action=(clone {outport = "ls2-ro2"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:201), action=(clone 
{outport = "ls2-ro2"; 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 == 192.168.2.1 && 
arp.spa == 192.168.2.1), 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 == 20.0.0.100 && arp.spa 
== 20.0.0.100), 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 == 20.0.0.200 && arp.spa 
== 20.0.0.200), 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 == 40.0.0.100 && arp.spa 
== 40.0.0.100), 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 == 40.0.0.200 && arp.spa 
== 40.0.0.200), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 AS_BOX([Adding load balancer reachable VIPs to ro1])
@@ -6111,19 +6111,19 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:01:01} && 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 && 
arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = 
"ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.100 && arp.spa == 10.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200 && arp.spa == 10.0.0.200), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1 && arp.spa == 192.168.1.1), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.100 && arp.spa == 192.168.1.100), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100 && arp.spa == 30.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200 && arp.spa == 30.0.0.200), 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 == 10.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 10.0.0.200), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.1), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.100), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.200), 
action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone 
{outport = "ls1-ro1"; 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 == 10.0.0.100 && arp.spa 
== 10.0.0.100), 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 == 10.0.0.200 && arp.spa 
== 10.0.0.200), 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 == 192.168.1.1 && 
arp.spa == 192.168.1.1), 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 == 192.168.1.100 && 
arp.spa == 192.168.1.100), 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 == 30.0.0.100 && arp.spa 
== 30.0.0.100), 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 == 30.0.0.200 && arp.spa 
== 30.0.0.200), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 AS_BOX([Adding load balancer unreachable VIPs to ro1])
@@ -6141,19 +6141,19 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:01:01} && 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 && 
arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = 
"ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.100 && arp.spa == 10.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200 && arp.spa == 10.0.0.200), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1 && arp.spa == 192.168.1.1), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.100 && arp.spa == 192.168.1.100), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100 && arp.spa == 30.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200 && arp.spa == 30.0.0.200), 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 == 10.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 10.0.0.200), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.1), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.100), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.200), 
action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone 
{outport = "ls1-ro1"; 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 == 10.0.0.100 && arp.spa 
== 10.0.0.100), 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 == 10.0.0.200 && arp.spa 
== 10.0.0.200), 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 == 192.168.1.1 && 
arp.spa == 192.168.1.1), 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 == 192.168.1.100 && 
arp.spa == 192.168.1.100), 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 == 30.0.0.100 && arp.spa 
== 30.0.0.100), 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 == 30.0.0.200 && arp.spa 
== 30.0.0.200), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 # Make sure that there is no flow for VIP 192.168.4.100 as ro1-ls1 doesn't
@@ -6178,19 +6178,19 @@ AT_CHECK([grep "ls_in_l2_lkup" ls1_lflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; output;)
   table=??(ls_in_l2_lkup      ), priority=75   , match=(eth.src == 
{00:00:00:00:01:01} && 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 && 
arp.op == 1 && arp.tpa == 10.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200), action=(clone {outport = "ls1-ro1"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone {outport = 
"ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.100 && arp.spa == 10.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 10.0.0.200 && arp.spa == 10.0.0.200), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.1 && arp.spa == 192.168.1.1), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 192.168.1.100 && arp.spa == 192.168.1.100), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.100 && arp.spa == 30.0.0.100), action=(outport 
= "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 30.0.0.200 && arp.spa == 30.0.0.200), 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 == 10.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 10.0.0.200), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.1), 
action=(clone {outport = "ls1-ro1"; 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 == 192.168.1.100), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.100), 
action=(clone {outport = "ls1-ro1"; 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 == 30.0.0.200), 
action=(clone {outport = "ls1-ro1"; output; }; outport = "_MC_unknown"; output;)
+  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:101), action=(clone 
{outport = "ls1-ro1"; 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 == 10.0.0.100 && arp.spa 
== 10.0.0.100), 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 == 10.0.0.200 && arp.spa 
== 10.0.0.200), 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 == 192.168.1.1 && 
arp.spa == 192.168.1.1), 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 == 192.168.1.100 && 
arp.spa == 192.168.1.100), 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 == 30.0.0.100 && arp.spa 
== 30.0.0.100), 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 == 30.0.0.200 && arp.spa 
== 30.0.0.200), action=(outport = "_MC_flood_l2"; output;)
 ])
 
 
@@ -14631,15 +14631,15 @@ AT_CHECK([grep "ls_in_l2_lkup" publicflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; 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 && 
arp.op == 1 && arp.tpa == 172.168.0.10), action=(clone {outport = "public-lr0"; 
output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 172.168.0.100), action=(clone {outport = 
"public-lr0"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=80   , match=(flags[[1]] == 0 && 
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 && 
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 && 
nd_ns && nd.target == fe80::200:ff:fe00:ff02), action=(clone {outport = 
"public-lr0"; output; }; outport = "_MC_unknown"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 172.168.0.10 && arp.spa == 172.168.0.10), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 172.168.0.100 && arp.spa == 172.168.0.100), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
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 && 
arp.op == 1 && arp.tpa == 172.168.0.120 && arp.spa == 172.168.0.120), 
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.10), 
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.100), 
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), 
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.mcast && nd_ns && nd.target == fe80::200:ff:fe00:ff02), 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.10 && 
arp.spa == 172.168.0.10), 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.100 && 
arp.spa == 172.168.0.100), 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.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;)
 ])
 
 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" lr0flows | ovn_strip_lflows], 
[0], [dnl
@@ -14666,10 +14666,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 && 
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 && 
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=90   , match=(flags[[1]] == 0 && 
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 && 
arp.op == 1 && arp.tpa == 172.168.0.120 && arp.spa == 172.168.0.120), 
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=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;)
 ])
 }
 
@@ -14813,20 +14813,20 @@ AT_CHECK([grep "ls_in_l2_lkup" publicflows | 
ovn_strip_lflows], [0], [dnl
   table=??(ls_in_l2_lkup      ), priority=71   , match=(eth.mcast && ip), 
action=(outport = "_MC_flood_l2"; output;)
   table=??(ls_in_l2_lkup      ), priority=72   , match=(eth.mcast && (nd_na || 
nd_rs || nd_ra)), action=(outport = "_MC_flood"; 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 && 
arp.op == 1 && arp.tpa == 172.168.0.10 && 
!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 && 
arp.op == 1 && arp.tpa == 172.168.0.10 && 
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 && 
arp.op == 1 && arp.tpa == 172.168.0.100 && 
!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 && 
arp.op == 1 && arp.tpa == 172.168.0.100 && 
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 && 
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 && 
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 && 
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 && 
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=80   , match=(flags[[1]] == 0 && 
nd_ns && nd.target == fe80::200:ff:fe00:ff02 && 
!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 && 
nd_ns && nd.target == fe80::200:ff:fe00:ff02 && 
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 && 
arp.op == 1 && arp.tpa == 172.168.0.10 && arp.spa == 172.168.0.10), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
arp.op == 1 && arp.tpa == 172.168.0.100 && arp.spa == 172.168.0.100), 
action=(outport = "_MC_flood_l2"; output;)
-  table=??(ls_in_l2_lkup      ), priority=90   , match=(flags[[1]] == 0 && 
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 && 
arp.op == 1 && arp.tpa == 172.168.0.120 && arp.spa == 172.168.0.120), 
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.10 && 
!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.10 && 
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.100 && 
!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.100 && 
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.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=80   , match=(flags[[1]] == 0 && 
eth.mcast && nd_ns && nd.target == fe80::200:ff:fe00:ff02 && 
!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.mcast && nd_ns && nd.target == fe80::200:ff:fe00:ff02 && 
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.10 && 
arp.spa == 172.168.0.10), 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.100 && 
arp.spa == 172.168.0.100), 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.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;)
 ])
 
 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" lr0flows | ovn_strip_lflows], 
[0], [dnl
@@ -14851,12 +14851,12 @@ 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 && 
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 && 
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 && 
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 && 
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 && 
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 && 
arp.op == 1 && arp.tpa == 172.168.0.120 && arp.spa == 172.168.0.120), 
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 && 
!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;)
 ])
 }
 
@@ -14916,10 +14916,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 && 
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 && 
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=90   , match=(flags[[1]] == 0 && 
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 && 
arp.op == 1 && arp.tpa == 172.168.0.120 && arp.spa == 172.168.0.120), 
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=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;)
 ])
 
 OVN_CLEANUP_NORTHD
@@ -20316,6 +20316,35 @@ OVN_CLEANUP_NORTHD
 AT_CLEANUP
 ])
 
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([ovn-northd - broadcast restriction on rport ARP/ND req flows in 
l2_lkup])
+AT_KEYWORDS([ovn])
+ovn_start
+
+check ovn-nbctl lr-add lr0
+check ovn-nbctl lrp-add lr0 lr0-ls0 00:00:00:00:00:01 10.0.0.1/24 aef0::1/64
+
+check ovn-nbctl ls-add ls0
+check ovn-nbctl lsp-add-router-port ls0 ls0-lr0 lr0-ls0
+
+check ovn-nbctl lsp-add ls0 lsp1 \
+    -- lsp-set-addresses lsp1 "00:00:00:00:00:02 10.0.0.2 aef0::2"
+
+check ovn-nbctl --wait=sb sync
+
+dnl Priority 80 IPv4 ARP request flow must restrict to broadcast.
+AT_CHECK([ovn-sbctl dump-flows ls0 | grep ls_in_l2_lkup | grep "priority=80" | 
grep "arp.tpa == 10.0.0.1" | grep -q "eth.dst == ff:ff:ff:ff:ff:ff"])
+
+dnl Priority 90 GARP flow must also restrict to broadcast.
+AT_CHECK([ovn-sbctl dump-flows ls0 | grep ls_in_l2_lkup | grep "priority=90" | 
grep "arp.spa == 10.0.0.1" | grep -q "eth.dst == ff:ff:ff:ff:ff:ff"])
+
+dnl Priority 80 IPv6 ND_NS flow must restrict to multicast.
+AT_CHECK([ovn-sbctl dump-flows ls0 | grep ls_in_l2_lkup | grep "priority=80" | 
grep "nd.target == aef0::1" | grep -q "eth.mcast"])
+
+OVN_CLEANUP_NORTHD
+AT_CLEANUP
+])
+
 OVN_FOR_EACH_NORTHD_NO_HV([
 AT_SETUP([LS EVPN Advertised_MAC_Binding sync])
 ovn_start
diff --git a/tests/ovn.at b/tests/ovn.at
index 5dda500449..79cbc9d244 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -44959,6 +44959,212 @@ OVN_CLEANUP([hv1])
 AT_CLEANUP
 ])
 
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([Unicast ARP for router port not flooded to multicast group])
+ovn_start
+
+check ovn-nbctl ls-add ls1
+check ovn-nbctl lr-add lr1
+check ovn-nbctl lrp-add lr1 lr1-ls1 00:00:00:00:00:01 10.0.0.1/16
+check ovn-nbctl lsp-add-router-port ls1 ls1-lr1 lr1-ls1
+
+dnl Create 220 VIF ports in batch to make sure we don't trigger the 4096
+dnl resubmit limit due to incorrect forwarding to multicast flood groups.
+nbctl_cmd=""
+for i in $(seq 1 220); do
+    idx=$(printf "%04d" $i)
+    hex_hi=$(printf "%02x" $(($i / 256)))
+    hex_lo=$(printf "%02x" $(($i % 256)))
+    mac="f0:00:00:00:${hex_hi}:${hex_lo}"
+    nbctl_cmd="$nbctl_cmd -- lsp-add ls1 vif-$idx"
+    nbctl_cmd="$nbctl_cmd -- lsp-set-addresses vif-$idx \"$mac\""
+done
+eval check ovn-nbctl $nbctl_cmd
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+vsctl_cmd=""
+for i in $(seq 1 220); do
+    idx=$(printf "%04d" $i)
+    vsctl_cmd="$vsctl_cmd -- add-port br-int vif-$idx "
+    vsctl_cmd="$vsctl_cmd -- set Interface vif-$idx 
external-ids:iface-id=vif-$idx"
+done
+eval check ovs-vsctl $vsctl_cmd
+
+OVN_POPULATE_ARP
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+dnl Check that unicast GARP requests incorrectly spoofing the router port IP
+dnl don't cause the 4096 resubmit limit to be hit.
+ofport=$(as hv1 ovs-vsctl get Interface vif-0001 ofport)
+AT_CHECK([as hv1 ovs-appctl ofproto/trace br-int \
+    "in_port=$ofport,dl_src=f0:00:00:00:00:01,dl_dst=00:00:00:00:00:01,\
+     arp,arp_op=1,arp_spa=10.0.0.1,arp_tpa=10.0.0.1,\
+     arp_sha=f0:00:00:00:00:01,arp_tha=00:00:00:00:00:01"], [0], [stdout])
+AT_CHECK([grep "Translation failed" stdout], [1])
+AT_CHECK([grep "packet is dropped" stdout], [1])
+
+dnl Also check valid unicast ARP requests for the router port don't cause
+dnl the 4096 resubmit limit to be hit.
+AT_CHECK([as hv1 ovs-appctl ofproto/trace br-int \
+    "in_port=$ofport,dl_src=f0:00:00:00:00:01,dl_dst=00:00:00:00:00:01,\
+     arp,arp_op=1,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,\
+     arp_sha=f0:00:00:00:00:01,arp_tha=00:00:00:00:00:01"], [0], [stdout])
+AT_CHECK([grep "Translation failed" stdout], [1])
+AT_CHECK([grep "packet is dropped" stdout], [1])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([Unicast ARP for router IP with proxy ARP - resubmit overflow])
+ovn_start
+
+dnl Create a logical switch and router, connected via a router port.
+check ovn-nbctl ls-add ls1
+check ovn-nbctl lr-add lr1
+check ovn-nbctl lrp-add lr1 lr1-ls1 00:00:00:00:00:01 10.0.0.1/24
+check ovn-nbctl lsp-add-router-port ls1 ls1-lr1 lr1-ls1
+
+dnl Configure proxy ARP on the router port with a range that includes the
+dnl router IP (10.0.0.1 is within 10.0.0.0/24).
+check ovn-nbctl set logical_switch_port ls1-lr1 \
+    options:arp_proxy="10.0.0.0/24"
+
+dnl Add a VIF port that will send the unicast ARP.
+check ovn-nbctl lsp-add ls1 vm1 -- \
+      lsp-set-addresses vm1 "00:00:00:00:00:02 10.0.0.2"
+
+dnl Add 220 additional VIF ports to make MC_FLOOD_L2 large enough
+dnl that flooding to it would exceed the OVS 4096 resubmit limit.
+nbctl_cmd=""
+for i in $(seq 1 220); do
+    idx=$(printf "%04d" $i)
+    hex_hi=$(printf "%02x" $(($i / 256)))
+    hex_lo=$(printf "%02x" $(($i % 256)))
+    mac="f0:00:00:00:${hex_hi}:${hex_lo}"
+    nbctl_cmd="$nbctl_cmd -- lsp-add ls1 vif-$idx"
+    nbctl_cmd="$nbctl_cmd -- lsp-set-addresses vif-$idx \"$mac\""
+done
+eval check ovn-nbctl $nbctl_cmd
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+dnl Bind the sender VIF port.
+ovs-vsctl add-port br-int vif-vm1 -- \
+    set Interface vif-vm1 external-ids:iface-id=vm1 \
+    options:tx_pcap=hv1/vif-vm1-tx.pcap \
+    options:rxq_pcap=hv1/vif-vm1-rx.pcap
+
+dnl Bind all 220 additional VIF ports so they join MC_FLOOD_L2.
+vsctl_cmd=""
+for i in $(seq 1 220); do
+    idx=$(printf "%04d" $i)
+    vsctl_cmd="$vsctl_cmd -- add-port br-int vif-$idx"
+    vsctl_cmd="$vsctl_cmd -- set Interface vif-$idx 
external-ids:iface-id=vif-$idx"
+done
+eval check ovs-vsctl $vsctl_cmd
+
+OVN_POPULATE_ARP
+
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+dnl Trace a unicast ARP request from vm1 for the router IP,
+dnl eth.dst is the router MAC (unicast).
+dnl
+dnl The router port should answer with an ARP reply, since
+dnl the packet is unicast.  The proxy ARP is bypassed.
+dnl
+dnl Verify via ofproto/trace that the packet is not dropped.
+packet=""
+AT_CHECK([as hv1 ovs-appctl ofproto/trace br-int \
+            
"in_port=vif-vm1,dl_src=00:00:00:00:00:02,dl_dst=00:00:00:00:00:01, \
+            arp,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=1, \
+            arp_sha=00:00:00:00:00:02,arp_tha=00:00:00:00:00:01"], [0], 
[stdout])
+AT_CHECK([grep "Translation failed" stdout], [1])
+AT_CHECK([grep "packet is dropped" stdout], [1])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([Unicast ND_NS for router IPv6 with proxy ARP - resubmit overflow])
+ovn_start
+
+check ovn-nbctl ls-add ls1
+check ovn-nbctl lr-add lr1
+check ovn-nbctl lrp-add lr1 lr1-ls1 00:00:00:00:00:01 10.0.0.1/24 aef0::1/64
+check ovn-nbctl lsp-add-router-port ls1 ls1-lr1 lr1-ls1
+
+dnl Configure proxy ARP/ND on the router port with ranges that include
+dnl the router IPs (10.0.0.1 is within 10.0.0.0/24, aef0::1 is within
+dnl aef0::/64).
+check ovn-nbctl set logical_switch_port ls1-lr1 \
+    options:arp_proxy="10.0.0.0/24 aef0::/64"
+
+check ovn-nbctl lsp-add ls1 vm1 -- \
+      lsp-set-addresses vm1 "00:00:00:00:00:02 10.0.0.2 aef0::2"
+
+dnl Add 220 additional VIF ports to make MC_FLOOD_L2/MC_UNKNOWN large enough
+dnl that flooding to it would exceed the OVS 4096 resubmit limit.
+nbctl_cmd=""
+for i in $(seq 1 220); do
+    idx=$(printf "%04d" $i)
+    nbctl_cmd="$nbctl_cmd -- lsp-add ls1 vif-$idx"
+    nbctl_cmd="$nbctl_cmd -- lsp-set-addresses vif-$idx unknown"
+done
+eval check ovn-nbctl $nbctl_cmd
+
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+ovs-vsctl add-port br-int vif-vm1 -- \
+    set Interface vif-vm1 external-ids:iface-id=vm1 \
+    options:tx_pcap=hv1/vif-vm1-tx.pcap \
+    options:rxq_pcap=hv1/vif-vm1-rx.pcap
+
+vsctl_cmd=""
+for i in $(seq 1 220); do
+    idx=$(printf "%04d" $i)
+    vsctl_cmd="$vsctl_cmd -- add-port br-int vif-$idx"
+    vsctl_cmd="$vsctl_cmd -- set Interface vif-$idx 
external-ids:iface-id=vif-$idx"
+done
+eval check ovs-vsctl $vsctl_cmd
+
+OVN_POPULATE_ARP
+
+wait_for_ports_up
+check ovn-nbctl --wait=hv sync
+
+dnl Trace a unicast ND_NS from vm1 for the router IPv6 address.
+dnl eth.dst is the router MAC (unicast, NOT solicited-node multicast).
+AT_CHECK([as hv1 ovs-appctl ofproto/trace br-int \
+    "in_port=vif-vm1,dl_src=00:00:00:00:00:02,dl_dst=00:00:00:00:00:01, \
+    icmp6,ipv6_src=aef0::2,ipv6_dst=aef0::1,nw_ttl=255, \
+    icmpv6_type=135,icmpv6_code=0, \
+    nd_target=aef0::1,nd_sll=00:00:00:00:00:02"], [0], [stdout])
+AT_CHECK([grep "Translation failed" stdout], [1])
+AT_CHECK([grep "packet is dropped" stdout], [1])
+
+OVN_CLEANUP([hv1])
+AT_CLEANUP
+])
+
 OVN_FOR_EACH_NORTHD([
 AT_SETUP([Port security - VRRPv3 ARP/ND])
 CHECK_SCAPY
-- 
2.54.0

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

Reply via email to