From patchwork Wed Oct 30 14:53:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Bryant X-Patchwork-Id: 1186779 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=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 473BKV19Xdz9sCJ for ; Thu, 31 Oct 2019 01:53:34 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 68F91CAA; Wed, 30 Oct 2019 14:53:32 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 08DEBC87 for ; Wed, 30 Oct 2019 14:53:31 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id 67EAF8A for ; Wed, 30 Oct 2019 14:53:30 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-4-li_7Jb0UO_W-nSHfdATIfw-1; Wed, 30 Oct 2019 10:53:27 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id D156C800EB3; Wed, 30 Oct 2019 14:53:26 +0000 (UTC) Received: from t480s.redhat.com (ovpn-126-115.rdu2.redhat.com [10.10.126.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6CCD28D7A; Wed, 30 Oct 2019 14:53:26 +0000 (UTC) From: Russell Bryant To: dev@openvswitch.org Date: Wed, 30 Oct 2019 10:53:19 -0400 Message-Id: <20191030145324.9988-2-russell@ovn.org> In-Reply-To: <20191030145324.9988-1-russell@ovn.org> References: <20191030013138.9390-1-russell@ovn.org> <20191030145324.9988-1-russell@ovn.org> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: li_7Jb0UO_W-nSHfdATIfw-1 X-Mimecast-Spam-Score: 0 X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH ovn v2 1/6] northd: Fix table ID for IPv6 router ingress. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org I noticed that this table number was outdated. This is now table 3. There are a few other sections of code for this table that were all correctly referencing table 3. Signed-off-by: Russell Bryant --- northd/ovn-northd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index 194e4bf4a..ae81a6944 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -7064,7 +7064,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, free(snat_ips); } - /* Logical router ingress table 1: IP Input for IPv6. */ + /* Logical router ingress table 3: IP Input for IPv6. */ HMAP_FOR_EACH (op, key_node, ports) { if (!op->nbrp) { continue; From patchwork Wed Oct 30 14:53:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Bryant X-Patchwork-Id: 1186783 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=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 473BMP5j3Vz9sPK for ; Thu, 31 Oct 2019 01:55:13 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id B60DCE4F; Wed, 30 Oct 2019 14:53:36 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 883DED67 for ; Wed, 30 Oct 2019 14:53:33 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id BA8158A for ; Wed, 30 Oct 2019 14:53:32 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-224-qYKHb5RcMd6QGQDm3LvAUg-1; Wed, 30 Oct 2019 10:53:28 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6E0492B8; Wed, 30 Oct 2019 14:53:27 +0000 (UTC) Received: from t480s.redhat.com (ovpn-126-115.rdu2.redhat.com [10.10.126.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id 095B188E6; Wed, 30 Oct 2019 14:53:26 +0000 (UTC) From: Russell Bryant To: dev@openvswitch.org Date: Wed, 30 Oct 2019 10:53:20 -0400 Message-Id: <20191030145324.9988-3-russell@ovn.org> In-Reply-To: <20191030145324.9988-1-russell@ovn.org> References: <20191030013138.9390-1-russell@ovn.org> <20191030145324.9988-1-russell@ovn.org> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: qYKHb5RcMd6QGQDm3LvAUg-1 X-Mimecast-Spam-Score: 0 X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH ovn v2 2/6] actions: Add IPv6 support to lflow NAT actions X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Signed-off-by: Russell Bryant --- include/ovn/actions.h | 6 +++++- lib/actions.c | 35 +++++++++++++++++++++++++++-------- tests/ovn.at | 18 ++++++++++++------ utilities/ovn-trace.c | 15 ++++++++++----- 4 files changed, 54 insertions(+), 20 deletions(-) diff --git a/include/ovn/actions.h b/include/ovn/actions.h index 4e2f4d28d..f4997e9c9 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -225,7 +225,11 @@ struct ovnact_ct_commit { /* OVNACT_CT_DNAT, OVNACT_CT_SNAT. */ struct ovnact_ct_nat { struct ovnact ovnact; - ovs_be32 ip; + int family; + union { + struct in6_addr ipv6; + ovs_be32 ipv4; + }; uint8_t ltable; /* Logical table ID of next table. */ }; diff --git a/lib/actions.c b/lib/actions.c index c8c9cc5fd..a999a4fda 100644 --- a/lib/actions.c +++ b/lib/actions.c @@ -755,11 +755,18 @@ parse_ct_nat(struct action_context *ctx, const char *name, if (lexer_match(ctx->lexer, LEX_T_LPAREN)) { if (ctx->lexer->token.type != LEX_T_INTEGER - || ctx->lexer->token.format != LEX_F_IPV4) { - lexer_syntax_error(ctx->lexer, "expecting IPv4 address"); + || (ctx->lexer->token.format != LEX_F_IPV4 + && ctx->lexer->token.format != LEX_F_IPV6)) { + lexer_syntax_error(ctx->lexer, "expecting IPv4 or IPv6 address"); return; } - cn->ip = ctx->lexer->token.value.ipv4; + if (ctx->lexer->token.format == LEX_F_IPV4) { + cn->family = AF_INET; + cn->ipv4 = ctx->lexer->token.value.ipv4; + } else if (ctx->lexer->token.format == LEX_F_IPV6) { + cn->family = AF_INET6; + cn->ipv6 = ctx->lexer->token.value.ipv6; + } lexer_get(ctx->lexer); if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) { @@ -784,8 +791,12 @@ static void format_ct_nat(const struct ovnact_ct_nat *cn, const char *name, struct ds *s) { ds_put_cstr(s, name); - if (cn->ip) { - ds_put_format(s, "("IP_FMT")", IP_ARGS(cn->ip)); + if (cn->family == AF_INET) { + ds_put_format(s, "("IP_FMT")", IP_ARGS(cn->ipv4)); + } else if (cn->family == AF_INET6) { + ds_put_char(s, '('); + ipv6_format_addr(&cn->ipv6, s); + ds_put_char(s, ')'); } ds_put_char(s, ';'); } @@ -831,9 +842,17 @@ encode_ct_nat(const struct ovnact_ct_nat *cn, nat->flags = 0; nat->range_af = AF_UNSPEC; - if (cn->ip) { + if (cn->family == AF_INET) { nat->range_af = AF_INET; - nat->range.addr.ipv4.min = cn->ip; + nat->range.addr.ipv4.min = cn->ipv4; + if (snat) { + nat->flags |= NX_NAT_F_SRC; + } else { + nat->flags |= NX_NAT_F_DST; + } + } else if (cn->family == AF_INET6) { + nat->range_af = AF_INET6; + nat->range.addr.ipv6.min = cn->ipv6; if (snat) { nat->flags |= NX_NAT_F_SRC; } else { @@ -843,7 +862,7 @@ encode_ct_nat(const struct ovnact_ct_nat *cn, ofpacts->header = ofpbuf_push_uninit(ofpacts, nat_offset); ct = ofpacts->header; - if (cn->ip) { + if (cn->family == AF_INET || cn->family == AF_INET6) { ct->flags |= NX_CT_F_COMMIT; } ofpact_finish(ofpacts, &ct->ofpact); diff --git a/tests/ovn.at b/tests/ovn.at index 9f06059fa..d78689d86 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -1043,15 +1043,18 @@ ct_dnat; ct_dnat(192.168.1.2); encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=192.168.1.2)) has prereqs ip +ct_dnat(fd11::2); + encodes as ct(commit,table=19,zone=NXM_NX_REG11[0..15],nat(dst=fd11::2)) + has prereqs ip ct_dnat(192.168.1.2, 192.168.1.3); Syntax error at `,' expecting `)'. ct_dnat(foo); - Syntax error at `foo' expecting IPv4 address. + Syntax error at `foo' expecting IPv4 or IPv6 address. ct_dnat(foo, bar); - Syntax error at `foo' expecting IPv4 address. + Syntax error at `foo' expecting IPv4 or IPv6 address. ct_dnat(); - Syntax error at `)' expecting IPv4 address. + Syntax error at `)' expecting IPv4 or IPv6 address. # ct_snat ct_snat; @@ -1060,15 +1063,18 @@ ct_snat; ct_snat(192.168.1.2); encodes as ct(commit,table=19,zone=NXM_NX_REG12[0..15],nat(src=192.168.1.2)) has prereqs ip +ct_snat(fd11::2); + encodes as ct(commit,table=19,zone=NXM_NX_REG12[0..15],nat(src=fd11::2)) + has prereqs ip ct_snat(192.168.1.2, 192.168.1.3); Syntax error at `,' expecting `)'. ct_snat(foo); - Syntax error at `foo' expecting IPv4 address. + Syntax error at `foo' expecting IPv4 or IPv6 address. ct_snat(foo, bar); - Syntax error at `foo' expecting IPv4 address. + Syntax error at `foo' expecting IPv4 or IPv6 address. ct_snat(); - Syntax error at `)' expecting IPv4 address. + Syntax error at `)' expecting IPv4 or IPv6 address. # ct_clear ct_clear; diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index c95acb897..ea64dc673 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -1886,7 +1886,7 @@ execute_ct_nat(const struct ovnact_ct_nat *ct_nat, enum ovnact_pipeline pipeline, struct ovs_list *super) { bool is_dst = ct_nat->ovnact.type == OVNACT_CT_DNAT; - if (!is_dst && dp->has_local_l3gateway && !ct_nat->ip) { + if (!is_dst && dp->has_local_l3gateway && ct_nat->family == AF_UNSPEC) { /* "ct_snat;" has no visible effect in a gateway router. */ return; } @@ -1897,10 +1897,15 @@ execute_ct_nat(const struct ovnact_ct_nat *ct_nat, struct flow ct_flow = *uflow; struct ds s = DS_EMPTY_INITIALIZER; ds_put_format(&s, "ct_%cnat", direction[0]); - if (ct_nat->ip) { - ds_put_format(&s, "(ip4.%s="IP_FMT")", direction, IP_ARGS(ct_nat->ip)); - ovs_be32 *ip = is_dst ? &ct_flow.nw_dst : &ct_flow.nw_src; - *ip = ct_nat->ip; + if (ct_nat->family != AF_UNSPEC) { + if (ct_nat->family == AF_INET) { + ds_put_format(&s, "(ip4.%s="IP_FMT")", direction, + IP_ARGS(ct_nat->ipv4)); + } else { + ds_put_format(&s, "(ip6.%s=", direction); + ipv6_format_addr(&ct_nat->ipv6, &s); + ds_put_char(&s, ')'); + } uint8_t state = is_dst ? CS_DST_NAT : CS_SRC_NAT; ct_flow.ct_state |= state; From patchwork Wed Oct 30 14:53:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Bryant X-Patchwork-Id: 1186784 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=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 473BNX2C92z9sCJ for ; Thu, 31 Oct 2019 01:56:12 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 6D2BCDB2; Wed, 30 Oct 2019 14:53:37 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 1E221C90 for ; Wed, 30 Oct 2019 14:53:35 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-delivery-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id 2BD3A876 for ; Wed, 30 Oct 2019 14:53:34 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-303-7sTexYhTP8KWH2jKzGgDuQ-1; Wed, 30 Oct 2019 10:53:28 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 0948A5E4; Wed, 30 Oct 2019 14:53:28 +0000 (UTC) Received: from t480s.redhat.com (ovpn-126-115.rdu2.redhat.com [10.10.126.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id 978EF52FD; Wed, 30 Oct 2019 14:53:27 +0000 (UTC) From: Russell Bryant To: dev@openvswitch.org Date: Wed, 30 Oct 2019 10:53:21 -0400 Message-Id: <20191030145324.9988-4-russell@ovn.org> In-Reply-To: <20191030145324.9988-1-russell@ovn.org> References: <20191030013138.9390-1-russell@ovn.org> <20191030145324.9988-1-russell@ovn.org> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: 7sTexYhTP8KWH2jKzGgDuQ-1 X-Mimecast-Spam-Score: 0 X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH ovn v2 3/6] ovn-nbctl: Allow IPv6 NAT rules to be added X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Signed-off-by: Russell Bryant --- tests/ovn-nbctl.at | 41 ++++++++++++++++++++++++++++-------- utilities/ovn-nbctl.c | 49 ++++++++++++++++++++++++++++++++----------- 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 01091dd99..43a980bdf 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -407,16 +407,16 @@ AT_CHECK([ovn-nbctl lr-nat-add lr0 snatt 30.0.0.2 192.168.1.2], [1], [], [ovn-nbctl: snatt: type must be one of "dnat", "snat" and "dnat_and_snat". ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.2a 192.168.1.2], [1], [], -[ovn-nbctl: 30.0.0.2a: should be an IPv4 address. +[ovn-nbctl: 30.0.0.2a: Not a valid IPv4 or IPv6 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0 192.168.1.2], [1], [], -[ovn-nbctl: 30.0.0: should be an IPv4 address. +[ovn-nbctl: 30.0.0: Not a valid IPv4 or IPv6 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.2/24 192.168.1.2], [1], [], -[ovn-nbctl: 30.0.0.2/24: should be an IPv4 address. +[ovn-nbctl: 30.0.0.2/24: Not a valid IPv4 or IPv6 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.2:80 192.168.1.2], [1], [], -[ovn-nbctl: 30.0.0.2:80: should be an IPv4 address. +[ovn-nbctl: 30.0.0.2:80: Not a valid IPv4 or IPv6 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.2 192.168.1.2a], [1], [], [ovn-nbctl: 192.168.1.2a: should be an IPv4 address or network. @@ -431,19 +431,19 @@ AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.2 192.168.1.2/a], [1], [], [ovn-nbctl: 192.168.1.2/a: should be an IPv4 address or network. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.2 192.168.1.2a], [1], [], -[ovn-nbctl: 192.168.1.2a: should be an IPv4 address. +[ovn-nbctl: 192.168.1.2a: Not a valid IPv4 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.2 192.168.1], [1], [], -[ovn-nbctl: 192.168.1: should be an IPv4 address. +[ovn-nbctl: 192.168.1: Not a valid IPv4 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.2 192.168.1.2:80], [1], [], -[ovn-nbctl: 192.168.1.2:80: should be an IPv4 address. +[ovn-nbctl: 192.168.1.2:80: Not a valid IPv4 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.2 192.168.1.2/24], [1], [], -[ovn-nbctl: 192.168.1.2/24: should be an IPv4 address. +[ovn-nbctl: 192.168.1.2/24: Not a valid IPv4 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.2/24], [1], [], -[ovn-nbctl: 192.168.1.2/24: should be an IPv4 address. +[ovn-nbctl: 192.168.1.2/24: Not a valid IPv4 address. ]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.2 lp0], [1], [], [ovn-nbctl: lr-nat-add with logical_port must also specify external_mac. @@ -465,15 +465,23 @@ AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1.2 lp0 00:00: dnl Add snat and dnat AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 30.0.0.1 192.168.1.0/24]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 snat fd01::1 fd11::/64]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 30.0.0.1 192.168.1.2]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat fd01::1 fd11::2]) AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat_and_snat 30.0.0.1 192.168.1.2]) +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 EXTERNAL_IP 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 @@ -503,17 +511,26 @@ AT_CHECK([ovn-nbctl --may-exist lr-nat-add lr0 dnat_and_snat 30.0.0.2 192.168.1. AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl TYPE EXTERNAL_IP 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 EXTERNAL_IP 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 ]) dnl Deletes the NATs @@ -529,18 +546,24 @@ AT_CHECK([ovn-nbctl lr-nat-del lr0 snat 192.168.10.0/24], [1], [], AT_CHECK([ovn-nbctl --if-exists lr-nat-del lr0 snat 192.168.10.0/24]) 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 EXTERNAL_IP 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 fd01::2 fd11::3 snat 30.0.0.1 192.168.1.0/24 +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 EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT dnat_and_snat 30.0.0.2 192.168.1.3 +dnat_and_snat fd01::2 fd11::3 snat 30.0.0.1 192.168.1.0/24 +snat fd01::1 fd11::/64 ]) AT_CHECK([ovn-nbctl lr-nat-del lr0]) diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index a89a9cb4d..68ced987a 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -3867,26 +3867,51 @@ nbctl_lr_nat_add(struct ctl_context *ctx) ovs_be32 ipv4 = 0; unsigned int plen; + struct in6_addr ipv6; + bool is_v6 = false; if (!ip_parse(external_ip, &ipv4)) { - ctl_error(ctx, "%s: should be an IPv4 address.", external_ip); - return; + if (ipv6_parse(external_ip, &ipv6)) { + is_v6 = true; + } else { + ctl_error(ctx, "%s: Not a valid IPv4 or IPv6 address.", + external_ip); + return; + } } if (strcmp("snat", nat_type)) { - if (!ip_parse(logical_ip, &ipv4)) { - ctl_error(ctx, "%s: should be an IPv4 address.", logical_ip); - return; + if (is_v6) { + if (!ipv6_parse(logical_ip, &ipv6)) { + ctl_error(ctx, "%s: Not a valid IPv6 address.", logical_ip); + return; + } + } else { + if (!ip_parse(logical_ip, &ipv4)) { + ctl_error(ctx, "%s: Not a valid IPv4 address.", logical_ip); + return; + } } new_logical_ip = xstrdup(logical_ip); } else { - error = ip_parse_cidr(logical_ip, &ipv4, &plen); - if (error) { - free(error); - ctl_error(ctx, "%s: should be an IPv4 address or network.", - logical_ip); - return; + if (is_v6) { + error = ipv6_parse_cidr(logical_ip, &ipv6, &plen); + if (error) { + free(error); + ctl_error(ctx, "%s: should be an IPv6 address or network.", + logical_ip); + return; + } + new_logical_ip = normalize_ipv6_prefix(ipv6, plen); + } else { + error = ip_parse_cidr(logical_ip, &ipv4, &plen); + if (error) { + free(error); + ctl_error(ctx, "%s: should be an IPv4 address or network.", + logical_ip); + return; + } + new_logical_ip = normalize_ipv4_prefix(ipv4, plen); } - new_logical_ip = normalize_ipv4_prefix(ipv4, plen); } const char *logical_port; From patchwork Wed Oct 30 14:53:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Bryant X-Patchwork-Id: 1186789 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=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 473BQB5WtMz9sP3 for ; Thu, 31 Oct 2019 01:57:38 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 1F6A0E6C; Wed, 30 Oct 2019 14:53:39 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id CBB90E1E for ; Wed, 30 Oct 2019 14:53:35 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id 0E6A063D for ; Wed, 30 Oct 2019 14:53:32 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-354-U4N8p8D_Ns6WuT_6WoeS8g-1; Wed, 30 Oct 2019 10:53:29 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C227E5E6; Wed, 30 Oct 2019 14:53:28 +0000 (UTC) Received: from t480s.redhat.com (ovpn-126-115.rdu2.redhat.com [10.10.126.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id 324AA52FD; Wed, 30 Oct 2019 14:53:28 +0000 (UTC) From: Russell Bryant To: dev@openvswitch.org Date: Wed, 30 Oct 2019 10:53:22 -0400 Message-Id: <20191030145324.9988-5-russell@ovn.org> In-Reply-To: <20191030145324.9988-1-russell@ovn.org> References: <20191030013138.9390-1-russell@ovn.org> <20191030145324.9988-1-russell@ovn.org> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: U4N8p8D_Ns6WuT_6WoeS8g-1 X-Mimecast-Spam-Score: 0 X-Spam-Status: No, score=-2.2 required=5.0 tests=BAYES_00, HTML_SINGLET_MANY, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH ovn v2 4/6] northd: Add lflows for IPv6 NAT. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Signed-off-by: Russell Bryant --- northd/ovn-northd.8.xml | 233 +++++++++++++----------- northd/ovn-northd.c | 384 ++++++++++++++++++++++++++++++---------- 2 files changed, 418 insertions(+), 199 deletions(-) diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml index d3e0e5ef2..f6cafbd55 100644 --- a/northd/ovn-northd.8.xml +++ b/northd/ovn-northd.8.xml @@ -1511,11 +1511,55 @@ output;
  • - These flows reply to ARP requests for the virtual IP addresses - configured in the router for DNAT or load balancing. For a - configured DNAT IP address or a load balancer IPv4 VIP A, - for each router port P with Ethernet - address E, a priority-90 flow matches + Reply to IPv6 Neighbor Solicitations. These flows reply to + Neighbor Solicitation requests for the router's own IPv6 + address and populate the logical router's mac binding table. +

    + +

    + For each router port P that + owns IPv6 address A, solicited node address S, + and Ethernet address E, a priority-90 flow matches + inport == P && + nd_ns && ip6.dst == {A, E} && + nd.target == A with the following actions: +

    + +
    +nd_na_router {
    +    eth.src = E;
    +    ip6.src = A;
    +    nd.target = A;
    +    nd.tll = E;
    +    outport = inport;
    +    flags.loopback = 1;
    +    output;
    +};
    +        
    + +

    + For the gateway port on a distributed logical router (where + one of the logical router ports specifies a + redirect-chassis), the above flows replying to + IPv6 Neighbor Solicitations are only programmed on the + gateway port instance on the redirect-chassis. + This behavior avoids generation of multiple replies from + different chassis, and allows upstream MAC learning to point + to the redirect-chassis. +

    +
  • + +
  • +

    + These flows reply to ARP requests or IPv6 neighbor solicitation + for the virtual IP addresses configured in the router for DNAT + or load balancing. +

    + +

    + IPv4: For a configured DNAT IP address or a load balancer + IPv4 VIP A, for each router port P with + Ethernet address E, a priority-90 flow matches inport == P && arp.op == 1 && arp.tpa == A (ARP request) with the following actions: @@ -1534,6 +1578,30 @@ flags.loopback = 1; output; +

    + IPv6: For a configured DNAT IP address or a load balancer + IPv6 VIP A, solicited node address S, + for each router port P with + Ethernet address E, a priority-90 flow matches + inport == P && nd_ns && + ip6.dst == {A, S} && + nd.target == A + with the following actions: +

    + +
    +eth.dst = eth.src;
    +nd_na {
    +    eth.src = E;
    +    nd.tll = E;
    +    ip6.src = A;
    +    nd.target = A;
    +    outport = P;
    +    flags.loopback = 1;
    +    output;
    +}
    +        
    +

    For the gateway port on a distributed logical router with NAT (where one of the logical router ports specifies a @@ -1570,6 +1638,15 @@ eth.src = external_mac; arp.sha = external_mac; +

    + or in the case of IPv6 neighbor solicition: +

    + +
    +eth.src = external_mac;
    +nd.tll = external_mac;
    +            
    +

    This behavior avoids generation of multiple ARP responses from different chassis, and allows upstream MAC learning to @@ -1579,68 +1656,6 @@ arp.sha = external_mac;

  • -
  • -

    - Reply to IPv6 Neighbor Solicitations. These flows reply to - Neighbor Solicitation requests for the router's own IPv6 - address and load balancing IPv6 VIPs and populate the logical - router's mac binding table. -

    - -

    - For each router port P that - owns IPv6 address A, solicited node address S, - and Ethernet address E, a priority-90 flow matches - inport == P && - nd_ns && ip6.dst == {A, E} && - nd.target == A with the following actions: -

    - -
    -nd_na_router {
    -    eth.src = E;
    -    ip6.src = A;
    -    nd.target = A;
    -    nd.tll = E;
    -    outport = inport;
    -    flags.loopback = 1;
    -    output;
    -};
    -        
    - -

    - For each router port P that has load balancing VIP - A, solicited node address S, and Ethernet - address E, a priority-90 flow matches - inport == P && - nd_ns && ip6.dst == {A, E} && - nd.target == A with the following actions: -

    - -
    -nd_na {
    -    eth.src = E;
    -    ip6.src = A;
    -    nd.target = A;
    -    nd.tll = E;
    -    outport = inport;
    -    flags.loopback = 1;
    -    output;
    -};
    -        
    - -

    - For the gateway port on a distributed logical router (where - one of the logical router ports specifies a - redirect-chassis), the above flows replying to - IPv6 Neighbor Solicitations are only programmed on the - gateway port instance on the redirect-chassis. - This behavior avoids generation of multiple replies from - different chassis, and allows upstream MAC learning to point - to the redirect-chassis. -

    -
  • -
  • Priority-85 flows which drops the ARP and IPv6 Neighbor Discovery packets. @@ -1694,10 +1709,11 @@ nd_na { handled by one of the flows above, which amounts to ICMP (other than echo requests) and fragments with nonzero offsets. For each IP address A owned by the router, a priority-60 flow matches - ip4.dst == A and drops the traffic. An - exception is made and the above flow is not added if the router - port's own IP address is used to SNAT packets passing through that - router. + ip4.dst == A or + ip6.dst == A + and drops the traffic. An exception is made and the above flow + is not added if the router port's own IP address is used to SNAT + packets passing through that router.
  • @@ -1791,23 +1807,26 @@ icmp6 {

    If the Gateway router has been configured to force SNAT any previously DNATted packets to B, a priority-110 flow - matches ip && ip4.dst == B with - an action ct_snat; . + matches ip && ip4.dst == B or + ip && ip6.dst == B + with an action ct_snat; .

    If the Gateway router has been configured to force SNAT any previously load-balanced packets to B, a priority-100 flow - matches ip && ip4.dst == B with - an action ct_snat; . + matches ip && ip4.dst == B or + ip && ip6.dst == B + with an action ct_snat; .

    For each NAT configuration in the OVN Northbound database, that asks to change the source IP address of a packet from A to - B, a priority-90 flow matches ip && - ip4.dst == B with an action - ct_snat; . + B, a priority-90 flow matches + ip && ip4.dst == B or + ip && ip6.dst == B + with an action ct_snat; .

    @@ -1825,7 +1844,9 @@ icmp6 { For each configuration in the OVN Northbound database, that asks to change the source IP address of a packet from A to B, a priority-100 flow matches ip && - ip4.dst == B && inport == GW, + ip4.dst == B && inport == GW or + ip && + ip6.dst == B && inport == GW where GW is the logical router gateway port, with an action ct_snat;.

    @@ -1839,10 +1860,12 @@ icmp6 {

    For each configuration in the OVN Northbound database, that asks to change the source IP address of a packet from A to - B, a priority-50 flow matches ip && - ip4.dst == B with an action + B, a priority-50 flow matches + ip && ip4.dst == B or + ip && ip6.dst == B + with an action REGBIT_NAT_REDIRECT = 1; next;. This flow is for - east/west traffic to a NAT destination IPv4 address. By + east/west traffic to a NAT destination IPv4/IPv6 address. By setting the REGBIT_NAT_REDIRECT flag, in the ingress table Gateway Redirect this will trigger a redirect to the instance of the gateway port on the @@ -1888,25 +1911,27 @@ icmp6 { For all the configured load balancing rules for a Gateway router or Router with gateway port in OVN_Northbound database that includes a L4 port PORT of protocol P and IPv4 - address VIP, a priority-120 flow that matches on + or IPv6 address VIP, a priority-120 flow that matches on ct.new && ip && ip4.dst == VIP && P && P.dst == PORT - with an action of ct_lb(args), - where args contains comma separated IPv4 addresses (and - optional port numbers) to load balance to. If the router is configured - to force SNAT any load-balanced packets, the above action will be - replaced by flags.force_snat_for_lb = 1; + (ip6.dst == VIP in the IPv6 case) + with an action of ct_lb(args), + where args contains comma separated IPv4 or IPv6 addresses + (and optional port numbers) to load balance to. If the router is + configured to force SNAT any load-balanced packets, the above action + will be replaced by flags.force_snat_for_lb = 1; ct_lb(args);.

  • For all the configured load balancing rules for a router in OVN_Northbound database that includes a L4 port - PORT of protocol P and IPv4 address + PORT of protocol P and IPv4 or IPv6 address VIP, a priority-120 flow that matches on ct.est && ip && ip4.dst == VIP && P && P.dst == PORT - with an action of ct_dnat;. If the router is + (ip6.dst == VIP in the IPv6 case) + with an action of ct_dnat;. If the router is configured to force SNAT any load-balanced packets, the above action will be replaced by flags.force_snat_for_lb = 1; ct_dnat;.
  • @@ -1916,11 +1941,13 @@ icmp6 { OVN_Northbound database that includes just an IP address VIP to match on, a priority-110 flow that matches on ct.new && ip && ip4.dst == - VIP with an action of + VIP (ip6.dst == VIP in the + IPv6 case) with an action of ct_lb(args), where args contains - comma separated IPv4 addresses. If the router is configured to force - SNAT any load-balanced packets, the above action will be replaced by - flags.force_snat_for_lb = 1; ct_lb(args);. + comma separated IPv4 or IPv6 addresses. If the router is configured + to force SNAT any load-balanced packets, the above action will be + replaced by flags.force_snat_for_lb = 1; + ct_lb(args);.
  • @@ -1928,7 +1955,8 @@ icmp6 { OVN_Northbound database that includes just an IP address VIP to match on, a priority-110 flow that matches on ct.est && ip && ip4.dst == - VIP with an action of ct_dnat;. + VIP (or ip6.dst == VIP) + with an action of ct_dnat;. If the router is configured to force SNAT any load-balanced packets, the above action will be replaced by flags.force_snat_for_lb = 1; ct_dnat;. @@ -1942,7 +1970,8 @@ icmp6 { For each configuration in the OVN Northbound database, that asks to change the destination IP address of a packet from A to B, a priority-100 flow matches ip && - ip4.dst == A with an action + ip4.dst == A or ip && + ip6.dst == A with an action flags.loopback = 1; ct_dnat(B);. If the Gateway router is configured to force SNAT any DNATed packet, the above action will be replaced by @@ -1979,7 +2008,8 @@ icmp6 { B, a priority-100 flow matches ip && ip4.dst == B && inport == GW, where GW is the logical router gateway port, with an - action ct_dnat(B);. + action ct_dnat(B);. The match will + include ip6.dst == B in the IPv6 case.

    @@ -1992,9 +2022,10 @@ icmp6 { For each configuration in the OVN Northbound database, that asks to change the destination IP address of a packet from A to B, a priority-50 flow matches ip && - ip4.dst == B with an action + ip4.dst == B or ip && + ip6.dst == B with an action REGBIT_NAT_REDIRECT = 1; next;. This flow is for - east/west traffic to a NAT destination IPv4 address. By + east/west traffic to a NAT destination IPv4/IPv6 address. By setting the REGBIT_NAT_REDIRECT flag, in the ingress table Gateway Redirect this will trigger a redirect to the instance of the gateway port on the @@ -2149,8 +2180,8 @@ logical_ip{0,1} = LIP{0,1};

     eth.dst = MAC0;
     eth.src = MAC1;
    -reg0 = ip4.dst;
    -reg1 = EIP1;
    +reg0 = ip4.dst; /* xxreg0 = ip6.dst; in the IPv6 case */
    +reg1 = EIP1; /* xxreg1 in the IPv6 case */
     outport = redirect-chassis-port;
     REGBIT_DISTRIBUTED_NAT = 1; next;.
             
    diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c index ae81a6944..71ee0b678 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -66,6 +66,15 @@ struct northd_context { struct ovsdb_idl_index *sbrec_ip_mcast_by_dp; }; +/* An IPv4 or IPv6 address */ +struct v46_ip { + int family; + union { + ovs_be32 ipv4; + struct in6_addr ipv6; + }; +}; + static const char *ovnnb_db; static const char *ovnsb_db; static const char *unixctl_path; @@ -2273,6 +2282,15 @@ get_nat_addresses(const struct ovn_port *op, size_t *n) break; } } + if (!is_router_ip) { + for (size_t j = 0; j < op->lrp_networks.n_ipv6_addrs; j++) { + if (!strcmp(nat->external_ip, + op->lrp_networks.ipv6_addrs[j].addr_s)) { + is_router_ip = true; + break; + } + } + } if (!is_router_ip) { ds_put_format(&c_addresses, " %s", nat->external_ip); @@ -6031,9 +6049,28 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) continue; } + /* Determine if we need to create IPv4 or IPv6 flows */ + ovs_be32 ip; + struct in6_addr ipv6; + int family = AF_INET; + if (!ip_parse(nat->external_ip, &ip) || !ip) { + family = AF_INET6; + if (!ipv6_parse(nat->external_ip, &ipv6)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad ip address %s in nat configuration " + "for router %s", nat->external_ip, op->key); + /* We'll create IPv6 flows anyway, but the address + * is probably bogus ... */ + } + } + ds_put_format(&match, "inport == %s && " - "ip4.src == %s && ip4.dst == %s", - op->json_key, nat->logical_ip, nat->external_ip); + "ip%s.src == %s && ip%s.dst == %s", + op->json_key, + family == AF_INET ? "4" : "6", + nat->logical_ip, + family == AF_INET ? "4" : "6", + nat->external_ip); ds_put_format(&actions, "outport = %s; eth.dst = %s; " REGBIT_DISTRIBUTED_NAT" = 1; " REGBIT_NAT_REDIRECT" = 0; next;", @@ -6051,17 +6088,38 @@ add_distributed_nat_routes(struct hmap *lflows, const struct ovn_port *op) !nat2->external_mac || !nat2->external_ip) continue; + family = AF_INET; + if (!ip_parse(nat2->external_ip, &ip) || !ip) { + family = AF_INET6; + if (!ipv6_parse(nat2->external_ip, &ipv6)) { + static struct vlog_rate_limit rl = + VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad ip address %s in nat configuration " + "for router %s", nat2->external_ip, op->key); + /* We'll create IPv6 flows anyway, but the address + * is probably bogus ... */ + } + } + ds_put_format(&match, "inport == %s && " - "ip4.src == %s && ip4.dst == %s", - op->json_key, nat->logical_ip, nat2->external_ip); + "ip%s.src == %s && ip%s.dst == %s", + op->json_key, + family == AF_INET ? "4" : "6", + nat->logical_ip, + family == AF_INET ? "4" : "6", + nat2->external_ip); ds_put_format(&actions, "outport = %s; " "eth.src = %s; eth.dst = %s; " - "reg0 = ip4.dst; reg1 = %s; " + "%sreg0 = ip%s.dst; %sreg1 = %s; " REGBIT_DISTRIBUTED_NAT" = 1; " REGBIT_NAT_REDIRECT" = 0; next;", op->od->l3dgw_port->json_key, op->od->l3dgw_port->lrp_networks.ea_s, - nat2->external_mac, nat->external_ip); + nat2->external_mac, + family == AF_INET ? "" : "xx", + family == AF_INET ? "4" : "6", + family == AF_INET ? "" : "xx", + nat->external_ip); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, 400, ds_cstr(&match), ds_cstr(&actions)); ds_clear(&match); @@ -6298,7 +6356,8 @@ op_put_v6_networks(struct ds *ds, const struct ovn_port *op) } static const char * -get_force_snat_ip(struct ovn_datapath *od, const char *key_type, ovs_be32 *ip) +get_force_snat_ip(struct ovn_datapath *od, const char *key_type, + struct v46_ip *ip) { char *key = xasprintf("%s_force_snat_ip", key_type); const char *ip_address = smap_get(&od->nbr->options, key); @@ -6306,19 +6365,27 @@ get_force_snat_ip(struct ovn_datapath *od, const char *key_type, ovs_be32 *ip) if (ip_address) { ovs_be32 mask; - char *error = ip_parse_masked(ip_address, ip, &mask); + ip->family = AF_INET; + char *error = ip_parse_masked(ip_address, &ip->ipv4, &mask); if (error || mask != OVS_BE32_MAX) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad ip %s in options of router "UUID_FMT"", - ip_address, UUID_ARGS(&od->key)); free(error); - *ip = 0; - return NULL; + struct in6_addr mask_v6, v6_exact = IN6ADDR_EXACT_INIT; + ip->family = AF_INET6; + error = ipv6_parse_masked(ip_address, &ip->ipv6, &mask_v6); + if (error || memcmp(&mask_v6, &v6_exact, sizeof(mask_v6))) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad ip %s in options of router "UUID_FMT"", + ip_address, UUID_ARGS(&od->key)); + memset(ip, 0, sizeof *ip); + ip->family = AF_UNSPEC; + return NULL; + } } return ip_address; } - *ip = 0; + memset(ip, 0, sizeof *ip); + ip->family = AF_UNSPEC; return NULL; } @@ -6884,11 +6951,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* A gateway router can have 2 SNAT IP addresses to force DNATed and * LBed traffic respectively to be SNATed. In addition, there can be * a number of SNAT rules in the NAT table. */ - ovs_be32 *snat_ips = xmalloc(sizeof *snat_ips * - (op->od->nbr->n_nat + 2)); + struct v46_ip *snat_ips = xmalloc(sizeof *snat_ips + * (op->od->nbr->n_nat + 2)); size_t n_snat_ips = 0; - ovs_be32 snat_ip; + struct v46_ip snat_ip; const char *dnat_force_snat_ip = get_force_snat_ip(op->od, "dnat", &snat_ip); if (dnat_force_snat_ip) { @@ -6907,44 +6974,85 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, nat = op->od->nbr->nat[i]; ovs_be32 ip; + struct in6_addr ipv6; + bool is_v6 = false; if (!ip_parse(nat->external_ip, &ip) || !ip) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad ip address %s in nat configuration " - "for router %s", nat->external_ip, op->key); - continue; + if (!ipv6_parse(nat->external_ip, &ipv6)) { + static struct vlog_rate_limit rl = + VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad ip address %s in nat configuration " + "for router %s", nat->external_ip, op->key); + continue; + } + is_v6 = true; } if (!strcmp(nat->type, "snat")) { - snat_ips[n_snat_ips++] = ip; + if (is_v6) { + snat_ips[n_snat_ips].family = AF_INET6; + snat_ips[n_snat_ips++].ipv6 = ipv6; + } else { + snat_ips[n_snat_ips].family = AF_INET; + snat_ips[n_snat_ips++].ipv4 = ip; + } continue; } - /* ARP handling for external IP addresses. + /* ARP / ND handling for external IP addresses. * * DNAT IP addresses are external IP addresses that need ARP * handling. */ + char addr_s[INET6_ADDRSTRLEN + 1]; ds_clear(&match); - ds_put_format(&match, - "inport == %s && arp.tpa == "IP_FMT" && arp.op == 1", - op->json_key, IP_ARGS(ip)); - ds_clear(&actions); - ds_put_format(&actions, - "eth.dst = eth.src; " - "arp.op = 2; /* ARP reply */ " - "arp.tha = arp.sha; "); + if (is_v6) { + /* For ND solicitations, we need to listen for both the + * unicast IPv6 address and its all-nodes multicast address, + * but always respond with the unicast IPv6 address. */ + char sn_addr_s[INET6_ADDRSTRLEN + 1]; + struct in6_addr sn_addr; + in6_addr_solicited_node(&sn_addr, &ipv6); + ipv6_string_mapped(sn_addr_s, &sn_addr); + ipv6_string_mapped(addr_s, &ipv6); + + ds_put_format(&match, "inport == %s && " + "nd_ns && ip6.dst == {%s, %s} && nd.target == %s", + op->json_key, addr_s, sn_addr_s, addr_s); + ds_put_format(&actions, + "eth.dst = eth.src; " + "nd_na { "); + } else { + ds_put_format(&match, + "inport == %s " + "&& arp.tpa == "IP_FMT" && arp.op == 1", + op->json_key, IP_ARGS(ip)); + + ds_put_format(&actions, + "eth.dst = eth.src; " + "arp.op = 2; /* ARP reply */ " + "arp.tha = arp.sha; "); + } if (op->od->l3dgw_port && op == op->od->l3dgw_port) { struct eth_addr mac; if (nat->external_mac && eth_addr_from_string(nat->external_mac, &mac) && nat->logical_port) { /* distributed NAT case, use nat->external_mac */ - ds_put_format(&actions, - "eth.src = "ETH_ADDR_FMT"; " - "arp.sha = "ETH_ADDR_FMT"; ", - ETH_ADDR_ARGS(mac), - ETH_ADDR_ARGS(mac)); + if (is_v6) { + ds_put_format(&actions, + "eth.src = "ETH_ADDR_FMT"; " + "nd.tll = "ETH_ADDR_FMT"; ", + ETH_ADDR_ARGS(mac), + ETH_ADDR_ARGS(mac)); + + } else { + ds_put_format(&actions, + "eth.src = "ETH_ADDR_FMT"; " + "arp.sha = "ETH_ADDR_FMT"; ", + ETH_ADDR_ARGS(mac), + ETH_ADDR_ARGS(mac)); + } /* Traffic with eth.src = nat->external_mac should only be * sent from the chassis where nat->logical_port is * resident, so that upstream MAC learning points to the @@ -6953,11 +7061,20 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_put_format(&match, " && is_chassis_resident(\"%s\")", nat->logical_port); } else { - ds_put_format(&actions, - "eth.src = %s; " - "arp.sha = %s; ", - op->lrp_networks.ea_s, - op->lrp_networks.ea_s); + if (is_v6) { + ds_put_format(&actions, + "eth.src = %s; " + "nd.tll = %s; ", + op->lrp_networks.ea_s, + op->lrp_networks.ea_s); + + } else { + ds_put_format(&actions, + "eth.src = %s; " + "arp.sha = %s; ", + op->lrp_networks.ea_s, + op->lrp_networks.ea_s); + } /* Traffic with eth.src = l3dgw_port->lrp_networks.ea_s * should only be sent from the "redirect-chassis", so that * upstream MAC learning points to the "redirect-chassis". @@ -6968,21 +7085,40 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, op->od->l3redirect_port->json_key); } } + } else { + if (is_v6) { + ds_put_format(&actions, + "eth.src = %s; " + "nd.tll = %s; ", + op->lrp_networks.ea_s, + op->lrp_networks.ea_s); + } else { + ds_put_format(&actions, + "eth.src = %s; " + "arp.sha = %s; ", + op->lrp_networks.ea_s, + op->lrp_networks.ea_s); + } + } + if (is_v6) { + ds_put_format(&actions, + "ip6.src = %s; " + "nd.target = %s; " + "outport = %s; " + "flags.loopback = 1; " + "output; " + "};", + addr_s, addr_s, op->json_key); } else { ds_put_format(&actions, - "eth.src = %s; " - "arp.sha = %s; ", - op->lrp_networks.ea_s, - op->lrp_networks.ea_s); + "arp.tpa = arp.spa; " + "arp.spa = "IP_FMT"; " + "outport = %s; " + "flags.loopback = 1; " + "output;", + IP_ARGS(ip), + op->json_key); } - ds_put_format(&actions, - "arp.tpa = arp.spa; " - "arp.spa = "IP_FMT"; " - "outport = %s; " - "flags.loopback = 1; " - "output;", - IP_ARGS(ip), - op->json_key); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, ds_cstr(&match), ds_cstr(&actions)); } @@ -7039,7 +7175,36 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, bool snat_ip_is_router_ip = false; for (int j = 0; j < n_snat_ips; j++) { /* Packets to SNAT IPs should not be dropped. */ - if (op->lrp_networks.ipv4_addrs[i].addr == snat_ips[j]) { + if (snat_ips[j].family == AF_INET + && op->lrp_networks.ipv4_addrs[i].addr + == snat_ips[j].ipv4) { + snat_ip_is_router_ip = true; + break; + } + } + if (snat_ip_is_router_ip) { + continue; + } + ds_put_format(&match, "%s, ", + op->lrp_networks.ipv4_addrs[i].addr_s); + has_drop_ips = true; + } + if (has_drop_ips) { + ds_chomp(&match, ' '); + ds_chomp(&match, ','); + ds_put_cstr(&match, "} || ip6.dst == {"); + } else { + ds_clear(&match); + ds_put_cstr(&match, "ip6.dst == {"); + } + + for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { + bool snat_ip_is_router_ip = false; + for (int j = 0; j < n_snat_ips; j++) { + /* Packets to SNAT IPs should not be dropped. */ + if (snat_ips[j].family == AF_INET6 + && !memcmp(&op->lrp_networks.ipv6_addrs[i].addr, + &snat_ips[j].ipv6, sizeof snat_ips[j].ipv6)) { snat_ip_is_router_ip = true; break; } @@ -7048,9 +7213,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } ds_put_format(&match, "%s, ", - op->lrp_networks.ipv4_addrs[i].addr_s); + op->lrp_networks.ipv6_addrs[i].addr_s); has_drop_ips = true; } + ds_chomp(&match, ' '); ds_chomp(&match, ','); ds_put_cstr(&match, "}"); @@ -7077,14 +7243,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } if (op->lrp_networks.n_ipv6_addrs) { - /* L3 admission control: drop packets that originate from an - * IPv6 address owned by the router (priority 100). */ - ds_clear(&match); - ds_put_cstr(&match, "ip6.src == "); - op_put_v6_networks(&match, op); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100, - ds_cstr(&match), "drop;"); - /* ICMPv6 echo reply. These flows reply to echo requests * received for the router's IP address. */ ds_clear(&match); @@ -7101,13 +7259,6 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, "next; "); ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90, ds_cstr(&match), ds_cstr(&actions)); - - /* Drop IPv6 traffic to this router. */ - ds_clear(&match); - ds_put_cstr(&match, "ip6.dst == "); - op_put_v6_networks(&match, op); - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60, - ds_cstr(&match), "drop;"); } /* ND reply. These flows reply to ND solicitations for the @@ -7249,11 +7400,11 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } - ovs_be32 snat_ip; + struct v46_ip snat_ip, lb_snat_ip; const char *dnat_force_snat_ip = get_force_snat_ip(od, "dnat", &snat_ip); const char *lb_force_snat_ip = get_force_snat_ip(od, "lb", - &snat_ip); + &lb_snat_ip); for (int i = 0; i < od->nbr->n_nat; i++) { const struct nbrec_nat *nat; @@ -7261,21 +7412,38 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, nat = od->nbr->nat[i]; ovs_be32 ip, mask; + struct in6_addr ipv6, mask_v6, v6_exact = IN6ADDR_EXACT_INIT; + bool is_v6 = false; char *error = ip_parse_masked(nat->external_ip, &ip, &mask); if (error || mask != OVS_BE32_MAX) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "bad external ip %s for nat", - nat->external_ip); free(error); - continue; + error = ipv6_parse_masked(nat->external_ip, &ipv6, &mask_v6); + if (error || memcmp(&mask_v6, &v6_exact, sizeof(mask_v6))) { + /* Invalid for both IPv4 and IPv6 */ + static struct vlog_rate_limit rl = + VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "bad external ip %s for nat", + nat->external_ip); + free(error); + continue; + } + /* It was an invalid IPv4 address, but valid IPv6. + * Treat the rest of the handling of this NAT rule + * as IPv6. */ + is_v6 = true; } /* Check the validity of nat->logical_ip. 'logical_ip' can * be a subnet when the type is "snat". */ - error = ip_parse_masked(nat->logical_ip, &ip, &mask); + if (is_v6) { + error = ipv6_parse_masked(nat->external_ip, &ipv6, &mask_v6); + } else { + error = ip_parse_masked(nat->logical_ip, &ip, &mask); + } if (!strcmp(nat->type, "snat")) { if (error) { + /* Invalid for both IPv4 and IPv6 */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); VLOG_WARN_RL(&rl, "bad ip network or ip %s for snat " @@ -7285,7 +7453,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, continue; } } else { - if (error || mask != OVS_BE32_MAX) { + if (error || (!is_v6 && mask != OVS_BE32_MAX) + || (is_v6 && memcmp(&mask_v6, &v6_exact, + sizeof mask_v6))) { + /* Invalid for both IPv4 and IPv6 */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); VLOG_WARN_RL(&rl, "bad ip %s for dnat in router " @@ -7326,7 +7497,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (!od->l3dgw_port) { /* Gateway router. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s", + ds_put_format(&match, "ip && ip%s.dst == %s", + is_v6 ? "6" : "4", nat->external_ip); ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 90, ds_cstr(&match), "ct_snat;"); @@ -7335,8 +7507,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* Traffic received on l3dgw_port is subject to NAT. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s" + ds_put_format(&match, "ip && ip%s.dst == %s" " && inport == %s", + is_v6 ? "6" : "4", nat->external_ip, od->l3dgw_port->json_key); if (!distributed && od->l3redirect_port) { @@ -7352,7 +7525,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * redirected to the central instance of the l3dgw_port * for NAT processing. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s", + ds_put_format(&match, "ip && ip%s.dst == %s", + is_v6 ? "6" : "4", nat->external_ip); ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 50, ds_cstr(&match), @@ -7371,7 +7545,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * We need to set flags.loopback because the router can * send the packet back through the same interface. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s", + ds_put_format(&match, "ip && ip%s.dst == %s", + is_v6 ? "6" : "4", nat->external_ip); ds_clear(&actions); if (dnat_force_snat_ip) { @@ -7390,8 +7565,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* Traffic received on l3dgw_port is subject to NAT. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s" + ds_put_format(&match, "ip && ip%s.dst == %s" " && inport == %s", + is_v6 ? "6" : "4", nat->external_ip, od->l3dgw_port->json_key); if (!distributed && od->l3redirect_port) { @@ -7410,7 +7586,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * redirected to the central instance of the l3dgw_port * for NAT processing. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s", + ds_put_format(&match, "ip && ip%s.dst == %s", + is_v6 ? "6" : "4", nat->external_ip); ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 50, ds_cstr(&match), @@ -7429,8 +7606,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (od->l3dgw_port && (!strcmp(nat->type, "dnat") || !strcmp(nat->type, "dnat_and_snat"))) { ds_clear(&match); - ds_put_format(&match, "ip && ip4.src == %s" + ds_put_format(&match, "ip && ip%s.src == %s" " && outport == %s", + is_v6 ? "6" : "4", nat->logical_ip, od->l3dgw_port->json_key); if (!distributed && od->l3redirect_port) { @@ -7457,7 +7635,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (!od->l3dgw_port) { /* Gateway router. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.src == %s", + ds_put_format(&match, "ip && ip%s.src == %s", + is_v6 ? "6" : "4", nat->logical_ip); ds_clear(&actions); ds_put_format(&actions, "ct_snat(%s);", nat->external_ip); @@ -7473,8 +7652,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, /* Distributed router. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.src == %s" + ds_put_format(&match, "ip && ip%s.src == %s" " && outport == %s", + is_v6 ? "6" : "4", nat->logical_ip, od->l3dgw_port->json_key); if (!distributed && od->l3redirect_port) { @@ -7523,7 +7703,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * can be applied in a distributed manner. */ if (distributed) { ds_clear(&match); - ds_put_format(&match, "ip4.src == %s && outport == %s", + ds_put_format(&match, "ip%s.src == %s && outport == %s", + is_v6 ? "6" : "4", nat->logical_ip, od->l3dgw_port->json_key); ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 100, @@ -7550,9 +7731,10 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&match); ds_put_format(&match, "is_chassis_resident(\"%s\") && " - "ip4.src == %s && ip4.dst == %s", - nat->logical_port, nat2->external_ip, - nat->external_ip); + "ip%s.src == %s && ip%s.dst == %s", + nat->logical_port, + is_v6 ? "6" : "4", nat2->external_ip, + is_v6 ? "6" : "4", nat->external_ip); ds_clear(&actions); ds_put_format(&actions, "inport = outport; outport = \"\"; " @@ -7564,8 +7746,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, ds_clear(&match); ds_put_format(&match, - "ip4.src == %s && ip4.dst == %s", - nat2->external_ip, nat->external_ip); + "ip%s.src == %s && ip%s.dst == %s", + is_v6 ? "6" : "4", nat2->external_ip, + is_v6 ? "6" : "4", nat->external_ip); ovn_lflow_add(lflows, od, S_ROUTER_OUT_EGR_LOOP, 200, ds_cstr(&match), "next;"); ds_clear(&match); @@ -7573,7 +7756,8 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, } ds_clear(&match); - ds_put_format(&match, "ip4.dst == %s && outport == %s", + ds_put_format(&match, "ip%s.dst == %s && outport == %s", + is_v6 ? "6" : "4", nat->external_ip, od->l3dgw_port->json_key); ds_clear(&actions); @@ -7597,7 +7781,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * gateway router (as set in options:dnat_force_snat_ip) is seen, * UNSNAT it. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s", dnat_force_snat_ip); + ds_put_format(&match, "ip && ip%s.dst == %s", + snat_ip.family == AF_INET ? "4" : "6", + dnat_force_snat_ip); ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 110, ds_cstr(&match), "ct_snat;"); @@ -7616,7 +7802,9 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, * gateway router (as set in options:lb_force_snat_ip) is seen, * UNSNAT it. */ ds_clear(&match); - ds_put_format(&match, "ip && ip4.dst == %s", lb_force_snat_ip); + ds_put_format(&match, "ip && ip%s.dst == %s", + lb_snat_ip.family == AF_INET ? "4" : "6", + lb_force_snat_ip); ovn_lflow_add(lflows, od, S_ROUTER_IN_UNSNAT, 100, ds_cstr(&match), "ct_snat;"); @@ -7718,7 +7906,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (addr_family == AF_INET) { ds_put_format(&match, "ip && ip4.dst == %s", ip_address); - } else { + } else if (addr_family == AF_INET6) { ds_put_format(&match, "ip && ip6.dst == %s", ip_address); } @@ -7738,7 +7926,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, if (addr_family == AF_INET) { ds_put_format(&match, "ip && ip4.dst == %s", ip_address); - } else { + } else if (addr_family == AF_INET6) { ds_put_format(&match, "ip && ip6.dst == %s", ip_address); } From patchwork Wed Oct 30 14:53:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Bryant X-Patchwork-Id: 1186790 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=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 473BRJ1X27z9sP3 for ; Thu, 31 Oct 2019 01:58:36 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 2D063E5A; Wed, 30 Oct 2019 14:53:41 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 47AAADB2 for ; Wed, 30 Oct 2019 14:53:37 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id 9354687B for ; Wed, 30 Oct 2019 14:53:34 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-66-mSTqcgoVP9auclDNNYLkKw-1; Wed, 30 Oct 2019 10:53:30 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 5D198800C61; Wed, 30 Oct 2019 14:53:29 +0000 (UTC) Received: from t480s.redhat.com (ovpn-126-115.rdu2.redhat.com [10.10.126.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id EED5B52FD; Wed, 30 Oct 2019 14:53:28 +0000 (UTC) From: Russell Bryant To: dev@openvswitch.org Date: Wed, 30 Oct 2019 10:53:23 -0400 Message-Id: <20191030145324.9988-6-russell@ovn.org> In-Reply-To: <20191030145324.9988-1-russell@ovn.org> References: <20191030013138.9390-1-russell@ovn.org> <20191030145324.9988-1-russell@ovn.org> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: mSTqcgoVP9auclDNNYLkKw-1 X-Mimecast-Spam-Score: 0 X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH ovn v2 5/6] system-ovn: Add IPv6 NAT test cases X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org These tests failed prior to the changes leading up to this one. Signed-off-by: Russell Bryant --- tests/system-ovn.at | 862 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 860 insertions(+), 2 deletions(-) diff --git a/tests/system-ovn.at b/tests/system-ovn.at index f88ad31e4..b3f90aae2 100644 --- a/tests/system-ovn.at +++ b/tests/system-ovn.at @@ -176,6 +176,186 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /connection dropped.*/d"]) AT_CLEANUP +AT_SETUP([ovn -- 2 LRs connected via LS, gateway router, SNAT and DNAT - IPv6]) +AT_KEYWORDS([ovnnat]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# Two LRs - R1 and R2 that are connected to each other via LS "join" +# in fd00::/64 network. R1 has switchess foo (fd11::/64) and +# bar (fd12::/64) connected to it. R2 has alice (fd21::/64) connected +# to it. R2 is a gateway router on which we add NAT rules. +# +# foo -- R1 -- join - R2 -- alice +# | +# bar ---- + +ovn-nbctl create Logical_Router name=R1 +ovn-nbctl create Logical_Router name=R2 options:chassis=hv1 + +ovn-nbctl ls-add foo +ovn-nbctl ls-add bar +ovn-nbctl ls-add alice +ovn-nbctl ls-add join + +# Connect foo to R1 +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64 +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ + type=router options:router-port=foo addresses=\"00:00:01:01:02:03\" + +# Connect bar to R1 +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64 +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ + type=router options:router-port=bar addresses=\"00:00:01:01:02:04\" + +# Connect alice to R2 +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd21::1/64 +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ + type=router options:router-port=alice addresses=\"00:00:02:01:02:03\" + +# Connect R1 to join +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd00::1/64 +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \ + type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"' + +# Connect R2 to join +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd00::2/64 +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \ + type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"' + +# Static routes. +ovn-nbctl lr-route-add R1 fd21::/64 fd00::2 +ovn-nbctl lr-route-add R2 fd11::/64 fd00::1 +ovn-nbctl lr-route-add R2 fd12::/64 fd00::1 + +# Logical port 'foo1' in switch 'foo'. +ADD_NAMESPACES(foo1) +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ + "fd11::1") +OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add foo foo1 \ +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" + +# Logical port 'alice1' in switch 'alice'. +ADD_NAMESPACES(alice1) +ADD_VETH(alice1, alice1, br-int, "fd21::2/64", "f0:00:00:01:02:04", \ + "fd21::1") +OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd21::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add alice alice1 \ +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd21::2" + +# Logical port 'bar1' in switch 'bar'. +ADD_NAMESPACES(bar1) +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \ + "fd12::1") +OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add bar bar1 \ +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2" + +# Add a DNAT rule. +ovn-nbctl -- --id=@nat create nat type="dnat" logical_ip=\"fd11::2\" \ + external_ip=\"fd30::2\" -- add logical_router R2 nat @nat + +# Add a SNAT rule +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=\"fd12::2\" \ + external_ip=\"fd30::1\" -- add logical_router R2 nat @nat + +# wait for ovn-controller to catch up. +ovn-nbctl --wait=hv sync +OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd30::1)']) + +# 'alice1' should be able to ping 'foo1' directly. +NS_CHECK_EXEC([alice1], [ping -6 -v -q -c 3 -i 0.3 -w 2 fd11::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# North-South DNAT: 'alice1' should also be able to ping 'foo1' via fd30::2 +NS_CHECK_EXEC([alice1], [ping -6 -q -c 3 -i 0.3 -w 2 fd30::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# Check conntrack entries. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd21::2) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd21::2,dst=fd30::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd21::2,id=,type=129,code=0),zone= +]) + +# South-North SNAT: 'bar1' pings 'alice1'. But 'alice1' receives traffic +# from fd30::1 +NS_CHECK_EXEC([bar1], [ping -6 -q -c 3 -i 0.3 -w 2 fd21::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that SNAT indeed happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd12::2,dst=fd21::2,id=,type=128,code=0),reply=(src=fd21::2,dst=fd30::1,id=,type=129,code=0),zone= +]) + +# Add static routes to handle east-west NAT. +ovn-nbctl lr-route-add R1 fd30::/64 fd00::2 + +# wait for ovn-controller to catch up. +ovn-nbctl --wait=hv sync + +# Flush conntrack entries for easier output parsing of next test. +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) + +# East-west DNAT and SNAT: 'bar1' pings fd30::2. 'foo1' receives it. +NS_CHECK_EXEC([bar1], [ping -6 -q -c 3 -i 0.3 -w 2 fd30::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# As we have a static route that sends all packets with destination +# fd30::2 to R2, it hits the DNAT rule and converts fd30::2 to fd11::2 +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::2) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd12::2,dst=fd30::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd12::2,id=,type=129,code=0),zone= +]) + +# As we have a SNAT rule that converts fd12::2 to fd30::1, the source is +# SNATted and 'foo1' receives it. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd12::2,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd30::1,id=,type=129,code=0),zone= +]) + +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 + AT_SETUP([ovn -- 2 LRs connected via LS, gateway router, easy SNAT]) AT_KEYWORDS([ovnnat]) @@ -286,6 +466,118 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /connection dropped.*/d"]) AT_CLEANUP +AT_SETUP([ovn -- 2 LRs connected via LS, gateway router, easy SNAT - IPv6]) +AT_KEYWORDS([ovnnat]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# Two LRs - R1 and R2 that are connected to each other via LS "join" +# in fd20::/64 network. R1 has switchess foo (fd10::/64) connected +# to it. R2 has alice (fd30::/64) connected to it. +# R2 is a gateway router on which we add NAT rules. +# +# foo -- R1 -- join - R2 -- alice + +ovn-nbctl lr-add R1 +ovn-nbctl lr-add R2 -- set Logical_Router R2 options:chassis=hv1 + +ovn-nbctl ls-add foo +ovn-nbctl ls-add alice +ovn-nbctl ls-add join + +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd10::1/64 +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd30::1/64 +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64 +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64 + +# Connect foo to R1 +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ + type=router options:router-port=foo addresses=\"00:00:01:01:02:03\" + +# Connect alice to R2 +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ + type=router options:router-port=alice addresses=\"00:00:02:01:02:03\" + +# Connect R1 to join +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \ + type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"' + +# Connect R2 to join +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \ + type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"' + +# Static routes. +ovn-nbctl lr-route-add R1 fd30::/64 fd20::2 +ovn-nbctl lr-route-add R2 fd10::/64 fd20::1 + +# Logical port 'foo1' in switch 'foo'. +ADD_NAMESPACES(foo1) +ADD_VETH(foo1, foo1, br-int, "fd10::2/64", "f0:00:00:01:02:03", \ + "fd10::1") +OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd10::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add foo foo1 \ +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd10::2" + +# Logical port 'alice1' in switch 'alice'. +ADD_NAMESPACES(alice1) +ADD_VETH(alice1, alice1, br-int, "fd30::2/64", "f0:00:00:01:02:04", \ + "fd30::1") +OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd30::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add alice alice1 \ +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd30::2" + +# Add a SNAT rule +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip=\"fd10::2\" \ + external_ip=\"fd30::1\" -- add logical_router R2 nat @nat + +ovn-nbctl --wait=hv sync +OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd30::1)']) + +# South-North SNAT: 'foo1' pings 'alice1'. But 'alice1' receives traffic +# from fd30::1 +NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 fd30::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that SNAT indeed happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::1) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd10::2,dst=fd30::2,id=,type=128,code=0),reply=(src=fd30::2,dst=fd30::1,id=,type=129,code=0),zone= +]) + +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 + AT_SETUP([ovn -- multiple gateway routers, SNAT and DNAT]) AT_KEYWORDS([ovnnat]) @@ -485,9 +777,237 @@ NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 172.16.1.3 | FORMAT_PING], \ ]) # We verify that SNAT indeed happened via 'dump-conntrack' command. -AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(30.0.0.1) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmp,orig=(src=192.168.1.2,dst=172.16.1.3,id=,type=8,code=0),reply=(src=172.16.1.3,dst=30.0.0.1,id=,type=0,code=0),zone= +]) + +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 + +AT_SETUP([ovn -- multiple gateway routers, SNAT and DNAT - IPv6]) +AT_KEYWORDS([ovnnat]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# Three LRs - R1, R2 and R3 that are connected to each other via LS "join" +# in fd20::/64 network. R1 has switchess foo (fd11::/64) and +# bar (fd12::/64) connected to it. R2 has alice (fd30::/64) connected +# to it. R3 has bob (fd30::/64) connected to it. Note how both alice and +# bob have the same subnet behind it. We are trying to simulate external +# network via those 2 switches. In real world the switch ports of these +# switches will have addresses set as "unknown" to make them learning switches. +# Or those switches will be "localnet" ones. +# +# foo -- R1 -- join - R2 -- alice +# | | +# bar ---- - R3 --- bob + +ovn-nbctl create Logical_Router name=R1 +ovn-nbctl create Logical_Router name=R2 options:chassis=hv1 +ovn-nbctl create Logical_Router name=R3 options:chassis=hv1 + +ovn-nbctl ls-add foo +ovn-nbctl ls-add bar +ovn-nbctl ls-add alice +ovn-nbctl ls-add bob +ovn-nbctl ls-add join + +# Connect foo to R1 +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64 +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ + type=router options:router-port=foo addresses=\"00:00:01:01:02:03\" + +# Connect bar to R1 +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64 +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ + type=router options:router-port=bar addresses=\"00:00:01:01:02:04\" + +# Connect alice to R2 +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 fd30::1/64 +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ + type=router options:router-port=alice addresses=\"00:00:02:01:02:03\" + +# Connect bob to R3 +ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 fd30::2/64 +ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \ + type=router options:router-port=bob addresses=\"00:00:03:01:02:03\" + +# Connect R1 to join +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 fd20::1/64 +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \ + type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"' + +# Connect R2 to join +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 fd20::2/64 +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \ + type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"' + +# Connect R3 to join +ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 fd20::3/64 +ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \ + type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"' + +# Install static routes with source ip address as the policy for routing. +# We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3. +ovn-nbctl --policy="src-ip" lr-route-add R1 fd11::/64 fd20::2 +ovn-nbctl --policy="src-ip" lr-route-add R1 fd12::/64 fd20::3 + +# Static routes. +ovn-nbctl lr-route-add R2 fd11::/64 fd20::1 +ovn-nbctl lr-route-add R2 fd12::/64 fd20::1 +ovn-nbctl lr-route-add R3 fd11::/64 fd20::1 +ovn-nbctl lr-route-add R3 fd12::/64 fd20::1 + +# For gateway routers R2 and R3, set a force SNAT rule. +ovn-nbctl set logical_router R2 options:dnat_force_snat_ip=fd20::2 +ovn-nbctl set logical_router R3 options:dnat_force_snat_ip=fd20::3 + +# Logical port 'foo1' in switch 'foo'. +ADD_NAMESPACES(foo1) +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ + "fd11::1") +OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add foo foo1 \ +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" + +# Logical port 'alice1' in switch 'alice'. +ADD_NAMESPACES(alice1) +ADD_VETH(alice1, alice1, br-int, "fd30::3/64", "f0:00:00:01:02:04", \ + "fd30::1") +OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd30::3 | grep tentative)" = ""]) +ovn-nbctl lsp-add alice alice1 \ +-- lsp-set-addresses alice1 "f0:00:00:01:02:04 fd30::3" + +# Logical port 'bar1' in switch 'bar'. +ADD_NAMESPACES(bar1) +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:05", \ + "fd12::1") +OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add bar bar1 \ +-- lsp-set-addresses bar1 "f0:00:00:01:02:05 fd12::2" + +# Logical port 'bob1' in switch 'bob'. +ADD_NAMESPACES(bob1) +ADD_VETH(bob1, bob1, br-int, "fd30::4/64", "f0:00:00:01:02:06", \ + "fd30::2") +OVS_WAIT_UNTIL([test "$(ip netns exec bob1 ip a | grep fd30::4 | grep tentative)" = ""]) +ovn-nbctl lsp-add bob bob1 \ +-- lsp-set-addresses bob1 "f0:00:00:01:02:06 fd30::4" + +# External IPs -- 30.0.0.N --> fd40::N (from IPv4 version of test case) + +# Router R2 +# Add a DNAT rule. +ovn-nbctl -- --id=@nat create nat type="dnat" logical_ip='"fd11::2"' \ + external_ip='"fd40::2"' -- add logical_router R2 nat @nat + +# Add a SNAT rule +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip='"fd11::2"' \ + external_ip='"fd40::1"' -- add logical_router R2 nat @nat + +# Router R3 +# Add a DNAT rule. +ovn-nbctl -- --id=@nat create nat type="dnat" logical_ip='"fd11::2"' \ + external_ip='"fd40::3"' -- add logical_router R3 nat @nat + +# Add a SNAT rule +ovn-nbctl -- --id=@nat create nat type="snat" logical_ip='"fd12::2"' \ + external_ip='"fd40::4"' -- add logical_router R3 nat @nat + +# wait for ovn-controller to catch up. +ovn-nbctl --wait=hv sync +OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd40::4)']) + +# North-South DNAT: 'alice1' should be able to ping 'foo1' via fd30::2 +NS_CHECK_EXEC([alice1], [ping -6 -q -c 3 -i 0.3 -w 2 fd40::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# Check conntrack entries. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::3) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd30::3,dst=fd40::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd30::3,id=,type=129,code=0),zone= +]) + +# But foo1 should receive traffic from fd20::2 +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::2) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd30::3,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd20::2,id=,type=129,code=0),zone= +]) + +# North-South DNAT: 'bob1' should be able to ping 'foo1' via fd40::3 +NS_CHECK_EXEC([bob1], [ping -6 -q -c 3 -i 0.3 -w 2 fd40::3 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# Check conntrack entries. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd30::4) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd30::4,dst=fd40::3,id=,type=128,code=0),reply=(src=fd11::2,dst=fd30::4,id=,type=129,code=0),zone= +]) + +# But foo1 should receive traffic from fd20::3 +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::3) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd30::4,dst=fd11::2,id=,type=128,code=0),reply=(src=fd11::2,dst=fd20::3,id=,type=129,code=0),zone= +]) + +# South-North SNAT: 'bar1' pings 'bob1'. But 'bob1' receives traffic +# from fd40::4 +NS_CHECK_EXEC([bar1], [ping -6 -q -c 3 -i 0.3 -w 2 fd30::4 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that SNAT indeed happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd40::4) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd12::2,dst=fd30::4,id=,type=128,code=0),reply=(src=fd30::4,dst=fd40::4,id=,type=129,code=0),zone= +]) + +# South-North SNAT: 'foo1' pings 'alice1'. But 'alice1' receives traffic +# from fd40::1 +NS_CHECK_EXEC([foo1], [ping -6 -q -c 3 -i 0.3 -w 2 fd30::3 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that SNAT indeed happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd40::1) | \ sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl -icmp,orig=(src=192.168.1.2,dst=172.16.1.3,id=,type=8,code=0),reply=(src=172.16.1.3,dst=30.0.0.1,id=,type=0,code=0),zone= +icmpv6,orig=(src=fd11::2,dst=fd30::3,id=,type=128,code=0),reply=(src=fd30::3,dst=fd40::1,id=,type=129,code=0),zone= ]) OVS_APP_EXIT_AND_WAIT([ovn-controller]) @@ -1370,6 +1890,162 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /connection dropped.*/d"]) AT_CLEANUP +AT_SETUP([ovn -- DNAT and SNAT on distributed router - N/S - IPv6]) +AT_KEYWORDS([ovnnat]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# One LR R1 with switches foo (fd11::/64), bar (fd12::/64), +# and alice (fd20::/64) connected to it. The port between R1 and +# alice is the router gateway port where the R1 NAT rules are applied. +# +# foo -- R1 -- alice +# | +# bar ---- + +ovn-nbctl lr-add R1 + +ovn-nbctl ls-add foo +ovn-nbctl ls-add bar +ovn-nbctl ls-add alice + +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64 +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64 +ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 fd20::1/64 \ + -- set Logical_Router_Port alice options:redirect-chassis=hv1 + +# Connect foo to R1 +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ + type=router options:router-port=foo \ + -- lsp-set-addresses rp-foo router + +# Connect bar to R1 +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ + type=router options:router-port=bar \ + -- lsp-set-addresses rp-bar router + +# Connect alice to R1 +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ + type=router options:router-port=alice \ + -- lsp-set-addresses rp-alice router + +# Logical port 'foo1' in switch 'foo'. +ADD_NAMESPACES(foo1) +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ + "fd11::1") +OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add foo foo1 \ +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" + +# Logical port 'foo2' in switch 'foo'. +ADD_NAMESPACES(foo2) +ADD_VETH(foo2, foo2, br-int, "fd11::3/64", "f0:00:00:01:02:06", \ + "fd11::1") +OVS_WAIT_UNTIL([test "$(ip netns exec foo2 ip a | grep fd11::3 | grep tentative)" = ""]) +ovn-nbctl lsp-add foo foo2 \ +-- lsp-set-addresses foo2 "f0:00:00:01:02:06 fd11::3" + +# Logical port 'bar1' in switch 'bar'. +ADD_NAMESPACES(bar1) +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:04", \ + "fd12::1") +OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add bar bar1 \ +-- lsp-set-addresses bar1 "f0:00:00:01:02:04 fd12::2" + +# Logical port 'alice1' in switch 'alice'. +ADD_NAMESPACES(alice1) +ADD_VETH(alice1, alice1, br-int, "fd20::2/64", "f0:00:00:01:02:05", \ + "fd20::1") +OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd20::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add alice alice1 \ +-- lsp-set-addresses alice1 "f0:00:00:01:02:05 fd20::2" + +ovn-nbctl --wait=hv sync + +# Add DNAT rules +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::3 fd11::2 foo1 00:00:02:02:03:04]) +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::4 fd11::3 foo2 00:00:02:02:03:05]) + +# Add a SNAT rule +AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd11::/64]) +AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd12::/64]) + +ovn-nbctl --wait=hv sync +OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd20::1)']) + +# North-South DNAT: 'alice1' pings 'foo1' using fd20::3 +NS_CHECK_EXEC([alice1], [ping -6 -q -c 3 -i 0.3 -w 2 fd20::3 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that DNAT indeed happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::3) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd20::2,dst=fd20::3,id=,type=128,code=0),reply=(src=fd11::2,dst=fd20::2,id=,type=129,code=0),zone= +]) + +# South-North SNAT: 'foo2' pings 'alice1'. But 'alice1' receives traffic +# from 172.16.1.4 +NS_CHECK_EXEC([foo2], [ping -6 -q -c 3 -i 0.3 -w 2 fd20::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that SNAT indeed happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::1) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd11::3,dst=fd20::2,id=,type=128,code=0),reply=(src=fd20::2,dst=fd20::1,id=,type=129,code=0),zone= +]) + +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) + +# South-North SNAT: 'bar1' pings 'alice1'. But 'alice1' receives traffic +# from fd20::1 +NS_CHECK_EXEC([bar1], [ping -6 -q -c 3 -i 0.3 -w 2 fd20::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that SNAT indeed happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::1) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd12::2,dst=fd20::2,id=,type=128,code=0),reply=(src=fd20::2,dst=fd20::1,id=,type=129,code=0),zone= +]) + +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 + AT_SETUP([ovn -- DNAT and SNAT on distributed router - E/W]) AT_KEYWORDS([ovnnat]) @@ -1547,6 +2223,188 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d /connection dropped.*/d"]) AT_CLEANUP +AT_SETUP([ovn -- DNAT and SNAT on distributed router - E/W - IPv6]) +AT_KEYWORDS([ovnnat]) + +CHECK_CONNTRACK() +CHECK_CONNTRACK_NAT() +ovn_start +OVS_TRAFFIC_VSWITCHD_START() +ADD_BR([br-int]) + +# Set external-ids in br-int needed for ovn-controller +ovs-vsctl \ + -- set Open_vSwitch . external-ids:system-id=hv1 \ + -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \ + -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \ + -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \ + -- set bridge br-int fail-mode=secure other-config:disable-in-band=true + +# Start ovn-controller +start_daemon ovn-controller + +# Logical network: +# One LR R1 with switches foo (fd11::/64), bar (fd12::/64), +# and alice (fd20::/64) connected to it. The port between R1 and +# alice is the router gateway port where the R1 NAT rules are applied. +# +# foo -- R1 -- alice +# | +# bar ---- + +ovn-nbctl lr-add R1 + +ovn-nbctl ls-add foo +ovn-nbctl ls-add bar +ovn-nbctl ls-add alice + +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 fd11::1/64 +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 fd12::1/64 +ovn-nbctl lrp-add R1 alice 00:00:02:01:02:03 fd20::1/64 \ + -- set Logical_Router_Port alice options:redirect-chassis=hv1 + +# Connect foo to R1 +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo \ + type=router options:router-port=foo \ + -- lsp-set-addresses rp-foo router + +# Connect bar to R1 +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \ + type=router options:router-port=bar \ + -- lsp-set-addresses rp-bar router + +# Connect alice to R1 +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ + type=router options:router-port=alice \ + -- lsp-set-addresses rp-alice router + +# Logical port 'foo1' in switch 'foo'. +ADD_NAMESPACES(foo1) +ADD_VETH(foo1, foo1, br-int, "fd11::2/64", "f0:00:00:01:02:03", \ + "fd11::1") +OVS_WAIT_UNTIL([test "$(ip netns exec foo1 ip a | grep fd11::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add foo foo1 \ +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 fd11::2" + +# Logical port 'foo2' in switch 'foo'. +ADD_NAMESPACES(foo2) +ADD_VETH(foo2, foo2, br-int, "fd11::3/64", "f0:00:00:01:02:06", \ + "fd11::1") +OVS_WAIT_UNTIL([test "$(ip netns exec foo2 ip a | grep fd11::3 | grep tentative)" = ""]) +ovn-nbctl lsp-add foo foo2 \ +-- lsp-set-addresses foo2 "f0:00:00:01:02:06 fd11::3" + +# Logical port 'bar1' in switch 'bar'. +ADD_NAMESPACES(bar1) +ADD_VETH(bar1, bar1, br-int, "fd12::2/64", "f0:00:00:01:02:04", \ + "fd12::1") +OVS_WAIT_UNTIL([test "$(ip netns exec bar1 ip a | grep fd12::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add bar bar1 \ +-- lsp-set-addresses bar1 "f0:00:00:01:02:04 fd12::2" + +# Logical port 'alice1' in switch 'alice'. +ADD_NAMESPACES(alice1) +ADD_VETH(alice1, alice1, br-int, "fd20::2/64", "f0:00:00:01:02:05", \ + "fd20::1") +OVS_WAIT_UNTIL([test "$(ip netns exec alice1 ip a | grep fd20::2 | grep tentative)" = ""]) +ovn-nbctl lsp-add alice alice1 \ +-- lsp-set-addresses alice1 "f0:00:00:01:02:05 fd20::2" + +# Add DNAT rules +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::3 fd11::2 foo1 00:00:02:02:03:04]) +AT_CHECK([ovn-nbctl lr-nat-add R1 dnat_and_snat fd20::4 fd12::2 bar1 00:00:02:02:03:05]) + +# Add a SNAT rule +AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd11::/64]) +AT_CHECK([ovn-nbctl lr-nat-add R1 snat fd20::1 fd12::/64]) + +ovn-nbctl --wait=hv sync +OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int | grep 'nat(src=fd20::1)']) + +echo "------ hv dump ------" +ovs-ofctl show br-int +ovs-ofctl dump-flows br-int +echo "---------------------" + +# East-West No NAT: 'foo1' pings 'bar1' using fd12::2. +NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 fd12::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that no NAT happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd12::2) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | wc -l], [0], [0 +]) + +# East-West No NAT: 'foo2' pings 'bar1' using fd12::2. +NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 fd12::2 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that no NAT happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd12::2) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | wc -l], [0], [0 +]) + +# East-West No NAT: 'bar1' pings 'foo2' using fd11::3. +NS_CHECK_EXEC([bar1], [ping -q -c 3 -i 0.3 -w 2 fd11::3 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# We verify that no NAT happened via 'dump-conntrack' command. +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd12::2) | \ +sed -e 's/zone=[[0-9]]*/zone=/' | wc -l], [0], [0 +]) + +# East-West NAT: 'foo1' pings 'bar1' using fd20::4. +NS_CHECK_EXEC([foo1], [ping -q -c 3 -i 0.3 -w 2 fd20::4 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# Check conntrack entries. First SNAT of 'foo1' address happens. +# Then DNAT of 'bar1' address happens (listed first below). +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::4) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd11::2,dst=fd20::4,id=,type=128,code=0),reply=(src=fd20::4,dst=fd20::1,id=,type=129,code=0),zone= +icmpv6,orig=(src=fd20::1,dst=fd20::4,id=,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=,type=129,code=0),zone= +]) + +AT_CHECK([ovs-appctl dpctl/flush-conntrack]) + +# East-West NAT: 'foo2' pings 'bar1' using fd20::4. +NS_CHECK_EXEC([foo2], [ping -q -c 3 -i 0.3 -w 2 fd20::4 | FORMAT_PING], \ +[0], [dnl +3 packets transmitted, 3 received, 0% packet loss, time 0ms +]) + +# Check conntrack entries. First SNAT of 'foo2' address happens. +# Then DNAT of 'bar1' address happens (listed first below). +AT_CHECK([ovs-appctl dpctl/dump-conntrack | FORMAT_CT(fd20::1) | \ +sed -e 's/zone=[[0-9]]*/zone=/'], [0], [dnl +icmpv6,orig=(src=fd11::3,dst=fd20::4,id=,type=128,code=0),reply=(src=fd20::4,dst=fd20::1,id=,type=129,code=0),zone= +icmpv6,orig=(src=fd20::1,dst=fd20::4,id=,type=128,code=0),reply=(src=fd12::2,dst=fd20::1,id=,type=129,code=0),zone= +]) + +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 + AT_SETUP([ovn -- 2 LSs IGMP]) AT_KEYWORDS([ovnigmp]) From patchwork Wed Oct 30 14:53:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russell Bryant X-Patchwork-Id: 1186788 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=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ovn.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 473BPQ48YPz9sP3 for ; Thu, 31 Oct 2019 01:56:58 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 28D1FE5B; Wed, 30 Oct 2019 14:53:38 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 4A421C90 for ; Wed, 30 Oct 2019 14:53:35 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from us-smtp-delivery-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id C0EDF87C for ; Wed, 30 Oct 2019 14:53:34 +0000 (UTC) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-252-dpiaAeIwOoO2tlaOaEIiiA-1; Wed, 30 Oct 2019 10:53:30 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id E9E041800D67; Wed, 30 Oct 2019 14:53:29 +0000 (UTC) Received: from t480s.redhat.com (ovpn-126-115.rdu2.redhat.com [10.10.126.115]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8A6731FE04; Wed, 30 Oct 2019 14:53:29 +0000 (UTC) From: Russell Bryant To: dev@openvswitch.org Date: Wed, 30 Oct 2019 10:53:24 -0400 Message-Id: <20191030145324.9988-7-russell@ovn.org> In-Reply-To: <20191030145324.9988-1-russell@ovn.org> References: <20191030013138.9390-1-russell@ovn.org> <20191030145324.9988-1-russell@ovn.org> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: dpiaAeIwOoO2tlaOaEIiiA-1 X-Mimecast-Spam-Score: 0 X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH ovn v2 6/6] NEWS: Add IPv6 NAT support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Signed-off-by: Russell Bryant --- NEWS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NEWS b/NEWS index 73045d65f..ab2f13318 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +Post-OVS-v2.12.0 +--------------------- + - OVN was split out from the OVS repository and is now released + independently. + - Added IPv6 NAT support for OVN routers. + Post-v2.11.0 --------------------- - DPDK: