From patchwork Wed May 29 15:56:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ales Musil X-Patchwork-Id: 1941334 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=AZ4gp9el; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VqDXG0Dg3z20Q9 for ; Thu, 30 May 2024 01:56:44 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 31E9840BFA; Wed, 29 May 2024 15:56:41 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id eKvI3U6mw98I; Wed, 29 May 2024 15:56:40 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 1C48C40111 Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=AZ4gp9el Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTPS id 1C48C40111; Wed, 29 May 2024 15:56:40 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id D6F3CC0072; Wed, 29 May 2024 15:56:39 +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 BD00FC0037 for ; Wed, 29 May 2024 15:56:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 9EBB740992 for ; Wed, 29 May 2024 15:56:38 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id A9eFGwqVN_tN for ; Wed, 29 May 2024 15:56:37 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp2.osuosl.org 9780F40111 Authentication-Results: smtp2.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org 9780F40111 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 9780F40111 for ; Wed, 29 May 2024 15:56:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716998196; 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: in-reply-to:in-reply-to:references:references; bh=KBssU2rOxaskfpnJWPwv66znwt2s0lS4d0tdDDCKs44=; b=AZ4gp9el8fd+N+3mtbDtKT+hSOsfXNqdfh1JhzJww8lmGHYJ1sQ7DPEX316knEjJE29ksZ 71wJIGUzqa9AD5St4f6MHHtLP0Z9K0Ddnv0b4xWvJEtSe0y/I/a8c38NSO6pUfx/ZTszou rtSfWuCHZMOG71CxOl5VU680MaGFunw= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-486-WTA7BGqtMxCW4rQvBnKpgg-1; Wed, 29 May 2024 11:56:34 -0400 X-MC-Unique: WTA7BGqtMxCW4rQvBnKpgg-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C758D3806701 for ; Wed, 29 May 2024 15:56:33 +0000 (UTC) Received: from amusil.redhat.com (unknown [10.45.225.45]) by smtp.corp.redhat.com (Postfix) with ESMTP id DFCDF492BC6; Wed, 29 May 2024 15:56:32 +0000 (UTC) From: Ales Musil To: dev@openvswitch.org Date: Wed, 29 May 2024 17:56:28 +0200 Message-ID: <20240529155630.478992-2-amusil@redhat.com> In-Reply-To: <20240529155630.478992-1-amusil@redhat.com> References: <20240529155630.478992-1-amusil@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH ovn v2 1/3] nothd: Unify the priority calculation for NAT flows. 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" The priority calculation was scattered in multiple places which could result in errors when the code is being updated. Move it to common function that makes it very clear how is the priority calculated. Signed-off-by: Ales Musil Acked-by: Mark Michelson --- v2: Rebase on top of current main. Add ack from Mark. --- northd/northd.c | 82 +++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 50 deletions(-) diff --git a/northd/northd.c b/northd/northd.c index a78cbcd53..c5f69f469 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -11566,6 +11566,25 @@ lrouter_dnat_and_snat_is_stateless(const struct nbrec_nat *nat) !strcmp(nat->type, "dnat_and_snat"); } +static inline uint16_t +lrouter_nat_get_priority(const struct ovn_datapath *od, bool is_dnat, + uint16_t prefix_len) +{ + if (is_dnat) { + return 100; + } + + /* The priority here is calculated such that the + * nat->logical_ip with the longest mask gets a higher + * priority. */ + uint16_t priority = prefix_len + 1; + if (!od->is_gw_router && od->n_l3dgw_ports) { + priority += 128; + } + + return priority; +} + /* Handles the match criteria and actions in logical flow * based on external ip based NAT rule filter. * @@ -11596,7 +11615,6 @@ lrouter_nat_add_ext_ip_match(const struct ovn_datapath *od, } else if (exempted_ext_ips) { struct ds match_exempt = DS_EMPTY_INITIALIZER; enum ovn_stage stage = is_src ? S_ROUTER_IN_DNAT : S_ROUTER_OUT_SNAT; - uint16_t priority; /* Priority of logical flows corresponding to exempted_ext_ips is * +2 of the corresponding regular NAT rule. @@ -11612,17 +11630,8 @@ lrouter_nat_add_ext_ip_match(const struct ovn_datapath *od, * lr_out_snat...priority=161, match=(..), action=(ct_snat(....);) * */ - if (is_src) { - /* S_ROUTER_IN_DNAT uses priority 100 */ - priority = 100 + 2; - } else { - /* S_ROUTER_OUT_SNAT uses priority (mask + 1 + 128 + 1) */ - priority = cidr_bits + 3; - - if (!od->is_gw_router) { - priority += 128; - } - } + uint16_t priority = + lrouter_nat_get_priority(od, is_src, cidr_bits) + 2; ds_clone(&match_exempt, match); ds_put_format(&match_exempt, " && ip%s.%s == $%s", @@ -14637,7 +14646,8 @@ build_lrouter_in_dnat_flow(struct lflow_table *lflows, ds_put_format(actions, ");"); } - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, 100, + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, + lrouter_nat_get_priority(od, true, cidr_bits), ds_cstr(match), ds_cstr(actions), &nat->header_, lflow_ref); } @@ -14780,25 +14790,14 @@ build_lrouter_out_snat_stateless_flow(struct lflow_table *lflows, ds_clear(actions); - /* The priority here is calculated such that the - * nat->logical_ip with the longest mask gets a higher - * priority. */ - uint16_t priority = cidr_bits + 1; - + uint16_t priority = lrouter_nat_get_priority(od, false, cidr_bits); build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat, cidr_bits, is_v6, l3dgw_port, lflow_ref, false); - if (!od->is_gw_router) { - /* Distributed router. */ - if (od->n_l3dgw_ports) { - priority += 128; - } - - if (distributed_nat) { - ds_put_format(actions, "eth.src = "ETH_ADDR_FMT"; ", - ETH_ADDR_ARGS(mac)); - } + if (!od->is_gw_router && distributed_nat) { + ds_put_format(actions, "eth.src = "ETH_ADDR_FMT"; ", + ETH_ADDR_ARGS(mac)); } ds_put_format(actions, "ip%c.src=%s; next;", @@ -14826,20 +14825,13 @@ build_lrouter_out_snat_in_czone_flow(struct lflow_table *lflows, ds_clear(actions); - /* The priority here is calculated such that the - * nat->logical_ip with the longest mask gets a higher - * priority. */ - uint16_t priority = cidr_bits + 1; + uint16_t priority = lrouter_nat_get_priority(od, false, cidr_bits); struct ds zone_actions = DS_EMPTY_INITIALIZER; build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat, cidr_bits, is_v6, l3dgw_port, lflow_ref, false); - if (od->n_l3dgw_ports) { - priority += 128; - } - if (distributed_nat) { ds_put_format(actions, "eth.src = "ETH_ADDR_FMT"; ", ETH_ADDR_ARGS(mac)); @@ -14892,26 +14884,16 @@ build_lrouter_out_snat_flow(struct lflow_table *lflows, ds_clear(actions); - /* The priority here is calculated such that the - * nat->logical_ip with the longest mask gets a higher - * priority. */ - uint16_t priority = cidr_bits + 1; + uint16_t priority = lrouter_nat_get_priority(od, false, cidr_bits); build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat, cidr_bits, is_v6, l3dgw_port, lflow_ref, false); size_t original_match_len = match->length; - if (!od->is_gw_router) { - /* Distributed router. */ - if (od->n_l3dgw_ports) { - priority += 128; - } - - if (distributed_nat) { - ds_put_format(actions, "eth.src = "ETH_ADDR_FMT"; ", - ETH_ADDR_ARGS(mac)); - } + if (!od->is_gw_router && distributed_nat) { + ds_put_format(actions, "eth.src = "ETH_ADDR_FMT"; ", + ETH_ADDR_ARGS(mac)); } ds_put_cstr(match, " && (!ct.trk || !ct.rpl)"); From patchwork Wed May 29 15:56:29 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ales Musil X-Patchwork-Id: 1941336 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=OR4avDIR; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VqDXQ6y7Zz20Pb for ; Thu, 30 May 2024 01:56:54 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 0E56482998; Wed, 29 May 2024 15:56:52 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id zVw1dZ_HgBWC; Wed, 29 May 2024 15:56:45 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=140.211.9.56; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 9F8F8824DD Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=OR4avDIR Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTPS id 9F8F8824DD; Wed, 29 May 2024 15:56:44 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BB9DCC0DD3; Wed, 29 May 2024 15:56:43 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 047BDC0DD2 for ; Wed, 29 May 2024 15:56:41 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id C8D6160B4A for ; Wed, 29 May 2024 15:56:40 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 3lkhl0aZYdDh for ; Wed, 29 May 2024 15:56:39 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org CFBDF6081C Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org CFBDF6081C Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=OR4avDIR Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id CFBDF6081C for ; Wed, 29 May 2024 15:56:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716998197; 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: in-reply-to:in-reply-to:references:references; bh=mtV1vQEbM+3WcS/b2bVaj9EPR8L3cgObjLC6FiXN4k4=; b=OR4avDIR8hArdUwxgWUWaNriohVl+g3fgWAogCuJCXOs2E8v2zSi2JfNuxmSdHzfgopDr8 V8Aj9RLQJ8XP+tdy8BRSD0ARAS188AxyXzKH8WWnvBfH0IMxGhoG/Tb3q484Jhzp/Ij+Ft ZIrVJoxVZddb08B2WarEjhtf3WE6pRI= Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-547-qHeANGZFOn-rEXOpYg9iYQ-1; Wed, 29 May 2024 11:56:35 -0400 X-MC-Unique: qHeANGZFOn-rEXOpYg9iYQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 481FC3806701 for ; Wed, 29 May 2024 15:56:35 +0000 (UTC) Received: from amusil.redhat.com (unknown [10.45.225.45]) by smtp.corp.redhat.com (Postfix) with ESMTP id 238D4492BC6; Wed, 29 May 2024 15:56:33 +0000 (UTC) From: Ales Musil To: dev@openvswitch.org Date: Wed, 29 May 2024 17:56:29 +0200 Message-ID: <20240529155630.478992-3-amusil@redhat.com> In-Reply-To: <20240529155630.478992-1-amusil@redhat.com> References: <20240529155630.478992-1-amusil@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH ovn v2 2/3] nb: Add support for match and priority in NAT. 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" Add support for match and priority in NAT table. This allows to define NAT that has extra match condition to have more fine-grained control over the final NAT rule application. At the same time it allows for NAT rules that would be considered as duplicates otherwise e.g. multiple SNATs with same logical IP, but different external IP. Also, when the match is specified allow addition of priority to order the NAT rule valuation as needed. Signed-off-by: Ales Musil --- v2: Rebase on top of current main. --- ovn-nb.ovsschema | 8 +- ovn-nb.xml | 15 +++ tests/ovn-nbctl.at | 220 +++++++++++++++++++++++++++----------- utilities/ovn-nbctl.8.xml | 14 ++- utilities/ovn-nbctl.c | 189 ++++++++++++++++++++------------ 5 files changed, 307 insertions(+), 139 deletions(-) diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema index 10ce50b25..e3c4aff9d 100644 --- a/ovn-nb.ovsschema +++ b/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "7.3.1", - "cksum": "3899022625 35372", + "version": "7.4.0", + "cksum": "1908497390 35615", "tables": { "NB_Global": { "columns": { @@ -524,6 +524,10 @@ "refType": "weak"}, "min": 0, "max": 1}}, + "priority": {"type": {"key": {"type": "integer", + "minInteger": 0, + "maxInteger": 32767}}}, + "match": {"type": "string"}, "options": {"type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}, "external_ids": { diff --git a/ovn-nb.xml b/ovn-nb.xml index 7bc77da68..ed5ad5b1a 100644 --- a/ovn-nb.xml +++ b/ovn-nb.xml @@ -3935,6 +3935,21 @@ or

+ + The packets that the NAT rules should match, in addition to the match + that is created based on the NAT type, in the same expression + language used for the column in the OVN + Southbound database's + table. This allows for more fine-grained control over the NAT rule. + + + + The NAT rule's priority. Rules with numerically higher priority + take precedence over those with lower. The priority is taken into + account only if the match is defined. + + Indicates if a dnat_and_snat rule should lead to connection tracking state or not. diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 5248e6c76..19c83a4a5 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -625,15 +625,15 @@ AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat fd01::1 fd11::2]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.3 lp0 00:00:00:01:02:03]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat fd01::2 fd11::3 lp0 00:00:00:01:02:03]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -dnat 30.0.0.1 192.168.1.2 -dnat fd01::1 fd11::2 -dnat_and_snat 30.0.0.1 192.168.1.2 -dnat_and_snat 30.0.0.2 192.168.1.3 00:00:00:01:02:03 lp0 -dnat_and_snat fd01::1 fd11::2 -dnat_and_snat fd01::2 fd11::3 00:00:00:01:02:03 lp0 -snat 30.0.0.1 192.168.1.0/24 -snat fd01::1 fd11::/64 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 30.0.0.1 192.168.1.2 +dnat fd01::1 fd11::2 +dnat_and_snat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.2 192.168.1.3 00:00:00:01:02:03 lp0 +dnat_and_snat fd01::1 fd11::2 +dnat_and_snat fd01::2 fd11::3 00:00:00:01:02:03 lp0 +snat 30.0.0.1 192.168.1.0/24 +snat fd01::1 fd11::/64 ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.1 192.168.1.0/24], [1], [], [ovn-nbctl: 30.0.0.1, 192.168.1.0/24: a NAT with this external_ip and logical_ip already exists @@ -661,28 +661,28 @@ AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.1 192.168.1.3], [1], [], ]) AT_CHECK([ovn-nbctl --may-exist lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.3 lp0 00:00:00:04:05:06]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -dnat 30.0.0.1 192.168.1.2 -dnat fd01::1 fd11::2 -dnat_and_snat 30.0.0.1 192.168.1.2 -dnat_and_snat 30.0.0.2 192.168.1.3 00:00:00:04:05:06 lp0 -dnat_and_snat fd01::1 fd11::2 -dnat_and_snat fd01::2 fd11::3 00:00:00:01:02:03 lp0 -snat 30.0.0.1 192.168.1.0/24 -snat fd01::1 fd11::/64 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 30.0.0.1 192.168.1.2 +dnat fd01::1 fd11::2 +dnat_and_snat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.2 192.168.1.3 00:00:00:04:05:06 lp0 +dnat_and_snat fd01::1 fd11::2 +dnat_and_snat fd01::2 fd11::3 00:00:00:01:02:03 lp0 +snat 30.0.0.1 192.168.1.0/24 +snat fd01::1 fd11::/64 ]) AT_CHECK([ovn-nbctl --may-exist lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.3]) AT_CHECK([ovn-nbctl --may-exist lr-nat-add lr0 dnat_and_snat fd01::2 fd11::3]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -dnat 30.0.0.1 192.168.1.2 -dnat fd01::1 fd11::2 -dnat_and_snat 30.0.0.1 192.168.1.2 -dnat_and_snat 30.0.0.2 192.168.1.3 -dnat_and_snat fd01::1 fd11::2 -dnat_and_snat fd01::2 fd11::3 -snat 30.0.0.1 192.168.1.0/24 -snat fd01::1 fd11::/64 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 30.0.0.1 192.168.1.2 +dnat fd01::1 fd11::2 +dnat_and_snat 30.0.0.1 192.168.1.2 +dnat_and_snat 30.0.0.2 192.168.1.3 +dnat_and_snat fd01::1 fd11::2 +dnat_and_snat fd01::2 fd11::3 +snat 30.0.0.1 192.168.1.0/24 +snat fd01::1 fd11::/64 ]) check_row_count nb:NAT 0 options:stateless=true @@ -720,26 +720,26 @@ AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.3]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.1]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat fd01::1]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -dnat 30.0.0.1 192.168.1.2 -dnat fd01::1 fd11::2 -dnat_and_snat 30.0.0.2 192.168.1.3 -dnat_and_snat 40.0.0.2 192.168.1.4 -dnat_and_snat fd01::2 fd11::3 -snat 30.0.0.1 192.168.1.0/24 -snat 40.0.0.3 192.168.1.6 -snat fd01::1 fd11::/64 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 30.0.0.1 192.168.1.2 +dnat fd01::1 fd11::2 +dnat_and_snat 30.0.0.2 192.168.1.3 +dnat_and_snat 40.0.0.2 192.168.1.4 +dnat_and_snat fd01::2 fd11::3 +snat 30.0.0.1 192.168.1.0/24 +snat 40.0.0.3 192.168.1.6 +snat fd01::1 fd11::/64 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -dnat_and_snat 30.0.0.2 192.168.1.3 -dnat_and_snat 40.0.0.2 192.168.1.4 -dnat_and_snat fd01::2 fd11::3 -snat 30.0.0.1 192.168.1.0/24 -snat 40.0.0.3 192.168.1.6 -snat fd01::1 fd11::/64 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat_and_snat 30.0.0.2 192.168.1.3 +dnat_and_snat 40.0.0.2 192.168.1.4 +dnat_and_snat fd01::2 fd11::3 +snat 30.0.0.1 192.168.1.0/24 +snat 40.0.0.3 192.168.1.6 +snat fd01::1 fd11::/64 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0]) @@ -810,12 +810,12 @@ AT_CHECK([ovn-nbctl show lr0 | grep -C2 'external port(s): "1"' | uuidfilt], [0] ]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -dnat 40.0.0.4 1-3000 192.168.1.7 -dnat 40.0.0.5 1 192.168.1.10 -dnat_and_snat 40.0.0.5 1-3000 192.168.1.8 -dnat_and_snat 40.0.0.6 1-3000 192.168.1.9 00:00:00:04:05:06 lp0 -snat 40.0.0.3 21-65535 192.168.1.6 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 40.0.0.4 1-3000 192.168.1.7 +dnat 40.0.0.5 1 192.168.1.10 +dnat_and_snat 40.0.0.5 1-3000 192.168.1.8 +dnat_and_snat 40.0.0.6 1-3000 192.168.1.9 00:00:00:04:05:06 lp0 +snat 40.0.0.3 21-65535 192.168.1.6 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0]) @@ -895,39 +895,39 @@ AT_CHECK([ovn-nbctl --gateway-port=lrp00 lr-nat-add lr0 dnat 30.0.0.10 20.0.0.11 AT_CHECK([ovn-nbctl --gateway-port=lrp01 lr-nat-add lr0 dnat 30.0.0.10 20.0.0.10]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -dnat lrp00 30.0.0.10 20.0.0.10 -dnat lrp01 30.0.0.10 20.0.0.10 -snat 172.64.1.10 20.0.0.10 -snat lrp00 172.64.0.10 20.0.0.10 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat lrp00 30.0.0.10 20.0.0.10 +dnat lrp01 30.0.0.10 20.0.0.10 +snat 172.64.1.10 20.0.0.10 +snat lrp00 172.64.0.10 20.0.0.10 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat 30.0.0.10]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -snat 172.64.1.10 20.0.0.10 -snat lrp00 172.64.0.10 20.0.0.10 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +snat 172.64.1.10 20.0.0.10 +snat lrp00 172.64.0.10 20.0.0.10 ]) AT_CHECK([ovn-nbctl --gateway-port=lrp00 lr-nat-add lr0 snat 30.0.0.10 20.0.0.20]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -snat 172.64.1.10 20.0.0.10 -snat lrp00 172.64.0.10 20.0.0.10 -snat lrp00 30.0.0.10 20.0.0.20 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +snat 172.64.1.10 20.0.0.10 +snat lrp00 172.64.0.10 20.0.0.10 +snat lrp00 30.0.0.10 20.0.0.20 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat lrp11], [1], [], [ovn-nbctl: lrp11: port name not found ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 snat lrp00]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -snat 172.64.1.10 20.0.0.10 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +snat 172.64.1.10 20.0.0.10 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 snat lrp01]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl -TYPE GATEWAY_PORT EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT -snat 172.64.1.10 20.0.0.10 +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +snat 172.64.1.10 20.0.0.10 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0 snat 20.0.0 lrp01], [1], [], @@ -938,6 +938,96 @@ AT_CHECK([ovn-nbctl lr-nat-del lr0 snat 20.0.0.10 lrp01], [1], [], ]) AT_CHECK([ovn-nbctl --if-exists lr-nat-del lr0 snat 20.0.0.10 lrp01]) AT_CHECK([ovn-nbctl lr-nat-del lr0 snat]) + +AT_CHECK([ovn-nbctl lr-nat-del lr0]) +AT_CHECK([ovn-nbctl lrp-del-gateway-chassis lrp00 chassis1]) +AT_CHECK([ovn-nbctl lrp-del-gateway-chassis lrp01 chassis2]) + +AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 10.0.0.1 192.168.0.0/24]) +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 snat 10.0.0.2 192.168.0.0/24]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +snat 10.0.0.1 192.168.0.0/24 +snat tcp 10.0.0.2 192.168.0.0/24 +]) + +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 snat 10.0.0.3 192.168.0.0/24], [1], [], +[ovn-nbctl: a NAT with this type (snat), logical_ip (192.168.0.0/24) and match "tcp" already exists +]) +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 snat 10.0.0.2 192.168.0.0/24], [1], [], +[ovn-nbctl: 10.0.0.2, 192.168.0.0/24: a NAT with this external_ip and logical_ip already exists +]) +AT_CHECK([ovn-nbctl --may-exist --priority=5 --match="udp" lr-nat-add lr0 snat 10.0.0.2 192.168.0.0/24]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +snat 10.0.0.1 192.168.0.0/24 +snat udp 10.0.0.2 192.168.0.0/24 +]) + +AT_CHECK([ovn-nbctl --match="udp" lr-nat-del lr0 snat 192.168.0.0/24]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +snat 10.0.0.1 192.168.0.0/24 +]) + +AT_CHECK([ovn-nbctl lr-nat-del lr0 snat 192.168.0.0/24]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0]) + +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 10.0.0.1 192.168.0.1]) +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 dnat 10.0.0.1 192.168.0.2]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 10.0.0.1 192.168.0.1 +dnat tcp 10.0.0.1 192.168.0.2 +]) + +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 dnat 10.0.0.1 192.168.0.3], [1], [], +[ovn-nbctl: a NAT with this type (dnat), external_ip (10.0.0.1) and match "tcp" already exists +]) +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 dnat 10.0.0.1 192.168.0.2], [1], [], +[ovn-nbctl: 10.0.0.1, 192.168.0.2: a NAT with this external_ip and logical_ip already exists +]) +AT_CHECK([ovn-nbctl --may-exist --priority=10 --match="udp" lr-nat-add lr0 dnat 10.0.0.1 192.168.0.2]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 10.0.0.1 192.168.0.1 +dnat udp 10.0.0.1 192.168.0.2 +]) + +AT_CHECK([ovn-nbctl --match="udp" lr-nat-del lr0 dnat 10.0.0.1]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat 10.0.0.1 192.168.0.1 +]) + +AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat 10.0.0.1]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0]) + +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 10.0.0.1 192.168.0.1]) +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 dnat_and_snat 10.0.0.1 192.168.0.2]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat_and_snat 10.0.0.1 192.168.0.1 +dnat_and_snat tcp 10.0.0.1 192.168.0.2 +]) + +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 dnat_and_snat 10.0.0.1 192.168.0.3], [1], [], +[ovn-nbctl: a NAT with this type (dnat_and_snat), external_ip (10.0.0.1) and match "tcp" already exists +]) +AT_CHECK([ovn-nbctl --match="tcp" lr-nat-add lr0 dnat_and_snat 10.0.0.1 192.168.0.2], [1], [], +[ovn-nbctl: 10.0.0.1, 192.168.0.2: a NAT with this external_ip and logical_ip already exists +]) +AT_CHECK([ovn-nbctl --may-exist --priority=10 --match="udp" lr-nat-add lr0 dnat_and_snat 10.0.0.1 192.168.0.2]) +AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl +TYPE GATEWAY_PORT MATCH EXTERNAL_IP EXTERNAL_PORT LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT +dnat_and_snat 10.0.0.1 192.168.0.1 +dnat_and_snat udp 10.0.0.1 192.168.0.2 +]) + +AT_CHECK([ovn-nbctl --priority=5 lr-nat-add lr0 snat 10.0.0.2 192.168.0.0/24], [1], [], +[ovn-nbctl: priority can be set only with --match option. +]) + ]) dnl --------------------------------------------------------------------- diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index ea2b201a5..9e31d1cf0 100644 --- a/utilities/ovn-nbctl.8.xml +++ b/utilities/ovn-nbctl.8.xml @@ -1175,7 +1175,7 @@

