Add a new "pass-related" action that behaves like "pass" for verdict (no verdict bit is set, so evaluation continues to the next tier) but follows the stateful path like "allow-related": it matches on hint registers, commits the connection via conntrack, and allows established/related traffic flows.
Reported-at: https://redhat.atlassian.net/browse/FDP-3166 Signed-off-by: Mairtin O'Loingsigh <[email protected]> --- NEWS | 3 + northd/en-acl-ids.c | 3 +- northd/en-ls-stateful.c | 5 +- northd/northd.c | 17 ++++-- ovn-nb.ovsschema | 7 ++- ovn-nb.xml | 24 +++++++- tests/ovn-nbctl.at | 6 +- tests/ovn-northd.at | 84 +++++++++++++++++++++++++++ tests/ovn.at | 123 ++++++++++++++++++++++++++++++++++++++++ tests/system-ovn.at | 87 ++++++++++++++++++++++++++++ utilities/ovn-nbctl.c | 19 ++++--- 11 files changed, 353 insertions(+), 25 deletions(-) diff --git a/NEWS b/NEWS index d1a6ad27f..d18800599 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ Post v26.03.0 ------------- + - Added "pass-related" ACL action, a stateful version of "pass" that + commits connections and allows established/related traffic through + the fast-path. - Load balancer health checks now "fail closed" for newly added backends: ovn-northd initializes a newly created Service_Monitor row to the "offline" state, so traffic is not forwarded to a backend until its first diff --git a/northd/en-acl-ids.c b/northd/en-acl-ids.c index 09c7955cb..79e8156d2 100644 --- a/northd/en-acl-ids.c +++ b/northd/en-acl-ids.c @@ -36,7 +36,8 @@ en_acl_id_init(struct engine_node *node OVS_UNUSED, static bool should_sync_to_sb(const struct nbrec_acl *nb_acl) { - return !strcmp(nb_acl->action, "allow-related") && + return (!strcmp(nb_acl->action, "allow-related") || + !strcmp(nb_acl->action, "pass-related")) && smap_get_bool(&nb_acl->options, "persist-established", false); diff --git a/northd/en-ls-stateful.c b/northd/en-ls-stateful.c index 1127b7d50..ab97e917b 100644 --- a/northd/en-ls-stateful.c +++ b/northd/en-ls-stateful.c @@ -468,8 +468,9 @@ ls_stateful_record_set_acls_(struct ls_stateful_record *ls_stateful_rec, const struct nbrec_acl *acl = acls[i]; update_ls_max_acl_tier(ls_stateful_rec, acl); uuidset_insert(&ls_stateful_rec->related_acls, &acl->header_.uuid); - if (!ls_stateful_rec->has_stateful_acl - && !strcmp(acl->action, "allow-related")) { + if (!ls_stateful_rec->has_stateful_acl && + (!strcmp(acl->action, "allow-related") || + !strcmp(acl->action, "pass-related"))) { ls_stateful_rec->has_stateful_acl = true; } } diff --git a/northd/northd.c b/northd/northd.c index 8ce06da78..035be09d7 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -7116,7 +7116,8 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl, ds_put_cstr(actions, "verdict=drop, "); } else if (!strcmp(acl->action, "reject")) { ds_put_cstr(actions, "verdict=reject, "); - } else if (!strcmp(acl->action, "pass")) { + } else if (!strcmp(acl->action, "pass") || + !strcmp(acl->action, "pass-related")) { ds_put_cstr(actions, "verdict=pass, "); } else if (!strcmp(acl->action, "allow") || !strcmp(acl->action, "allow-related") @@ -7522,7 +7523,8 @@ build_acl_sample_flows(const struct ls_stateful_record *ls_stateful_rec, bool should_sample_established = ls_stateful_rec->has_stateful_acl && acl->sample_est - && !strcmp(acl->action, "allow-related"); + && (!strcmp(acl->action, "allow-related") || + !strcmp(acl->action, "pass-related")); bool stateful_match = ls_stateful_rec->has_stateful_acl @@ -7631,7 +7633,8 @@ consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od, verdict = REGBIT_ACL_VERDICT_DROP " = 1; "; } else if (!strcmp(acl->action, "reject")) { verdict = REGBIT_ACL_VERDICT_REJECT " = 1; "; - } else if (!strcmp(acl->action, "pass")) { + } else if (!strcmp(acl->action, "pass") || + !strcmp(acl->action, "pass-related")) { verdict = ""; } else { verdict = REGBIT_ACL_VERDICT_ALLOW " = 1; "; @@ -7681,7 +7684,8 @@ consider_acl(struct lflow_table *lflows, const struct ovn_datapath *od, } if (!strcmp(acl->action, "allow") - || !strcmp(acl->action, "allow-related")) { + || !strcmp(acl->action, "allow-related") + || !strcmp(acl->action, "pass-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 @@ -8035,8 +8039,9 @@ build_acl_log_related_flows(const struct ovn_datapath *od, return; } - if (strcmp(acl->action, "allow") && strcmp(acl->action, "allow-related")) { - /* Not an allow ACL */ + if (strcmp(acl->action, "allow") && strcmp(acl->action, "allow-related") && + strcmp(acl->action, "pass-related")) { + /* Not an allow or pass-related ACL */ return; } diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index e5945b831..626b3def5 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "7.18.0", - "cksum": "1537030958 45190", + "version": "7.19.0", + "cksum": "956969323 45254", "tables": { "NB_Global": { "columns": { @@ -386,7 +386,8 @@ "enum": ["set", ["allow", "allow-related", "allow-stateless", "drop", - "reject", "pass"]]}}}, + "reject", "pass", + "pass-related"]]}}}, "network_function_group": { "type": {"key": {"type": "uuid", "refTable": "Network_Function_Group", diff --git a/ovn-nb.xml b/ovn-nb.xml index 33a6dc676..73f84706c 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -2888,7 +2888,7 @@ or For example, through this "label" we can backtrack to the ACL rule which is causing a "leaked" connection. Connection tracker entries are created only for allowed connections so the label is valid only - for allow and allow-related actions. + for allow, allow-related, and pass-related actions. </p> <p> @@ -2906,8 +2906,9 @@ or </p> <p> - Return traffic from an <code>allow-related</code> flow is always - allowed and cannot be changed through an ACL. + Return traffic from an <code>allow-related</code> or + <code>allow-related</code> flow is always allowed and cannot be + changed through an ACL. </p> <p> @@ -3004,6 +3005,23 @@ or option from the <ref table="NB_Global" /> table is used to determine how to proceed. </li> + + <li> + <code>pass-related</code>: A stateful version of + <code>pass</code>. Like <code>pass</code>, a match on this + action stops evaluating ACLs at the current tier and moves to + the next one. Unlike <code>pass</code>, the connection is + committed through conntrack, and established or related return + traffic (e.g. inbound replies to an outbound connection) is + allowed to bypass subsequent ACL evaluation, the same way it + does for <code>allow-related</code>. If not using ACL tiers + or if a <code>pass-related</code> ACL is matched at the final + tier, then the + <ref column="options" key="default_acl_drop" table="NB_Global" /> + option from the <ref table="NB_Global" /> table is used to + determine how to proceed. + </li> + </ul> </column> diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index bf3896361..d33a2a675 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -222,7 +222,8 @@ ovn_nbctl_test_acl() { AT_CHECK([ovn-nbctl $2 acl-add $1 from-lport 200 ip drop]) AT_CHECK([ovn-nbctl $2 acl-add $1 to-lport 100 ip drop]) AT_CHECK([ovn-nbctl $2 --label=1234 acl-add $1 from-lport 70 icmp allow-related]) - AT_CHECK([ovn-nbctl $2 --label=1235 acl-add $1 to-lport 70 icmp allow-related]) + AT_CHECK([ovn-nbctl $2 --tier=0 --label=1235 acl-add $1 to-lport 80 icmp pass-related]) + AT_CHECK([ovn-nbctl $2 --tier=1 --label=1235 acl-add $1 to-lport 70 icmp allow-related]) AT_CHECK([ovn-nbctl $2 --apply-after-lb acl-add $1 from-lport 500 tcp allow]) AT_CHECK([ovn-nbctl $2 --apply-after-lb acl-add $1 from-lport 300 tcp drop]) AT_CHECK([ovn-nbctl $2 --apply-after-lb acl-add $1 from-lport 300 udp allow]) @@ -256,7 +257,8 @@ from-lport 300 (udp) allow [[tier 0]] [[after-lb]] to-lport 500 (udp) drop log(name=test,severity=info) [[tier 0]] to-lport 300 (tcp) drop [[tier 0]] to-lport 100 (ip) drop [[tier 0]] - to-lport 70 (icmp) allow-related label=1235 [[tier 0]] + to-lport 80 (icmp) pass-related label=1235 [[tier 0]] + to-lport 70 (icmp) allow-related label=1235 [[tier 1]] ]) dnl Delete in one direction. diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 59ac23cdc..d2140ca09 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -11574,6 +11574,90 @@ OVN_CLEANUP_NORTHD AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([ACL "pass-related" logical flows]) +AT_KEYWORDS([acl]) + +ovn_start +check ovn-nbctl ls-add ls +check ovn-nbctl lsp-add ls lsp +check ovn-nbctl pg-add pg lsp + +m4_define([ACL_FLOWS], [grep -w $1 lflows | grep "$2" | ovn_strip_lflows | sed "s/\($1[[^)]]*\)/$1/" ]) + +acl_test() { + direction=$1 + options=$2 + thing=$3 + eval_stage=$4 + + ovn-sbctl lflow-list ls > lflows + AT_CHECK([ACL_FLOWS([$eval_stage], [priority=2000])], [0], []) + + # Unlike "pass" which generates a single stateless flow, "pass-related" + # goes through the stateful path and generates two flows: one matching + # REGBIT_ACL_HINT_ALLOW_NEW and one matching REGBIT_ACL_HINT_ALLOW. + # Neither sets a verdict bit. + check ovn-nbctl --wait=sb $options acl-add $thing $direction 1000 "ip4.addr == 80.111.111.112" pass-related + ovn-sbctl lflow-list ls > lflows + AT_CHECK_UNQUOTED([ACL_FLOWS([$eval_stage], [priority=2000])], [0], [dnl + table=??($eval_stage), priority=2000 , match=(reg0[[7]] == 1 && (ip4.addr == 80.111.111.112)), action=(next;) + table=??($eval_stage), priority=2000 , match=(reg0[[8]] == 1 && (ip4.addr == 80.111.111.112)), action=(next;) +]) + + check ovn-nbctl --wait=sb acl-del $thing + ovn-sbctl lflow-list ls > lflows + AT_CHECK([ACL_FLOWS([$eval_stage], [priority=2000])], [0], []) +} + +acl_test from-lport "" ls ls_in_acl_eval +acl_test from-lport "--apply-after-lb" ls ls_in_acl_after_lb_eval +acl_test to-lport "" ls ls_out_acl_eval +acl_test from-lport "" pg ls_in_acl_eval +acl_test from-lport "--apply-after-lb" pg ls_in_acl_after_lb_eval +acl_test to-lport "" pg ls_out_acl_eval + +OVN_CLEANUP_NORTHD +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([ACL "pass-related" with label]) +AT_KEYWORDS([acl]) + +ovn_start + +check ovn-nbctl \ + -- ls-add ls \ + -- lsp-add ls lsp1 \ + -- lsp-set-addresses lsp1 "00:00:00:00:00:01" \ + -- lsp-add ls lsp2 \ + -- lsp-set-addresses lsp2 "00:00:00:00:00:02" \ + -- lb-add lb-test 42.42.42.42:4242 43.43.43.43:4343 udp \ + -- ls-lb-add ls lb-test + +check ovn-nbctl --wait=sb --label=1234 acl-add ls from-lport 1 ip pass-related + +ovn-sbctl dump-flows ls > lflows +AT_CAPTURE_FILE([lflows]) + +dnl Verify label registers are set. Unlike allow-related, no verdict bit +dnl (reg8[[16]]) appears in the action. +AT_CHECK([grep -w "ls_in_acl_eval" lflows | grep 1001 | ovn_strip_lflows], [0], [dnl + table=??(ls_in_acl_eval ), priority=1001 , match=(reg0[[7]] == 1 && (ip)), action=(reg0[[13]] = 1; reg3 = 1234; reg9 = 1234; reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;) + table=??(ls_in_acl_eval ), priority=1001 , match=(reg0[[8]] == 1 && (ip)), action=(reg0[[1]] = 1; reg0[[13]] = 1; reg3 = 1234; reg9 = 1234; reg8[[0..7]] = 0; reg8[[8..15]] = 0; reg8[[19..20]] = 0; next;) +]) + +dnl Verify commit happens via ovn_trace. +flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02 && ip4.src == 42.42.42.1 && ip4.dst == 42.42.42.42 && ip.ttl==64 && udp.dst == 4242" +AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new --ct new ls "$flow" | grep -e ls_in_stateful -A 2 | grep commit], [0], [dnl + ct_commit { ct_mark.blocked = 0; ct_mark.allow_established = reg0[[20]]; ct_mark.obs_stage = reg8[[19..20]]; ct_mark.obs_collector_id = reg8[[8..15]]; ct_label.obs_point_id = reg9; ct_label.acl_id = reg2[[16..31]]; ct_label.nf = 0; ct_label.nf_id = 0; }; +]) + +OVN_CLEANUP_NORTHD +AT_CLEANUP +]) + OVN_FOR_EACH_NORTHD_NO_HV([ AT_SETUP([ACL - ct state clear on router ports]) AT_KEYWORDS([acl]) diff --git a/tests/ovn.at b/tests/ovn.at index 286395298..0455753b3 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -43672,6 +43672,129 @@ OVN_CLEANUP_NORTHD AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([ACL "pass-related" with drop on same tier]) +AT_KEYWORDS([acl]) + +ovn_start + +check ovn-nbctl \ + -- ls-add ls \ + -- lsp-add ls lsp1 \ + -- lsp-set-addresses lsp1 "00:00:00:00:00:01 10.0.0.1" \ + -- lsp-add ls lsp2 \ + -- lsp-set-addresses lsp2 "00:00:00:00:00:02 10.0.0.2" + +dnl Tier 0: pass-related at priority 500, drop at priority 450. +dnl Tier 1: allow-related at priority 400. +check ovn-nbctl --wait=sb \ + --tier=0 acl-add ls from-lport 500 "ip4.src == 10.0.0.1" pass-related \ + -- --tier=0 acl-add ls from-lport 450 "ip4" drop \ + -- --tier=1 acl-add ls from-lport 400 "ip4" allow-related + +flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02 && ip4.src == 10.0.0.1 && ip4.dst == 10.0.0.2 && ip.ttl == 64 && udp.dst == 80" + +dnl Verify pass-related generates stateful-path flows with hint register +dnl matches, unlike pass which uses the stateless path. +ovn-sbctl lflow-list ls > lflows +AT_CAPTURE_FILE([lflows]) +AT_CHECK([grep -w "ls_in_acl_eval" lflows | grep "10.0.0.1" | grep -qF "reg0"]) + +dnl New connection: pass-related on tier 0 sets no verdict, falls through to +dnl tier 1 where allow-related sets VERDICT_ALLOW. The ingress stateful stage +dnl commits the connection. +AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new ls "$flow" | grep -e ls_in_stateful -A 2 | grep commit], [0], [dnl + ct_commit { ct_mark.blocked = 0; ct_mark.allow_established = reg0[[20]]; ct_label.acl_id = reg2[[16..31]]; ct_label.nf = 0; ct_label.nf_id = 0; }; +]) + +dnl Established reply: hits the priority-65532 fast-path, bypasses the +dnl drop ACL entirely. Verify output is reached. +AT_CHECK([ovn_trace --ct est,rpl --ct est,rpl --minimal ls "$flow" | grep -q 'output("lsp2")']) + +OVN_CLEANUP_NORTHD +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([ACL "pass-related" multi-tier]) +AT_KEYWORDS([acl]) + +ovn_start + +check ovn-nbctl \ + -- ls-add ls \ + -- lsp-add ls lsp1 \ + -- lsp-set-addresses lsp1 "00:00:00:00:00:01 10.0.0.1" \ + -- lsp-add ls lsp2 \ + -- lsp-set-addresses lsp2 "00:00:00:00:00:02 10.0.0.2" + +dnl Tier 0: pass-related. Tier 1: allow-related. +check ovn-nbctl --wait=sb --tier=0 acl-add ls from-lport 500 "ip4.src == 10.0.0.1" pass-related +check ovn-nbctl --wait=sb --tier=1 acl-add ls from-lport 400 "ip4" allow-related + +flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02 && ip4.src == 10.0.0.1 && ip4.dst == 10.0.0.2 && ip.ttl == 64 && udp.dst == 80" + +dnl Verify tier increment flow exists in the action stage. +ovn-sbctl lflow-list ls > lflows +AT_CAPTURE_FILE([lflows]) +AT_CHECK([grep -w "ls_in_acl_action" lflows | grep "priority=500" | ovn_strip_lflows | grep -q "next(pipeline=ingress,table=??)"]) +dnl New connection passes tier 0 (pass-related) and tier 1 (allow-related), +dnl gets committed in the ingress stateful stage. +AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new ls "$flow" | grep -e ls_in_stateful -A 2 | grep commit], [0], [dnl + ct_commit { ct_mark.blocked = 0; ct_mark.allow_established = reg0[[20]]; ct_label.acl_id = reg2[[16..31]]; ct_label.nf = 0; ct_label.nf_id = 0; }; +]) + +dnl Established reply uses the fast-path. +AT_CHECK([ovn_trace --ct est,rpl --ct est,rpl --minimal ls "$flow" | grep -q 'output("lsp2")']) + +dnl Remove the tier 1 ACL. With only tier 0 pass-related and no explicit +dnl tier 1 ACL, the default action (allow) applies after the pass. +check ovn-nbctl --wait=sb acl-del ls +check ovn-nbctl --wait=sb \ + --tier=0 acl-add ls from-lport 500 "ip4.src == 10.0.0.1" pass-related + +dnl pass-related alone makes the switch stateful, so the connection +dnl gets committed even without an explicit tier 1 ACL. +AT_CHECK_UNQUOTED([ovn_trace --ct new --ct new ls "$flow" | grep -e ls_in_stateful -A 2 | grep commit], [0], [dnl + ct_commit { ct_mark.blocked = 0; ct_mark.allow_established = reg0[[20]]; ct_label.acl_id = reg2[[16..31]]; ct_label.nf = 0; ct_label.nf_id = 0; }; +]) + +OVN_CLEANUP_NORTHD +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([ACL "pass-related" ICMP related traffic]) +AT_KEYWORDS([acl]) + +ovn_start + +check ovn-nbctl \ + -- ls-add ls \ + -- lsp-add ls lsp1 \ + -- lsp-set-addresses lsp1 "00:00:00:00:00:01 10.0.0.1" \ + -- lsp-add ls lsp2 \ + -- lsp-set-addresses lsp2 "00:00:00:00:00:02 10.0.0.2" + +dnl Tier 0: pass-related at priority 500, drop at priority 450. +dnl Tier 1: allow-related at priority 400. +check ovn-nbctl --wait=sb \ + --tier=0 acl-add ls from-lport 500 "ip4.src == 10.0.0.1" pass-related \ + -- --tier=0 acl-add ls from-lport 450 "ip4" drop \ + -- --tier=1 acl-add ls from-lport 400 "ip4" allow-related + +flow="inport == \"lsp1\" && eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02 && ip4.src == 10.0.0.1 && ip4.dst == 10.0.0.2 && ip.ttl == 64 && udp.dst == 80" + +dnl Related traffic (e.g., ICMP destination-unreachable) for a committed +dnl connection hits the ct.rel fast-path at priority 65532 and is allowed +dnl through with ct_commit_nat, bypassing the drop ACL on tier 0. +AT_CHECK([ovn_trace --ct rel --ct rel ls "$flow" | grep -q "ct_commit_nat"]) +AT_CHECK([ovn_trace --ct rel --ct rel --minimal ls "$flow" | grep -q 'output("lsp2")']) + +OVN_CLEANUP_NORTHD +AT_CLEANUP +]) + OVN_FOR_EACH_NORTHD_NO_HV([ AT_SETUP([ovn-controller -- local datapaths check]) ovn_start diff --git a/tests/system-ovn.at b/tests/system-ovn.at index 17b4dcb3d..8c7685b9b 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -21859,6 +21859,93 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ACL pass-related conntrack]) +AT_KEYWORDS([acl]) + +CHECK_CONNTRACK() +ovn_start + +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +check ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +start_daemon ovn-controller + +check ovn-nbctl ls-add sw0 + +check ovn-nbctl lsp-add sw0 sw0-p1 +check ovn-nbctl lsp-set-addresses sw0-p1 "50:54:00:00:00:03 10.0.0.3" +check ovn-nbctl lsp-set-port-security sw0-p1 "50:54:00:00:00:03 10.0.0.3" + +check ovn-nbctl lsp-add sw0 sw0-p2 +check ovn-nbctl lsp-set-addresses sw0-p2 "50:54:00:00:00:04 10.0.0.4" +check ovn-nbctl lsp-set-port-security sw0-p2 "50:54:00:00:00:04 10.0.0.4" + +ADD_NAMESPACES(sw0-p1) +ADD_VETH(sw0-p1, sw0-p1, br-int, "10.0.0.3/24", "50:54:00:00:00:03", \ + "10.0.0.1") + +ADD_NAMESPACES(sw0-p2) +ADD_VETH(sw0-p2, sw0-p2, br-int, "10.0.0.4/24", "50:54:00:00:00:04", \ + "10.0.0.1") + +wait_for_ports_up sw0-p1 sw0-p2 +check ovn-nbctl --wait=hv sync + +dnl Phase 1: pass-related alone creates conntrack entries. +dnl Unlike plain "pass", pass-related makes the switch stateful and commits +dnl connections to conntrack even without an explicit allow-related ACL. +check ovn-nbctl --wait=sb acl-add sw0 from-lport 1000 "ip4.src == 10.0.0.3" pass-related +check ovn-nbctl --wait=hv sync + +NS_CHECK_EXEC([sw0-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.0.0.4) | \ +sed -e 's/zone=[[0-9]]*/zone=<cleared>/' | grep icmp], [0], [ignore]) +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.0.0.3) | \ +sed -e 's/zone=[[0-9]]*/zone=<cleared>/' | grep icmp], [0], [ignore]) + +dnl Phase 2: Multi-tier with drop bypass. +dnl pass-related at higher priority skips the drop, falls through to tier 1 +dnl where allow-related commits the connection. Reply traffic uses +dnl the established fast-path, bypassing the tier 0 drop ACL. +check ovn-nbctl acl-del sw0 +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) +check ovn-nbctl --wait=hv sync + +check ovn-nbctl --tier=0 acl-add sw0 from-lport 1000 "ip4.src == 10.0.0.3" pass-related +check ovn-nbctl --tier=0 acl-add sw0 from-lport 500 "ip4" drop +check ovn-nbctl --tier=1 acl-add sw0 from-lport 1000 "ip4" allow-related +check ovn-nbctl --wait=hv sync + +NS_CHECK_EXEC([sw0-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.0.4 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(10.0.0.4) | \ +sed -e 's/zone=[[0-9]]*/zone=<cleared>/' | grep icmp], [0], [ignore]) + +OVN_CLEANUP_CONTROLLER([hv1]) +OVN_CLEANUP_NORTHD + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/connection dropped.*/d"]) + +AT_CLEANUP +]) + OVN_FOR_EACH_NORTHD([ AT_SETUP([DHCPv6 - Options heap overread]) CHECK_SCAPY diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 4e2271d07..b3a0290c9 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -2951,10 +2951,11 @@ nbctl_acl_add(struct ctl_context *ctx) /* Validate action. */ if (strcmp(action, "allow") && strcmp(action, "allow-related") && strcmp(action, "allow-stateless") && strcmp(action, "drop") - && strcmp(action, "reject") && strcmp(action, "pass")) { + && strcmp(action, "reject") && strcmp(action, "pass") + && strcmp(action, "pass-related")) { ctl_error(ctx, "%s: action must be one of \"allow\", " "\"allow-related\", \"allow-stateless\", \"drop\", " - "and \"reject\"", action); + "\"pass\", \"pass-related\", and \"reject\"", action); return; } @@ -3027,12 +3028,14 @@ nbctl_acl_add(struct ctl_context *ctx) /* Set the ACL label */ const char *label = shash_find_data(&ctx->options, "--label"); if (label) { - /* Ensure that the action is either allow or allow-related */ - if (strcmp(action, "allow") && strcmp(action, "allow-related")) { - ctl_error(ctx, "label can only be set with actions \"allow\" or " - "\"allow-related\""); - return; - } + /* Ensure that the action is either allow, allow-related or + * pass-related */ + if (strcmp(action, "allow") && strcmp(action, "allow-related") && + strcmp(action, "pass-related")) { + ctl_error(ctx, "label can only be set with actions \"allow\", " + "\"allow-related\" or \"pass-related\""); + return; + } int64_t label_value = 0; error = parse_acl_label(label, &label_value); -- 2.54.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
