public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
* [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly
@ 2023-05-01 11:06 David Gibson
  2023-05-01 11:06 ` [PATCH 1/7] udp: Simplify setting of source IPv6 address for inbound packets David Gibson
                   ` (7 more replies)
  0 siblings, 8 replies; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:06 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

Since the passt/pasta guest and host (usually) have the same address,
it's not possible for the guest to address the host, which is a
serious limitation.  So, passt/pasta NATs the address of the default
gateway to the host as a special case.

That can be quite limiting however.  Most obviously this prevents the
guest from addressing the gateway, which is less common than needing
to address the host, but certainly possible.  The combination of the
concepts of "gateway" and "nat to host" address makes for some extra
confusion as well.

This series separates the two concepts in both the code and the tests,
and adds a command line option for configuring the NAT to host address
explicitly (by default it remains the same as the gateway).

This isn't quite ready for merge yet.  First, I think there might be a
bug I haven't managed to track down yet which causes intermittent
failures in some of the UDP throughput tests.  Second, I don't think
we want to commit to this command line option just yet, without a look
at what further NAT cleanups we might want to do (which I'll be
looking at in the near term future).

David Gibson (7):
  udp: Simplify setting of source IPv6 address for inbound packets
  udp: Simplify setting od destination IPv6 address for inbound packets
  nat: Split notion of gateway/router from from guest-visible host
    address
  nat: Simplify --no-map-gw handling
  nat: Centralise handling of gateway versus link-local address for host
    NAT
  Allow nat-to-host addresses to be overridden
  nat, test: Test --nat-to-host option

 conf.c                | 113 ++++++++++++++++++++++++++++++------------
 dhcp.c                |  14 +++---
 dhcpv6.c              |   4 +-
 ndp.c                 |   4 +-
 passt.h               |  14 +++---
 pasta.c               |   4 +-
 tcp.c                 |  17 +++----
 test/lib/setup        |  19 +++++--
 test/lib/test         |  12 +++++
 test/passt/dhcp       |   7 ++-
 test/passt/tcp        |  10 ++--
 test/passt/udp        |   5 +-
 test/passt_in_ns/dhcp |  73 +++++++++++++++++++++++++++
 test/passt_in_ns/tcp  |  28 +++++------
 test/passt_in_ns/udp  |  14 +++---
 test/pasta/tcp        |  11 ++--
 test/pasta/udp        |   6 +--
 test/perf/passt_tcp   |  30 ++++++-----
 test/perf/passt_udp   |  26 +++++-----
 test/perf/pasta_tcp   |  26 +++++-----
 test/perf/pasta_udp   |  22 ++++----
 test/run              |   4 +-
 test/two_guests/basic |  10 ++--
 udp.c                 |  41 ++++++---------
 24 files changed, 313 insertions(+), 201 deletions(-)
 create mode 100644 test/passt_in_ns/dhcp

-- 
2.40.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/7] udp: Simplify setting of source IPv6 address for inbound packets
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
@ 2023-05-01 11:06 ` David Gibson
  2023-05-01 11:06 ` [PATCH 2/7] udp: Simplify setting od destination " David Gibson
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:06 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

Depending on the original source address, udp_update_hdr6() can take one of
several paths to handle the cases where we need NAT or other adjustments.
In each path we explicitly set the source IPv6 address in the packet
buffer.

Simplify this slightly to update src to point to the corrected source
address in each branch, then have a common write to the packet buffer.
This will enable future cleanups.

To make this work we do need a slightly re-order to avoid making tests on
the update 'src' when we need to test the original source.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 udp.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/udp.c b/udp.c
index 39c59d4..361f24c 100644
--- a/udp.c
+++ b/udp.c
@@ -632,35 +632,26 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 			      const struct timespec *now)
 {
 	struct udp6_l2_buf_t *b = &udp6_l2_buf[n];
-	struct in6_addr *src;
-	in_port_t src_port;
+	in_port_t src_port = ntohs(b->s_in6.sin6_port);
+	const struct in6_addr *src = &b->s_in6.sin6_addr;
 	size_t ip_len;
 
-	src = &b->s_in6.sin6_addr;
-	src_port = ntohs(b->s_in6.sin6_port);
-
 	ip_len = udp6_l2_mh_sock[n].msg_len + sizeof(b->ip6h) + sizeof(b->uh);
 
 	b->ip6h.payload_len = htons(udp6_l2_mh_sock[n].msg_len + sizeof(b->uh));
 
 	if (IN6_IS_ADDR_LINKLOCAL(src)) {
 		b->ip6h.daddr = c->ip6.addr_ll_seen;
-		b->ip6h.saddr = b->s_in6.sin6_addr;
 	} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns_host) &&
 		   src_port == 53) {
 		b->ip6h.daddr = c->ip6.addr_seen;
-		b->ip6h.saddr = c->ip6.dns_match;
+		src = &c->ip6.dns_match;
 	} else if (IN6_IS_ADDR_LOOPBACK(src)			||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen)	||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
 		b->ip6h.daddr = c->ip6.addr_ll_seen;
 
-		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
-			b->ip6h.saddr = c->ip6.gw;
-		else
-			b->ip6h.saddr = c->ip6.addr_ll;
-
 		udp_tap_map[V6][src_port].ts = now->tv_sec;
 		udp_tap_map[V6][src_port].flags |= PORT_LOCAL;
 
@@ -675,11 +666,17 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 			udp_tap_map[V6][src_port].flags &= ~PORT_GUA;
 
 		bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
+
+		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
+			src = &c->ip6.gw;
+		else
+			src = &c->ip6.addr_ll;
 	} else {
 		b->ip6h.daddr = c->ip6.addr_seen;
-		b->ip6h.saddr = b->s_in6.sin6_addr;
 	}
 
+	b->ip6h.saddr = *src;
+
 	b->uh.source = b->s_in6.sin6_port;
 	b->uh.dest = htons(dstport);
 	b->uh.len = b->ip6h.payload_len;
-- 
@@ -632,35 +632,26 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 			      const struct timespec *now)
 {
 	struct udp6_l2_buf_t *b = &udp6_l2_buf[n];
-	struct in6_addr *src;
-	in_port_t src_port;
+	in_port_t src_port = ntohs(b->s_in6.sin6_port);
+	const struct in6_addr *src = &b->s_in6.sin6_addr;
 	size_t ip_len;
 
-	src = &b->s_in6.sin6_addr;
-	src_port = ntohs(b->s_in6.sin6_port);
-
 	ip_len = udp6_l2_mh_sock[n].msg_len + sizeof(b->ip6h) + sizeof(b->uh);
 
 	b->ip6h.payload_len = htons(udp6_l2_mh_sock[n].msg_len + sizeof(b->uh));
 
 	if (IN6_IS_ADDR_LINKLOCAL(src)) {
 		b->ip6h.daddr = c->ip6.addr_ll_seen;
-		b->ip6h.saddr = b->s_in6.sin6_addr;
 	} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns_host) &&
 		   src_port == 53) {
 		b->ip6h.daddr = c->ip6.addr_seen;
-		b->ip6h.saddr = c->ip6.dns_match;
+		src = &c->ip6.dns_match;
 	} else if (IN6_IS_ADDR_LOOPBACK(src)			||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen)	||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
 		b->ip6h.daddr = c->ip6.addr_ll_seen;
 
-		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
-			b->ip6h.saddr = c->ip6.gw;
-		else
-			b->ip6h.saddr = c->ip6.addr_ll;
-
 		udp_tap_map[V6][src_port].ts = now->tv_sec;
 		udp_tap_map[V6][src_port].flags |= PORT_LOCAL;
 
@@ -675,11 +666,17 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 			udp_tap_map[V6][src_port].flags &= ~PORT_GUA;
 
 		bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
+
+		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
+			src = &c->ip6.gw;
+		else
+			src = &c->ip6.addr_ll;
 	} else {
 		b->ip6h.daddr = c->ip6.addr_seen;
-		b->ip6h.saddr = b->s_in6.sin6_addr;
 	}
 
+	b->ip6h.saddr = *src;
+
 	b->uh.source = b->s_in6.sin6_port;
 	b->uh.dest = htons(dstport);
 	b->uh.len = b->ip6h.payload_len;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/7] udp: Simplify setting od destination IPv6 address for inbound packets
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
  2023-05-01 11:06 ` [PATCH 1/7] udp: Simplify setting of source IPv6 address for inbound packets David Gibson
@ 2023-05-01 11:06 ` David Gibson
  2023-05-04 21:53   ` Stefano Brivio
  2023-05-01 11:06 ` [PATCH 3/7] nat: Split notion of gateway/router from from guest-visible host address David Gibson
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:06 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

Depending on several possible NAT situations, udp_update_hdr6() has a few
different paths for setting the destination IPv6 address.  However, this
isn't really separate from the selection of the IPv6 source address:
if the adjusted source address is link-local then we need to use a link
local destination, otherwise we need the global destination address.

This fixes a small bug: it's theoretically possible, although unlikely, for
the dns_match address to be link-local, in which case the previous code
would have used the wrong destination.

This does do slightly more work in the case of NATting packets originating
on the host.  Currently we always NAT those to a link-local address so we
could statically set a link-local destination address, but we now recheck.
However, as well as being simpler, the new approach is more robust if we
want to allow non-link-local NAT-to-host addresses, which we do plan to in
future.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 udp.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/udp.c b/udp.c
index 361f24c..9c96c0f 100644
--- a/udp.c
+++ b/udp.c
@@ -640,18 +640,13 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 
 	b->ip6h.payload_len = htons(udp6_l2_mh_sock[n].msg_len + sizeof(b->uh));
 
-	if (IN6_IS_ADDR_LINKLOCAL(src)) {
-		b->ip6h.daddr = c->ip6.addr_ll_seen;
-	} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
+	if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns_host) &&
 		   src_port == 53) {
-		b->ip6h.daddr = c->ip6.addr_seen;
 		src = &c->ip6.dns_match;
 	} else if (IN6_IS_ADDR_LOOPBACK(src)			||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen)	||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
-		b->ip6h.daddr = c->ip6.addr_ll_seen;
-
 		udp_tap_map[V6][src_port].ts = now->tv_sec;
 		udp_tap_map[V6][src_port].flags |= PORT_LOCAL;
 
@@ -671,11 +666,13 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 			src = &c->ip6.gw;
 		else
 			src = &c->ip6.addr_ll;
-	} else {
-		b->ip6h.daddr = c->ip6.addr_seen;
 	}
 
 	b->ip6h.saddr = *src;
+	if (IN6_IS_ADDR_LINKLOCAL(src))
+		b->ip6h.daddr = c->ip6.addr_ll_seen;
+	else
+		b->ip6h.daddr = c->ip6.addr_seen;
 
 	b->uh.source = b->s_in6.sin6_port;
 	b->uh.dest = htons(dstport);
-- 
@@ -640,18 +640,13 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 
 	b->ip6h.payload_len = htons(udp6_l2_mh_sock[n].msg_len + sizeof(b->uh));
 
-	if (IN6_IS_ADDR_LINKLOCAL(src)) {
-		b->ip6h.daddr = c->ip6.addr_ll_seen;
-	} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
+	if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns_host) &&
 		   src_port == 53) {
-		b->ip6h.daddr = c->ip6.addr_seen;
 		src = &c->ip6.dns_match;
 	} else if (IN6_IS_ADDR_LOOPBACK(src)			||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen)	||
 		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
-		b->ip6h.daddr = c->ip6.addr_ll_seen;
-
 		udp_tap_map[V6][src_port].ts = now->tv_sec;
 		udp_tap_map[V6][src_port].flags |= PORT_LOCAL;
 
@@ -671,11 +666,13 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 			src = &c->ip6.gw;
 		else
 			src = &c->ip6.addr_ll;
-	} else {
-		b->ip6h.daddr = c->ip6.addr_seen;
 	}
 
 	b->ip6h.saddr = *src;
+	if (IN6_IS_ADDR_LINKLOCAL(src))
+		b->ip6h.daddr = c->ip6.addr_ll_seen;
+	else
+		b->ip6h.daddr = c->ip6.addr_seen;
 
 	b->uh.source = b->s_in6.sin6_port;
 	b->uh.dest = htons(dstport);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/7] nat: Split notion of gateway/router from from guest-visible host address
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
  2023-05-01 11:06 ` [PATCH 1/7] udp: Simplify setting of source IPv6 address for inbound packets David Gibson
  2023-05-01 11:06 ` [PATCH 2/7] udp: Simplify setting od destination " David Gibson
@ 2023-05-01 11:06 ` David Gibson
  2023-05-01 11:06 ` [PATCH 4/7] nat: Simplify --no-map-gw handling David Gibson
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:06 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=domail, Size: 49445 bytes --]

