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: