public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: passt-dev@passt.top
Subject: [PATCH 1/7] Allow different external interfaces for IPv4 and IPv6 connectivity
Date: Fri, 22 Jul 2022 15:31:12 +1000	[thread overview]
Message-ID: <20220722053118.1067459-2-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20220722053118.1067459-1-david@gibson.dropbear.id.au>

[-- Attachment #1: Type: text/plain, Size: 6554 bytes --]

It's quite plausible for a host to have both IPv4 and IPv6 connectivity,
but only via different interfaces.  For example, this will happen in the
case that IPv6 connectivity is via a tunnel (e.g. 6in4 or 6rd).  It would
also happen in the case that IPv4 access is via a tunnel on an otherwise
IPv6 only local network, which is a setup that might become more common in
the post IPv4 address exhaustion world.

In turns out there's no real need for passt/pasta to get its IPv4 and IPv6
connectivity via the same interface, so we can handle this situation fairly
easily.  Change the core to allow eparate external interfaces for IPv4 and
IPv6.  We don't actually set these separately for now.

Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au>
---
 conf.c  | 38 +++++++++++++++++++++-----------------
 passt.h |  6 ++++--
 tcp.c   |  2 +-
 util.c  |  2 +-
 4 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/conf.c b/conf.c
index cddc769..943526d 100644
--- a/conf.c
+++ b/conf.c
@@ -630,17 +630,17 @@ static void conf_ip(struct ctx *c)
 		v4 = v6		= IP_VERSION_PROBE;
 	}
 
-	if (!c->ifi)
-		c->ifi = nl_get_ext_if(&v4, &v6);
+	if (!c->ifi4 && !c->ifi6)
+		c->ifi4 = c->ifi6 = nl_get_ext_if(&v4, &v6);
 
 	if (v4 != IP_VERSION_DISABLED) {
 		if (!c->gw4)
-			nl_route(0, c->ifi, AF_INET, &c->gw4);
+			nl_route(0, c->ifi4, AF_INET, &c->gw4);
 
 		if (!c->addr4) {
 			int mask_len = 0;
 
-			nl_addr(0, c->ifi, AF_INET, &c->addr4, &mask_len, NULL);
+			nl_addr(0, c->ifi4, AF_INET, &c->addr4, &mask_len, NULL);
 			c->mask4 = htonl(0xffffffff << (32 - mask_len));
 		}
 
@@ -658,7 +658,7 @@ static void conf_ip(struct ctx *c)
 		memcpy(&c->addr4_seen, &c->addr4, sizeof(c->addr4_seen));
 
 		if (!memcmp(c->mac, MAC_ZERO, ETH_ALEN))
-			nl_link(0, c->ifi, c->mac, 0, 0);
+			nl_link(0, c->ifi4, c->mac, 0, 0);
 	}
 
 	if (c->mode == MODE_PASST)
@@ -668,9 +668,9 @@ static void conf_ip(struct ctx *c)
 		int prefix_len = 0;
 
 		if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6))
-			nl_route(0, c->ifi, AF_INET6, &c->gw6);
+			nl_route(0, c->ifi6, AF_INET6, &c->gw6);
 