The @gw fields in the ip4_ctx and ip6_ctx give the (host's) default
route gateway.  We use this for two quite distinct things: actually
advertising the correct gateway to the guest/ns (e.g. in DHCP and NDP)
and for a limited form of NAT.  So that the guest can access services
on the host, we map the gateway address within the guest to the
loopback address on the host.

Using the gateway address for this isn't necessarily the best choice
for this purpose, certainly not for all circumstances.  So, start off
by splitting the notion of these into two different values: @router
which is the actual router address and @nattohost which is the guest
visible address to remap to the host's loopback.

For now they always have the same value, but we can change that in future.

Similarly, we make changes to the tests so they no longer assume that
the gateway and nat-to-host address are the same.  Rather than using
__GW__ throughout, use __NAT_TO_{HOST,NS}[46]__ variables which are
provided by the setup functions.  For now those are always set to the
gateway address, but that can change in future.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c                | 46 +++++++++++++++++++++++--------------------
 dhcp.c                | 14 ++++++-------
 dhcpv6.c              |  4 ++--
 ndp.c                 |  4 ++--
 passt.h               | 12 +++++++----
 pasta.c               |  4 ++--
 tcp.c                 | 10 +++++-----
 test/lib/setup        | 12 +++++++++++
 test/lib/test         | 12 +++++++++++
 test/passt/dhcp       |  7 +++++--
 test/passt/tcp        | 10 ++++------
 test/passt/udp        |  5 ++---
 test/passt_in_ns/tcp  | 28 +++++++++++---------------
 test/passt_in_ns/udp  | 14 ++++++-------
 test/pasta/tcp        | 11 ++++-------
 test/pasta/udp        |  6 ++----
 test/perf/passt_tcp   | 30 +++++++++++++---------------
 test/perf/passt_udp   | 26 +++++++++++-------------
 test/perf/pasta_tcp   | 26 +++++++++++-------------
 test/perf/pasta_udp   | 22 ++++++++++-----------
 test/two_guests/basic | 10 ++++------
 udp.c                 | 10 +++++-----
 22 files changed, 167 insertions(+), 156 deletions(-)

diff --git a/conf.c b/conf.c
index 447b000..bfc825b 100644
--- a/conf.c
+++ b/conf.c
@@ -419,11 +419,11 @@ static void add_dns4(struct ctx *c, struct in_addr *addr, struct in_addr **conf)
 	/* Guest or container can only access local addresses via redirect */
 	if (IN4_IS_ADDR_LOOPBACK(addr)) {
 		if (!c->no_map_gw) {
-			**conf = c->ip4.gw;
+			**conf = c->ip4.nattohost;
 			(*conf)++;
 
 			if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_match))
-				c->ip4.dns_match = c->ip4.gw;
+				c->ip4.dns_match = c->ip4.nattohost;
 		}
 	} else {
 		**conf = *addr;
@@ -446,7 +446,7 @@ static void add_dns6(struct ctx *c,
 	/* Guest or container can only access local addresses via redirect */
 	if (IN6_IS_ADDR_LOOPBACK(addr)) {
 		if (!c->no_map_gw) {
-			memcpy(*conf, &c->ip6.gw, sizeof(**conf));
+			memcpy(*conf, &c->ip6.nattohost, sizeof(**conf));
 			(*conf)++;
 
 			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match))
@@ -645,14 +645,14 @@ static unsigned int conf_ip4(unsigned int ifi,
 		return 0;
 	}
 
-	if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw))
-		nl_route(0, ifi, AF_INET, &ip4->gw);
+	if (IN4_IS_ADDR_UNSPECIFIED(&ip4->router))
+		nl_route(0, ifi, AF_INET, &ip4->router);
 
 	if (IN4_IS_ADDR_UNSPECIFIED(&ip4->addr))
 		nl_addr(0, ifi, AF_INET, &ip4->addr, &ip4->prefix_len, NULL);
 
 	addr = ntohl(ip4->addr.s_addr);
-	gw = ntohl(ip4->gw.s_addr);
+	gw = ntohl(ip4->router.s_addr);
 
 	if (!ip4->prefix_len) {
 		if (IN_CLASSA(addr))
@@ -688,7 +688,9 @@ static unsigned int conf_ip4(unsigned int ifi,
 	if (MAC_IS_ZERO(mac))
 		nl_link(0, ifi, mac, 0, 0);
 
-	if (IN4_IS_ADDR_UNSPECIFIED(&ip4->gw) ||
+	ip4->nattohost = ip4->router;
+
+	if (IN4_IS_ADDR_UNSPECIFIED(&ip4->router) ||
 	    IN4_IS_ADDR_UNSPECIFIED(&ip4->addr) ||
 	    MAC_IS_ZERO(mac))
 		return 0;
@@ -717,8 +719,8 @@ static unsigned int conf_ip6(unsigned int ifi,
 		return 0;
 	}
 
-	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw))
-		nl_route(0, ifi, AF_INET6, &ip6->gw);
+	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->router))
+		nl_route(0, ifi, AF_INET6, &ip6->router);
 
 	nl_addr(0, ifi, AF_INET6,
 		IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ? &ip6->addr : NULL,
@@ -730,7 +732,9 @@ static unsigned int conf_ip6(unsigned int ifi,
 	if (MAC_IS_ZERO(mac))
 		nl_link(0, ifi, mac, 0, 0);
 
-	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->gw) ||
+	ip6->nattohost = ip6->router;
+
+	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->router) ||
 	    IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ||
 	    IN6_IS_ADDR_UNSPECIFIED(&ip6->addr_ll) ||
 	    MAC_IS_ZERO(mac))
@@ -984,7 +988,7 @@ static void conf_print(const struct ctx *c)
 			info("    mask: %s",
 			     inet_ntop(AF_INET, &mask,        buf4, sizeof(buf4)));
 			info("    router: %s",
-			     inet_ntop(AF_INET, &c->ip4.gw,   buf4, sizeof(buf4)));
+			     inet_ntop(AF_INET, &c->ip4.router, buf4, sizeof(buf4)));
 		}
 
 		for (i = 0; !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns[i]); i++) {
@@ -1014,7 +1018,7 @@ static void conf_print(const struct ctx *c)
 		info("    assign: %s",
 		     inet_ntop(AF_INET6, &c->ip6.addr, buf6, sizeof(buf6)));
 		info("    router: %s",
-		     inet_ntop(AF_INET6, &c->ip6.gw,   buf6, sizeof(buf6)));
+		     inet_ntop(AF_INET6, &c->ip6.router, buf6, sizeof(buf6)));
 		info("    our link-local: %s",
 		     inet_ntop(AF_INET6, &c->ip6.addr_ll, buf6, sizeof(buf6)));
 
@@ -1518,17 +1522,17 @@ void conf(struct ctx *c, int argc, char **argv)
 			}
 			break;
 		case 'g':
-			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw)		&&
-			    inet_pton(AF_INET6, optarg, &c->ip6.gw)	&&
-			    !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw)	&&
-			    !IN6_IS_ADDR_LOOPBACK(&c->ip6.gw))
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.router)	&&
+			    inet_pton(AF_INET6, optarg, &c->ip6.router)	&&
+			    !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.router)	&&
+			    !IN6_IS_ADDR_LOOPBACK(&c->ip6.router))
 				break;
 
-			if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw)		&&
-			    inet_pton(AF_INET, optarg, &c->ip4.gw)	&&
-			    !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw)	&&
-			    !IN4_IS_ADDR_BROADCAST(&c->ip4.gw)		&&
-			    !IN4_IS_ADDR_LOOPBACK(&c->ip4.gw))
+			if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.router)	&&
+			    inet_pton(AF_INET, optarg, &c->ip4.router)	&&
+			    !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.router)	&&
+			    !IN4_IS_ADDR_BROADCAST(&c->ip4.router)	&&
+			    !IN4_IS_ADDR_LOOPBACK(&c->ip4.router))
 				break;
 
 			die("Invalid gateway address: %s", optarg);
diff --git a/dhcp.c b/dhcp.c
index d04648c..1910c0c 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -336,20 +336,20 @@ int dhcp(const struct ctx *c, const struct pool *p)
 
 	m->yiaddr = c->ip4.addr;
 	mask.s_addr = htonl(0xffffffff << (32 - c->ip4.prefix_len));
-	memcpy(opts[1].s,  &mask,        sizeof(mask));
-	memcpy(opts[3].s,  &c->ip4.gw,   sizeof(c->ip4.gw));
-	memcpy(opts[54].s, &c->ip4.gw,   sizeof(c->ip4.gw));
+	memcpy(opts[1].s,  &mask,          sizeof(mask));
+	memcpy(opts[3].s,  &c->ip4.router, sizeof(c->ip4.router));
+	memcpy(opts[54].s, &c->ip4.router, sizeof(c->ip4.router));
 
 	/* If the gateway is not on the assigned subnet, send an option 121
 	 * (Classless Static Routing) adding a dummy route to it.
 	 */
 	if ((c->ip4.addr.s_addr & mask.s_addr)
-	    != (c->ip4.gw.s_addr & mask.s_addr)) {
+	    != (c->ip4.router.s_addr & mask.s_addr)) {
 		/* a.b.c.d/32:0.0.0.0, 0:a.b.c.d */
 		opts[121].slen = 14;
 		opts[121].s[0] = 32;
-		memcpy(opts[121].s + 1,  &c->ip4.gw, sizeof(c->ip4.gw));
-		memcpy(opts[121].s + 10, &c->ip4.gw, sizeof(c->ip4.gw));
+		memcpy(opts[121].s + 1,  &c->ip4.router, sizeof(c->ip4.router));
+		memcpy(opts[121].s + 10, &c->ip4.router, sizeof(c->ip4.router));
 	}
 
 	if (c->mtu != -1) {
@@ -368,7 +368,7 @@ int dhcp(const struct ctx *c, const struct pool *p)
 		opt_set_dns_search(c, sizeof(m->o));
 
 	len = offsetof(struct msg, o) + fill(m);
-	tap_udp4_send(c, c->ip4.gw, 67, c->ip4.addr, 68, m, len);
+	tap_udp4_send(c, c->ip4.router, 67, c->ip4.addr, 68, m, len);
 
 	return 1;
 }
diff --git a/dhcpv6.c b/dhcpv6.c
index fc42a84..84e6ff1 100644
--- a/dhcpv6.c
+++ b/dhcpv6.c
@@ -440,8 +440,8 @@ int dhcpv6(struct ctx *c, const struct pool *p,
 
 	c->ip6.addr_ll_seen = *saddr;
 
-	if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
-		src = &c->ip6.gw;
+	if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.router))
+		src = &c->ip6.router;
 	else
 		src = &c->ip6.addr_ll;
 
diff --git a/ndp.c b/ndp.c
index adab1d2..febb1da 100644
--- a/ndp.c
+++ b/ndp.c
@@ -181,8 +181,8 @@ dns_done:
 	else
 		c->ip6.addr_seen = *saddr;
 
-	if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
-		rsaddr = &c->ip6.gw;
+	if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.router))
+		rsaddr = &c->ip6.router;
 	else
 		rsaddr = &c->ip6.addr_ll;
 
diff --git a/passt.h b/passt.h
index 73fe808..e308fe1 100644
--- a/passt.h
+++ b/passt.h
@@ -102,7 +102,8 @@ enum passt_modes {
  * @addr:		IPv4 address for external, routable interface
  * @addr_seen:		Latest IPv4 address seen as source from tap
  * @prefixlen:		IPv4 prefix length (netmask)
- * @gw:			Default IPv4 gateway, network order
+ * @router:		Default IPv4 router, network order
+ * @nattohost:		NAT this address from guest to host's 127.0.0.1
  * @dns:		DNS addresses for DHCP, zero-terminated, network order
  * @dns_match:		Forward DNS query if sent to this address, network order
  * @dns_host:		Use this DNS on the host for forwarding, network order
@@ -113,7 +114,8 @@ struct ip4_ctx {
 	struct in_addr addr;
 	struct in_addr addr_seen;
 	int prefix_len;
-	struct in_addr gw;
+	struct in_addr router;
+	struct in_addr nattohost;
 	struct in_addr dns[MAXNS + 1];
 	struct in_addr dns_match;
 	struct in_addr dns_host;
@@ -128,7 +130,8 @@ struct ip4_ctx {
  * @addr_ll:		Link-local IPv6 address on external, routable interface
  * @addr_seen:		Latest IPv6 global/site address seen as source from tap
  * @addr_ll_seen:	Latest IPv6 link-local address seen as source from tap
- * @gw:			Default IPv6 gateway
+ * @router:		Default IPv6 router
+ * @nattohost:		NAT this address from guest to host's ::1
  * @dns:		DNS addresses for DHCPv6 and NDP, zero-terminated
  * @dns_match:		Forward DNS query if sent to this address
  * @dns_host:		Use this DNS on the host for forwarding
@@ -140,7 +143,8 @@ struct ip6_ctx {
 	struct in6_addr addr_ll;
 	struct in6_addr addr_seen;
 	struct in6_addr addr_ll_seen;
-	struct in6_addr gw;
+	struct in6_addr router;
+	struct in6_addr nattohost;
 	struct in6_addr dns[MAXNS + 1];
 	struct in6_addr dns_match;
 	struct in6_addr dns_host;
diff --git a/pasta.c b/pasta.c
index 3a4d704..c706cb1 100644
--- a/pasta.c
+++ b/pasta.c
@@ -268,14 +268,14 @@ void pasta_ns_conf(struct ctx *c)
 		if (c->ifi4) {
 			nl_addr(1, c->pasta_ifi, AF_INET, &c->ip4.addr,
 				&c->ip4.prefix_len, NULL);
-			nl_route(1, c->pasta_ifi, AF_INET, &c->ip4.gw);
+			nl_route(1, c->pasta_ifi, AF_INET, &c->ip4.router);
 		}
 
 		if (c->ifi6) {
 			int prefix_len = 64;
 			nl_addr(1, c->pasta_ifi, AF_INET6, &c->ip6.addr,
 				&prefix_len, NULL);
-			nl_route(1, c->pasta_ifi, AF_INET6, &c->ip6.gw);
+			nl_route(1, c->pasta_ifi, AF_INET6, &c->ip6.router);
 		}
 	} else {
 		nl_link(1, c->pasta_ifi, c->mac_guest, 0, 0);
diff --git a/tcp.c b/tcp.c
index 0ed9bfa..b0dacab 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2041,9 +2041,9 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
 			return;
 
 	if (!c->no_map_gw) {
-		if (af == AF_INET && IN4_ARE_ADDR_EQUAL(addr, &c->ip4.gw))
+		if (af == AF_INET && IN4_ARE_ADDR_EQUAL(addr, &c->ip4.nattohost))
 			addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-		if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw))
+		if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost))
 			addr6.sin6_addr	= in6addr_loopback;
 	}
 
