For allow ACLs, bypass connection tracking by avoiding setting ct
hints for matching traffic. Avoid sending all traffic to ct when a
stateful ACL is present. Before the patch, this unnecessarily hit
performance when mixed ACL action types were used for the same
datapath.
===
Reusing an existing 'allow' verb for truly stateless matching may have
its drawbacks, specifically, when it comes to backwards
incompatibility of the new behavior with existing environments. This
issue could be solved by e.g. introducing a new action verb to
describe stateless behavior.
Another complexity to consider is the fact that with stateless
matching, one would not be able to rely on 'related' magic that
guarantees that reply traffic is passed through. Instead, the user
would have to accurately define matching rules both for request and
reply directions of a protocol session. Specifically, when allowing
ICMP for a specific peer host, one have to define 'allow' rules that
would match against ip.dst for request direction and ip.src for reply
direction. Other protocols and scenarios will require their own fine
grained matching approaches implemented by the user.
===
For performance measurements, ovn-fake-multinode environment and qperf
were used. Performance measured between two virtual nodes, two ports
that belong to different LSs connected via router. Using qperf,
performance was measured for UDP, TCP, SCTP protocols (using
<proto>_lat and <proto>_bw tests). The qperf version used:
0.4.9-16.fc31.x86_64. Each test scenario was executed five times and
averages compared.
Tests were executed with `allow` rules for the tested protocol and
`allow-related` for another protocol set for both ports, both
directions, e.g. for TCP scenario, the following ACLs were defined:
ovn-nbctl acl-add sw0 to-lport 100 tcp allow
ovn-nbctl acl-add sw0 from-lport 100 tcp allow
ovn-nbctl acl-add sw1 to-lport 100 tcp allow
ovn-nbctl acl-add sw1 from-lport 100 tcp allow
ovn-nbctl acl-add sw0 to-lport 100 sctp allow-related
ovn-nbctl acl-add sw0 from-lport 100 sctp allow-related
ovn-nbctl acl-add sw1 to-lport 100 sctp allow-related
ovn-nbctl acl-add sw1 from-lport 100 sctp allow-related
In this particular environment, improvement was seen in send_bw,
latency, and msg_rate measurements, where applicable, for all three
protocols under test.
for UDP, send_bw: 293.6 MB/sec => 313.2 MB/sec (+6.68%)
latency: 16 us => 14.08 us (-12%)
msg_rate: 62.56 K/sec => 71.06 K/sec (+13.59%)
for TCP, latency: 18.6 us => 14.88 us (-20%)
msg_rate: 53.8 K/sec => 67.28 K/sec (+25.06%)
for SCTP, latency: 21.98 us => 19.42 us (-11.65%)
msg_rate: 45.58 K/sec => 51.54 K/sec (+13.08%)
Interestingly, some performance improvement was also seen for the same
scenarios with no ACLs set at all, albeit significantly more
negligible.
for UDP, send_bw: 320.0 MB/sec => 338.6 MB/sec (+5.81%)
latency: 13.74 us => 12.88 us (-6.68%)
msg_rate: 73.02 K/sec => 77.84 K/sec (+6.6%)
for TCP, latency: 15.62 us => 14.26 us (-9.54%)
msg_rate: 64.02 K/sec => 70.26 K/sec (+9.75%)
for SCTP, latency: 19.56 us => 18.16 us (-7.16%)
msg_rate: 51.16 K/sec => 55.12 K/sec (+7.74%)
Comparable numbers can be captured with iperf. It may be useful to run
more tests in a more elaborate (bare metal) environment.
===
The patch takes inspiration from a now abandoned patch:
"ovn-northd: Support mixing stateless/stateful ACLs with
Stateless_Filter." by Dumitru Ceara.
The original patch assumed CMS doesn't require full flexibility of
matching rules for stateless matching (for example, to be used by
OpenShift). But other CMS interfaces may require the same
customizability for stateless as well as stateful matching, like in
OpenStack Neutron API. Which is why this patch reuses existing ACL
object type to describe stateless rules.
Signed-off-by: Ihar Hrachyshka <[email protected]>
---
v1: initial version.
v2: rebased after conflict.
v3: added ddlog implementation.
v3: apply stateless skip-hint-set rules to appropriate direction only.
v3: added more background as to implementation in commit message.
v3: test stateless scenarios with ddlog too.
v3: rebased after conflict.
---
NEWS | 1 +
northd/ovn-northd.8.xml | 9 +-
northd/ovn-northd.c | 169 ++++++++++++++--------
northd/ovn_northd.dl | 107 ++++++++------
tests/ovn-northd.at | 309 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 486 insertions(+), 109 deletions(-)
diff --git a/NEWS b/NEWS
index f84d236e4..3dae85f4d 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Post-v21.03.0
- Introduce ovn-controller incremetal processing engine statistics
- Introduced parallel processing in ovn-northd with the NB_Global config
option
'use_parallel_build' to enable it. It is disabled by default.
+ - Bypass connection tracking for ACL "allow" action processing.
OVN v21.03.0 - 12 Mar 2021
-------------------------
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index 8197aa513..5ad70763f 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -419,7 +419,9 @@
before eventually advancing to ingress table <code>ACLs</code>. If
special ports such as route ports or localnet ports can't use ct(), a
priority-110 flow is added to skip over stateful ACLs. IPv6 Neighbor
- Discovery and MLD traffic also skips stateful ACLs.
+ Discovery and MLD traffic also skips stateful ACLs. For stateless "allow"
+ ACLs, a flow is added to bypass setting the hint for connection tracker
+ processing.
</p>
<p>
@@ -603,10 +605,7 @@
<ul>
<li>
<code>allow</code> ACLs translate into logical flows with
- the <code>next;</code> action. If there are any stateful ACLs
- on this datapath, then <code>allow</code> ACLs translate to
- <code>ct_commit; next;</code> (which acts as a hint for the next tables
- to commit the connection to conntrack),
+ the <code>next;</code> action.
</li>
<li>
<code>allow-related</code> ACLs translate into logical
diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index 80ee05b8b..f5124d665 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -4969,7 +4969,61 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct
ovn_port *op,
}
static void
-build_pre_acls(struct ovn_datapath *od, struct hmap *lflows)
+build_stateless_filter(struct ovn_datapath *od,
+ const struct nbrec_acl *acl,
+ struct hmap *lflows)
+{
+ /* Stateless filters must be applied in both directions so that reply
+ * traffic bypasses conntrack too.
+ */
+ 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_);
+ } else {
+ ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ acl->match,
+ "next;",
+ &acl->header_);
+ }
+}
+
+static bool
+acl_is_stateless(const struct nbrec_acl *acl)
+{
+ return !strcmp(acl->action, "allow");
+}
+
+static void
+build_stateless_filters(struct ovn_datapath *od, 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 (acl_is_stateless(acl)) {
+ build_stateless_filter(od, acl, 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 (acl_is_stateless(acl)) {
+ build_stateless_filter(od, acl, lflows);
+ }
+ }
+ }
+ }
+}
+
+static void
+build_pre_acls(struct ovn_datapath *od, struct hmap *port_groups,
+ struct hmap *lflows)
{
/* Ingress and Egress Pre-ACL Table (Priority 0): Packets are
* allowed by default. */
@@ -4997,6 +5051,8 @@ build_pre_acls(struct ovn_datapath *od, struct hmap
*lflows)
110, lflows);
}
+ build_stateless_filters(od, port_groups, lflows);
+
/* Ingress and Egress Pre-ACL Table (Priority 110).
*
* Not to do conntrack on ND and ICMP destination
@@ -5423,70 +5479,67 @@ consider_acl(struct hmap *lflows, struct ovn_datapath
*od,
bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : S_SWITCH_OUT_ACL;
- if (!strcmp(acl->action, "allow")
- || !strcmp(acl->action, "allow-related")) {
+ if (!strcmp(acl->action, "allow")) {
/* If there are any stateful flows, we must even commit "allow"
* actions. This is because, while the initiater's
* direction may not have any stateful rules, the server's
* may and then its return traffic would not have an
* associated conntrack entry and would return "+invalid". */
- if (!has_stateful) {
- struct ds actions = DS_EMPTY_INITIALIZER;
- build_acl_log(&actions, acl, meter_groups);
- ds_put_cstr(&actions, "next;");
- ovn_lflow_add_with_hint(lflows, od, stage,
- acl->priority + OVN_ACL_PRI_OFFSET,
- acl->match, ds_cstr(&actions),
- &acl->header_);
- ds_destroy(&actions);
- } else {
- struct ds match = DS_EMPTY_INITIALIZER;
- struct ds actions = DS_EMPTY_INITIALIZER;
+ struct ds actions = DS_EMPTY_INITIALIZER;
+ build_acl_log(&actions, acl, meter_groups);
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add_with_hint(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ acl->match, ds_cstr(&actions),
+ &acl->header_);
+ ds_destroy(&actions);
+ } else if (!strcmp(acl->action, "allow-related")) {
+ struct ds match = DS_EMPTY_INITIALIZER;
+ struct ds actions = DS_EMPTY_INITIALIZER;
- /* Commit the connection tracking entry if it's a new
- * connection that matches this ACL. After this commit,
- * the reply traffic is allowed by a flow we create at
- * priority 65535, defined earlier.
- *
- * It's also possible that a known connection was marked for
- * deletion after a policy was deleted, but the policy was
- * re-added while that connection is still known. We catch
- * that case here and un-set ct_label.blocked (which will be done
- * by ct_commit in the "stateful" stage) to indicate that the
- * connection should be allowed to resume.
- */
- ds_put_format(&match, REGBIT_ACL_HINT_ALLOW_NEW " == 1 && (%s)",
- acl->match);
- ds_put_cstr(&actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
- build_acl_log(&actions, acl, meter_groups);
- ds_put_cstr(&actions, "next;");
- ovn_lflow_add_with_hint(lflows, od, stage,
- acl->priority + OVN_ACL_PRI_OFFSET,
- ds_cstr(&match),
- ds_cstr(&actions),
- &acl->header_);
-
- /* Match on traffic in the request direction for an established
- * connection tracking entry that has not been marked for
- * deletion. There is no need to commit here, so we can just
- * proceed to the next table. We use this to ensure that this
- * connection is still allowed by the currently defined
- * policy. Match untracked packets too. */
- ds_clear(&match);
- ds_clear(&actions);
- ds_put_format(&match, REGBIT_ACL_HINT_ALLOW " == 1 && (%s)",
- acl->match);
+ /* Commit the connection tracking entry if it's a new
+ * connection that matches this ACL. After this commit,
+ * the reply traffic is allowed by a flow we create at
+ * priority 65535, defined earlier.
+ *
+ * It's also possible that a known connection was marked for
+ * deletion after a policy was deleted, but the policy was
+ * re-added while that connection is still known. We catch
+ * that case here and un-set ct_label.blocked (which will be done
+ * by ct_commit in the "stateful" stage) to indicate that the
+ * connection should be allowed to resume.
+ */
+ ds_put_format(&match, REGBIT_ACL_HINT_ALLOW_NEW " == 1 && (%s)",
+ acl->match);
+ ds_put_cstr(&actions, REGBIT_CONNTRACK_COMMIT" = 1; ");
+ build_acl_log(&actions, acl, meter_groups);
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add_with_hint(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ ds_cstr(&match),
+ ds_cstr(&actions),
+ &acl->header_);
+
+ /* Match on traffic in the request direction for an established
+ * connection tracking entry that has not been marked for
+ * deletion. There is no need to commit here, so we can just
+ * proceed to the next table. We use this to ensure that this
+ * connection is still allowed by the currently defined
+ * policy. Match untracked packets too. */
+ ds_clear(&match);
+ ds_clear(&actions);
+ ds_put_format(&match, REGBIT_ACL_HINT_ALLOW " == 1 && (%s)",
+ acl->match);
- build_acl_log(&actions, acl, meter_groups);
- ds_put_cstr(&actions, "next;");
- ovn_lflow_add_with_hint(lflows, od, stage,
- acl->priority + OVN_ACL_PRI_OFFSET,
- ds_cstr(&match), ds_cstr(&actions),
- &acl->header_);
+ build_acl_log(&actions, acl, meter_groups);
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add_with_hint(lflows, od, stage,
+ acl->priority + OVN_ACL_PRI_OFFSET,
+ ds_cstr(&match), ds_cstr(&actions),
+ &acl->header_);
- ds_destroy(&match);
- ds_destroy(&actions);
- }
+ ds_destroy(&match);
+ ds_destroy(&actions);
} else if (!strcmp(acl->action, "drop")
|| !strcmp(acl->action, "reject")) {
struct ds match = DS_EMPTY_INITIALIZER;
@@ -6823,7 +6876,7 @@ build_lswitch_lflows_pre_acl_and_acl(struct ovn_datapath
*od,
od->has_stateful_acl = ls_has_stateful_acl(od);
od->has_lb_vip = ls_has_lb_vip(od);
- build_pre_acls(od, lflows);
+ build_pre_acls(od, port_groups, lflows);
build_pre_lb(od, lflows, meter_groups, lbs);
build_pre_stateful(od, lflows);
build_acl_hints(od, lflows);
diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl
index 4c02e2d5a..4055075dc 100644
--- a/northd/ovn_northd.dl
+++ b/northd/ovn_northd.dl
@@ -1815,6 +1815,28 @@ for (&Switch(.ls =ls)) {
.external_ids = map_empty())
}
+for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter =
fair_meter)) {
+ var has_stateful = sw.has_stateful_acl in
+ if (sw.has_stateful_acl) {
+ if (acl.action == "allow") {
+ if (acl.direction == "from-lport") {
+ Flow(.logical_datapath = ls._uuid,
+ .stage = s_SWITCH_IN_PRE_ACL(),
+ .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
+ .__match = acl.__match,
+ .actions = "next;",
+ .external_ids = stage_hint(acl._uuid))
+ } else {
+ Flow(.logical_datapath = ls._uuid,
+ .stage = s_SWITCH_OUT_PRE_ACL(),
+ .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
+ .__match = acl.__match,
+ .actions = "next;",
+ .external_ids = stage_hint(acl._uuid))
+ }
+ }
+ }
+}
/* If there are any stateful ACL rules in this datapath, we must
* send all IP packets through the conntrack action, which handles
@@ -2491,52 +2513,45 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl =
&acl, .has_fair_meter = fair_
var pipeline = if ingress Ingress else Egress in
var stage_hint = stage_hint(acl._uuid) in
var acl_log = build_acl_log(acl, fair_meter) in
- if (acl.action == "allow" or acl.action == "allow-related") {
- /* If there are any stateful flows, we must even commit "allow"
- * actions. This is because, while the initiater's
- * direction may not have any stateful rules, the server's
- * may and then its return traffic would not have an
- * associated conntrack entry and would return "+invalid". */
- if (not has_stateful) {
- Flow(.logical_datapath = ls._uuid,
- .stage = stage,
- .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
- .__match = acl.__match,
- .actions = "${acl_log}next;",
- .external_ids = stage_hint)
- } else {
- /* Commit the connection tracking entry if it's a new
- * connection that matches this ACL. After this commit,
- * the reply traffic is allowed by a flow we create at
- * priority 65535, defined earlier.
- *
- * It's also possible that a known connection was marked for
- * deletion after a policy was deleted, but the policy was
- * re-added while that connection is still known. We catch
- * that case here and un-set ct_label.blocked (which will be done
- * by ct_commit in the "stateful" stage) to indicate that the
- * connection should be allowed to resume.
- */
- Flow(.logical_datapath = ls._uuid,
- .stage = stage,
- .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
- .__match = "${rEGBIT_ACL_HINT_ALLOW_NEW()} == 1 &&
(${acl.__match})",
- .actions = "${rEGBIT_CONNTRACK_COMMIT()} = 1;
${acl_log}next;",
- .external_ids = stage_hint);
-
- /* Match on traffic in the request direction for an established
- * connection tracking entry that has not been marked for
- * deletion. There is no need to commit here, so we can just
- * proceed to the next table. We use this to ensure that this
- * connection is still allowed by the currently defined
- * policy. Match untracked packets too. */
- Flow(.logical_datapath = ls._uuid,
- .stage = stage,
- .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
- .__match = "${rEGBIT_ACL_HINT_ALLOW()} == 1 &&
(${acl.__match})",
- .actions = "${acl_log}next;",
- .external_ids = stage_hint)
- }
+ if (acl.action == "allow") {
+ Flow(.logical_datapath = ls._uuid,
+ .stage = stage,
+ .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
+ .__match = acl.__match,
+ .actions = "${acl_log}next;",
+ .external_ids = stage_hint)
+ } else if (acl.action == "allow-related") {
+ /* Commit the connection tracking entry if it's a new
+ * connection that matches this ACL. After this commit,
+ * the reply traffic is allowed by a flow we create at
+ * priority 65535, defined earlier.
+ *
+ * It's also possible that a known connection was marked for
+ * deletion after a policy was deleted, but the policy was
+ * re-added while that connection is still known. We catch
+ * that case here and un-set ct_label.blocked (which will be done
+ * by ct_commit in the "stateful" stage) to indicate that the
+ * connection should be allowed to resume.
+ */
+ Flow(.logical_datapath = ls._uuid,
+ .stage = stage,
+ .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
+ .__match = "${rEGBIT_ACL_HINT_ALLOW_NEW()} == 1 &&
(${acl.__match})",
+ .actions = "${rEGBIT_CONNTRACK_COMMIT()} = 1;
${acl_log}next;",
+ .external_ids = stage_hint);
+
+ /* Match on traffic in the request direction for an established
+ * connection tracking entry that has not been marked for
+ * deletion. There is no need to commit here, so we can just
+ * proceed to the next table. We use this to ensure that this
+ * connection is still allowed by the currently defined
+ * policy. Match untracked packets too. */
+ Flow(.logical_datapath = ls._uuid,
+ .stage = stage,
+ .priority = acl.priority + oVN_ACL_PRI_OFFSET(),
+ .__match = "${rEGBIT_ACL_HINT_ALLOW()} == 1 &&
(${acl.__match})",
+ .actions = "${acl_log}next;",
+ .external_ids = stage_hint)
} else if (acl.action == "drop" or acl.action == "reject") {
/* The implementation of "drop" differs if stateful ACLs are in
* use for this datapath. In that case, the actions differ
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index eef360802..6ff44d94d 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -2575,6 +2575,315 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] ==
<cleared>/' | sort], [0],
AT_CLEANUP
])
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn -- ACL allow omit conntrack - Logical_Switch])
+ovn_start
+
+ovn-nbctl ls-add ls
+ovn-nbctl lsp-add ls lsp1
+ovn-nbctl lsp-set-addresses lsp1 00:00:00:00:00:01
+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 2 "udp" allow-related
+ ovn-nbctl acl-add ls ${direction}-lport 1 "ip" drop
+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_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}"
+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
+ct_next(ct_state=new|trk) {
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+};
+])
+
+# UDP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+};
+])
+
+# Allow stateless for TCP.
+for direction in from to; do
+ ovn-nbctl acl-add ls ${direction}-lport 1 tcp allow
+done
+ovn-nbctl --wait=sb sync
+
+# TCP packets should not go to conntrack anymore.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+output("lsp2");
+])
+
+# UDP packets still go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+};
+])
+
+# Add a load balancer.
+ovn-nbctl lb-add lb-tcp 66.66.66.66:80 42.42.42.2:8080 tcp
+ovn-nbctl lb-add lb-udp 66.66.66.66:80 42.42.42.2:8080 udp
+ovn-nbctl ls-lb-add ls lb-tcp
+ovn-nbctl ls-lb-add ls lb-udp
+
+# Remove stateless for TCP.
+ovn-nbctl acl-del ls
+ovn-nbctl --wait=sb sync
+
+# TCP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+# UDP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+# Allow stateless for TCP.
+for direction in from to; do
+ ovn-nbctl acl-add ls ${direction}-lport 1 tcp allow
+done
+ovn-nbctl --wait=sb sync
+
+# TCP packets should go to conntrack for load balancing.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+# UDP packets still go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+AT_CLEANUP
+])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn -- ACL allow omit conntrack - Port_Group])
+ovn_start
+
+ovn-nbctl ls-add ls
+ovn-nbctl lsp-add ls lsp1
+ovn-nbctl lsp-set-addresses lsp1 00:00:00:00:00:01
+ovn-nbctl lsp-add ls lsp2
+ovn-nbctl lsp-set-addresses lsp2 00:00:00:00:00:02
+
+ovn-nbctl pg-add pg lsp1 lsp2
+
+for direction in from to; do
+ ovn-nbctl acl-add pg ${direction}-lport 3 "tcp" allow-related
+ ovn-nbctl acl-add pg ${direction}-lport 2 "udp" allow-related
+ ovn-nbctl acl-add pg ${direction}-lport 1 "ip" drop
+done
+ovn-nbctl --wait=sb sync
+
+lsp1_inport=$(fetch_column Port_Binding tunnel_key logical_port=lsp1)
+echo $lsp1_inport
+
+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_tcp='tcp && tcp.dst == 80'
+flow_udp='udp && udp.dst == 80'
+
+# TCP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+};
+])
+
+# UDP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+};
+])
+
+# Allow stateless for TCP.
+for direction in from to; do
+ ovn-nbctl acl-add pg ${direction}-lport 1 tcp allow
+done
+ovn-nbctl --wait=sb sync
+
+# TCP packets should not go to conntrack anymore.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+output("lsp2");
+])
+
+# UDP packets still go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+};
+])
+
+# Add a load balancer.
+ovn-nbctl lb-add lb-tcp 66.66.66.66:80 42.42.42.2:8080 tcp
+ovn-nbctl lb-add lb-udp 66.66.66.66:80 42.42.42.2:8080 udp
+ovn-nbctl ls-lb-add ls lb-tcp
+ovn-nbctl ls-lb-add ls lb-udp
+
+# Remove stateless for TCP.
+ovn-nbctl acl-del pg
+ovn-nbctl --wait=sb sync
+
+# TCP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+# UDP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+# Allow stateless for TCP.
+for direction in from to; do
+ ovn-nbctl acl-add pg ${direction}-lport 1 tcp allow
+done
+ovn-nbctl --wait=sb sync
+
+# TCP packets should go to conntrack for load balancing.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+# UDP packets still go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${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
+ct_next(ct_state=new|trk) {
+ ct_lb {
+ reg0[[6]] = 0;
+ *** chk_lb_hairpin_reply action not implemented;
+ reg0[[12]] = 0;
+ ct_next(ct_state=new|trk) {
+ output("lsp2");
+ };
+ };
+};
+])
+
+AT_CLEANUP
+])
+
OVN_FOR_EACH_NORTHD([
AT_SETUP([ovn -- check BFD config propagation to SBDB])
AT_KEYWORDS([northd-bfd])
--
2.30.2
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev