It was unsupported - to have a mix of stateless ACLs with lower than
stateful priority at the same time with stateful (related) ACLs.

This patch changes stateless ACLs behaviour, but this change should not
be harmful for users. Likely nobody mixed rules in the described manner,
so this change should be okay.

Signed-off-by: Vladislav Odintsov <odiv...@gmail.com>
---
 northd/northd.c         | 92 +++++++++++++++++++++++++----------------
 northd/ovn-northd.8.xml |  4 +-
 tests/ovn-northd.at     | 48 ++++++++++++---------
 3 files changed, 87 insertions(+), 57 deletions(-)

diff --git a/northd/northd.c b/northd/northd.c
index 2efc4bb1f..1831e6e79 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -592,6 +592,7 @@ struct ovn_datapath {
     uint32_t port_key_hint;
 
     bool has_stateful_acl;
+    bool has_stateless_acl;
     bool has_lb_vip;
     bool has_unknown;
     bool has_acls;
@@ -5416,15 +5417,26 @@ ls_get_acl_flags(struct ovn_datapath *od)
 {
     od->has_acls = false;
     od->has_stateful_acl = false;
+    od->has_stateless_acl = false;
 
     if (od->nbs->n_acls) {
         od->has_acls = true;
 
         for (size_t i = 0; i < od->nbs->n_acls; i++) {
             struct nbrec_acl *acl = od->nbs->acls[i];
-            if (!strcmp(acl->action, "allow-related")) {
+            if (!od->has_stateful_acl &&
+                !strcmp(acl->action, "allow-related")) {
                 od->has_stateful_acl = true;
-                return;
+                if (od->has_stateless_acl) {
+                    return;
+                }
+            }
+            if (!od->has_stateless_acl &&
+                !strcmp(acl->action, "allow-stateless")) {
+                od->has_stateless_acl = true;
+                if (od->has_stateful_acl) {
+                    return;
+                }
             }
         }
     }
@@ -5436,9 +5448,19 @@ ls_get_acl_flags(struct ovn_datapath *od)
 
             for (size_t i = 0; i < ls_pg->nb_pg->n_acls; i++) {
                 struct nbrec_acl *acl = ls_pg->nb_pg->acls[i];
-                if (!strcmp(acl->action, "allow-related")) {
+                if (!od->has_stateful_acl &&
+                    !strcmp(acl->action, "allow-related")) {
                     od->has_stateful_acl = true;
-                    return;
+                    if (od->has_stateless_acl) {
+                        return;
+                    }
+                }
+                if (!od->has_stateless_acl &&
+                    !strcmp(acl->action, "allow-stateless")) {
+                    od->has_stateless_acl = true;
+                    if (od->has_stateful_acl) {
+                        return;
+                    }
                 }
             }
         }
@@ -5647,45 +5669,42 @@ skip_port_from_conntrack(struct ovn_datapath *od, 
struct ovn_port *op,
 }
 
 static void
-build_stateless_filter(struct ovn_datapath *od,
-                       const struct nbrec_acl *acl,
-                       struct hmap *lflows)
+build_acl_filter(struct ovn_datapath *od, const struct nbrec_acl *acl,
+                 struct hmap *lflows)
 {
+    int direction;
+    char *actions;
+
     if (!strcmp(acl->direction, "from-lport")) {
-        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL,
-                                acl->priority + OVN_ACL_PRI_OFFSET,
-                                acl->match,
-                                "next;",
-                                &acl->header_);
+        direction = S_SWITCH_IN_PRE_ACL;
     } else {
-        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
-                                acl->priority + OVN_ACL_PRI_OFFSET,
-                                acl->match,
-                                "next;",
-                                &acl->header_);
+        direction = S_SWITCH_OUT_PRE_ACL;
+    }
+
+    if (!strcmp(acl->action, "allow-stateless")) {
+        actions = "next;";
+    } else {
+        actions = REGBIT_CONNTRACK_DEFRAG" = 1; next;";
     }
+
+    ovn_lflow_add_with_hint(lflows, od, direction,
+                            acl->priority + OVN_ACL_PRI_OFFSET, acl->match,
+                            actions, &acl->header_);
 }
 
 static void
-build_stateless_filters(struct ovn_datapath *od,
-                        const struct hmap *port_groups,
-                        struct hmap *lflows)
+build_acl_filters(struct ovn_datapath *od, const struct hmap *port_groups,
+                  struct hmap *lflows)
 {
     for (size_t i = 0; i < od->nbs->n_acls; i++) {
-        const struct nbrec_acl *acl = od->nbs->acls[i];
-        if (!strcmp(acl->action, "allow-stateless")) {
-            build_stateless_filter(od, acl, lflows);
-        }
+        build_acl_filter(od, od->nbs->acls[i], lflows);
     }
 
     struct ovn_port_group *pg;
     HMAP_FOR_EACH (pg, key_node, port_groups) {
         if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) {
             for (size_t i = 0; i < pg->nb_pg->n_acls; i++) {
-                const struct nbrec_acl *acl = pg->nb_pg->acls[i];
-                if (!strcmp(acl->action, "allow-stateless")) {
-                    build_stateless_filter(od, acl, lflows);
-                }
+                build_acl_filter(od, pg->nb_pg->acls[i], lflows);
             }
         }
     }
@@ -5700,10 +5719,10 @@ build_pre_acls(struct ovn_datapath *od, const struct 
hmap *port_groups,
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;");
 
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 65535,
                   "eth.dst == $svc_monitor_mac", "next;");
 
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 65535,
                   "eth.src == $svc_monitor_mac", "next;");
 
     /* If there are any stateful ACL rules in this datapath, we may
@@ -5713,25 +5732,26 @@ build_pre_acls(struct ovn_datapath *od, const struct 
hmap *port_groups,
         for (size_t i = 0; i < od->n_router_ports; i++) {
             skip_port_from_conntrack(od, od->router_ports[i],
                                      S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
-                                     110, lflows);
+                                     65535, lflows);
         }
         for (size_t i = 0; i < od->n_localnet_ports; i++) {
             skip_port_from_conntrack(od, od->localnet_ports[i],
                                      S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
-                                     110, lflows);
+                                     65535, lflows);
         }
 
-        /* stateless filters always take precedence over stateful ACLs. */
-        build_stateless_filters(od, port_groups, lflows);
+        if (od->has_stateless_acl) {
+            build_acl_filters(od, port_groups, lflows);
+        }
 
         /* Ingress and Egress Pre-ACL Table (Priority 110).
          *
          * Not to do conntrack on ND and ICMP destination
          * unreachable packets. */
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 65535,
                       "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 65535,
                       "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
 
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index bd3c3aa26..f92906e5b 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -459,7 +459,9 @@
       priority-110 flow is added to skip over stateful ACLs. IPv6 Neighbor
       Discovery and MLD traffic also skips stateful ACLs. For "allow-stateless"
       ACLs, a flow is added to bypass setting the hint for connection tracker