@@ -2713,15 +2713,15 @@ static void tcp_snat_inbound(const struct ctx *c, union inany_addr *addr)
 		if (IN4_IS_ADDR_LOOPBACK(addr4) ||
 		    IN4_IS_ADDR_UNSPECIFIED(addr4) ||
 		    IN4_ARE_ADDR_EQUAL(addr4, &c->ip4.addr_seen))
-			*addr4 = c->ip4.gw;
+			*addr4 = c->ip4.nattohost;
 	} else {
 		struct in6_addr *addr6 = &addr->a6;
 
 		if (IN6_IS_ADDR_LOOPBACK(addr6) ||
 		    IN6_ARE_ADDR_EQUAL(addr6, &c->ip6.addr_seen) ||
 		    IN6_ARE_ADDR_EQUAL(addr6, &c->ip6.addr)) {
-			if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
-				*addr6 = c->ip6.gw;
+			if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.nattohost))
+				*addr6 = c->ip6.nattohost;
 			else
 				*addr6 = c->ip6.addr_ll;
 		}
diff --git a/test/lib/setup b/test/lib/setup
index 9b39b9f..d85002e 100755
--- a/test/lib/setup
+++ b/test/lib/setup
@@ -40,6 +40,9 @@ setup_passt() {
 	#  10001     as server  |  forwarded to guest
 	#  10003                |      as server
 
+        __nat_to_host4="$(ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway')"
+        __nat_to_host6="$(ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway')"
+
 	__opts=
 	[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt.pcap"
 	[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
@@ -87,6 +90,9 @@ setup_pasta() {
 	#  10002      as server     |    spliced to ns
 	#  10003   spliced to init  |      as server
 
+        __nat_to_host4="$(ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway')"
+        __nat_to_host6="$(ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway')"
+
 	__opts=
 	[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta.pcap"
 	[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
@@ -118,6 +124,10 @@ setup_passt_in_ns() {
 	#
 	#  10021    as server  | forwarded to guest |
 	#  10031    as server  | forwarded to guest |
+        __nat_to_host4="$(ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway')"
+        __nat_to_host6="$(ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway')"
+        __nat_to_ns4="${__nat_to_host4}"
+        __nat_to_ns6="${__nat_to_host6}"
 
 	__opts=
 	[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta_with_passt.pcap"
@@ -181,6 +191,8 @@ setup_two_guests() {
 	#  10003            |           |  to init  |  to init   |  as server
 	#  10004            | as server |  to init  |  to guest  |  to ns #2
 	#  10005            |           |           |  as server |  to ns #2
+        __nat_to_host4="$(ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway')"
+        __nat_to_host6="$(ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway')"
 
 	__opts=
 	[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta_1.pcap"
diff --git a/test/lib/test b/test/lib/test
index 115dd21..f4c4c43 100755
--- a/test/lib/test
+++ b/test/lib/test
@@ -356,6 +356,18 @@ test_one() {
 	STATEDIR="${STATEBASE}/${1}"
 	mkdir -p "${STATEDIR}"
 	TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__STATEDIR__" "${STATEDIR}")"
+        if [ -n "${__nat_to_host4}" ]; then
+                TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__NAT_TO_HOST4__" "${__nat_to_host4}")"
+        fi
+        if [ -n "${__nat_to_host6}" ]; then
+                TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__NAT_TO_HOST6__" "${__nat_to_host6}")"
+        fi
+        if [ -n "${__nat_to_ns4}" ]; then
+                TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__NAT_TO_NS4__" "${__nat_to_ns4}")"
+        fi
+        if [ -n "${__nat_to_ns6}" ]; then
+                TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__NAT_TO_NS6__" "${__nat_to_ns6}")"
+        fi
 	TEST_ONE_nok=-1
 	TEST_ONE_perf_nok=0
 	TEST_ONE_skip=0
diff --git a/test/passt/dhcp b/test/passt/dhcp
index 7272755..be6ab02 100644
--- a/test/passt/dhcp
+++ b/test/passt/dhcp
@@ -14,6 +14,9 @@
 gtools	ip jq dhclient sed tr
 htools	ip jq sed tr head
 
+test	Provided addresses
+gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+
 test	Interface name
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 hout	HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
@@ -38,7 +41,7 @@ check	[ __MTU__ = 65520 ]
 test	DHCP: DNS
 gout	DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
 hout	HOST_DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | head -n3 | tr '\n' ',' | sed 's/,$//;s/$/\n/'
-check	[ "__DNS__" = "__HOST_DNS__" ] || [ "__DNS__" = "__HOST_GW__" -a "__HOST_DNS__" = "127.0.0.1" ]
+check	[ "__DNS__" = "__HOST_DNS__" ] || [ "__DNS__" = "__NAT_TO_HOST4__" -a "__HOST_DNS__" = "127.0.0.1" ]
 
 # FQDNs should be terminated by dots, but the guest DHCP client might omit them:
 # strip them first
@@ -62,7 +65,7 @@ check	[ "__GW6__" = "__HOST_GW6__" ]
 test	DHCPv6: DNS
 gout	DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
 hout	HOST_DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
-check	[ "__DNS6__" = "__HOST_DNS6__" ] || [ "__DNS6__" = "__HOST_GW6__" -a "__HOST_DNS6__" = "::1" ]
+check	[ "__DNS6__" = "__HOST_DNS6__" ] || [ "__DNS6__" = "__NAT_TO_HOST6__" -a "__HOST_DNS6__" = "::1" ]
 
 test	DHCPv6: search list
 gout	SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
diff --git a/test/passt/tcp b/test/passt/tcp
index 91e49e0..cc8d1cf 100644
--- a/test/passt/tcp
+++ b/test/passt/tcp
@@ -26,8 +26,7 @@ guest	cmp /root/big.bin test_big.bin
 
 test	TCP/IPv4: guest to host: big transfer
 hostb	socat -u TCP4-LISTEN:10003,bind=127.0.0.1,reuseaddr OPEN:__TEMP_BIG__,create,trunc
-gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-guest	socat -u OPEN:/root/big.bin TCP4:__GW__:10003
+guest	socat -u OPEN:/root/big.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __BASEPATH__/big.bin __TEMP_BIG__
 
@@ -41,7 +40,7 @@ guest	cmp /root/small.bin test_small.bin
 test	TCP/IPv4: guest to host: small transfer
 hostb	socat -u TCP4-LISTEN:10003,bind=127.0.0.1,reuseaddr OPEN:__TEMP_SMALL__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP4:__GW__:10003
+guest	socat -u OPEN:/root/small.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __BASEPATH__/small.bin __TEMP_SMALL__
 
@@ -55,9 +54,8 @@ guest	cmp /root/big.bin test_big.bin
 
 test	TCP/IPv6: guest to host: big transfer
 hostb	socat -u TCP6-LISTEN:10003,bind=[::1],reuseaddr OPEN:__TEMP_BIG__,create,trunc
-gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-guest	socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10003
+guest	socat -u OPEN:/root/big.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __BASEPATH__/big.bin __TEMP_BIG__
 
@@ -71,6 +69,6 @@ guest	cmp /root/small.bin test_small.bin
 test	TCP/IPv6: guest to host: small transfer
 hostb	socat -u TCP6-LISTEN:10003,bind=[::1],reuseaddr OPEN:__TEMP_SMALL__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10003
+guest	socat -u OPEN:/root/small.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __BASEPATH__/small.bin __TEMP_SMALL__
diff --git a/test/passt/udp b/test/passt/udp
index 80d0fa3..d358b29 100644
--- a/test/passt/udp
+++ b/test/passt/udp
@@ -25,8 +25,7 @@ guest	cmp /root/medium.bin test.bin
 
 test	UDP/IPv4: guest to host
 hostb	socat -u UDP4-LISTEN:10003,bind=127.0.0.1,null-eof OPEN:__TEMP__,create,trunc
-gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-guest	socat -u OPEN:/root/medium.bin UDP4:__GW__:10003,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP4:__NAT_TO_HOST4__:10003,shut-null
 hostw
 check	cmp __BASEPATH__/medium.bin __TEMP__
 
@@ -41,6 +40,6 @@ test	UDP/IPv6: guest to host
 hostb	socat -u UDP6-LISTEN:10003,bind=[::1],null-eof OPEN:__TEMP__,create,trunc
 gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-guest	socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP6:[__NAT_TO_HOST6__%__IFNAME__]:10003,shut-null
 hostw
 check	cmp __BASEPATH__/medium.bin __TEMP__
diff --git a/test/passt_in_ns/tcp b/test/passt_in_ns/tcp
index cdb7060..51d0379 100644
--- a/test/passt_in_ns/tcp
+++ b/test/passt_in_ns/tcp
@@ -36,16 +36,15 @@ check	cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
 
 test	TCP/IPv4: guest to host: big transfer
 hostb	socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
-gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
 sleep	1
-guest	socat -u OPEN:/root/big.bin TCP4:__GW__:10003
+guest	socat -u OPEN:/root/big.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __TEMP_BIG__ __BASEPATH__/big.bin
 
 test	TCP/IPv4: guest to ns: big transfer
 nsb	socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/big.bin TCP4:__GW__:10002
+guest	socat -u OPEN:/root/big.bin TCP4:__NAT_TO_NS4__:10002
 nsw
 check	cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
 
@@ -59,7 +58,7 @@ check	cmp __TEMP_BIG__ __BASEPATH__/big.bin
 test	TCP/IPv4: ns to host (via tap): big transfer
 hostb	socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/big.bin TCP4:__GW__:10003
+ns	socat -u OPEN:__BASEPATH__/big.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __TEMP_BIG__ __BASEPATH__/big.bin
 
@@ -95,16 +94,15 @@ check	cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
 
 test	TCP/IPv4: guest to host: small transfer
 hostb	socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
-gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP4:__GW__:10003
+guest	socat -u OPEN:/root/small.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __TEMP_SMALL__ __BASEPATH__/small.bin
 
 test	TCP/IPv4: guest to ns: small transfer
 nsb	socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP4:__GW__:10002
+guest	socat -u OPEN:/root/small.bin TCP4:__NAT_TO_NS4__:10002
 nsw
 check	cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
 
@@ -118,7 +116,7 @@ check	cmp __TEMP_SMALL__ __BASEPATH__/small.bin
 test	TCP/IPv4: ns to host (via tap): small transfer
 hostb	socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/small.bin TCP4:__GW__:10003
+ns	socat -u OPEN:__BASEPATH__/small.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __TEMP_SMALL__ __BASEPATH__/small.bin
 
@@ -152,17 +150,16 @@ check	cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
 
 test	TCP/IPv6: guest to host: big transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
-gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-guest	socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10003
+guest	socat -u OPEN:/root/big.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __TEMP_BIG__ __BASEPATH__/big.bin
 
 test	TCP/IPv6: guest to ns: big transfer
 nsb	socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10002
+guest	socat -u OPEN:/root/big.bin TCP6:[__NAT_TO_NS6__%__IFNAME__]:10002
 nsw
 check	cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
 
@@ -177,7 +174,7 @@ test	TCP/IPv6: ns to host (via tap): big transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/big.bin TCP6:[__GW6__%__IFNAME__]:10003
+ns	socat -u OPEN:__BASEPATH__/big.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __TEMP_BIG__ __BASEPATH__/big.bin
 
@@ -212,17 +209,16 @@ check	cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
 
 test	TCP/IPv6: guest to host: small transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
-gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10003
+guest	socat -u OPEN:/root/small.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __TEMP_SMALL__ __BASEPATH__/small.bin
 
 test	TCP/IPv6: guest to ns: small transfer
 nsb	socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_SMALL__
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10002
+guest	socat -u OPEN:/root/small.bin TCP6:[__NAT_TO_NS6__%__IFNAME__]:10002
 nsw
 check	cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
 
@@ -237,7 +233,7 @@ test	TCP/IPv6: ns to host (via tap): small transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/small.bin TCP6:[__GW6__%__IFNAME__]:10003
+ns	socat -u OPEN:__BASEPATH__/small.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __TEMP_SMALL__ __BASEPATH__/small.bin
 
diff --git a/test/passt_in_ns/udp b/test/passt_in_ns/udp
index 8a02513..40e687f 100644
--- a/test/passt_in_ns/udp
+++ b/test/passt_in_ns/udp
@@ -34,16 +34,15 @@ check	cmp __TEMP_NS__ __BASEPATH__/medium.bin
 
 test	UDP/IPv4: guest to host
 hostb	socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
-gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
 sleep	1
-guest	socat -u OPEN:/root/medium.bin UDP4:__GW__:10003,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP4:__NAT_TO_HOST4__:10003,shut-null
 hostw
 check	cmp __TEMP__ __BASEPATH__/medium.bin
 
 test	UDP/IPv4: guest to ns
 nsb	socat -u UDP4-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/medium.bin UDP4:__GW__:10002,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP4:__NAT_TO_NS4__:10002,shut-null
 nsw
 check	cmp __TEMP_NS__ __BASEPATH__/medium.bin
 
@@ -57,7 +56,7 @@ check	cmp __TEMP__ __BASEPATH__/medium.bin
 test	UDP/IPv4: ns to host (via tap)
 hostb	socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/medium.bin UDP4:__GW__:10003,shut-null
+ns	socat -u OPEN:__BASEPATH__/medium.bin UDP4:__NAT_TO_HOST4__:10003,shut-null
 hostw
 check	cmp __TEMP__ __BASEPATH__/medium.bin
 
@@ -93,17 +92,16 @@ check	cmp __TEMP_NS__ __BASEPATH__/medium.bin
 
 test	UDP/IPv6: guest to host
 hostb	socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
-gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-guest	socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP6:[__NAT_TO_HOST6__%__IFNAME__]:10003,shut-null
 hostw
 check	cmp __TEMP__ __BASEPATH__/medium.bin
 
 test	UDP/IPv6: guest to ns
 nsb	socat -u UDP6-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10002,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP6:[__NAT_TO_NS6__%__IFNAME__]:10002,shut-null
 nsw
 check	cmp __TEMP_NS__ __BASEPATH__/medium.bin
 
@@ -118,7 +116,7 @@ test	UDP/IPv6: ns to host (via tap)
 hostb	socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null
+ns	socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__NAT_TO_HOST6__%__IFNAME__]:10003,shut-null
 hostw
 check	cmp __TEMP__ __BASEPATH__/medium.bin
 
diff --git a/test/pasta/tcp b/test/pasta/tcp
index 6ab18c5..4f6684f 100644
--- a/test/pasta/tcp
+++ b/test/pasta/tcp
@@ -33,8 +33,7 @@ check	cmp __BASEPATH__/big.bin __TEMP_BIG__
 
 test	TCP/IPv4: ns to host (via tap): big transfer
 hostb	socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
-nsout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-ns	socat -u OPEN:__BASEPATH__/big.bin TCP4:__GW__:10003
+ns	socat -u OPEN:__BASEPATH__/big.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __BASEPATH__/big.bin __TEMP_BIG__
 
@@ -52,8 +51,7 @@ check	cmp __BASEPATH__/small.bin __TEMP_SMALL__
 
 test	TCP/IPv4: ns to host (via tap): small transfer
 hostb	socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
-nsout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-ns	socat -u OPEN:__BASEPATH__/small.bin TCP4:__GW__:10003
+ns	socat -u OPEN:__BASEPATH__/small.bin TCP4:__NAT_TO_HOST4__:10003
 hostw
 check	cmp __BASEPATH__/small.bin __TEMP_SMALL__
 
@@ -71,9 +69,8 @@ check	cmp __BASEPATH__/big.bin __TEMP_BIG__
 
 test	TCP/IPv6: ns to host (via tap): big transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
-nsout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-ns	socat -u OPEN:__BASEPATH__/big.bin TCP6:[__GW6__%__IFNAME__]:10003
+ns	socat -u OPEN:__BASEPATH__/big.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __BASEPATH__/big.bin __TEMP_BIG__
 
@@ -91,6 +88,6 @@ check	cmp __BASEPATH__/small.bin __TEMP_SMALL__
 
 test	TCP/IPv6: ns to host (via tap): small transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
-ns	socat -u OPEN:__BASEPATH__/small.bin TCP6:[__GW6__%__IFNAME__]:10003
+ns	socat -u OPEN:__BASEPATH__/small.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
 hostw
 check	cmp __BASEPATH__/small.bin __TEMP_SMALL__
diff --git a/test/pasta/udp b/test/pasta/udp
index 30e3a85..bd87948 100644
--- a/test/pasta/udp
+++ b/test/pasta/udp
@@ -32,8 +32,7 @@ check	cmp __BASEPATH__/medium.bin __TEMP__
 
 test	UDP/IPv4: ns to host (via tap)
 hostb	socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
-nsout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-ns	socat -u OPEN:__BASEPATH__/medium.bin UDP4:__GW__:10003,shut-null
+ns	socat -u OPEN:__BASEPATH__/medium.bin UDP4:__NAT_TO_HOST4__:10003,shut-null
 hostw
 check	cmp __BASEPATH__/medium.bin __TEMP__
 
@@ -52,8 +51,7 @@ check	cmp __BASEPATH__/medium.bin __TEMP__
 
 test	UDP/IPv6: ns to host (via tap)
 hostb	socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
-nsout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
-ns	socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null
+ns	socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__NAT_TO_HOST6__%__IFNAME__]:10003,shut-null
 hostw
 check	cmp __BASEPATH__/medium.bin __TEMP__
diff --git a/test/perf/passt_tcp b/test/perf/passt_tcp
index 7046f3c..7852a7e 100644
--- a/test/perf/passt_tcp
+++ b/test/perf/passt_tcp
@@ -29,8 +29,6 @@ ns	/sbin/sysctl -w net.ipv4.tcp_rmem="4096 524288 134217728"
 ns	/sbin/sysctl -w net.ipv4.tcp_wmem="4096 524288 134217728"
 ns	/sbin/sysctl -w net.ipv4.tcp_timestamps=0
 
-gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 
 hout	FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1
@@ -54,16 +52,16 @@ bw	-
 bw	-
 
 guest	ip link set dev __IFNAME__ mtu 1280
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
 bw	__BW__ 1.2 1.5
 guest	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
 bw	__BW__ 1.6 1.8
 guest	ip link set dev __IFNAME__ mtu 9000
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 4.0 5.0
 guest	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M
 bw	__BW__ 7.0 8.0
 
 tl	TCP RR latency over IPv6: guest to host
@@ -73,7 +71,7 @@ lat	-
 lat	-
 lat	-
 nsb	tcp_rr --nolog -6
-gout	LAT tcp_rr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT tcp_rr --nolog -6 -c -H __NAT_TO_NS6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 200 150
 
 tl	TCP CRR latency over IPv6: guest to host
@@ -83,28 +81,28 @@ lat	-
 lat	-
 lat	-
 nsb	tcp_crr --nolog -6
-gout	LAT tcp_crr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT tcp_crr --nolog -6 -c -H __NAT_TO_NS6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 500 400
 
 
 tr	TCP throughput over IPv4: guest to host
 guest	ip link set dev __IFNAME__ mtu 256
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 1M
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 1M
 bw	__BW__ 0.2 0.3
 guest	ip link set dev __IFNAME__ mtu 576
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 1M
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 1M
 bw	__BW__ 0.5 0.8
 guest	ip link set dev __IFNAME__ mtu 1280
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
 bw	__BW__ 1.2 1.5
 guest	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
 bw	__BW__ 1.6 1.8
 guest	ip link set dev __IFNAME__ mtu 9000
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 4.0 5.0
 guest	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M
 bw	__BW__ 7.0 8.0
 
 tl	TCP RR latency over IPv4: guest to host
@@ -114,7 +112,7 @@ lat	-
 lat	-
 lat	-
 nsb	tcp_rr --nolog -4
-gout	LAT tcp_rr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT tcp_rr --nolog -4 -c -H __NAT_TO_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 200 150
 
 tl	TCP CRR latency over IPv4: guest to host
@@ -124,7 +122,7 @@ lat	-
 lat	-
 lat	-
 nsb	tcp_crr --nolog -4
-gout	LAT tcp_crr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT tcp_crr --nolog -4 -c -H __NAT_TO_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 500 400
 
 
diff --git a/test/perf/passt_udp b/test/perf/passt_udp
index a117b6a..e19dd8c 100644
--- a/test/perf/passt_udp
+++ b/test/perf/passt_udp
@@ -22,8 +22,6 @@ guest	/sbin/sysctl -w net.core.wmem_max=16777216
 guest	/sbin/sysctl -w net.core.rmem_default=16777216
 guest	/sbin/sysctl -w net.core.wmem_default=16777216
 
-gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 
 hout	FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1
@@ -46,16 +44,16 @@ tr	UDP throughput over IPv6: guest to host
 bw	-
 bw	-
 guest	ip link set dev __IFNAME__ mtu 1280
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G
 bw	__BW__ 0.8 1.2
 guest	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G
 bw	__BW__ 1.0 1.5
 guest	ip link set dev __IFNAME__ mtu 9000
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 5G
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 5G
 bw	__BW__ 4.0 5.0
 guest	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G
+iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G
 bw	__BW__ 4.0 5.0
 
 tl	UDP RR latency over IPv6: guest to host
@@ -65,28 +63,28 @@ lat	-
 lat	-
 lat	-
 nsb	udp_rr --nolog -6
-gout	LAT udp_rr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT udp_rr --nolog -6 -c -H __NAT_TO_NS6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 200 150
 
 
 tr	UDP throughput over IPv4: guest to host
 guest	ip link set dev __IFNAME__ mtu 256
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 500M
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 500M
 bw	__BW__ 0.0 0.0
 guest	ip link set dev __IFNAME__ mtu 576
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 1G
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 1G
 bw	__BW__ 0.4 0.6
 guest	ip link set dev __IFNAME__ mtu 1280
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G
 bw	__BW__ 0.8 1.2
 guest	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G
 bw	__BW__ 1.0 1.5
 guest	ip link set dev __IFNAME__ mtu 9000
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 6G
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 6G
 bw	__BW__ 4.0 5.0
 guest	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G
+iperf3	BW guest ns __NAT_TO_NS4__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G
 bw	__BW__ 4.0 5.0
 
 tl	UDP RR latency over IPv4: guest to host
@@ -96,7 +94,7 @@ lat	-
 lat	-
 lat	-
 nsb	udp_rr --nolog -4
-gout	LAT udp_rr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT udp_rr --nolog -4 -c -H __NAT_TO_NS4__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 200 150
 
 
diff --git a/test/perf/pasta_tcp b/test/perf/pasta_tcp
index 4b13384..8053800 100644
--- a/test/perf/pasta_tcp
+++ b/test/perf/pasta_tcp
@@ -162,8 +162,6 @@ te
 
 test	pasta: throughput and latency (connections via tap)
 
-nsout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-nsout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 set	THREADS 1
 set	STREAMS 2
@@ -177,16 +175,16 @@ th	MTU 1500B 4000B 16384B 65520B
 
 tr	TCP throughput over IPv6: ns to host
 ns	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k
 bw	__BW__ 0.2 0.4
 ns	ip link set dev __IFNAME__ mtu 4000
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M
 bw	__BW__ 0.3 0.5
 ns	ip link set dev __IFNAME__ mtu 16384
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 1.5 2.0
 ns	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 2.0 2.5
 
 tl	TCP RR latency over IPv6: ns to host
@@ -194,7 +192,7 @@ lat	-
 lat	-
 lat	-
 hostb	tcp_rr --nolog -P 10003 -C 10013 -6
-nsout	LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 150 100
 
@@ -203,23 +201,23 @@ lat	-
 lat	-
 lat	-
 hostb	tcp_crr --nolog -P 10003 -C 10013 -6
-nsout	LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 1500 500
 
 
 tr	TCP throughput over IPv4: ns to host
 ns	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k
+iperf3	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k
 bw	__BW__ 0.2 0.4
 ns	ip link set dev __IFNAME__ mtu 4000
-iperf3s	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M
+iperf3s	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M
 bw	__BW__ 0.3 0.5
 ns	ip link set dev __IFNAME__ mtu 16384
-iperf3	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 1.5 2.0
 ns	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 2.0 2.5
 
 tl	TCP RR latency over IPv4: ns to host
@@ -227,7 +225,7 @@ lat	-
 lat	-
 lat	-
 hostb	tcp_rr --nolog -P 10003 -C 10013 -4
-nsout	LAT tcp_rr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT tcp_rr --nolog -P 10003 -C 10013 -4 -c -H __NAT_TO_HOST4__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 150 100
 
@@ -236,7 +234,7 @@ lat	-
 lat	-
 lat	-
 hostb	tcp_crr --nolog -P 10003 -C 10013 -4
-nsout	LAT tcp_crr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT tcp_crr --nolog -P 10003 -C 10013 -4 -c -H __NAT_TO_HOST4__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 1500 500
 
diff --git a/test/perf/pasta_udp b/test/perf/pasta_udp
index 7007b6f..1d3d5d4 100644
--- a/test/perf/pasta_udp
+++ b/test/perf/pasta_udp
@@ -123,8 +123,6 @@ te
 
 test	pasta: throughput and latency (traffic via tap)
 
-nsout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
-nsout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 
 info	Throughput in Gbps, latency in ��s, one thread at __FREQ__ GHz, __STREAMS__ streams
@@ -134,16 +132,16 @@ th	MTU 1500B 4000B 16384B 65520B
 
 tr	UDP throughput over IPv6: ns to host
 ns	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G
 bw	__BW__ 0.3 0.5
 ns	ip link set dev __IFNAME__ mtu 4000
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G
 bw	__BW__ 0.5 0.8
 ns	ip link set dev __IFNAME__ mtu 16384
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G
 bw	__BW__ 3.0 4.0
 ns	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G
+iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G
 bw	__BW__ 6.0 7.0
 
 tl	UDP RR latency over IPv6: ns to host
@@ -151,23 +149,23 @@ lat	-
 lat	-
 lat	-
 hostb	udp_rr --nolog -P 10003 -C 10013 -6
-nsout	LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 200 150
 
 
 tr	UDP throughput over IPv4: ns to host
 ns	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G
+iperf3	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G
 bw	__BW__ 0.3 0.5
 ns	ip link set dev __IFNAME__ mtu 4000
-iperf3	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G
+iperf3	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G
 bw	__BW__ 0.5 0.8
 ns	ip link set dev __IFNAME__ mtu 16384
-iperf3	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G
+iperf3	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G
 bw	__BW__ 3.0 4.0
 ns	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G
+iperf3	BW ns host __NAT_TO_HOST4__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G
 bw	__BW__ 6.0 7.0
 
 tl	UDP RR latency over IPv4: ns to host
@@ -175,7 +173,7 @@ lat	-
 lat	-
 lat	-
 hostb	udp_rr --nolog -P 10003 -C 10013 -4
-nsout	LAT udp_rr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT udp_rr --nolog -P 10003 -C 10013 -4 -c -H __NAT_TO_HOST4__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 200 150
 
diff --git a/test/two_guests/basic b/test/two_guests/basic
index 09fbd3e..b948757 100644
--- a/test/two_guests/basic
+++ b/test/two_guests/basic
@@ -46,18 +46,16 @@ check	[ "__ADDR1_6__" = "__HOST_ADDR6__" ]
 check	[ "__ADDR2_6__" = "__HOST_ADDR6__" ]
 
 test	TCP/IPv4: guest 1 > guest 2
-g1out	GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
 guest2b	socat -u TCP4-LISTEN:10004 OPEN:msg,create,trunc
-guest1	echo "Hello_from_guest_1" | socat -u STDIN TCP4:__GW1__:10004
+guest1	echo "Hello_from_guest_1" | socat -u STDIN TCP4:__NAT_TO_HOST4__:10004
 guest2w
 sleep	1
 g2out	MSG2 cat msg
 check	[ "__MSG2__" = "Hello_from_guest_1" ]
 
 test	TCP/IPv6: guest 2 > guest 1
-g2out	GW2_6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
 guest1b	socat -u TCP6-LISTEN:10001 OPEN:msg,create,trunc
-guest2	echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__GW2_6__%__IFNAME2__]:10001
+guest2	echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__NAT_TO_HOST6__%__IFNAME2__]:10001
 guest1w
 sleep	1
 g1out	MSG1 cat msg
@@ -65,7 +63,7 @@ check	[ "__MSG1__" = "Hello_from_guest_2" ]
 
 test	UDP/IPv4: guest 1 > guest 2
 guest2b	socat -u TCP4-LISTEN:10004 OPEN:msg,create,trunc
-guest1	echo "Hello_from_guest_1" | socat -u STDIN TCP4:__GW1__:10004
+guest1	echo "Hello_from_guest_1" | socat -u STDIN TCP4:__NAT_TO_HOST4__:10004
 guest2w
 sleep	1
 g2out	MSG2 cat msg
@@ -73,7 +71,7 @@ check	[ "__MSG2__" = "Hello_from_guest_1" ]
 
 test	UDP/IPv6: guest 2 > guest 1
 guest1b	socat -u TCP6-LISTEN:10001 OPEN:msg,create,trunc
-guest2	echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__GW2_6__%__IFNAME2__]:10001
+guest2	echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__NAT_TO_HOST6__%__IFNAME2__]:10001
 guest1w
 sleep	1
 g1out	MSG1 cat msg
diff --git a/udp.c b/udp.c
index 9c96c0f..1533cee 100644
--- a/udp.c
+++ b/udp.c
@@ -597,7 +597,7 @@ static size_t udp_update_hdr4(const struct ctx *c, int n, in_port_t dstport,
 	} else if (IN4_IS_ADDR_LOOPBACK(&b->s_in.sin_addr) ||
 		   IN4_IS_ADDR_UNSPECIFIED(&b->s_in.sin_addr)||
 		   IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.addr_seen)) {
-		b->iph.saddr = c->ip4.gw.s_addr;
+		b->iph.saddr = c->ip4.nattohost.s_addr;
 		udp_tap_map[V4][src_port].ts = now->tv_sec;
 		udp_tap_map[V4][src_port].flags |= PORT_LOCAL;
 
@@ -662,8 +662,8 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 
 		bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
 
-		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
-			src = &c->ip6.gw;
+		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.nattohost))
+			src = &c->ip6.nattohost;
 		else
 			src = &c->ip6.addr_ll;
 	}
@@ -841,7 +841,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_match) &&
 		    ntohs(s_in.sin_port) == 53) {
 			s_in.sin_addr = c->ip4.dns_host;
-		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) &&
+		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.nattohost) &&
 			   !c->no_map_gw) {
 			if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
@@ -887,7 +887,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
 		    ntohs(s_in6.sin6_port) == 53) {
 			s_in6.sin6_addr = c->ip6.dns_host;
-		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) &&
+		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost) &&
 			   !c->no_map_gw) {
 			if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
-- 
@@ -597,7 +597,7 @@ static size_t udp_update_hdr4(const struct ctx *c, int n, in_port_t dstport,
 	} else if (IN4_IS_ADDR_LOOPBACK(&b->s_in.sin_addr) ||
 		   IN4_IS_ADDR_UNSPECIFIED(&b->s_in.sin_addr)||
 		   IN4_ARE_ADDR_EQUAL(&b->s_in.sin_addr, &c->ip4.addr_seen)) {
-		b->iph.saddr = c->ip4.gw.s_addr;
+		b->iph.saddr = c->ip4.nattohost.s_addr;
 		udp_tap_map[V4][src_port].ts = now->tv_sec;
 		udp_tap_map[V4][src_port].flags |= PORT_LOCAL;
 
@@ -662,8 +662,8 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 
 		bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
 
-		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
-			src = &c->ip6.gw;
+		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.nattohost))
+			src = &c->ip6.nattohost;
 		else
 			src = &c->ip6.addr_ll;
 	}