-		nl_addr(0, c->ifi, AF_INET6,
+		nl_addr(0, c->ifi6, AF_INET6,
 			IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ? &c->addr6 : NULL,
 			&prefix_len, &c->addr6_ll);
 
@@ -883,12 +883,12 @@ static void conf_print(const struct ctx *c)
 	char buf4[INET_ADDRSTRLEN], ifn[IFNAMSIZ];
 	int i;
 
-	if (c->mode == MODE_PASTA) {
-		info("Outbound interface: %s, namespace interface: %s",
-		     if_indextoname(c->ifi, ifn), c->pasta_ifn);
-	} else {
-		info("Outbound interface: %s", if_indextoname(c->ifi, ifn));
-	}
+	if (c->ifi4)
+		info("Outbound interface (IPv4): %s", if_indextoname(c->ifi4, ifn));
+	if (c->ifi6)
+		info("Outbound interface (IPv6): %s", if_indextoname(c->ifi6, ifn));
+	if (c->mode == MODE_PASTA)
+		info("Namespace interface: %s", c->pasta_ifn);
 
 	if (c->v4) {
 		info("ARP:");
@@ -1395,12 +1395,12 @@ void conf(struct ctx *c, int argc, char **argv)
 			usage(argv[0]);
 			break;
 		case 'i':
-			if (c->ifi) {
+			if (c->ifi4 || c->ifi6) {
 				err("Redundant interface: %s", optarg);
 				usage(argv[0]);
 			}
 
-			if (!(c->ifi = if_nametoindex(optarg))) {
+			if (!(c->ifi4 = c->ifi6 = if_nametoindex(optarg))) {
 				err("Invalid interface name %s: %s", optarg,
 				    strerror(errno));
 				usage(argv[0]);
@@ -1559,8 +1559,12 @@ void conf(struct ctx *c, int argc, char **argv)
 
 	get_dns(c);
 
-	if (!*c->pasta_ifn)
-		if_indextoname(c->ifi, c->pasta_ifn);
+	if (!*c->pasta_ifn) {
+		if (c->ifi4)
+			if_indextoname(c->ifi4, c->pasta_ifn);
+		else
+			if_indextoname(c->ifi6, c->pasta_ifn);
+	}
 
 	c->tcp.ns_detect_ports   = c->udp.ns_detect_ports   = 0;
 	c->tcp.init_detect_ports = c->udp.init_detect_ports = 0;
diff --git a/passt.h b/passt.h
index e541341..23145c6 100644
--- a/passt.h
+++ b/passt.h
@@ -122,6 +122,7 @@ enum passt_modes {
  * @mac:		Host MAC address
  * @mac_guest:		MAC address of guest or namespace, seen or configured
  * @v4:			Enable IPv4 transport
+ * @ifi4:		Index of routable interface for IPv4
  * @addr4:		IPv4 address for external, routable interface
  * @addr4_seen:		Latest IPv4 address seen as source from tap
  * @mask4:		IPv4 netmask, network order
@@ -130,6 +131,7 @@ enum passt_modes {
  * @dns4_fwd:		Address forwarded (UDP) to first IPv4 DNS, network order
  * @dns_search:		DNS search list
  * @v6:			Enable IPv6 transport
+ * @ifi6:		Index of routable interface for IPv6
  * @addr6:		IPv6 address for external, routable interface
  * @addr6_ll:		Link-local IPv6 address on external, routable interface
  * @addr6_seen:		Latest IPv6 global/site address seen as source from tap
@@ -137,7 +139,6 @@ enum passt_modes {
  * @gw6:		Default IPv6 gateway
  * @dns6:		IPv6 DNS addresses, zero-terminated
  * @dns6_fwd:		Address forwarded (UDP) to first IPv6 DNS, network order
- * @ifi:		Index of routable interface
  * @pasta_ifn:		Name of namespace interface for pasta
  * @pasta_ifn:		Index of namespace interface for pasta
  * @pasta_conf_ns:	Configure namespace interface after creating it
@@ -193,6 +194,7 @@ struct ctx {
 	unsigned char mac_guest[ETH_ALEN];
 
 	int v4;
+	unsigned int ifi4;
 	uint32_t addr4;
 	uint32_t addr4_seen;
 	uint32_t mask4;
@@ -203,6 +205,7 @@ struct ctx {
 	struct fqdn dns_search[MAXDNSRCH];
 
 	int v6;
+	unsigned int ifi6;
 	struct in6_addr addr6;
 	struct in6_addr addr6_ll;
 	struct in6_addr addr6_seen;
@@ -211,7 +214,6 @@ struct ctx {
 	struct in6_addr dns6[MAXNS + 1];
 	struct in6_addr dns6_fwd;
 
-	unsigned int ifi;
 	char pasta_ifn[IF_NAMESIZE];
 	unsigned int pasta_ifi;
 	int pasta_conf_ns;
diff --git a/tcp.c b/tcp.c
index 5b84110..3b27f11 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2207,7 +2207,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, const void *addr,
 		struct sockaddr_in6 addr6_ll = {
 			.sin6_family = AF_INET6,
 			.sin6_addr = c->addr6_ll,
-			.sin6_scope_id = c->ifi,
+			.sin6_scope_id = c->ifi6,
 		};
 		if (bind(s, (struct sockaddr *)&addr6_ll, sizeof(addr6_ll))) {
 			close(s);
diff --git a/util.c b/util.c
index 2eea0ef..f4ec102 100644
--- a/util.c
+++ b/util.c
@@ -280,7 +280,7 @@ int sock_l4(const struct ctx *c, int af, uint8_t proto,
 
 			if (!memcmp(bind_addr, &c->addr6_ll,
 			    sizeof(c->addr6_ll)))
-				addr6.sin6_scope_id = c->ifi;
+				addr6.sin6_scope_id = c->ifi6;
 		} else {
 			addr6.sin6_addr = in6addr_any;
 		}
-- 
@@ -280,7 +280,7 @@ int sock_l4(const struct ctx *c, int af, uint8_t proto,
 
 			if (!memcmp(bind_addr, &c->addr6_ll,
 			    sizeof(c->addr6_ll)))
-				addr6.sin6_scope_id = c->ifi;
+				addr6.sin6_scope_id = c->ifi6;
 		} else {
 			addr6.sin6_addr = in6addr_any;
 		}
-- 
2.37.1


  reply	other threads:[~2022-07-22  5:31 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-22  5:31 [PATCH 0/7] Improved selection of external interface and IP configuration David Gibson
2022-07-22  5:31 ` David Gibson [this message]
2022-07-22  5:31 ` [PATCH 2/7] Separately locate external interfaces for IPv4 and IPv6 David Gibson
2022-08-01 10:23   ` Stefano Brivio
2022-07-22  5:31 ` [PATCH 3/7] Initialize host side MAC when in IPv6 only mode David Gibson
2022-07-22  5:31 ` [PATCH 4/7] Move passt mac_guest init to be more symmetric with pasta David Gibson
2022-07-22  5:31 ` [PATCH 5/7] Clarify semantics of c->v4 and c->v6 variables David Gibson
2022-08-01 10:24   ` Stefano Brivio
2022-07-22  5:31 ` [PATCH 6/7] Separate IPv4 and IPv6 configuration David Gibson
2022-08-01 10:24   ` Stefano Brivio
2022-07-22  5:31 ` [PATCH 7/7] Make substructures for IPv4 and IPv6 specific context information David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220722053118.1067459-2-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).