-      processing.
+      processing.  If datapath has "allow-stateless" and "allow-related" ACLs,
+      a flow for each ACL would be added with priority value calculated as 1000
+      plus ACL's priority and action <code>reg0[0] = 1; next;</code>.
     </p>
 
     <p>
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index c4424ab14..b168b79c9 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -3100,7 +3100,7 @@ AT_CLEANUP
 ])
 
 OVN_FOR_EACH_NORTHD([
-AT_SETUP([ACL allow-stateless overrides stateful rules with higher priority - 
Logical_Switch])
+AT_SETUP([ACL allow-stateless doesn't override stateful rules with higher 
priority - Logical_Switch])
 ovn_start
 
 ovn-nbctl ls-add ls
@@ -3110,22 +3110,29 @@ ovn-nbctl lsp-add ls lsp2
 ovn-nbctl lsp-set-addresses lsp2 00:00:00:00:00:02
 
 for direction in from to; do
-    ovn-nbctl acl-add ls ${direction}-lport 3 "tcp" allow-related
-    ovn-nbctl acl-add ls ${direction}-lport 3 "udp" allow
+    ovn-nbctl acl-add ls ${direction}-lport 3 "ip4.src == 10.0.0.0/24 && tcp" 
allow-related
+    ovn-nbctl acl-add ls ${direction}-lport 3 "ip4.src == 10.0.0.0/24 && udp" 
allow
+done
+
+# Allow stateless with *lower* priority. It should not override stateful rules.
+for direction in from to; do
+    ovn-nbctl acl-add ls ${direction}-lport 1 tcp allow-stateless
+    ovn-nbctl acl-add ls ${direction}-lport 1 udp allow-stateless
 done
 ovn-nbctl --wait=sb sync
 
 flow_eth='eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02'
-flow_ip='ip.ttl==64 && ip4.src == 42.42.42.1 && ip4.dst == 66.66.66.66'
+flow_ip_10='ip.ttl==64 && ip4.src == 10.0.0.1 && ip4.dst == 66.66.66.66'
+flow_ip_20='ip.ttl==64 && ip4.src == 20.0.0.1 && ip4.dst == 66.66.66.66'
 flow_tcp='tcp && tcp.dst == 80'
 flow_udp='udp && udp.dst == 80'
 
 lsp1_inport=$(fetch_column Port_Binding tunnel_key logical_port=lsp1)
 
-# TCP packets should go to conntrack.
-flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
+# TCP and UDP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_10} && ${flow_tcp}"
 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], 
[dnl
-# 
tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
+# 
tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=10.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
 ct_next(ct_state=new|trk) {
     ct_next(ct_state=new|trk) {
         output("lsp2");
@@ -3133,24 +3140,25 @@ ct_next(ct_state=new|trk) {
 };
 ])
 
-# Allow stateless with *lower* priority. It always beats stateful rules.
-for direction in from to; do
-    ovn-nbctl acl-add ls ${direction}-lport 1 tcp allow-stateless
-    ovn-nbctl acl-add ls ${direction}-lport 1 udp allow-stateless
-done
-ovn-nbctl --wait=sb sync
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_10} && ${flow_udp}"
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], 
[dnl
+# 
udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=10.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
+ct_next(ct_state=new|trk) {
+    ct_next(ct_state=new|trk) {
+        output("lsp2");
+    };
+};
+])
 
-# TCP packets should not go to conntrack anymore.
-flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
+# TCP and UDP packets from 20.0.0.1 should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_20} && ${flow_tcp}"
 AT_CHECK_UNQUOTED([ovn-trace --minimal ls "${flow}"], [0], [dnl
-# 
tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
+# 
tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=20.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
 output("lsp2");
 ])
-
-# UDP packets should not go to conntrack anymore.
-flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}"
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_20} && ${flow_udp}"
 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], 
[dnl
-# 
udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
+# 
udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=20.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
 output("lsp2");
 ])
 
-- 
2.30.0

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

Reply via email to