@@ -841,7 +841,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_match) &&
 		    ntohs(s_in.sin_port) == 53) {
 			s_in.sin_addr = c->ip4.dns_host;
-		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.gw) &&
+		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.nattohost) &&
 			   !c->no_map_gw) {
 			if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
@@ -887,7 +887,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
 		    ntohs(s_in6.sin6_port) == 53) {
 			s_in6.sin6_addr = c->ip6.dns_host;
-		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.gw) &&
+		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost) &&
 			   !c->no_map_gw) {
 			if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/7] nat: Simplify --no-map-gw handling
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
                   ` (2 preceding siblings ...)
  2023-05-01 11:06 ` [PATCH 3/7] nat: Split notion of gateway/router from from guest-visible host address David Gibson
@ 2023-05-01 11:06 ` David Gibson
  2023-05-01 11:07 ` [PATCH 5/7] nat: Centralise handling of gateway versus link-local address for host NAT David Gibson
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:06 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

Currently, most places we use c->ip[46].nattohost we also need to
check c->no_map_gw to see if we should even be applying this address
remapping.  However, now that the remapping address is split into its
own field we can just use the unspecified address to indicate no
remapping, and avoid the extra flag.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c  | 35 +++++++++++++++++++++--------------
 passt.h |  2 --
 tcp.c   | 10 ++++------
 udp.c   |  6 ++----
 4 files changed, 27 insertions(+), 26 deletions(-)

