From patchwork Thu May 6 14:34:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ihar Hrachyshka X-Patchwork-Id: 1475039 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=EfXVE6LC; dkim-atps=neutral Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4Fbbhg3hJzz9sWY for ; Fri, 7 May 2021 00:35:15 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 4108160775; Thu, 6 May 2021 14:35:13 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2RU2hjs07NaO; Thu, 6 May 2021 14:35:11 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTP id 4E80960633; Thu, 6 May 2021 14:35:10 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2C1A8C000E; Thu, 6 May 2021 14:35:10 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 14014C0001 for ; Thu, 6 May 2021 14:35:08 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id EF9394028B for ; Thu, 6 May 2021 14:35:07 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Authentication-Results: smtp2.osuosl.org (amavisd-new); dkim=pass (1024-bit key) header.d=redhat.com Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WzSj7DyxtltI for ; Thu, 6 May 2021 14:35:05 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp2.osuosl.org (Postfix) with ESMTPS id B3D60401EB for ; Thu, 6 May 2021 14:35:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1620311703; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=nB1Cui/DXNn+6DpoBdgKRCfiSIyyZL7v+Cy8l57ohlA=; b=EfXVE6LCxGmCZ//uRAnuiYwUoROY66CuyZ2HuY6Ei3HxUK1borkwtMpUvqIof/qaKpp0bF sR9rQECxRYi7mcZDMrROv3Oxmio8bzj23bSNplETdMCJCv2vt9a0B+j6j0VcBoZ85Zsy3r iNZ2OTFbKSzUnPI0x1FZ8dVlgTVnFks= Received: from mail-qv1-f71.google.com (mail-qv1-f71.google.com [209.85.219.71]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-424-amJrEKU5Ov63Cc7nTSExcQ-1; Thu, 06 May 2021 10:34:57 -0400 X-MC-Unique: amJrEKU5Ov63Cc7nTSExcQ-1 Received: by mail-qv1-f71.google.com with SMTP id t1-20020a0ca6810000b029019e892416e6so4249777qva.9 for ; Thu, 06 May 2021 07:34:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=nB1Cui/DXNn+6DpoBdgKRCfiSIyyZL7v+Cy8l57ohlA=; b=B2HgJEITdvJ7Ue6myuhrzynDM5OWWbdFWlT3m9KWDhh3MBwx78wqPInCyCTFFU4gF5 8mqNaqNG30lcgRpPoPk0AjItvnM8vk91ket1aLWQFX7QdeCDlDAcRJOaEfYapNQOYjDJ t36cKKA0DsKvRflInxUpFW48YeQ7Z87lY3UCEl5NMXk4mG+Gq3yhO/JulsnzNZfNuA5F KCt7RcEts2EFKJ5Ouv7A3/DqwtzrEKv1wuoHQtvv55oS6Tva3uh101hGwOJAH3xHMGCP mb1iCmRRgAnN6uhVO3TDNOrn5DvBoKPpgPUMJPmWmIpo0bB9M642BEzW1kPfxMtQQiDs QHxQ== X-Gm-Message-State: AOAM532jwIJOoQeCEwwTG0R3iSExrL9zxBX6+VdiyLGY15lEvCk5AGm4 aky3zEJWsCqwMWMWOHybrNlzFlWNJU48q2xVqxGLtEPsYwkNaefwSK6sdEb9lSgWxMXoNsWR8z4 tWjR+BdGFBdgVTWPwrXCWB0841HFp20CfS/PG4CQxe6l5GxF/CxDdzeRlt/4nXzPn X-Received: by 2002:a05:622a:50a:: with SMTP id l10mr4411402qtx.235.1620311693914; Thu, 06 May 2021 07:34:53 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxxBFzV6n0xqOLzBj81S3xUIY9Pj8rSwTK0T8W7WfqPmse1ix7UPGd3kwuBeatV5PZC6/HJbw== X-Received: by 2002:a05:622a:50a:: with SMTP id l10mr4411343qtx.235.1620311693232; Thu, 06 May 2021 07:34:53 -0700 (PDT) Received: from localhost.localdomain.com (cpe-172-73-180-250.carolina.res.rr.com. [172.73.180.250]) by smtp.googlemail.com with ESMTPSA id c20sm2482725qtg.84.2021.05.06.07.34.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 06 May 2021 07:34:51 -0700 (PDT) From: Ihar Hrachyshka To: dev@openvswitch.org Date: Thu, 6 May 2021 10:34:46 -0400 Message-Id: <20210506143446.638103-1-ihrachys@redhat.com> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=ihrachys@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH v9 ovn] ovn-northd: introduce new allow-stateless ACL verb X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" For allow-stateless ACLs, bypass connection tracking by avoiding setting ct hints for matching traffic. Avoid sending all traffic to ct when a stateful ACL is present. === Reusing an existing 'allow' verb for stateless matching would have its drawbacks, specifically, when it comes to backwards incompatibility of the new behavior with existing environments. When using "allow" ACLs in mixed allow/allow-related environment, we still commit "allow" traffic to conntrack. This unnecessarily hits performance when mixed ACL action types were used for the same datapath. This is why we introduce 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 has to define 'allow-stateless' 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, qperf was used. Tests were executed on two setups: 1) ovn-fake-multinode virtual environment; 2) Supermicro SYS-5039MS-H8TRF 3-node RH-OSP 16.x cluster with 2 compute nodes, NIC: "Intel Corporation Ethernet Controller XXV710 for 25GbE SFP28 (rev 02)", using fake_nova_driver to avoid qemu overhead. 1) ovn-fake-multinode: 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 _lat and _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-stateless` 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-stateless ovn-nbctl acl-add sw0 from-lport 100 tcp allow-stateless ovn-nbctl acl-add sw1 to-lport 100 tcp allow-stateless ovn-nbctl acl-add sw1 from-lport 100 tcp allow-stateless 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%) 2) Supermicro RH-OSP cluster: Two scenarios executed: - connectivity between two ports on the same switch - connectivity between two ports on different switches connected via router For the same switch, improvements are as follows: - TCP latency: -5.3%, UDP latency: -13.5%, SCTP latency: -10.8% - TCP bw: +0.8%, UDP bw, +12.25%, SCTP bw: +21.29% For different switches, improvements are as follows: - TCP latency: -6%, UDP: -11.2%, SCTP: -0.2% - TCP bw: -0.7%, UDP bw: +2%, SCTP bw: +9.9% The effect is more noticeable in same switch scenario. 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 --- 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. v4: introduce a separate allow-stateless ACL match verb. v5: rebased. v6: updated docs for new allow-stateless approach. v6: removed no longer valid comments. v6: removed acl_is_stateless. v7: bump north db schema version to 5.31.0 -> 5.32.0. v8: fixed checkpatch failure on a too long line in dbschema. v8: added perf data on baremetal lab testing. v9: fixed ovsdb checksum. --- NEWS | 2 + northd/ovn-northd.8.xml | 8 +- northd/ovn-northd.c | 65 ++++++++- northd/ovn_northd.dl | 31 ++++ ovn-nb.ovsschema | 9 +- ovn-nb.xml | 9 +- tests/ovn-northd.at | 309 ++++++++++++++++++++++++++++++++++++++++ utilities/ovn-nbctl.c | 6 +- 8 files changed, 428 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 1ddde15f8..d72139e76 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ Post-v21.03.0 'use_parallel_build' to enable it. It is disabled by default. - Support vlan-passthru mode for tag=0 localnet ports. - Support custom 802.11ad EthType for localnet ports. + - Introduce a new "allow-stateless" ACL verb to always bypass connection + tracking. The existing "allow" verb behavior is left intact. OVN v21.03.0 - 12 Mar 2021 ------------------------- diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 54e88d3fa..08c4ea852 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -419,7 +419,9 @@ before eventually advancing to ingress table ACLs. 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 "allow-stateless" + ACLs, a flow is added to bypass setting the hint for connection tracker + processing.

