When setting flows for LS, OVN distinguishes between two states: where
there’s a stateful ACL present in its list (has_stateful == true *)
and when it’s missing (all ACLs are stateless).

When has_stateful == true, the following is done (among other things):
- ct handling flows are set;
- they are omitted by a higher priority flow for “service” protocols:
  NA, RA, MLD.

The latter is done because of a known issue in kernel ct
implementation for the protocols:

* https://bugzilla.kernel.org/show_bug.cgi?id=11797

The assumption is that by default OVN allows all traffic unless
explicitly forbidden, so omitting ct flows only avoids ct machinery
but doesn't affect functional behavior of flow tables for the
protocols.

But if an ACL that forbids these protocols is configured, because of
the ct omittance, this ACL is not in effect. (But only when
has_stateful == true.)

This behavior results in inconsistent and confusing behavior in
OpenStack Neutron where

(1) the default security group behavior is drop all IP traffic
(achieved with default "drop" Port_Group); and
(2) ports that have stateful and stateless ACLs configured can
co-exist in the same network.

In which case, depending on other "stateful" ports present in the
network, "stateless" ports may or may not observe RA / NA / MLD
traffic. Which affects their IPv6 address configuration.

In this patch, I suggest that we don't make RA / NA / MLD behavior
dependent on whether "stateful" ACLs are present. Instead, make the
protocols always allowed, regardless of ACLs configured (whether
stateful ACLs or ACLs that forbid packets of these protocols).

Note: an argument can be made that the same "always-on" behavior
should be guaranteed for ARP protocol that serves a similar goal in a
IPv4 network as RA / NA do for IPv6 networks. This scenario is not
directly related to the inconsistency between "purely stateless" and
"mixed-stateful" networks and hence is left for a follow-up patch.

Note: this patch carries a test case that utilizes scapy tool to
construct packets for the protocols under test. A proper backport may
demand backporting scapy related patches too.

Reported-At: https://bugs.launchpad.net/neutron/+bug/2006949
Reported-At: https://bugzilla.redhat.com/show_bug.cgi?id=2149731
Signed-off-by: Ihar Hrachyshka <ihrac...@redhat.com>
---
v1: initial version.
v2: remove debug ov?-*ctl commands from the new test case.
v2: adjust failing test cases that didn't expect new flows.
v3: add always-on flow for S_SWITCH_IN_ACL_AFTER_LB stage too.
v3: adjust acls used in test case to include --apply-after-lb.
v3: update more test cases that match the list of flows against
    expected.
v4: added missing 'check' prefixes for test case ctl commands.
v5: fixed a test failure due to a typo in v4.
---
 NEWS                    |   2 +
 northd/northd.c         |  24 +++++---
 northd/ovn-northd.8.xml |  18 ++++--
 tests/ovn-northd.at     |  49 ++++++++++++++++
 tests/ovn.at            | 127 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 206 insertions(+), 14 deletions(-)

diff --git a/NEWS b/NEWS
index f71f408d0..60467581a 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,8 @@ Post v23.03.0
     target mac address matches. Arp requests matching no Logical Router will
     only be forwarded to non-router ports. Default is true which keeps the
     existing behaviour of flooding these arp requests to all attached Ports.
+  - Always allow IPv6 Router Discovery, Neighbor Discovery, and Multicast
+    Listener Discovery protocols, regardless of ACLs defined.
 
 OVN v23.03.0 - 03 Mar 2023
 --------------------------
diff --git a/northd/northd.c b/northd/northd.c
index c10e5c20c..51cf11609 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -6796,6 +6796,8 @@ build_port_group_lswitches(
     }
 }
 