diff --git a/conf.c b/conf.c
index bfc825b..dd8a835 100644
--- a/conf.c
+++ b/conf.c
@@ -418,12 +418,13 @@ static void add_dns4(struct ctx *c, struct in_addr *addr, struct in_addr **conf)
 {
 	/* Guest or container can only access local addresses via redirect */
 	if (IN4_IS_ADDR_LOOPBACK(addr)) {
-		if (!c->no_map_gw) {
-			**conf = c->ip4.nattohost;
+		const struct in_addr *nat = &c->ip4.nattohost;
+		if (!IN4_IS_ADDR_UNSPECIFIED(nat)) {
+			**conf = *nat;
 			(*conf)++;
 
 			if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_match))
-				c->ip4.dns_match = c->ip4.nattohost;
+				c->ip4.dns_match = *nat;
 		}
 	} else {
 		**conf = *addr;
@@ -445,8 +446,9 @@ static void add_dns6(struct ctx *c,
 {
 	/* Guest or container can only access local addresses via redirect */
 	if (IN6_IS_ADDR_LOOPBACK(addr)) {
-		if (!c->no_map_gw) {
-			memcpy(*conf, &c->ip6.nattohost, sizeof(**conf));
+		const struct in6_addr *nat = &c->ip6.nattohost;
+		if (!IN6_IS_ADDR_UNSPECIFIED(nat)) {
+			memcpy(*conf, nat, sizeof(**conf));
 			(*conf)++;
 
 			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match))
@@ -628,11 +630,12 @@ static int conf_ip4_prefix(const char *arg)
  * @ifi:	Host interface to attempt (0 to determine one)
  * @ip4:	IPv4 context (will be written)
  * @mac:	MAC address to use (written if unset)
+ * @gwnat:	If set, use gateway as default nattohost address
  *
  * Return:	Interface index for IPv4, or 0 on failure.
  */
-static unsigned int conf_ip4(unsigned int ifi,
-			     struct ip4_ctx *ip4, unsigned char *mac)
+static unsigned int conf_ip4(unsigned int ifi, struct ip4_ctx *ip4,
+			     unsigned char *mac, bool gwnat)
 {
 	in_addr_t addr, gw;
 	int shift;
@@ -688,7 +691,8 @@ static unsigned int conf_ip4(unsigned int ifi,
 	if (MAC_IS_ZERO(mac))
 		nl_link(0, ifi, mac, 0, 0);
 
-	ip4->nattohost = ip4->router;
+	if (gwnat && IN4_IS_ADDR_UNSPECIFIED(&ip4->nattohost))
+		ip4->nattohost = ip4->router;
 
 	if (IN4_IS_ADDR_UNSPECIFIED(&ip4->router) ||
 	    IN4_IS_ADDR_UNSPECIFIED(&ip4->addr) ||
@@ -703,11 +707,12 @@ static unsigned int conf_ip4(unsigned int ifi,
  * @ifi:	Host interface to attempt (0 to determine one)
  * @ip6:	IPv6 context (will be written)
  * @mac:	MAC address to use (written if unset)
+ * @gwnat:	If set, use gateway as default nattohost address
  *
  * Return:	Interface index for IPv6, or 0 on failure.
  */
-static unsigned int conf_ip6(unsigned int ifi,
-			     struct ip6_ctx *ip6, unsigned char *mac)
+static unsigned int conf_ip6(unsigned int ifi, struct ip6_ctx *ip6,
+			     unsigned char *mac, bool gwnat)
 {
 	int prefix_len = 0;
 
@@ -732,7 +737,8 @@ static unsigned int conf_ip6(unsigned int ifi,
 	if (MAC_IS_ZERO(mac))
 		nl_link(0, ifi, mac, 0, 0);
 
-	ip6->nattohost = ip6->router;
+	if (gwnat && IN6_IS_ADDR_UNSPECIFIED(&ip6->nattohost))
+		ip6->nattohost = ip6->router;
 
 	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->router) ||
 	    IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ||
@@ -1163,6 +1169,7 @@ static void conf_ugid(char *runas, uid_t *uid, gid_t *gid)
 void conf(struct ctx *c, int argc, char **argv)
 {
 	int netns_only = 0;
+	int no_map_gw = 0;
 	struct option options[] = {
 		{"debug",	no_argument,		NULL,		'd' },
 		{"quiet",	no_argument,		NULL,		'q' },
@@ -1191,7 +1198,7 @@ void conf(struct ctx *c, int argc, char **argv)
 		{"no-dhcpv6",	no_argument,		&c->no_dhcpv6,	1 },
 		{"no-ndp",	no_argument,		&c->no_ndp,	1 },
 		{"no-ra",	no_argument,		&c->no_ra,	1 },
-		{"no-map-gw",	no_argument,		&c->no_map_gw,	1 },
+		{"no-map-gw",	no_argument,		&no_map_gw,	1 },
 		{"ipv4-only",	no_argument,		NULL,		'4' },
 		{"ipv6-only",	no_argument,		NULL,		'6' },
 		{"one-off",	no_argument,		NULL,		'1' },
@@ -1671,9 +1678,9 @@ void conf(struct ctx *c, int argc, char **argv)
 
 	nl_sock_init(c, false);
 	if (!v6_only)
-		c->ifi4 = conf_ip4(ifi4, &c->ip4, c->mac);
+		c->ifi4 = conf_ip4(ifi4, &c->ip4, c->mac, !no_map_gw);
 	if (!v4_only)
-		c->ifi6 = conf_ip6(ifi6, &c->ip6, c->mac);
+		c->ifi6 = conf_ip6(ifi6, &c->ip6, c->mac, !no_map_gw);
 	if ((!c->ifi4 && !c->ifi6) ||
 	    (*c->ip4.ifname_out && !c->ifi4) ||
 	    (*c->ip6.ifname_out && !c->ifi6))
diff --git a/passt.h b/passt.h
index e308fe1..9f05bca 100644
--- a/passt.h
+++ b/passt.h
@@ -201,7 +201,6 @@ struct ip6_ctx {
  * @no_dhcpv6:		Disable DHCPv6 server
  * @no_ndp:		Disable NDP handler altogether
  * @no_ra:		Disable router advertisements
- * @no_map_gw:		Don't map connections, untracked UDP to gateway to host
  * @low_wmem:		Low probed net.core.wmem_max
  * @low_rmem:		Low probed net.core.rmem_max
  */
@@ -261,7 +260,6 @@ struct ctx {
 	int no_dhcpv6;
 	int no_ndp;
 	int no_ra;
-	int no_map_gw;
 
 	int low_wmem;
 	int low_rmem;
diff --git a/tcp.c b/tcp.c
index b0dacab..aa65d6e 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2040,12 +2040,10 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
 		if ((s = tcp_conn_new_sock(c, af)) < 0)
 			return;
 
-	if (!c->no_map_gw) {
-		if (af == AF_INET && IN4_ARE_ADDR_EQUAL(addr, &c->ip4.nattohost))
-			addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-		if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost))
-			addr6.sin6_addr	= in6addr_loopback;
-	}
+	if (af == AF_INET && IN4_ARE_ADDR_EQUAL(addr, &c->ip4.nattohost))
+		addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	if (af == AF_INET6 && IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost))
+		addr6.sin6_addr	= in6addr_loopback;
 
 	if (af == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr)) {
 		struct sockaddr_in6 addr6_ll = {
diff --git a/udp.c b/udp.c
index 1533cee..6234a8d 100644
--- a/udp.c
+++ b/udp.c
@@ -841,8 +841,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_match) &&
 		    ntohs(s_in.sin_port) == 53) {
 			s_in.sin_addr = c->ip4.dns_host;
-		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.nattohost) &&
-			   !c->no_map_gw) {
+		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.nattohost)) {
 			if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
 				s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
@@ -887,8 +886,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
 		    ntohs(s_in6.sin6_port) == 53) {
 			s_in6.sin6_addr = c->ip6.dns_host;
-		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost) &&
-			   !c->no_map_gw) {
+		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost)) {
 			if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
 				s_in6.sin6_addr = in6addr_loopback;
-- 
@@ -841,8 +841,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.dns_match) &&
 		    ntohs(s_in.sin_port) == 53) {
 			s_in.sin_addr = c->ip4.dns_host;
-		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.nattohost) &&
-			   !c->no_map_gw) {
+		} else if (IN4_ARE_ADDR_EQUAL(&s_in.sin_addr, &c->ip4.nattohost)) {
 			if (!(udp_tap_map[V4][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V4][dst].flags & PORT_LOOPBACK))
 				s_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
@@ -887,8 +886,7 @@ int udp_tap_handler(struct ctx *c, int af, const void *addr,
 		if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.dns_match) &&
 		    ntohs(s_in6.sin6_port) == 53) {
 			s_in6.sin6_addr = c->ip6.dns_host;
-		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost) &&
-			   !c->no_map_gw) {
+		} else if (IN6_ARE_ADDR_EQUAL(addr, &c->ip6.nattohost)) {
 			if (!(udp_tap_map[V6][dst].flags & PORT_LOCAL) ||
 			    (udp_tap_map[V6][dst].flags & PORT_LOOPBACK))
 				s_in6.sin6_addr = in6addr_loopback;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/7] nat: Centralise handling of gateway versus link-local address for host NAT
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
                   ` (3 preceding siblings ...)
  2023-05-01 11:06 ` [PATCH 4/7] nat: Simplify --no-map-gw handling David Gibson
@ 2023-05-01 11:07 ` David Gibson
  2023-05-01 11:07 ` [PATCH 6/7] Allow nat-to-host addresses to be overridden David Gibson
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:07 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

For inbound packets address to host's ::1 we rewrite the source
address to be the @nattohost address.  Unless the @nattohost address
is not link local, in which case we use the host's link-local address
instead.

Confusingly we don't mirror this logic for outbound packets.  We
rewrite the destination for packets bound to @nattohost into ::1, but
we don't alter packets bound for the host's link-local address.  This
will probably still work in most cases, since the host's link-local
address will still go to the host, but it's a weird assymetry.

Remove the assymetry and simplify the code, by always using the
@nattohost address alone, but instead setting the @nattohost address
to the host link-local address rather than the gateway if the gateway
isn't a link-local address.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c | 8 ++++++--
 tcp.c  | 5 +----
 udp.c  | 5 +----
 3 files changed, 8 insertions(+), 10 deletions(-)

diff --git a/conf.c b/conf.c
index dd8a835..45f49eb 100644
--- a/conf.c
+++ b/conf.c
@@ -737,8 +737,12 @@ static unsigned int conf_ip6(unsigned int ifi, struct ip6_ctx *ip6,
 	if (MAC_IS_ZERO(mac))
 		nl_link(0, ifi, mac, 0, 0);
 
-	if (gwnat && IN6_IS_ADDR_UNSPECIFIED(&ip6->nattohost))
-		ip6->nattohost = ip6->router;
+	if (gwnat && IN6_IS_ADDR_UNSPECIFIED(&ip6->nattohost)) {
+		if (IN6_IS_ADDR_LINKLOCAL(&ip6->router))
+			ip6->nattohost = ip6->router;
+		else
+			ip6->nattohost = ip6->addr_ll;
+	}
 
 	if (IN6_IS_ADDR_UNSPECIFIED(&ip6->router) ||
 	    IN6_IS_ADDR_UNSPECIFIED(&ip6->addr) ||
diff --git a/tcp.c b/tcp.c
index aa65d6e..d91e786 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2718,10 +2718,7 @@ static void tcp_snat_inbound(const struct ctx *c, union inany_addr *addr)
 		if (IN6_IS_ADDR_LOOPBACK(addr6) ||
 		    IN6_ARE_ADDR_EQUAL(addr6, &c->ip6.addr_seen) ||
 		    IN6_ARE_ADDR_EQUAL(addr6, &c->ip6.addr)) {
-			if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.nattohost))
-				*addr6 = c->ip6.nattohost;
-			else
-				*addr6 = c->ip6.addr_ll;
+			*addr6 = c->ip6.nattohost;
 		}
 	}
 }