@@ -614,6 +616,10 @@ for new connections and reg0[1] = 1; next; for existing connections. +

  • + allow-stateless ACLs translate into logical + flows with the next; action. +
  • reject ACLs translate into logical flows with the diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 94fae5648..4032f1441 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -4974,7 +4974,52 @@ 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) +{ + 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 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 (!strcmp(acl->action, "allow-stateless")) { + 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 (!strcmp(acl->action, "allow-stateless")) { + 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. */ @@ -5002,6 +5047,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 @@ -5369,7 +5416,8 @@ build_acl_log(struct ds *actions, const struct nbrec_acl *acl, } else if (!strcmp(acl->action, "reject")) { ds_put_cstr(actions, "verdict=reject, "); } else if (!strcmp(acl->action, "allow") - || !strcmp(acl->action, "allow-related")) { + || !strcmp(acl->action, "allow-related") + || !strcmp(acl->action, "allow-stateless")) { ds_put_cstr(actions, "verdict=allow, "); } @@ -5428,7 +5476,16 @@ 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") + if (!strcmp(acl->action, "allow-stateless")) { + 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") || !strcmp(acl->action, "allow-related")) { /* If there are any stateful flows, we must even commit "allow" * actions. This is because, while the initiater's @@ -6828,7 +6885,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 7953325aa..5ae52b3e8 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -1824,6 +1824,27 @@ for (&Switch(.ls =ls)) { .external_ids = map_empty()) } +for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_meter)) { + if (sw.has_stateful_acl) { + if (acl.action == "allow-stateless") { + 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 @@ -2168,6 +2189,9 @@ function build_acl_log(acl: nb::ACL, fair_meter: bool): string = "allow-related" -> { strs.push("verdict=allow") }, + "allow-stateless" -> { + strs.push("verdict=allow") + }, _ -> () }; match (acl.meter) { @@ -2546,6 +2570,13 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_ .actions = "${acl_log}next;", .external_ids = stage_hint) } + } else if (acl.action == "allow-stateless") { + 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 == "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/ovn-nb.ovsschema b/ovn-nb.ovsschema index 29019809c..faf619a1c 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.31.0", - "cksum": "2352750632 28701", + "version": "5.32.0", + "cksum": "204590300 28863", "tables": { "NB_Global": { "columns": { @@ -221,7 +221,10 @@ "enum": ["set", ["from-lport", "to-lport"]]}}}, "match": {"type": "string"}, "action": {"type": {"key": {"type": "string", - "enum": ["set", ["allow", "allow-related", "drop", "reject"]]}}}, + "enum": ["set", + ["allow", "allow-related", + "allow-stateless", "drop", + "reject"]]}}}, "log": {"type": "boolean"}, "severity": {"type": {"key": {"type": "string", "enum": ["set", diff --git a/ovn-nb.xml b/ovn-nb.xml index feb38b5d3..5386c8fef 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -1791,7 +1791,9 @@

    The action to take when the ACL rule matches:

    • - allow: Forward the packet. + allow: Forward the packet. It will also send the + packets through connection tracking when + allow-related rules exist on the logical switch.
    • @@ -1799,6 +1801,11 @@ (e.g. inbound replies to an outbound connection).
    • +
    • + allow-stateless: Always forward the packet in stateless + manner. May require defining additional rules for inbound replies. +
    • +
    • drop: Silently drop the packet.
    • diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index 32afb4fa8..f62526fd3 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -2592,6 +2592,315 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == /' | sort], [0], AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD([ +AT_SETUP([ovn -- ACL allow-stateless 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-stateless +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-stateless +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-stateless 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-stateless +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-stateless +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]) diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 042c21002..48fd0b7ee 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -2303,9 +2303,11 @@ nbctl_acl_add(struct ctl_context *ctx) /* Validate action. */ if (strcmp(action, "allow") && strcmp(action, "allow-related") - && strcmp(action, "drop") && strcmp(action, "reject")) { + && strcmp(action, "allow-stateless") && strcmp(action, "drop") + && strcmp(action, "reject")) { ctl_error(ctx, "%s: action must be one of \"allow\", " - "\"allow-related\", \"drop\", and \"reject\"", action); + "\"allow-related\", \"allow-stateless\", \"drop\", " + "and \"reject\"", action); return; }