NAT Commands

-
[--may-exist] [--stateless] [--gateway-port=GATEWAY_PORT] [--portrange] lr-nat-add router type external_ip logical_ip [logical_port external_mac] [external_port_range]
+
[--may-exist] [--stateless] [--gateway-port=GATEWAY_PORT] [--portrange] [--match=MATCH] [--priority=PRIORITY] lr-nat-add router type external_ip logical_ip [logical_port external_mac] [external_port_range]

Adds the specified NAT to router. @@ -1224,6 +1224,18 @@ external_port_range is 1-65535.

+

+ The --match allows to specify the extra match condition. + The extra match is for more fine-grained control over the NAT rule. +

+ +

+ The --priority option allows to specify order of NAT + rule evaluation. Priority must be between 0 and + 32767, inclusive and can be only specified together + with --match. +

+

When type is dnat, the externally visible IP address external_ip is DNATted to the diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 618f3a18b..da31c45f1 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -4981,6 +4981,8 @@ nbctl_pre_lr_nat_add(struct ctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_logical_port); ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_external_mac); ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_gateway_port); + ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_match); + ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_priority); ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_options); ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); @@ -5177,6 +5179,21 @@ nbctl_lr_nat_add(struct ctl_context *ctx) } } + int64_t priority = 0; + const char *match = shash_find_data(&ctx->options, "--match"); + const char *priority_opt = shash_find_data(&ctx->options, "--priority"); + + if (!match && priority_opt) { + ctl_error(ctx, "priority can be set only with --match option."); + goto cleanup; + } else if (match && priority_opt) { + error = parse_priority(priority_opt, &priority); + if (error) { + ctx->error = error; + goto cleanup; + } + } + for (size_t i = 0; i < lr->n_nat; i++) { const struct nbrec_nat *nat = lr->nat[i]; @@ -5207,6 +5224,10 @@ nbctl_lr_nat_add(struct ctl_context *ctx) nbrec_nat_verify_external_mac(nat); nbrec_nat_set_logical_port(nat, logical_port); nbrec_nat_set_external_mac(nat, external_mac); + if (match) { + nbrec_nat_set_match(nat, match); + nbrec_nat_set_priority(nat, priority); + } should_return = true; } else { ctl_error(ctx, "%s, %s: a NAT with this " @@ -5215,12 +5236,19 @@ nbctl_lr_nat_add(struct ctl_context *ctx) new_logical_ip); should_return = true; } - } else { - ctl_error(ctx, "a NAT with this type (%s), %s (%s) " - "already exists", - nat_type, - is_snat ? "logical_ip" : "external_ip", - is_snat ? new_logical_ip : new_external_ip); + } else if (!match || !strcmp(nat->match, match)) { + if (match) { + ctl_error(ctx, "a NAT with this type (%s), %s (%s) " + "and match \"%s\" already exists", nat_type, + is_snat ? "logical_ip" : "external_ip", + is_snat ? new_logical_ip : new_external_ip, + match); + } else { + ctl_error(ctx, "a NAT with this type (%s), %s (%s) " + "already exists", nat_type, + is_snat ? "logical_ip" : "external_ip", + is_snat ? new_logical_ip : new_external_ip); + } should_return = true; } } @@ -5273,6 +5301,11 @@ nbctl_lr_nat_add(struct ctl_context *ctx) } nbrec_nat_set_options(nat, &nat_options); + if (match) { + nbrec_nat_set_match(nat, match); + nbrec_nat_set_priority(nat, priority); + } + smap_destroy(&nat_options); /* Insert the NAT into the logical router. */ @@ -5293,30 +5326,79 @@ nbctl_pre_lr_nat_del(struct ctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_logical_ip); ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_external_ip); ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_gateway_port); + ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_match); ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); } +static size_t +lr_nat_del_matching(const struct nbrec_logical_router *lr, const char *type, + const char *ip, + const struct nbrec_logical_router_port *dgw_port, + const char *match, bool is_snat) +{ + size_t n_deleted = 0; + + for (size_t i = 0; i < lr->n_nat; i++) { + struct nbrec_nat *nat = lr->nat[i]; + char *old_ip = normalize_prefix_str(is_snat + ? nat->logical_ip + : nat->external_ip); + if (!old_ip) { + continue; + } + + bool delete = true; + + if (type && strcmp(type, nat->type)) { + delete = false; + } + + if (ip && strcmp(ip, old_ip)) { + delete = false; + } + + if (dgw_port && nat->gateway_port != dgw_port) { + delete = false; + } + + if (match && strcmp(match, nat->match)) { + delete = false; + } + + if (delete) { + nbrec_logical_router_update_nat_delvalue(lr, nat); + n_deleted++; + } + + free(old_ip); + } + + return n_deleted; +} + static void nbctl_lr_nat_del(struct ctl_context *ctx) { const struct nbrec_logical_router *lr = NULL; bool must_exist = !shash_find(&ctx->options, "--if-exists"); + const char *match = shash_find_data(&ctx->options, "--match"); char *error = lr_by_name_or_uuid(ctx, ctx->argv[1], true, &lr); if (error) { ctx->error = error; return; } - if (ctx->argc == 2) { - /* If type, external_ip and logical_ip are not specified, delete - * all NATs. */ + if (ctx->argc == 2 && !match) { + /* If type, external_ip, logical_ip and match are not specified, + * delete all NATs. */ nbrec_logical_router_verify_nat(lr); nbrec_logical_router_set_nat(lr, NULL, 0); return; } const char *nat_type = ctx->argv[2]; + int is_snat = !strcmp("snat", nat_type); if (strcmp(nat_type, "dnat") && strcmp(nat_type, "snat") && strcmp(nat_type, "dnat_and_snat")) { ctl_error(ctx, "%s: type must be one of \"dnat\", \"snat\" and " @@ -5326,16 +5408,11 @@ nbctl_lr_nat_del(struct ctl_context *ctx) if (ctx->argc == 3) { /*Deletes all NATs with the specified type. */ - for (size_t i = 0; i < lr->n_nat; i++) { - if (!strcmp(nat_type, lr->nat[i]->type)) { - nbrec_logical_router_update_nat_delvalue(lr, lr->nat[i]); - } - } + lr_nat_del_matching(lr, nat_type, NULL, NULL, match, is_snat); return; } char *nat_ip = normalize_prefix_str(ctx->argv[3]); - int is_snat = !strcmp("snat", nat_type); const struct nbrec_logical_router_port *dgw_port = NULL; if (ctx->argc == 4) { @@ -5346,32 +5423,9 @@ nbctl_lr_nat_del(struct ctl_context *ctx) ctx->error = error; return; } - - /* Deletes all NATs matching the type and gateway_port - * specified. */ - for (size_t i = 0; i < lr->n_nat; i++) { - if (!strcmp(nat_type, lr->nat[i]->type) && - lr->nat[i]->gateway_port == dgw_port) { - nbrec_logical_router_update_nat_delvalue(lr, lr->nat[i]); - } - } - return; } - /* Remove NAT rules matching the type and IP (based on type). */ - for (size_t i = 0; i < lr->n_nat; i++) { - struct nbrec_nat *nat = lr->nat[i]; - char *old_ip = normalize_prefix_str(is_snat - ? nat->logical_ip - : nat->external_ip); - if (!old_ip) { - continue; - } - if (!strcmp(nat_type, nat->type) && !strcmp(nat_ip, old_ip)) { - nbrec_logical_router_update_nat_delvalue(lr, nat); - } - free(old_ip); - } + lr_nat_del_matching(lr, nat_type, nat_ip, dgw_port, match, is_snat); goto cleanup; } @@ -5386,32 +5440,22 @@ nbctl_lr_nat_del(struct ctl_context *ctx) goto cleanup; } - /* Remove matching NAT. */ - for (size_t i = 0; i < lr->n_nat; i++) { - struct nbrec_nat *nat = lr->nat[i]; - bool should_return = false; - char *old_ip = normalize_prefix_str(is_snat - ? nat->logical_ip - : nat->external_ip); - if (!old_ip) { - continue; - } - if (!strcmp(nat_type, nat->type) && !strcmp(nat_ip, old_ip) && - nat->gateway_port == dgw_port) { - nbrec_logical_router_update_nat_delvalue(lr, nat); - should_return = true; - } - free(old_ip); - if (should_return) { - goto cleanup; + size_t n_deleted = lr_nat_del_matching(lr, nat_type, nat_ip, dgw_port, + match, is_snat); + if (must_exist && !n_deleted) { + struct ds ds = DS_EMPTY_INITIALIZER; + ds_put_format(&ds, "no matching NAT with the type (%s), %s (%s)", + nat_type, is_snat ? "logical_ip" : "external_ip", + nat_ip); + if (match) { + ds_put_format(&ds, ", gateway_port (%s) and match (%s)", + ctx->argv[4], match); + } else { + ds_put_format(&ds, " and gateway_port (%s)", ctx->argv[4]); } - } - if (must_exist) { - ctl_error(ctx, "no matching NAT with the type (%s), %s (%s) and " - "gateway_port (%s)", nat_type, - is_snat ? "logical_ip" : "external_ip", nat_ip, - ctx->argv[4]); + ctx->error = xstrdup(ds_cstr_ro(&ds)); + ds_destroy(&ds); } cleanup: @@ -5431,6 +5475,7 @@ nbctl_pre_lr_nat_list(struct ctl_context *ctx) ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_external_mac); ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_logical_port); ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_gateway_port); + ovsdb_idl_add_column(ctx->idl, &nbrec_nat_col_match); ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); } @@ -5448,11 +5493,12 @@ nbctl_lr_nat_list(struct ctl_context *ctx) struct smap lr_nats = SMAP_INITIALIZER(&lr_nats); for (size_t i = 0; i < lr->n_nat; i++) { const struct nbrec_nat *nat = lr->nat[i]; - char *key = xasprintf("%-17.13s%-22.18s%s", + char *key = xasprintf("%-17.13s%-22.18s%-22.18s%-19.15s", nat->type, nat->gateway_port ? nat->gateway_port->name : "", + nat->match, nat->external_ip); if (nat->external_mac && nat->logical_port) { smap_add_format(&lr_nats, key, @@ -5472,13 +5518,13 @@ nbctl_lr_nat_list(struct ctl_context *ctx) const struct smap_node **nodes = smap_sort(&lr_nats); if (nodes) { ds_put_format(&ctx->output, - "%-17.13s%-22.18s%-19.15s%-17.13s%-20.16s%-21.17s%s\n", - "TYPE", "GATEWAY_PORT", "EXTERNAL_IP", "EXTERNAL_PORT", - "LOGICAL_IP", "EXTERNAL_MAC", "LOGICAL_PORT"); + "%-17.13s%-22.18s%-22.18s%-19.15s%-17.13s%-20.16s%-21.17s%s\n", + "TYPE", "GATEWAY_PORT", "MATCH", "EXTERNAL_IP", + "EXTERNAL_PORT", "LOGICAL_IP", "EXTERNAL_MAC", "LOGICAL_PORT"); for (size_t i = 0; i < smap_count(&lr_nats); i++) { const struct smap_node *node = nodes[i]; - ds_put_format(&ctx->output, "%-58.54s%s\n", - node->key, node->value); + ds_put_format(&ctx->output, "%-80.86s%s\n", + node->key, node->value); } free(nodes); } @@ -8022,9 +8068,10 @@ static const struct ctl_command_syntax nbctl_commands[] = { "[LOGICAL_PORT EXTERNAL_MAC] [EXTERNAL_PORT_RANGE]", nbctl_pre_lr_nat_add, nbctl_lr_nat_add, NULL, "--may-exist,--stateless,--portrange,--add-route," - "--gateway-port=", RW }, + "--gateway-port=,--priority=,--match=", RW }, { "lr-nat-del", 1, 4, "ROUTER [TYPE [IP] [GATEWAY_PORT]]", - nbctl_pre_lr_nat_del, nbctl_lr_nat_del, NULL, "--if-exists", RW }, + nbctl_pre_lr_nat_del, nbctl_lr_nat_del, NULL, + "--if-exists,--match=", RW }, { "lr-nat-list", 1, 1, "ROUTER", nbctl_pre_lr_nat_list, nbctl_lr_nat_list, NULL, "", RO }, { "lr-nat-update-ext-ip", 4, 4, "ROUTER TYPE IP ADDRESS_SET", From patchwork Wed May 29 15:56:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ales Musil X-Patchwork-Id: 1941337 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.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=drMkzQT4; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VqDXT4D7Hz20Pb for ; Thu, 30 May 2024 01:56:57 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 7F2AF822F6; Wed, 29 May 2024 15:56:52 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id oCIPWeRvm-B2; Wed, 29 May 2024 15:56:46 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 234B38281A Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=drMkzQT4 Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 234B38281A; Wed, 29 May 2024 15:56:45 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id DD5A2C0DD6; Wed, 29 May 2024 15:56:44 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2CC17C0037 for ; Wed, 29 May 2024 15:56:42 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 467CC60B53 for ; Wed, 29 May 2024 15:56:41 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id xcijbpqCanx6 for ; Wed, 29 May 2024 15:56:39 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=170.10.133.124; helo=us-smtp-delivery-124.mimecast.com; envelope-from=amusil@redhat.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org 2D0A460B3F Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 2D0A460B3F Authentication-Results: smtp3.osuosl.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=drMkzQT4 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by smtp3.osuosl.org (Postfix) with ESMTPS id 2D0A460B3F for ; Wed, 29 May 2024 15:56:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1716998198; 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: in-reply-to:in-reply-to:references:references; bh=u25vtSOE/m7nxEVBDX0dCvEorls7KXDkBBxr3SRqy5o=; b=drMkzQT4P4UrEaeGUgzhqDCCQRfoSX+R8zrUxVu+WfXMEa6OPzdw3UIbuX+12oQpekPi3G SbWNoXsm32UNYbRUutgtWWoSoU2HPWS0NSXWvLLjsIol9C/Y645Q83hXCUS3J5Gt4FXBOZ IBS5y4Ksv5peH2noRil6JMfxXjBhhbo= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-518-EPem2qixNVuGB34X-LnQAw-1; Wed, 29 May 2024 11:56:36 -0400 X-MC-Unique: EPem2qixNVuGB34X-LnQAw-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 53BCC812296 for ; Wed, 29 May 2024 15:56:36 +0000 (UTC) Received: from amusil.redhat.com (unknown [10.45.225.45]) by smtp.corp.redhat.com (Postfix) with ESMTP id A65F640005B; Wed, 29 May 2024 15:56:35 +0000 (UTC) From: Ales Musil To: dev@openvswitch.org Date: Wed, 29 May 2024 17:56:30 +0200 Message-ID: <20240529155630.478992-4-amusil@redhat.com> In-Reply-To: <20240529155630.478992-1-amusil@redhat.com> References: <20240529155630.478992-1-amusil@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Subject: [ovs-dev] [PATCH ovn v2 3/3] northd: Use the NAT match column. 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" Use the newly added NAT match and priority column in logical flows. This allows to differentiate between various scenarios and more fine-grained control over the resulting translation. The flows with the extra match have higher priority than regular flows as the flows without match are subset of the flows with match, the priority is calculated as 300 + priority column. Reported-at: https://issues.redhat.com/browse/FDP-433 Signed-off-by: Ales Musil --- v2: Rebase on top of current main. Fix the common zone issue noticed by Mark. --- northd/northd.c | 29 +++-- northd/ovn-northd.8.xml | 31 +++++ tests/ovn-northd.at | 79 ++++++++++++ tests/system-ovn.at | 272 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 404 insertions(+), 7 deletions(-) diff --git a/northd/northd.c b/northd/northd.c index c5f69f469..8e5642c57 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -11566,10 +11566,17 @@ lrouter_dnat_and_snat_is_stateless(const struct nbrec_nat *nat) !strcmp(nat->type, "dnat_and_snat"); } +#define NAT_PRIORITY_MATCH_OFFSET 300 + static inline uint16_t -lrouter_nat_get_priority(const struct ovn_datapath *od, bool is_dnat, +lrouter_nat_get_priority(const struct ovn_datapath *od, + const struct nbrec_nat *nat, bool is_dnat, uint16_t prefix_len) { + if (nat->match[0]) { + return NAT_PRIORITY_MATCH_OFFSET + nat->priority; + } + if (is_dnat) { return 100; } @@ -11631,7 +11638,7 @@ lrouter_nat_add_ext_ip_match(const struct ovn_datapath *od, * */ uint16_t priority = - lrouter_nat_get_priority(od, is_src, cidr_bits) + 2; + lrouter_nat_get_priority(od, nat, is_src, cidr_bits) + 2; ds_clone(&match_exempt, match); ds_put_format(&match_exempt, " && ip%s.%s == $%s", @@ -14600,6 +14607,7 @@ build_lrouter_in_dnat_flow(struct lflow_table *lflows, const char *nat_action = lrouter_use_common_zone(od) ? "ct_dnat_in_czone" : "ct_dnat"; + uint16_t priority = lrouter_nat_get_priority(od, nat, true, cidr_bits); ds_put_format(match, "ip && ip%c.dst == %s", is_v6 ? '6' : '4', nat->external_ip); @@ -14646,8 +14654,11 @@ build_lrouter_in_dnat_flow(struct lflow_table *lflows, ds_put_format(actions, ");"); } - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, - lrouter_nat_get_priority(od, true, cidr_bits), + if (nat->match[0]) { + ds_put_format(match, " && (%s)", nat->match); + } + + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_DNAT, priority, ds_cstr(match), ds_cstr(actions), &nat->header_, lflow_ref); } @@ -14772,6 +14783,10 @@ build_lrouter_out_snat_match(struct lflow_table *lflows, is_v6, is_reverse, cidr_bits, lflow_ref); } + + if (nat->match[0]) { + ds_put_format(match, " && (%s)", nat->match); + } } static void @@ -14790,7 +14805,7 @@ build_lrouter_out_snat_stateless_flow(struct lflow_table *lflows, ds_clear(actions); - uint16_t priority = lrouter_nat_get_priority(od, false, cidr_bits); + uint16_t priority = lrouter_nat_get_priority(od, nat, false, cidr_bits); build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat, cidr_bits, is_v6, l3dgw_port, lflow_ref, false); @@ -14825,7 +14840,7 @@ build_lrouter_out_snat_in_czone_flow(struct lflow_table *lflows, ds_clear(actions); - uint16_t priority = lrouter_nat_get_priority(od, false, cidr_bits); + uint16_t priority = lrouter_nat_get_priority(od, nat, false, cidr_bits); struct ds zone_actions = DS_EMPTY_INITIALIZER; build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat, @@ -14884,7 +14899,7 @@ build_lrouter_out_snat_flow(struct lflow_table *lflows, ds_clear(actions); - uint16_t priority = lrouter_nat_get_priority(od, false, cidr_bits); + uint16_t priority = lrouter_nat_get_priority(od, nat, false, cidr_bits); build_lrouter_out_snat_match(lflows, od, nat, match, distributed_nat, cidr_bits, is_v6, l3dgw_port, lflow_ref, diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index 973e8718e..3deaaa142 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -3794,6 +3794,23 @@ next; exempted_ext_ips.

+

+ For each configuration in the OVN Northbound database, that asks + to change the destination IP address of a packet from A + to B, match M and priority P, + a logical flow that matches ip && ip4.dst == + A or ip && ip6.dst == A + && (M) with an action + flags.loopback = 1; ct_dnat(B);. + The priority of the flow is calculated based as + 300 + P. If the Gateway router is + configured to force SNAT any DNATed packet, the above action will + be replaced by flags.force_snat_for_dnat = 1; + flags.loopback = 1; ct_dnat(B);. If the NAT rule + is of type dnat_and_snat and has stateless=true in the + options, then the action would be ip4/6.dst= + (B). +

  • @@ -5162,6 +5179,20 @@ nd_ns { options, then the action would be ip4/6.src= (B).

    + +

    + For each configuration in the OVN Northbound database, that asks + to change the source IP address of a packet from an IP address of + A or to change the source IP address of a packet that + belongs to network A to B, match M + and priority P, a flow matches ip && + ip4.src == A && (!ct.trk || !ct.rpl) && + (M) with an action ct_snat(B); + . The priority of the flow is calculated based as + 300 + P. If the NAT rule is of type + dnat_and_snat and has stateless=true in the options, + then the action would be ip4/6.src=(B). +

  • diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index f3ffb4a6d..9cc993bbe 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -1024,22 +1024,46 @@ ovn-nbctl --wait=sb lr-nat-add R1 dnat_and_snat 172.16.1.1 50.0.0.11 check_flow_match_sets 2 2 2 0 0 0 0 ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1 +echo +echo "IPv4: stateful with match" +ovn-nbctl --wait=sb --match="udp" lr-nat-add R1 dnat_and_snat 172.16.1.1 50.0.0.11 +check_flow_match_sets 2 2 2 0 0 0 0 +ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1 + echo echo "IPv4: stateless" ovn-nbctl --wait=sb --stateless lr-nat-add R1 dnat_and_snat 172.16.1.1 50.0.0.11 check_flow_match_sets 2 0 0 1 1 0 0 ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1 +echo +echo "IPv4: stateless with match" +ovn-nbctl --wait=sb --match="udp" --stateless lr-nat-add R1 dnat_and_snat 172.16.1.1 50.0.0.11 +check_flow_match_sets 2 0 0 1 1 0 0 +ovn-nbctl lr-nat-del R1 dnat_and_snat 172.16.1.1 + echo echo "IPv6: stateful" ovn-nbctl --wait=sb lr-nat-add R1 dnat_and_snat fd01::1 fd11::2 check_flow_match_sets 2 2 2 0 0 0 0 ovn-nbctl lr-nat-del R1 dnat_and_snat fd01::1 +echo +echo "IPv6: stateful with match" +ovn-nbctl --wait=sb --match="udp" lr-nat-add R1 dnat_and_snat fd01::1 fd11::2 +check_flow_match_sets 2 2 2 0 0 0 0 +ovn-nbctl lr-nat-del R1 dnat_and_snat fd01::1 + echo echo "IPv6: stateless" ovn-nbctl --wait=sb --stateless lr-nat-add R1 dnat_and_snat fd01::1 fd11::2 check_flow_match_sets 2 0 0 0 0 1 1 +ovn-nbctl lr-nat-del R1 dnat_and_snat fd01::1 + +echo +echo "IPv6: stateless with match" +ovn-nbctl --wait=sb --match="udp" --stateless lr-nat-add R1 dnat_and_snat fd01::1 fd11::2 +check_flow_match_sets 2 0 0 0 0 1 1 AT_CLEANUP ]) @@ -12612,3 +12636,58 @@ check_engine_stats northd recompute nocompute check_engine_stats lflow recompute nocompute AT_CLEANUP + +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([NAT with match]) +ovn_start + +check ovn-sbctl chassis-add hv1 geneve 127.0.0.1 + +check ovn-nbctl lr-add lr -- \ + lrp-add lr lr-ls 02:ac:10:01:00:01 172.16.1.1/24 + +check ovn-nbctl ls-add ls -- \ + lsp-add ls ls-lr -- \ + lsp-set-type ls-lr router -- \ + lsp-set-addresses ls-lr router -- \ + lsp-set-options ls-lr router-port=lr-ls + +check ovn-nbctl lr-nat-add lr snat 172.16.1.1 10.0.0.0/24 +check ovn-nbctl --match="udp" --priority=10 lr-nat-add lr snat 172.16.1.2 10.0.0.0/24 + +check ovn-nbctl lr-nat-add lr dnat 10.0.0.100 10.0.0.10 +check ovn-nbctl --match="udp" --priority=20 lr-nat-add lr dnat 10.0.0.100 10.0.0.20 + +check ovn-nbctl --wait=sb lrp-set-gateway-chassis lr-ls hv1 + +AT_CHECK([ovn-sbctl dump-flows lr | grep lr_out_snat | ovn_strip_lflows], [0], [dnl + table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) + table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) + table=??(lr_out_snat ), priority=153 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr-ls" && is_chassis_resident("cr-lr-ls") && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) + table=??(lr_out_snat ), priority=310 , match=(ip && ip4.src == 10.0.0.0/24 && outport == "lr-ls" && is_chassis_resident("cr-lr-ls") && (udp) && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) +]) + +AT_CHECK([ovn-sbctl dump-flows lr | grep lr_in_dnat | ovn_strip_lflows], [0], [dnl + table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=??(lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 10.0.0.100 && inport == "lr-ls" && is_chassis_resident("cr-lr-ls")), action=(ct_dnat(10.0.0.10);) + table=??(lr_in_dnat ), priority=320 , match=(ip && ip4.dst == 10.0.0.100 && inport == "lr-ls" && is_chassis_resident("cr-lr-ls") && (udp)), action=(ct_dnat(10.0.0.20);) +]) + +check ovn-nbctl lrp-del-gateway-chassis lr-ls hv1 +check ovn-nbctl --wait=sb set logical_router lr options:chassis=hv1 + +AT_CHECK([ovn-sbctl dump-flows lr | grep lr_out_snat | ovn_strip_lflows], [0], [dnl + table=??(lr_out_snat ), priority=0 , match=(1), action=(next;) + table=??(lr_out_snat ), priority=120 , match=(nd_ns), action=(next;) + table=??(lr_out_snat ), priority=25 , match=(ip && ip4.src == 10.0.0.0/24 && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.1);) + table=??(lr_out_snat ), priority=310 , match=(ip && ip4.src == 10.0.0.0/24 && (udp) && (!ct.trk || !ct.rpl)), action=(ct_snat(172.16.1.2);) +]) + +AT_CHECK([ovn-sbctl dump-flows lr | grep lr_in_dnat | ovn_strip_lflows], [0], [dnl + table=??(lr_in_dnat ), priority=0 , match=(1), action=(next;) + table=??(lr_in_dnat ), priority=100 , match=(ip && ip4.dst == 10.0.0.100), action=(flags.loopback = 1; ct_dnat(10.0.0.10);) + table=??(lr_in_dnat ), priority=320 , match=(ip && ip4.dst == 10.0.0.100 && (udp)), action=(flags.loopback = 1; ct_dnat(10.0.0.20);) +]) + +AT_CLEANUP +]) diff --git a/tests/system-ovn.at b/tests/system-ovn.at index f49330a1e..229b09fc0 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -12735,3 +12735,275 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d /.*terminating with signal 15.*/d"]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([NAT arbitrary match - IPv4]) +AT_KEYWORDS([ovnlb]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() + +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ext]) + +check ovs-ofctl add-flow br-ext action=normal +# Set external-ids in br-int needed for ovn-controller +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 \ + -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext + +# Start ovn-controller +start_daemon ovn-controller + +check ovn-nbctl lr-add lr +check ovn-nbctl ls-add internal +check ovn-nbctl ls-add public + +check ovn-nbctl lrp-add lr lr-pub 00:00:01:01:02:03 192.168.100.1/24 +check ovn-nbctl lsp-add public pub-lr -- set Logical_Switch_Port pub-lr \ + type=router options:router-port=lr-pub addresses=\"00:00:01:01:02:03\" + +check ovn-nbctl lrp-add lr lr-internal 00:00:01:01:02:04 192.168.200.1/24 +check ovn-nbctl lsp-add internal internal-lr -- set Logical_Switch_Port internal-lr \ + type=router options:router-port=lr-internal addresses=\"00:00:01:01:02:04\" + +check ovn-nbctl lsp-add internal vm0 \ + -- lsp-set-addresses vm0 "f0:00:0f:01:02:03 192.168.200.10" +check ovn-nbctl lsp-add internal vm2 \ + -- lsp-set-addresses vm2 "f0:00:0f:01:02:04 192.168.200.20" +check ovn-nbctl lsp-add internal vm3 \ + -- lsp-set-addresses vm3 "f0:00:0f:01:02:05 192.168.200.30" + +ovn-nbctl lsp-add public ln_port \ + -- lsp-set-addresses ln_port unknown \ + -- lsp-set-type ln_port localnet \ + -- lsp-set-options ln_port network_name=phynet + +check ovn-nbctl --wait=hv sync + +ADD_NAMESPACES(vm0) +ADD_VETH(vm0, vm0, br-int, "192.168.200.10/24", "f0:00:0f:01:02:03", "192.168.200.1") + +ADD_NAMESPACES(vm1) +ADD_VETH(vm1, vm1, br-ext, "192.168.100.10/24", "f0:00:00:01:02:03", "192.168.100.1") + +ADD_NAMESPACES(vm2) +ADD_VETH(vm2, vm2, br-int, "192.168.200.20/24", "f0:00:0f:01:02:04", "192.168.200.1") + +ADD_NAMESPACES(vm3) +ADD_VETH(vm3, vm3, br-int, "192.168.200.30/24", "f0:00:0f:01:02:05", "192.168.200.1") + +NETNS_DAEMONIZE([vm0], [nc -l -k 192.168.200.10 4242], [server0.pid]) +NETNS_DAEMONIZE([vm1], [nc -l -k 192.168.100.10 4242], [server1.pid]) +NETNS_DAEMONIZE([vm2], [nc -l -k 192.168.200.20 4242], [server2.pid]) +NETNS_DAEMONIZE([vm3], [nc -l -k 192.168.200.30 4242], [server3.pid]) + +check_snat() { + check ovn-nbctl lr-nat-del lr + check ovn-nbctl lr-nat-add lr snat 192.168.100.1 192.168.200.0/24 + check ovn-nbctl --match="tcp && tcp.src == 2001" lr-nat-add lr snat 192.168.100.11 192.168.200.0/24 + check ovn-nbctl --match="tcp && tcp.src == 2002" lr-nat-add lr snat 192.168.100.12 192.168.200.0/24 + check ovn-nbctl --wait=hv sync + + check ovs-appctl dpctl/flush-conntrack + + NS_CHECK_EXEC([vm0], [nc -z 192.168.100.10 4242 -p 2000]) + NS_CHECK_EXEC([vm0], [nc -z 192.168.100.10 4242 -p 2001]) + NS_CHECK_EXEC([vm0], [nc -z 192.168.100.10 4242 -p 2002]) + + snat_id=$(ovn-appctl -t ovn-controller ct-zone-list | grep lr_snat | cut -d ' ' -f2) + AT_CHECK_UNQUOTED([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.100.10) | grep "zone=$snat_id"], [0], [dnl +tcp,orig=(src=192.168.200.10,dst=192.168.100.10,sport=,dport=),reply=(src=192.168.100.10,dst=192.168.100.1,sport=,dport=),zone=$snat_id,protoinfo=(state=) +tcp,orig=(src=192.168.200.10,dst=192.168.100.10,sport=,dport=),reply=(src=192.168.100.10,dst=192.168.100.11,sport=,dport=),zone=$snat_id,protoinfo=(state=) +tcp,orig=(src=192.168.200.10,dst=192.168.100.10,sport=,dport=),reply=(src=192.168.100.10,dst=192.168.100.12,sport=,dport=),zone=$snat_id,protoinfo=(state=) +]) +} + +check_dnat() { + check ovn-nbctl lr-nat-del lr + check ovn-nbctl lr-nat-add lr dnat 192.168.100.100 192.168.200.10 + check ovn-nbctl --match="tcp && tcp.src == 2001" lr-nat-add lr dnat 192.168.100.100 192.168.200.20 + check ovn-nbctl --match="tcp && tcp.src == 2002" lr-nat-add lr dnat 192.168.100.100 192.168.200.30 + check ovn-nbctl --wait=hv sync + + check ovs-appctl dpctl/flush-conntrack + + NS_CHECK_EXEC([vm1], [nc -z 192.168.100.100 4242 -p 2000]) + NS_CHECK_EXEC([vm1], [nc -z 192.168.100.100 4242 -p 2001]) + NS_CHECK_EXEC([vm1], [nc -z 192.168.100.100 4242 -p 2002]) + + dnat_id=$(ovn-appctl -t ovn-controller ct-zone-list | grep lr_dnat | cut -d ' ' -f2) + AT_CHECK_UNQUOTED([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(192.168.100.100) | grep "zone=$dnat_id"], [0], [dnl +tcp,orig=(src=192.168.100.10,dst=192.168.100.100,sport=,dport=),reply=(src=192.168.200.10,dst=192.168.100.10,sport=,dport=),zone=$dnat_id,protoinfo=(state=) +tcp,orig=(src=192.168.100.10,dst=192.168.100.100,sport=,dport=),reply=(src=192.168.200.20,dst=192.168.100.10,sport=,dport=),zone=$dnat_id,protoinfo=(state=) +tcp,orig=(src=192.168.100.10,dst=192.168.100.100,sport=,dport=),reply=(src=192.168.200.30,dst=192.168.100.10,sport=,dport=),zone=$dnat_id,protoinfo=(state=) +]) +} + +check ovn-nbctl lrp-set-gateway-chassis lr-pub hv1 +check_snat +check_dnat +check ovn-nbctl lrp-del-gateway-chassis lr-pub hv1 + +check ovn-nbctl set logical_router lr options:chassis=hv1 +check_snat +check_dnat + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/connection dropped.*/d"]) +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([NAT arbitrary match - IPv6]) +AT_KEYWORDS([ovnlb]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() + +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) +ADD_BR([br-ext]) + +check ovs-ofctl add-flow br-ext action=normal +# Set external-ids in br-int needed for ovn-controller +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 \ + -- set Open_vSwitch . external-ids:ovn-bridge-mappings=phynet:br-ext + +# Start ovn-controller +start_daemon ovn-controller + +check ovn-nbctl lr-add lr +check ovn-nbctl ls-add internal +check ovn-nbctl ls-add public + +check ovn-nbctl lrp-add lr lr-pub 00:00:01:01:02:03 1000::1/64 +check ovn-nbctl lsp-add public pub-lr -- set Logical_Switch_Port pub-lr \ + type=router options:router-port=lr-pub addresses=\"00:00:01:01:02:03\" + +check ovn-nbctl lrp-add lr lr-internal 00:00:01:01:02:04 2000::1/64 +check ovn-nbctl lsp-add internal internal-lr -- set Logical_Switch_Port internal-lr \ + type=router options:router-port=lr-internal addresses=\"00:00:01:01:02:04\" + +check ovn-nbctl lsp-add internal vm0 \ + -- lsp-set-addresses vm0 "f0:00:0f:01:02:03 2000::10" +check ovn-nbctl lsp-add internal vm2 \ + -- lsp-set-addresses vm2 "f0:00:0f:01:02:04 2000::20" +check ovn-nbctl lsp-add internal vm3 \ + -- lsp-set-addresses vm3 "f0:00:0f:01:02:05 2000::30" + +ovn-nbctl lsp-add public ln_port \ + -- lsp-set-addresses ln_port unknown \ + -- lsp-set-type ln_port localnet \ + -- lsp-set-options ln_port network_name=phynet + +check ovn-nbctl --wait=hv sync + +ADD_NAMESPACES(vm0) +ADD_VETH(vm0, vm0, br-int, "2000::10/64", "f0:00:0f:01:02:03", "2000::1", "nodad") + +ADD_NAMESPACES(vm1) +ADD_VETH(vm1, vm1, br-ext, "1000::10/64", "f0:00:00:01:02:03", "1000::1", "nodad") + +ADD_NAMESPACES(vm2) +ADD_VETH(vm2, vm2, br-int, "2000::20/64", "f0:00:0f:01:02:04", "2000::1", "nodad") + +ADD_NAMESPACES(vm3) +ADD_VETH(vm3, vm3, br-int, "2000::30/64", "f0:00:0f:01:02:05", "2000::1", "nodad") + +NETNS_DAEMONIZE([vm0], [nc -lk 2000::10 4242 > /dev/null], [server0.pid]) +NETNS_DAEMONIZE([vm1], [nc -lk 1000::10 4242 > /dev/null], [server1.pid]) +NETNS_DAEMONIZE([vm2], [nc -lk 2000::20 4242 > /dev/null], [server2.pid]) +NETNS_DAEMONIZE([vm3], [nc -lk 2000::30 4242 > /dev/null], [server3.pid]) + +check_snat() { + check ovn-nbctl lr-nat-del lr + check ovn-nbctl lr-nat-add lr snat 1000::1 2000::/64 + check ovn-nbctl --match="tcp && tcp.src == 2001" lr-nat-add lr snat 1000::11 2000::/64 + check ovn-nbctl --match="tcp && tcp.src == 2002" lr-nat-add lr snat 1000::12 2000::/64 + check ovn-nbctl --wait=hv sync + + check ovs-appctl dpctl/flush-conntrack + + NS_CHECK_EXEC([vm0], [nc -z 1000::10 4242 -p 2000]) + NS_CHECK_EXEC([vm0], [nc -z 1000::10 4242 -p 2001]) + NS_CHECK_EXEC([vm0], [nc -z 1000::10 4242 -p 2002]) + + snat_id=$(ovn-appctl -t ovn-controller ct-zone-list | grep lr_snat | cut -d ' ' -f2) + AT_CHECK_UNQUOTED([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(1000::10) | grep "zone=$snat_id"], [0], [dnl +tcp,orig=(src=2000::10,dst=1000::10,sport=,dport=),reply=(src=1000::10,dst=1000::1,sport=,dport=),zone=$snat_id,protoinfo=(state=) +tcp,orig=(src=2000::10,dst=1000::10,sport=,dport=),reply=(src=1000::10,dst=1000::11,sport=,dport=),zone=$snat_id,protoinfo=(state=) +tcp,orig=(src=2000::10,dst=1000::10,sport=,dport=),reply=(src=1000::10,dst=1000::12,sport=,dport=),zone=$snat_id,protoinfo=(state=) +]) +} + +check_dnat() { + check ovn-nbctl lr-nat-del lr + check ovn-nbctl lr-nat-add lr dnat 1000::100 2000::10 + check ovn-nbctl --match="tcp && tcp.src == 2001" lr-nat-add lr dnat 1000::100 2000::20 + check ovn-nbctl --match="tcp && tcp.src == 2002" lr-nat-add lr dnat 1000::100 2000::30 + check ovn-nbctl --wait=hv sync + + check ovs-appctl dpctl/flush-conntrack + + NS_CHECK_EXEC([vm1], [nc -z 1000::100 4242 -p 2000]) + NS_CHECK_EXEC([vm1], [nc -z 1000::100 4242 -p 2001]) + NS_CHECK_EXEC([vm1], [nc -z 1000::100 4242 -p 2002]) + + dnat_id=$(ovn-appctl -t ovn-controller ct-zone-list | grep lr_dnat | cut -d ' ' -f2) + AT_CHECK_UNQUOTED([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(1000::100) | grep "zone=$dnat_id"], [0], [dnl +tcp,orig=(src=1000::10,dst=1000::100,sport=,dport=),reply=(src=2000::10,dst=1000::10,sport=,dport=),zone=$dnat_id,protoinfo=(state=) +tcp,orig=(src=1000::10,dst=1000::100,sport=,dport=),reply=(src=2000::20,dst=1000::10,sport=,dport=),zone=$dnat_id,protoinfo=(state=) +tcp,orig=(src=1000::10,dst=1000::100,sport=,dport=),reply=(src=2000::30,dst=1000::10,sport=,dport=),zone=$dnat_id,protoinfo=(state=) +]) +} + +check ovn-nbctl lrp-set-gateway-chassis lr-pub hv1 +check_snat +check_dnat +check ovn-nbctl lrp-del-gateway-chassis lr-pub hv1 + +check ovn-nbctl set logical_router lr options:chassis=hv1 +check_snat +check_dnat + +OVS_APP_EXIT_AND_WAIT([ovn-controller]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d +/connection dropped.*/d"]) +AT_CLEANUP +])