diff --git a/udp.c b/udp.c
index 6234a8d..6cd2813 100644
--- a/udp.c
+++ b/udp.c
@@ -662,10 +662,7 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 
 		bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
 
-		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.nattohost))
-			src = &c->ip6.nattohost;
-		else
-			src = &c->ip6.addr_ll;
+		src = &c->ip6.nattohost;
 	}
 
 	b->ip6h.saddr = *src;
-- 
@@ -662,10 +662,7 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
 
 		bitmap_set(udp_act[V6][UDP_ACT_TAP], src_port);
 
-		if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.nattohost))
-			src = &c->ip6.nattohost;
-		else
-			src = &c->ip6.addr_ll;
+		src = &c->ip6.nattohost;
 	}
 
 	b->ip6h.saddr = *src;
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 6/7] Allow nat-to-host addresses to be overridden
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
                   ` (4 preceding siblings ...)
  2023-05-01 11:07 ` [PATCH 5/7] nat: Centralise handling of gateway versus link-local address for host NAT David Gibson
@ 2023-05-01 11:07 ` David Gibson
  2023-05-01 11:07 ` [PATCH 7/7] nat, test: Test --nat-to-host option David Gibson
  2023-05-02 21:52 ` [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly Stefano Brivio
  7 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:07 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

Because the host and guest share the same IP address with passt/pasta, it's
not possible for the guest to directly address the host.  Therefore we
allow packets from the guest going to a special "NAT to host" address to be
redirected to the host, appearing there as though they have both source and
destination address of loopback.

Currently that special address is always the address of the default
gateway.  That can be a problem if we want that gateway to be addressable
by the guest.  Therefore, allow the special "NAT to host" address to be
overridden on the command line.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c | 38 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)

diff --git a/conf.c b/conf.c
index 45f49eb..ea56003 100644
--- a/conf.c
+++ b/conf.c
@@ -849,6 +849,12 @@ static void usage(const char *name)
 	else
 		info("  --no-dhcp-search	No list in DHCP/DHCPv6/NDP");
 
+	info(   "  -H, --nat-to-host ADDR	NAT packets sent to ADDR to go to host");
+	info(   "    NATted packets will appear on the host to have come from");
+	info(   "    foopback.  Can be specified zero to two times (for IPv4 and IPv6)");
+	info(   "    default: gateway address, or no NAT if --no-map-gw is also");
+	info(   "             specified");
+
 	info(   "  --dns-forward ADDR	Forward DNS queries sent to ADDR");
 	info(   "    can be specified zero to two times (for IPv4 and IPv6)");
 	info(   "    default: don't forward DNS queries");
@@ -987,6 +993,11 @@ static void conf_print(const struct ctx *c)
 	     c->mac[3], c->mac[4], c->mac[5]);
 
 	if (c->ifi4) {
+		if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.nattohost))
+			info("    NAT for host 127.0.0.1: %s",
+			     inet_ntop(AF_INET, &c->ip4.nattohost,
+				       buf4, sizeof(buf4)));
+
 		if (!c->no_dhcp) {
 			uint32_t mask;
 
@@ -1016,6 +1027,11 @@ static void conf_print(const struct ctx *c)
 	}
 
 	if (c->ifi6) {
+		if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.nattohost))
+			info("    NAT for host ::1: %s",
+			     inet_ntop(AF_INET6, &c->ip6.nattohost,
+				       buf6, sizeof(buf6)));
+
 		if (!c->no_ndp && !c->no_dhcpv6)
 			info("NDP/DHCPv6:");
 		else if (!c->no_ndp)
@@ -1191,6 +1207,7 @@ void conf(struct ctx *c, int argc, char **argv)
 		{"netmask",	required_argument,	NULL,		'n' },
 		{"mac-addr",	required_argument,	NULL,		'M' },
 		{"gateway",	required_argument,	NULL,		'g' },
+		{"host",	required_argument,	NULL,		'H' },
 		{"interface",	required_argument,	NULL,		'i' },
 		{"outbound",	required_argument,	NULL,		'o' },
 		{"dns",		required_argument,	NULL,		'D' },
@@ -1245,9 +1262,9 @@ void conf(struct ctx *c, int argc, char **argv)
 
 	if (c->mode == MODE_PASTA) {
 		c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
-		optstring = "dqfel:hF:I:p:P:m:a:n:M:g:i:o:D:S:46t:u:T:U:";
+		optstring = "dqfel:hF:I:p:P:m:a:n:M:g:i:o:D:S:46t:u:T:U:H:";
 	} else {
-		optstring = "dqfel:hs:F:p:P:m:a:n:M:g:i:o:D:S:461t:u:";
+		optstring = "dqfel:hs:F:p:P:m:a:n:M:g:i:o:D:S:461t:u:H:";
 	}
 
 	c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = 0;
@@ -1548,6 +1565,23 @@ void conf(struct ctx *c, int argc, char **argv)
 
 			die("Invalid gateway address: %s", optarg);
 			break;
+		case 'H':
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.nattohost)	&&
+			    inet_pton(AF_INET6, optarg, &c->ip6.nattohost)&&
+			    !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.nattohost)	&&
+			    !IN6_IS_ADDR_LOOPBACK(&c->ip6.nattohost))
+				break;
+
+			if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.nattohost)	&&
+			    inet_pton(AF_INET, optarg, &c->ip4.nattohost)	&&
+			    !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.nattohost)	&&
+			    !IN4_IS_ADDR_BROADCAST(&c->ip4.nattohost)	&&
+			    !IN4_IS_ADDR_LOOPBACK(&c->ip4.nattohost))
+				break;
+
+			err("Invalid host remap address: %s", optarg);
+			usage(argv[0]);
+			break;
 		case 'i':
 			if (ifi4 || ifi6)
 				die("Redundant interface: %s", optarg);
-- 
@@ -849,6 +849,12 @@ static void usage(const char *name)
 	else
 		info("  --no-dhcp-search	No list in DHCP/DHCPv6/NDP");
 
+	info(   "  -H, --nat-to-host ADDR	NAT packets sent to ADDR to go to host");
+	info(   "    NATted packets will appear on the host to have come from");
+	info(   "    foopback.  Can be specified zero to two times (for IPv4 and IPv6)");
+	info(   "    default: gateway address, or no NAT if --no-map-gw is also");
+	info(   "             specified");
+
 	info(   "  --dns-forward ADDR	Forward DNS queries sent to ADDR");
 	info(   "    can be specified zero to two times (for IPv4 and IPv6)");
 	info(   "    default: don't forward DNS queries");
@@ -987,6 +993,11 @@ static void conf_print(const struct ctx *c)
 	     c->mac[3], c->mac[4], c->mac[5]);
 
 	if (c->ifi4) {
+		if (!IN4_IS_ADDR_UNSPECIFIED(&c->ip4.nattohost))
+			info("    NAT for host 127.0.0.1: %s",
+			     inet_ntop(AF_INET, &c->ip4.nattohost,
+				       buf4, sizeof(buf4)));
+
 		if (!c->no_dhcp) {
 			uint32_t mask;
 
@@ -1016,6 +1027,11 @@ static void conf_print(const struct ctx *c)
 	}
 
 	if (c->ifi6) {
+		if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.nattohost))
+			info("    NAT for host ::1: %s",
+			     inet_ntop(AF_INET6, &c->ip6.nattohost,
+				       buf6, sizeof(buf6)));
+
 		if (!c->no_ndp && !c->no_dhcpv6)
 			info("NDP/DHCPv6:");
 		else if (!c->no_ndp)
@@ -1191,6 +1207,7 @@ void conf(struct ctx *c, int argc, char **argv)
 		{"netmask",	required_argument,	NULL,		'n' },
 		{"mac-addr",	required_argument,	NULL,		'M' },
 		{"gateway",	required_argument,	NULL,		'g' },
+		{"host",	required_argument,	NULL,		'H' },
 		{"interface",	required_argument,	NULL,		'i' },
 		{"outbound",	required_argument,	NULL,		'o' },
 		{"dns",		required_argument,	NULL,		'D' },
@@ -1245,9 +1262,9 @@ void conf(struct ctx *c, int argc, char **argv)
 
 	if (c->mode == MODE_PASTA) {
 		c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
-		optstring = "dqfel:hF:I:p:P:m:a:n:M:g:i:o:D:S:46t:u:T:U:";
+		optstring = "dqfel:hF:I:p:P:m:a:n:M:g:i:o:D:S:46t:u:T:U:H:";
 	} else {
-		optstring = "dqfel:hs:F:p:P:m:a:n:M:g:i:o:D:S:461t:u:";
+		optstring = "dqfel:hs:F:p:P:m:a:n:M:g:i:o:D:S:461t:u:H:";
 	}
 
 	c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = 0;
@@ -1548,6 +1565,23 @@ void conf(struct ctx *c, int argc, char **argv)
 
 			die("Invalid gateway address: %s", optarg);
 			break;
+		case 'H':
+			if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.nattohost)	&&
+			    inet_pton(AF_INET6, optarg, &c->ip6.nattohost)&&
+			    !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.nattohost)	&&
+			    !IN6_IS_ADDR_LOOPBACK(&c->ip6.nattohost))
+				break;
+
+			if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.nattohost)	&&
+			    inet_pton(AF_INET, optarg, &c->ip4.nattohost)	&&
+			    !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.nattohost)	&&
+			    !IN4_IS_ADDR_BROADCAST(&c->ip4.nattohost)	&&
+			    !IN4_IS_ADDR_LOOPBACK(&c->ip4.nattohost))
+				break;
+
+			err("Invalid host remap address: %s", optarg);
+			usage(argv[0]);
+			break;
 		case 'i':
 			if (ifi4 || ifi6)
 				die("Redundant interface: %s", optarg);
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 7/7] nat, test: Test --nat-to-host option
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
                   ` (5 preceding siblings ...)
  2023-05-01 11:07 ` [PATCH 6/7] Allow nat-to-host addresses to be overridden David Gibson
@ 2023-05-01 11:07 ` David Gibson
  2023-05-02 21:52 ` [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly Stefano Brivio
  7 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2023-05-01 11:07 UTC (permalink / raw)
  To: Stefano Brivio, passt-dev; +Cc: David Gibson

We've now added the --nat-to-host or -H option to change the address that
is NATted to the host loopback address coming from the guest.  However, the
tests don't currently exercise this option.

This updates all the passt_in_ns / passt in pasta tests to use this option,
with different nat-to-host addresses for the two layers of the environment.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 test/lib/setup        | 15 ++++-----
 test/passt_in_ns/dhcp | 73 +++++++++++++++++++++++++++++++++++++++++++
 test/passt_in_ns/tcp  | 12 +++----
 test/passt_in_ns/udp  |  6 ++--
 test/perf/passt_tcp   | 12 +++----
 test/perf/passt_udp   | 10 +++---
 test/perf/pasta_tcp   | 12 +++----
 test/perf/pasta_udp   | 10 +++---
 test/run              |  4 +--
 9 files changed, 114 insertions(+), 40 deletions(-)
 create mode 100644 test/passt_in_ns/dhcp

diff --git a/test/lib/setup b/test/lib/setup
index d85002e..3ef650b 100755
--- a/test/lib/setup
+++ b/test/lib/setup
@@ -124,17 +124,18 @@ setup_passt_in_ns() {
 	#
 	#  10021    as server  | forwarded to guest |
 	#  10031    as server  | forwarded to guest |
-        __nat_to_host4="$(ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway')"
-        __nat_to_host6="$(ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway')"
-        __nat_to_ns4="${__nat_to_host4}"
-        __nat_to_ns6="${__nat_to_host6}"
+
+        __nat_to_host4=192.0.2.1
+        __nat_to_host6=2001:db8:9a55::1
+        __nat_to_ns4=192.0.2.2
+        __nat_to_ns6=2001:db8:9a55::2
 
 	__opts=
 	[ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta_with_passt.pcap"
 	[ ${DEBUG} -eq 1 ] && __opts="${__opts} -d"
 	[ ${TRACE} -eq 1 ] && __opts="${__opts} --trace"
 
-	context_run_bg pasta "./pasta ${__opts} -t 10001,10002,10011,10012 -T 10003,10013 -u 10001,10002,10011,10012 -U 10003,10013 -P ${STATESETUP}/pasta.pid --config-net ${NSTOOL} hold ${STATESETUP}/ns.hold"
+	context_run_bg pasta "./pasta ${__opts} -t 10001,10002,10011,10012 -T 10003,10013 -u 10001,10002,10011,10012 -U 10003,10013 -P ${STATESETUP}/pasta.pid -H ${__nat_to_host4} -H ${__nat_to_host6} --config-net ${NSTOOL} hold ${STATESETUP}/ns.hold"
 	wait_for [ -f "${STATESETUP}/pasta.pid" ]
 
 	context_setup_nstool qemu ${STATESETUP}/ns.hold
@@ -149,11 +150,11 @@ setup_passt_in_ns() {
 	if [ ${VALGRIND} -eq 1 ]; then
 		context_run passt "make clean"
 		context_run passt "make valgrind"
-		context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid"
+		context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid -H ${__nat_to_ns4} -H ${__nat_to_ns6}"
 	else
 		context_run passt "make clean"
 		context_run passt "make"
-		context_run_bg passt "./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid"
+		context_run_bg passt "./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid -H ${__nat_to_ns4} -H ${__nat_to_ns6}"
 	fi
 	wait_for [ -f "${STATESETUP}/passt.pid" ]
 
diff --git a/test/passt_in_ns/dhcp b/test/passt_in_ns/dhcp
new file mode 100644
index 0000000..0c3ad61
--- /dev/null
+++ b/test/passt_in_ns/dhcp
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# PASST - Plug A Simple Socket Transport
+#  for qemu/UNIX domain socket mode
+#
+# PASTA - Pack A Subtle Tap Abstraction
+#  for network namespace/tap device mode
+#
+# test/passt_in_ns/dhcp - Check DHCP and DHCPv6 functionality for passt in ns with pasta
+#
+# Copyright Red Hat
+# Author: Stefano Brivio <sbrivio@redhat.com>
+
+gtools	ip jq dhclient sed tr
+htools	ip jq sed tr head
+
+test	Provided addresses
+gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+
+test	Interface name
+gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
+hout	HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+hout	HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]'
+check	[ -n "__IFNAME__" ]
+
+test	DHCP: address
+guest	/sbin/dhclient -4 __IFNAME__
+gout	ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local'
+hout	HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local'
+check	[ "__ADDR__" = "__HOST_ADDR__" ]
+
+test	DHCP: route
+gout	GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway'
+hout	HOST_GW ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]'
+check	[ "__GW__" = "__HOST_GW__" ]
+
+test	DHCP: MTU
+gout	MTU ip -j link show | jq -rM '.[] | select(.ifname == "__IFNAME__").mtu'
+check	[ __MTU__ = 65520 ]
+
+test	DHCP: DNS
+gout	DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+hout	HOST_DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | head -n3 | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+check	[ "__DNS__" = "__HOST_DNS__" ] || [ "__DNS__" = "__NAT_TO_NS4__" -a "__HOST_DNS__" = "127.0.0.1" ]
+
+# FQDNs should be terminated by dots, but the guest DHCP client might omit them:
+# strip them first
+test	DHCP: search list
+gout	SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+hout	HOST_SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+check	[ "__SEARCH__" = "__HOST_SEARCH__" ]
+
+test	DHCPv6: address
+guest	/sbin/dhclient -6 __IFNAME__
+gout	ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local'
+hout	HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local'
+check	[ "__ADDR6__" = "__HOST_ADDR6__" ]
+
+test	DHCPv6: route
+gout	GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway'
+hout	HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]'
+check	[ "__GW6__" = "__HOST_GW6__" ]
+
+# Strip interface specifier: interface names might differ between host and guest
+test	DHCPv6: DNS
+gout	DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+hout	HOST_DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/'
+check	[ "__DNS6__" = "__HOST_DNS6__" ] || [ "__DNS6__" = "__NAT_TO_HOST6__" -a "__HOST_DNS6__" = "::1" ]
+
+test	DHCPv6: search list
+gout	SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+hout	HOST_SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/'
+check	[ "__SEARCH6__" = "__HOST_SEARCH6__" ]
diff --git a/test/passt_in_ns/tcp b/test/passt_in_ns/tcp
index 51d0379..e2ac215 100644
--- a/test/passt_in_ns/tcp
+++ b/test/passt_in_ns/tcp
@@ -152,14 +152,14 @@ test	TCP/IPv6: guest to host: big transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-guest	socat -u OPEN:/root/big.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
+guest	socat -u OPEN:/root/big.bin TCP6:[__NAT_TO_HOST6__]:10003
 hostw
 check	cmp __TEMP_BIG__ __BASEPATH__/big.bin
 
 test	TCP/IPv6: guest to ns: big transfer
 nsb	socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/big.bin TCP6:[__NAT_TO_NS6__%__IFNAME__]:10002
+guest	socat -u OPEN:/root/big.bin TCP6:[__NAT_TO_NS6__]:10002
 nsw
 check	cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin
 
@@ -174,7 +174,7 @@ test	TCP/IPv6: ns to host (via tap): big transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/big.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
+ns	socat -u OPEN:__BASEPATH__/big.bin TCP6:[__NAT_TO_HOST6__]:10003
 hostw
 check	cmp __TEMP_BIG__ __BASEPATH__/big.bin
 
@@ -211,14 +211,14 @@ test	TCP/IPv6: guest to host: small transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
+guest	socat -u OPEN:/root/small.bin TCP6:[__NAT_TO_HOST6__]:10003
 hostw
 check	cmp __TEMP_SMALL__ __BASEPATH__/small.bin
 
 test	TCP/IPv6: guest to ns: small transfer
 nsb	socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_SMALL__
 sleep	1
-guest	socat -u OPEN:/root/small.bin TCP6:[__NAT_TO_NS6__%__IFNAME__]:10002
+guest	socat -u OPEN:/root/small.bin TCP6:[__NAT_TO_NS6__]:10002
 nsw
 check	cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin
 
@@ -233,7 +233,7 @@ test	TCP/IPv6: ns to host (via tap): small transfer
 hostb	socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/small.bin TCP6:[__NAT_TO_HOST6__%__IFNAME__]:10003
+ns	socat -u OPEN:__BASEPATH__/small.bin TCP6:[__NAT_TO_HOST6__]:10003
 hostw
 check	cmp __TEMP_SMALL__ __BASEPATH__/small.bin
 
diff --git a/test/passt_in_ns/udp b/test/passt_in_ns/udp
index 40e687f..a1f77fd 100644
--- a/test/passt_in_ns/udp
+++ b/test/passt_in_ns/udp
@@ -94,14 +94,14 @@ test	UDP/IPv6: guest to host
 hostb	socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
 gout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-guest	socat -u OPEN:/root/medium.bin UDP6:[__NAT_TO_HOST6__%__IFNAME__]:10003,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP6:[__NAT_TO_HOST6__]:10003,shut-null
 hostw
 check	cmp __TEMP__ __BASEPATH__/medium.bin
 
 test	UDP/IPv6: guest to ns
 nsb	socat -u UDP6-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc
 sleep	1
-guest	socat -u OPEN:/root/medium.bin UDP6:[__NAT_TO_NS6__%__IFNAME__]:10002,shut-null
+guest	socat -u OPEN:/root/medium.bin UDP6:[__NAT_TO_NS6__]:10002,shut-null
 nsw
 check	cmp __TEMP_NS__ __BASEPATH__/medium.bin
 
@@ -116,7 +116,7 @@ test	UDP/IPv6: ns to host (via tap)
 hostb	socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc
 nsout	IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname'
 sleep	1
-ns	socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__NAT_TO_HOST6__%__IFNAME__]:10003,shut-null
+ns	socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__NAT_TO_HOST6__]:10003,shut-null
 hostw
 check	cmp __TEMP__ __BASEPATH__/medium.bin
 
diff --git a/test/perf/passt_tcp b/test/perf/passt_tcp
index 7852a7e..6436677 100644
--- a/test/perf/passt_tcp
+++ b/test/perf/passt_tcp
@@ -52,16 +52,16 @@ bw	-
 bw	-
 
 guest	ip link set dev __IFNAME__ mtu 1280
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
 bw	__BW__ 1.2 1.5
 guest	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M
 bw	__BW__ 1.6 1.8
 guest	ip link set dev __IFNAME__ mtu 9000
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 4.0 5.0
 guest	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M
 bw	__BW__ 7.0 8.0
 
 tl	TCP RR latency over IPv6: guest to host
@@ -71,7 +71,7 @@ lat	-
 lat	-
 lat	-
 nsb	tcp_rr --nolog -6
-gout	LAT tcp_rr --nolog -6 -c -H __NAT_TO_NS6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT tcp_rr --nolog -6 -c -H __NAT_TO_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 200 150
 
 tl	TCP CRR latency over IPv6: guest to host
@@ -81,7 +81,7 @@ lat	-
 lat	-
 lat	-
 nsb	tcp_crr --nolog -6
-gout	LAT tcp_crr --nolog -6 -c -H __NAT_TO_NS6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT tcp_crr --nolog -6 -c -H __NAT_TO_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 500 400
 
 
diff --git a/test/perf/passt_udp b/test/perf/passt_udp
index e19dd8c..36fbddb 100644
--- a/test/perf/passt_udp
+++ b/test/perf/passt_udp
@@ -44,16 +44,16 @@ tr	UDP throughput over IPv6: guest to host
 bw	-
 bw	-
 guest	ip link set dev __IFNAME__ mtu 1280
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G
 bw	__BW__ 0.8 1.2
 guest	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G
 bw	__BW__ 1.0 1.5
 guest	ip link set dev __IFNAME__ mtu 9000
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 5G
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 5G
 bw	__BW__ 4.0 5.0
 guest	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW guest ns __NAT_TO_NS6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G
+iperf3	BW guest ns __NAT_TO_NS6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G
 bw	__BW__ 4.0 5.0
 
 tl	UDP RR latency over IPv6: guest to host
@@ -63,7 +63,7 @@ lat	-
 lat	-
 lat	-
 nsb	udp_rr --nolog -6
-gout	LAT udp_rr --nolog -6 -c -H __NAT_TO_NS6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+gout	LAT udp_rr --nolog -6 -c -H __NAT_TO_NS6__ | sed -n 's/^throughput=\(.*\)/\1/p'
 lat	__LAT__ 200 150
 
 
diff --git a/test/perf/pasta_tcp b/test/perf/pasta_tcp
index 8053800..d1270c8 100644
--- a/test/perf/pasta_tcp
+++ b/test/perf/pasta_tcp
@@ -175,16 +175,16 @@ th	MTU 1500B 4000B 16384B 65520B
 
 tr	TCP throughput over IPv6: ns to host
 ns	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k
 bw	__BW__ 0.2 0.4
 ns	ip link set dev __IFNAME__ mtu 4000
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M
 bw	__BW__ 0.3 0.5
 ns	ip link set dev __IFNAME__ mtu 16384
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 1.5 2.0
 ns	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M
 bw	__BW__ 2.0 2.5
 
 tl	TCP RR latency over IPv6: ns to host
@@ -192,7 +192,7 @@ lat	-
 lat	-
 lat	-
 hostb	tcp_rr --nolog -P 10003 -C 10013 -6
-nsout	LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 150 100
 
@@ -201,7 +201,7 @@ lat	-
 lat	-
 lat	-
 hostb	tcp_crr --nolog -P 10003 -C 10013 -6
-nsout	LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 1500 500
 
diff --git a/test/perf/pasta_udp b/test/perf/pasta_udp
index 1d3d5d4..ac2050b 100644
--- a/test/perf/pasta_udp
+++ b/test/perf/pasta_udp
@@ -132,16 +132,16 @@ th	MTU 1500B 4000B 16384B 65520B
 
 tr	UDP throughput over IPv6: ns to host
 ns	ip link set dev __IFNAME__ mtu 1500
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G
 bw	__BW__ 0.3 0.5
 ns	ip link set dev __IFNAME__ mtu 4000
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G
 bw	__BW__ 0.5 0.8
 ns	ip link set dev __IFNAME__ mtu 16384
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G
 bw	__BW__ 3.0 4.0
 ns	ip link set dev __IFNAME__ mtu 65520
-iperf3	BW ns host __NAT_TO_HOST6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G
+iperf3	BW ns host __NAT_TO_HOST6__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G
 bw	__BW__ 6.0 7.0
 
 tl	UDP RR latency over IPv6: ns to host
@@ -149,7 +149,7 @@ lat	-
 lat	-
 lat	-
 hostb	udp_rr --nolog -P 10003 -C 10013 -6
-nsout	LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p'
+nsout	LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H __NAT_TO_HOST6__ | sed -n 's/^throughput=\(.*\)/\1/p'
 hostw
 lat	__LAT__ 200 150
 
diff --git a/test/run b/test/run
index 8f4f845..65a3ff9 100755
--- a/test/run
+++ b/test/run
@@ -97,7 +97,7 @@ run() {
 	VALGRIND=1
 	setup passt_in_ns
 	test passt/ndp
-	test passt/dhcp
+	test passt_in_ns/dhcp
 	test passt_in_ns/icmp
 	test passt_in_ns/tcp
 	test passt_in_ns/udp
@@ -111,7 +111,7 @@ run() {
 	VALGRIND=0
 	setup passt_in_ns
 	test passt/ndp
-	test passt/dhcp
+	test passt_in_ns/dhcp
 	test perf/passt_tcp
 	test perf/passt_udp
 	test perf/pasta_tcp
-- 
@@ -97,7 +97,7 @@ run() {
 	VALGRIND=1
 	setup passt_in_ns
 	test passt/ndp
-	test passt/dhcp
+	test passt_in_ns/dhcp
 	test passt_in_ns/icmp
 	test passt_in_ns/tcp
 	test passt_in_ns/udp
@@ -111,7 +111,7 @@ run() {
 	VALGRIND=0
 	setup passt_in_ns
 	test passt/ndp
-	test passt/dhcp
+	test passt_in_ns/dhcp
 	test perf/passt_tcp
 	test perf/passt_udp
 	test perf/pasta_tcp
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly
  2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
                   ` (6 preceding siblings ...)
  2023-05-01 11:07 ` [PATCH 7/7] nat, test: Test --nat-to-host option David Gibson
@ 2023-05-02 21:52 ` Stefano Brivio
  7 siblings, 0 replies; 10+ messages in thread