+#define IPV6_CT_OMIT_MATCH "nd || nd_ra || nd_rs || mldv1 || mldv2"
+
 static void
 build_acls(struct ovn_datapath *od, const struct chassis_features *features,
            struct hmap *lflows, const struct hmap *port_groups,
@@ -6943,20 +6945,26 @@ build_acls(struct ovn_datapath *od, const struct 
chassis_features *features,
         ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
                       ds_cstr(&match), ct_out_acl_action);
 
-        /* Ingress and Egress ACL Table (Priority 65532).
-         *
-         * Not to do conntrack on ND packets. */
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
-                      "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
-                      "nd || nd_ra || nd_rs || mldv1 || mldv2", "next;");
-
         /* Reply and related traffic matched by an "allow-related" ACL
          * should be allowed in the ls_in_acl_after_lb stage too. */
         ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
                       REGBIT_ACL_HINT_ALLOW_REL" == 1", "next;");
     }
 
+    /* Ingress and Egress ACL Table (Priority 65532).
+     *
+     * Always allow service IPv6 protocols regardless of other ACLs defined.
+     *
+     * Also, don't send them to conntrack because session tracking
+     * for these protocols is not working properly:
+     * https://bugzilla.kernel.org/show_bug.cgi?id=11797. */
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX - 3,
+                  IPV6_CT_OMIT_MATCH, "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX - 3,
+                  IPV6_CT_OMIT_MATCH, "next;");
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL_AFTER_LB, UINT16_MAX - 3,
+                  IPV6_CT_OMIT_MATCH, "next;");
+
     /* Ingress or Egress ACL Table (Various priorities). */
     for (size_t i = 0; i < od->nbs->n_acls; i++) {
         struct nbrec_acl *acl = od->nbs->acls[i];
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 6a02a30e3..29eca7070 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -748,6 +748,12 @@
       drop behavior.
     </p>
 
+    <p>
+      A priority-65532 flow is added to allow IPv6 Neighbor solicitation,
+      Neighbor discover, Router solicitation, Router advertisement and MLD
+      packets regardless of other ACLs defined.
+    </p>
+
     <p>
       If the logical datapath has a stateful ACL or a load balancer with VIP
       configured, the following flows will also be added:
@@ -824,12 +830,6 @@
         in the request direction are skipped here to let a newly created
         ACL re-allow this connection.
       </li>
-
-      <li>
-        A priority-65532 flow that allows IPv6 Neighbor solicitation,
-        Neighbor discover, Router solicitation, Router advertisement and MLD
-        packets.
-      </li>
     </ul>
 
     <p>
@@ -2123,6 +2123,12 @@ output;
       <code>to-lport</code> ACLs.
     </p>
 
+    <p>
+      Similar to ingress table, a priority-65532 flow is added to allow IPv6
+      Neighbor solicitation, Neighbor discover, Router solicitation, Router
+      advertisement and MLD packets regardless of other ACLs defined.
+    </p>
+
     <p>
       In addition, the following flows are added.
     </p>
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 1d2febdac..b3d790a65 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2486,6 +2486,7 @@ check ovn-nbctl --wait=sb \
 
 AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint 
-e ls_in_acl -e ls_out_acl | sort], [0], [dnl
   table=17(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=17(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
   table=3 (ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=3 (ls_out_acl_hint    ), priority=1    , match=(ct.est && 
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
@@ -2530,9 +2531,12 @@ ovn-nbctl --wait=sb clear logical_switch ls load_balancer
 
 AT_CHECK([ovn-sbctl lflow-list ls | grep -e ls_in_acl_hint -e ls_out_acl_hint 
-e ls_in_acl -e ls_out_acl | sort], [0], [dnl
   table=17(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=17(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=3 (ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
+  table=4 (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=4 (ls_out_acl         ), priority=65535, match=(1), action=(next;)
   table=7 (ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
+  table=8 (ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=8 (ls_in_acl          ), priority=65535, match=(1), action=(next;)
 ])
 
@@ -6845,6 +6849,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 
's/table=../table=??/' | sort], [0],
   table=??(ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && 
ct.rpl && ct_mark.blocked == 1)), action=(drop;)
   table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && 
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
@@ -6899,6 +6904,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 
's/table=../table=??/' | sort], [0],
   table=??(ls_in_acl_after_lb ), priority=2003 , match=(reg0[[8]] == 1 && (ip4 
&& icmp)), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && 
(ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* 
drop */)
   table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 
&& ip4.dst == 10.0.0.2)), action=(/* drop */)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && 
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
@@ -6953,6 +6959,7 @@ AT_CHECK([grep -e "ls_in_acl" lsflows | sed 
's/table=../table=??/' | sort], [0],
   table=??(ls_in_acl_after_lb ), priority=2001 , match=(reg0[[9]] == 1 && 
(ip4)), action=(/* drop */)
   table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[10]] == 1 && 
(ip4 && ip4.dst == 10.0.0.2)), action=(ct_commit { ct_mark.blocked = 1; }; /* 
drop */)
   table=??(ls_in_acl_after_lb ), priority=2004 , match=(reg0[[9]] == 1 && (ip4 
&& ip4.dst == 10.0.0.2)), action=(/* drop */)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && 
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
@@ -7244,11 +7251,14 @@ flow="inport == \"lsp1\" && eth.src == 
00:00:00:00:00:01 && eth.dst == 00:00:00:
 AS_BOX([No ACL, default_acl_drop not set])
 check ovn-nbctl --wait=sb sync
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl          ), priority=65535, match=(1), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
   table=??(ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
@@ -7263,11 +7273,14 @@ output("lsp2");
 AS_BOX([No ACL, default_acl_drop false])
 check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=false
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl          ), priority=65535, match=(1), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
   table=??(ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
@@ -7282,11 +7295,14 @@ output("lsp2");
 AS_BOX([No ACL, default_acl_drop true])
 check ovn-nbctl --wait=sb set NB_Global . options:default_acl_drop=true
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl          ), priority=65535, match=(1), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=65535, match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl         ), priority=65535, match=(1), action=(next;)
   table=??(ls_out_acl_hint    ), priority=65535, match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
@@ -7308,12 +7324,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | 
sed 's/table=../table=??/
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7330,12 +7349,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | 
sed 's/table=../table=??/
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7352,12 +7374,15 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | 
sed 's/table=../table=??/
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
   table=??(ls_in_acl          ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7382,6 +7407,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | 
sed 's/table=../table=??/
   table=??(ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && 
ct.rpl && ct_mark.blocked == 1)), action=(drop;)
   table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && 
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
@@ -7433,13 +7459,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options 
default_acl_drop
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7455,13 +7484,16 @@ check ovn-nbctl --wait=sb set NB_Global . 
options:default_acl_drop=false
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7477,13 +7509,16 @@ check ovn-nbctl --wait=sb set NB_Global . 
options:default_acl_drop=true
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
   table=??(ls_in_acl_after_lb ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7508,6 +7543,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | 
sed 's/table=../table=??/
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
   table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[7]] == 1 && (ip4 
&& tcp)), action=(reg0[[1]] = 1; next;)
   table=??(ls_in_acl_after_lb ), priority=1001 , match=(reg0[[8]] == 1 && (ip4 
&& tcp)), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && 
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
@@ -7559,13 +7595,16 @@ check ovn-nbctl --wait=sb remove NB_Global . options 
default_acl_drop
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7581,13 +7620,16 @@ check ovn-nbctl --wait=sb set NB_Global . 
options:default_acl_drop=false
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(next;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7603,13 +7645,16 @@ check ovn-nbctl --wait=sb set NB_Global . 
options:default_acl_drop=true
 AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | sed 
's/table=../table=??/' | sort], [0], [dnl
   table=??(ls_in_acl          ), priority=0    , match=(1), action=(drop;)
   table=??(ls_in_acl          ), priority=34000, match=(eth.dst == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_pre_acl      ), priority=110  , match=(eth.dst == 
$svc_monitor_mac), action=(next;)
   table=??(ls_out_acl         ), priority=0    , match=(1), action=(drop;)
   table=??(ls_out_acl         ), priority=1001 , match=(ip4 && tcp), 
action=(next;)
   table=??(ls_out_acl         ), priority=34000, match=(eth.src == 
$svc_monitor_mac), action=(next;)
+  table=??(ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_out_acl_hint    ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=0    , match=(1), action=(next;)
   table=??(ls_out_pre_acl     ), priority=110  , match=(eth.src == 
$svc_monitor_mac), action=(next;)
@@ -7632,6 +7677,7 @@ AT_CHECK([ovn-sbctl dump-flows | grep -E "ls_.*_acl" | 
sed 's/table=../table=??/
   table=??(ls_in_acl          ), priority=65532, match=(ct.inv || (ct.est && 
ct.rpl && ct_mark.blocked == 1)), action=(drop;)
   table=??(ls_in_acl          ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=0    , match=(1), action=(drop;)
+  table=??(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
   table=??(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
   table=??(ls_in_acl_hint     ), priority=0    , match=(1), action=(next;)
   table=??(ls_in_acl_hint     ), priority=1    , match=(ct.est && 
ct_mark.blocked == 0), action=(reg0[[10]] = 1; next;)
@@ -8711,6 +8757,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows0 | 
grep "priority=65532"],
   table=? (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && 
!ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
   table=? (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && 
ct.rpl && ct_mark.blocked == 1)), action=(drop;)
   table=? (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
+  table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || 
mldv1 || mldv2), action=(next;)
   table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
 ])
 
@@ -8759,6 +8806,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows1 | 
grep "priority=65532"],
   table=? (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && 
!ct.new && !ct.inv && ct.rpl && ct_label.blocked == 0), action=(next;)
   table=? (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && 
ct.rpl && ct_label.blocked == 1)), action=(drop;)
   table=? (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
+  table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || 
mldv1 || mldv2), action=(next;)
   table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
 ])
 
@@ -8790,6 +8838,7 @@ AT_CHECK([grep -e "ls_in_acl" -e "ls_out_acl" lflows2 | 
grep "priority=65532"],
   table=? (ls_out_acl         ), priority=65532, match=(ct.est && !ct.rel && 
!ct.new && !ct.inv && ct.rpl && ct_mark.blocked == 0), action=(next;)
   table=? (ls_out_acl         ), priority=65532, match=(ct.inv || (ct.est && 
ct.rpl && ct_mark.blocked == 1)), action=(drop;)
   table=? (ls_out_acl         ), priority=65532, match=(nd || nd_ra || nd_rs 
|| mldv1 || mldv2), action=(next;)
+  table=?(ls_in_acl_after_lb ), priority=65532, match=(nd || nd_ra || nd_rs || 
mldv1 || mldv2), action=(next;)
   table=?(ls_in_acl_after_lb ), priority=65532, match=(reg0[[17]] == 1), 
action=(next;)
 ])
 
diff --git a/tests/ovn.at b/tests/ovn.at
index 8e80765c6..6637b091d 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -13898,6 +13898,133 @@ OVN_CLEANUP([gw1],[gw2],[hv1])
 AT_CLEANUP
 ])
 
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([allow IPv6 RA / NA / MLD by default])
+AT_SKIP_IF([test $HAVE_SCAPY = no])
+ovn_start
+net_add n1
+sim_add hv1
+as hv1
+ovs-vsctl add-br br-phys
+ovn_attach n1 br-phys 192.168.0.1
+
+lsp_mac_prefix=50:64:00:00:00:0
+lsp_ip_prefix=10.0.0.
+lsp_ip6_prefix=aef0::5264:00ff:fe00:000
+
+check ovn-nbctl ls-add ls0
+for i in 1 2; do
+  check ovn-nbctl lsp-add ls0 lsp$i
+  check ovn-nbctl lsp-set-addresses lsp$i \
+    "${lsp_mac_prefix}$i ${lsp_ip_prefix}$i ${lsp_ip6_prefix}$i"
+
+  # forbid all traffic for the ports
+  check ovn-nbctl acl-add ls0 \
+      from-lport 1000 "inport == \"lsp$i\"" drop
+  check ovn-nbctl --apply-after-lb acl-add ls0\
+      from-lport 1000 "inport == \"lsp$i\"" drop
+  check ovn-nbctl acl-add ls0 \
+      to-lport 1000 "outport == \"lsp$i\"" drop
+
+  check ovs-vsctl -- add-port br-int vif$i -- \
+      set interface vif$i external-ids:iface-id=lsp$i \
+      options:tx_pcap=hv1/vif$i-tx.pcap \
+      options:rxq_pcap=hv1/vif$i-rx.pcap
+  : > $i.expected
+done
+
+router_mac=fa:16:3e:00:00:01
+router_prefix=fdad:1234:5678::
+router_ip=${router_prefix}1
+check ovn-nbctl lr-add lr0
+check ovn-nbctl lrp-add lr0 lrp0 ${router_mac} ${router_ip}/64
+check ovn-nbctl set Logical_Router_Port lrp0 
ipv6_ra_configs:address_mode="slaac"
+check ovn-nbctl \
+    -- lsp-add ls0 rp0 \
+    -- set Logical_Switch_Port rp0 type=router \
+                     options:router-port=lrp0 \
+                     addresses='"${router_mac} ${router_ip}"'
+
+wait_for_ports_up
+
+test_ns_na() {
+    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
+
+    packet=$(fmt_pkt "
+        Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
+        IPv6(src='${src_ip}', dst='ff02::1:ff00:2') /
+        ICMPv6ND_NS(tgt='${dst_ip}')
+    ")
+    as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet
+
+    expected_packet=$(fmt_pkt "
+        Ether(dst='${src_mac}', src='${dst_mac}') /
+        IPv6(src='${dst_ip}', dst='${src_ip}') /
+        ICMPv6ND_NA(tgt='${dst_ip}', R=0, S=1) /
+        ICMPv6NDOptDstLLAddr(lladdr='${dst_mac}')
+    ")
+    echo $expected_packet >> $inport.expected
+}
+
+test_rs_ra() {
+    local inport=$1 src_mac=$2 src_ip=$3
+    local router_mac=$4 router_prefix=$5 router_ip=$6
+
+    packet=$(fmt_pkt "
+        Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
+        IPv6(src='${src_ip}', dst='ff02::2') /
+        ICMPv6ND_RS()
+    ")
+    as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet
+
+    expected_packet=$(fmt_pkt "
+        Ether(dst='${src_mac}', src='${router_mac}') /
+        IPv6(src='${router_ip}', dst='${src_ip}') /
+        ICMPv6ND_RA(chlim=255, prf=0, routerlifetime=65535) /
+        ICMPv6NDOptSrcLLAddr(lladdr='${router_mac}') /
+        ICMPv6NDOptPrefixInfo(prefix='${router_prefix}')
+    ")
+    echo $expected_packet >> $inport.expected
+}
+
+test_mldv2() {
+    local inport=$1 outport=$2 src_mac=$3 src_ip=$4
+
+    packet=$(fmt_pkt "
+        Ether(dst='ff:ff:ff:ff:ff:ff', src='${src_mac}') /
+        IPv6(src='${src_ip}', dst='ff02::2') /
+        ICMPv6MLQuery2()
+    ")
+    as hv1 ovs-appctl netdev-dummy/receive vif${inport} $packet
+
+    expected_packet=$packet
+    echo $expected_packet >> $outport.expected
+}
+
+src_mac=${lsp_mac_prefix}1
+dst_mac=${lsp_mac_prefix}2
+src_ip=${lsp_ip6_prefix}1
+dst_ip=${lsp_ip6_prefix}2
+
+as hv1
+test_ns_na 1 $src_mac $dst_mac $src_ip $dst_ip
+
+as hv1
+router_local_ip=fe80::f816:3eff:fe00:1
+test_rs_ra 1 $src_mac $src_ip $router_mac $router_prefix $router_local_ip
+
+as hv1
+src_ip=fe80::1
+test_mldv2 1 2 $src_mac $src_ip
+
+OVN_CHECK_PACKETS([hv1/vif1-tx.pcap], [1.expected])
+OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [2.expected])
+
+OVN_CLEANUP([hv1])
+
+AT_CLEANUP
+])
+
 OVN_FOR_EACH_NORTHD([
 AT_SETUP([IPv6 Neighbor Solicitation for unknown MAC])
 AT_KEYWORDS([ovn-nd_ns for unknown mac])
-- 
2.38.1


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

Reply via email to