From: Stefano Brivio @ 2023-05-02 21:52 UTC (permalink / raw)
  To: David Gibson; +Cc: passt-dev

On Mon,  1 May 2023 21:06:55 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:

> This isn't quite ready for merge yet.  First, I think there might be a
> bug I haven't managed to track down yet which causes intermittent
> failures in some of the UDP throughput tests.

I couldn't find any obvious offender at a quick glance, but I still
have to convince myself that 2/7 is correct (mostly in the sense of
"are those addresses always valid?").

I'll give another try at reviewing this tomorrow.

-- 
Stefano


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/7] udp: Simplify setting od destination IPv6 address for inbound packets
  2023-05-01 11:06 ` [PATCH 2/7] udp: Simplify setting od destination " David Gibson
@ 2023-05-04 21:53   ` Stefano Brivio
  0 siblings, 0 replies; 10+ messages in thread
From: Stefano Brivio @ 2023-05-04 21:53 UTC (permalink / raw)
  To: David Gibson; +Cc: passt-dev

On Mon,  1 May 2023 21:06:57 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:

> Depending on several possible NAT situations, udp_update_hdr6() has a few
> different paths for setting the destination IPv6 address.  However, this
> isn't really separate from the selection of the IPv6 source address:
> if the adjusted source address is link-local then we need to use a link
> local destination, otherwise we need the global destination address.
> 
> This fixes a small bug: it's theoretically possible, although unlikely, for
> the dns_match address to be link-local, in which case the previous code
> would have used the wrong destination.
> 
> This does do slightly more work in the case of NATting packets originating
> on the host.  Currently we always NAT those to a link-local address so we
> could statically set a link-local destination address, but we now recheck.
> However, as well as being simpler, the new approach is more robust if we
> want to allow non-link-local NAT-to-host addresses, which we do plan to in
> future.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  udp.c | 13 +++++--------
>  1 file changed, 5 insertions(+), 8 deletions(-)
> 
> diff --git a/udp.c b/udp.c
> index 361f24c..9c96c0f 100644
> --- a/udp.c
> +++ b/udp.c
> @@ -640,18 +640,13 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
>  
>  	b->ip6h.payload_len = htons(udp6_l2_mh_sock[n].msg_len + sizeof(b->uh));
>  
> -	if (IN6_IS_ADDR_LINKLOCAL(src)) {
> -		b->ip6h.daddr = c->ip6.addr_ll_seen;
> -	} else if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
> +	if (!IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) &&
>  		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.dns_host) &&
>  		   src_port == 53) {
> -		b->ip6h.daddr = c->ip6.addr_seen;
>  		src = &c->ip6.dns_match;
>  	} else if (IN6_IS_ADDR_LOOPBACK(src)			||
>  		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr_seen)	||
>  		   IN6_ARE_ADDR_EQUAL(src, &c->ip6.addr)) {
> -		b->ip6h.daddr = c->ip6.addr_ll_seen;
> -

This part...

>  		udp_tap_map[V6][src_port].ts = now->tv_sec;
>  		udp_tap_map[V6][src_port].flags |= PORT_LOCAL;
>  
> @@ -671,11 +666,13 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
>  			src = &c->ip6.gw;
>  		else
>  			src = &c->ip6.addr_ll;
> -	} else {
> -		b->ip6h.daddr = c->ip6.addr_seen;
>  	}
>  
>  	b->ip6h.saddr = *src;
> +	if (IN6_IS_ADDR_LINKLOCAL(src))
> +		b->ip6h.daddr = c->ip6.addr_ll_seen;
> +	else
> +		b->ip6h.daddr = c->ip6.addr_seen;

is not equivalent to this, and I guess not by intention.

The rationale for setting a link-local destination address if the
source address (on the host) is the loopback address (commit
86b273150a47 "tcp, udp: Allow binding ports in init namespace to
both tap and loopback"... not a great description) is that we might
otherwise collide with a global unicast destination address also
assigned to the host.

A link-local destination should be the only safe option. After all,
that's what link-local addresses are for: surely a packet with that
source address is local to the "link" to the guest.

If the source address matches the configured or observed address
(presumably local), the same reasoning applies: we want to actually
send that packet to the guest, and signal that it's local.

I guess this change might explain the failures you see: if we
already saw a non-link-local address from the guest, we'll use that
as destination, and the packet won't reach the guest.

The rest looks correct to me, and also the rest of the series...
just, as you mentioned, if we want to generalise this right away (and I
think it's a better approach), patches from 3/7 on will be
substantially different.

-- 
Stefano


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2023-05-04 21:53 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-01 11:06 [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly David Gibson
2023-05-01 11:06 ` [PATCH 1/7] udp: Simplify setting of source IPv6 address for inbound packets David Gibson
2023-05-01 11:06 ` [PATCH 2/7] udp: Simplify setting od destination " David Gibson
2023-05-04 21:53   ` Stefano Brivio
2023-05-01 11:06 ` [PATCH 3/7] nat: Split notion of gateway/router from from guest-visible host address David Gibson
2023-05-01 11:06 ` [PATCH 4/7] nat: Simplify --no-map-gw handling David Gibson
2023-05-01 11:07 ` [PATCH 5/7] nat: Centralise handling of gateway versus link-local address for host NAT David Gibson
2023-05-01 11:07 ` [PATCH 6/7] Allow nat-to-host addresses to be overridden David Gibson
2023-05-01 11:07 ` [PATCH 7/7] nat, test: Test --nat-to-host option David Gibson
2023-05-02 21:52 ` [PATCH 0/7] RFC: Allow NAT-to-host address to be configured explicitly Stefano Brivio

Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).