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, Stefano Brivio <sbrivio@redhat.com>
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v2 1/9] conf, fwd: Make overall forwarding mode local to conf path
Date: Wed, 11 Mar 2026 23:03:06 +1100	[thread overview]
Message-ID: <20260311120314.933546-2-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260311120314.933546-1-david@gibson.dropbear.id.au>

The 'mode' field of struct fwd_ports records the overall forwarding mode.
Now that runtime forwarding decisions are made based on the forwarding
table, this is almost unused outside conf().

The only exception is the auto-port scanning code, which uses it to
determine if a port scan is necessary.  We can instead derive that from the
forwarding table itself by checking if there are any entries with the
FWD_SCAN flag.

Once that's done, make the mode purely local to conf().  While we're there
rename the constants to FWD_MODE_* to avoid confusion with the forwarding
rule flag bits, which are also prefixed with FWD_.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 conf.c | 87 +++++++++++++++++++++++++++++++++++++---------------------
 fwd.c  | 27 ++++++++++++++----
 fwd.h  | 10 -------
 3 files changed, 77 insertions(+), 47 deletions(-)

diff --git a/conf.c b/conf.c
index 11d84536..a1a67f94 100644
--- a/conf.c
+++ b/conf.c
@@ -199,15 +199,32 @@ static void conf_ports_range_except(const struct ctx *c, char optname,
 	}
 }
 
+/**
+ * enum fwd_mode - Overall forwarding mode for a direction and protocol
+ * @FWD_MODE_UNSET	Initial value, not parsed/configured yet
+ * @FWD_MODE_SPEC	Forward specified ports
+ * @FWD_MODE_NONE	No forwarded ports
+ * @FWD_MODE_AUTO	Automatic detection and forwarding based on bound ports
+ * @FWD_MODE_ALL	Bind all free ports
+ */
+enum fwd_mode {
+	FWD_MODE_UNSET = 0,
+	FWD_MODE_SPEC,
+	FWD_MODE_NONE,
+	FWD_MODE_AUTO,
+	FWD_MODE_ALL,
+};
+
 /**
  * conf_ports() - Parse port configuration options, initialise UDP/TCP sockets
  * @c:		Execution context
  * @optname:	Short option name, t, T, u, or U
  * @optarg:	Option argument (port specification)
  * @fwd:	Pointer to @fwd_ports to be updated
+ * @mode:	Overall port forwarding mode (updated)
  */
 static void conf_ports(const struct ctx *c, char optname, const char *optarg,
-		       struct fwd_ports *fwd)
+		       struct fwd_ports *fwd, enum fwd_mode *mode)
 {
 	union inany_addr addr_buf = inany_any6, *addr = &addr_buf;
 	char buf[BUFSIZ], *spec, *ifname = NULL, *p;
@@ -216,10 +233,10 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 	unsigned i;
 
 	if (!strcmp(optarg, "none")) {
-		if (fwd->mode)
+		if (*mode)
 			goto mode_conflict;
 
-		fwd->mode = FWD_NONE;
+		*mode = FWD_MODE_NONE;
 		return;
 	}
 
@@ -229,7 +246,7 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 		die("UDP port forwarding requested but UDP is disabled");
 
 	if (!strcmp(optarg, "auto")) {
-		if (fwd->mode)
+		if (*mode)
 			goto mode_conflict;
 
 		if (c->mode != MODE_PASTA)
@@ -241,18 +258,18 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 			warn(
 "Forwarding from addresses other than 127.0.0.1 will not work");
 		}
-		fwd->mode = FWD_AUTO;
+		*mode = FWD_MODE_AUTO;
 		return;
 	}
 
 	if (!strcmp(optarg, "all")) {
-		if (fwd->mode)
+		if (*mode)
 			goto mode_conflict;
 
 		if (c->mode == MODE_PASTA)
 			die("'all' port forwarding is only allowed for passt");
 
-		fwd->mode = FWD_ALL;
+		*mode = FWD_MODE_ALL;
 
 		/* Exclude ephemeral ports */
 		for (i = 0; i < NUM_PORTS; i++)
@@ -266,10 +283,10 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
 		return;
 	}
 
-	if (fwd->mode > FWD_SPEC)
+	if (*mode > FWD_MODE_SPEC)
 		die("Specific ports cannot be specified together with all/none/auto");
 
-	fwd->mode = FWD_SPEC;
+	*mode = FWD_MODE_SPEC;
 
 	strncpy(buf, optarg, sizeof(buf) - 1);
 
@@ -1525,7 +1542,11 @@ void conf(struct ctx *c, int argc, char **argv)
 	const char *logname = (c->mode == MODE_PASTA) ? "pasta" : "passt";
 	char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 };
 	bool copy_addrs_opt = false, copy_routes_opt = false;
-	enum fwd_ports_mode fwd_default = FWD_NONE;
+	enum fwd_mode tcp_out_mode = FWD_MODE_UNSET;
+	enum fwd_mode udp_out_mode = FWD_MODE_UNSET;
+	enum fwd_mode tcp_in_mode = FWD_MODE_UNSET;
+	enum fwd_mode udp_in_mode = FWD_MODE_UNSET;
+	enum fwd_mode fwd_default = FWD_MODE_NONE;
 	bool v4_only = false, v6_only = false;
 	unsigned dns4_idx = 0, dns6_idx = 0;
 	unsigned long max_mtu = IP_MAX_MTU;
@@ -1540,17 +1561,16 @@ void conf(struct ctx *c, int argc, char **argv)
 	int name, ret;
 	uid_t uid;
 	gid_t gid;
+	
 
 	if (c->mode == MODE_PASTA) {
 		c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
-		fwd_default = FWD_AUTO;
+		fwd_default = FWD_MODE_AUTO;
 	}
 
 	if (tap_l2_max_len(c) - ETH_HLEN < max_mtu)
 		max_mtu = tap_l2_max_len(c) - ETH_HLEN;
 	c->mtu = ROUND_DOWN(max_mtu, sizeof(uint32_t));
-	c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = FWD_UNSET;
-	c->udp.fwd_in.mode = c->udp.fwd_out.mode = FWD_UNSET;
 	memcpy(c->our_tap_mac, MAC_OUR_LAA, ETH_ALEN);
 
 	optind = 0;
@@ -2100,9 +2120,11 @@ void conf(struct ctx *c, int argc, char **argv)
 		name = getopt_long(argc, argv, optstring, options, NULL);
 
 		if (name == 't') {
-			conf_ports(c, name, optarg, &c->tcp.fwd_in);
+			conf_ports(c, name, optarg,
+				   &c->tcp.fwd_in, &tcp_in_mode);
 		} else if (name == 'u') {
-			conf_ports(c, name, optarg, &c->udp.fwd_in);
+			conf_ports(c, name, optarg,
+				   &c->udp.fwd_in, &udp_in_mode);
 		} else if (name == 'D') {
 			struct in6_addr dns6_tmp;
 			struct in_addr dns4_tmp;
@@ -2172,10 +2194,13 @@ void conf(struct ctx *c, int argc, char **argv)
 	do {
 		name = getopt_long(argc, argv, optstring, options, NULL);
 
-		if (name == 'T')
-			conf_ports(c, name, optarg, &c->tcp.fwd_out);
-		else if (name == 'U')
-			conf_ports(c, name, optarg, &c->udp.fwd_out);
+		if (name == 'T') {
+			conf_ports(c, name, optarg,
+				   &c->tcp.fwd_out, &tcp_out_mode);
+		} else if (name == 'U') {
+			conf_ports(c, name, optarg,
+				   &c->udp.fwd_out, &udp_out_mode);
+		}
 	} while (name != -1);
 
 	if (!c->ifi4)
@@ -2197,31 +2222,31 @@ void conf(struct ctx *c, int argc, char **argv)
 			if_indextoname(c->ifi6, c->pasta_ifn);
 	}
 
-	if (!c->tcp.fwd_in.mode)
-		c->tcp.fwd_in.mode = fwd_default;
-	if (!c->tcp.fwd_out.mode)
-		c->tcp.fwd_out.mode = fwd_default;
-	if (!c->udp.fwd_in.mode)
-		c->udp.fwd_in.mode = fwd_default;
-	if (!c->udp.fwd_out.mode)
-		c->udp.fwd_out.mode = fwd_default;
+	if (!tcp_in_mode)
+		tcp_in_mode = fwd_default;
+	if (!tcp_out_mode)
+		tcp_out_mode = fwd_default;
+	if (!udp_in_mode)
+		udp_in_mode = fwd_default;
+	if (!udp_out_mode)
+		udp_out_mode = fwd_default;
 
-	if (c->tcp.fwd_in.mode == FWD_AUTO) {
+	if (tcp_in_mode == FWD_MODE_AUTO) {
 		conf_ports_range_except(c, 't', "auto", &c->tcp.fwd_in,
 					NULL, NULL, 1, NUM_PORTS - 1,
 					NULL, 1, FWD_SCAN);
 	}
-	if (c->tcp.fwd_out.mode == FWD_AUTO) {
+	if (tcp_out_mode == FWD_MODE_AUTO) {
 		conf_ports_range_except(c, 'T', "auto", &c->tcp.fwd_out,
 					NULL, "lo", 1, NUM_PORTS - 1,
 					NULL, 1, FWD_SCAN);
 	}
-	if (c->udp.fwd_in.mode == FWD_AUTO) {
+	if (udp_in_mode == FWD_MODE_AUTO) {
 		conf_ports_range_except(c, 'u', "auto", &c->udp.fwd_in,
 					NULL, NULL, 1, NUM_PORTS - 1,
 					NULL, 1, FWD_SCAN);
 	}
-	if (c->udp.fwd_out.mode == FWD_AUTO) {
+	if (udp_out_mode == FWD_MODE_AUTO) {
 		conf_ports_range_except(c, 'U', "auto", &c->udp.fwd_out,
 					NULL, "lo", 1, NUM_PORTS - 1,
 					NULL, 1, FWD_SCAN);
diff --git a/fwd.c b/fwd.c
index 4052b797..c5090fb1 100644
--- a/fwd.c
+++ b/fwd.c
@@ -717,6 +717,21 @@ static void procfs_scan_listen(int fd, unsigned int lstate, uint8_t *map)
 	}
 }
 
+/**
+ * has_scan_rules() - Does the given table have any FWD_SCAN rules?
+ * @fwd:	Forwarding table
+ */
+static bool has_scan_rules(const struct fwd_ports *fwd)
+{
+	unsigned i;
+
+	for (i = 0; i < fwd->count; i++) {
+		if (fwd->rules[i].flags & FWD_SCAN)
+			return true;
+	}
+	return false;
+}
+
 /**
  * fwd_scan_ports_tcp() - Scan /proc to update TCP forwarding map
  * @fwd:	Forwarding information to update
@@ -724,7 +739,7 @@ static void procfs_scan_listen(int fd, unsigned int lstate, uint8_t *map)
  */
 static void fwd_scan_ports_tcp(struct fwd_ports *fwd, const uint8_t *exclude)
 {
-	if (fwd->mode != FWD_AUTO)
+	if (!has_scan_rules(fwd))
 		return;
 
 	memset(fwd->map, 0, PORT_BITMAP_SIZE);
@@ -743,7 +758,7 @@ static void fwd_scan_ports_udp(struct fwd_ports *fwd,
 			       const struct fwd_ports *tcp_fwd,
 			       const uint8_t *exclude)
 {
-	if (fwd->mode != FWD_AUTO)
+	if (!has_scan_rules(fwd))
 		return;
 
 	memset(fwd->map, 0, PORT_BITMAP_SIZE);
@@ -816,19 +831,19 @@ void fwd_scan_ports_init(struct ctx *c)
 	c->udp.fwd_in.scan4 = c->udp.fwd_in.scan6 = -1;
 	c->udp.fwd_out.scan4 = c->udp.fwd_out.scan6 = -1;
 
-	if (c->tcp.fwd_in.mode == FWD_AUTO) {
+	if (has_scan_rules(&c->tcp.fwd_in)) {
 		c->tcp.fwd_in.scan4 = open_in_ns(c, "/proc/net/tcp", flags);
 		c->tcp.fwd_in.scan6 = open_in_ns(c, "/proc/net/tcp6", flags);
 	}
-	if (c->udp.fwd_in.mode == FWD_AUTO) {
+	if (has_scan_rules(&c->udp.fwd_in)) {
 		c->udp.fwd_in.scan4 = open_in_ns(c, "/proc/net/udp", flags);
 		c->udp.fwd_in.scan6 = open_in_ns(c, "/proc/net/udp6", flags);
 	}
-	if (c->tcp.fwd_out.mode == FWD_AUTO) {
+	if (has_scan_rules(&c->tcp.fwd_out)) {
 		c->tcp.fwd_out.scan4 = open("/proc/net/tcp", flags);
 		c->tcp.fwd_out.scan6 = open("/proc/net/tcp6", flags);
 	}
-	if (c->udp.fwd_out.mode == FWD_AUTO) {
+	if (has_scan_rules(&c->udp.fwd_out)) {
 		c->udp.fwd_out.scan4 = open("/proc/net/udp", flags);
 		c->udp.fwd_out.scan6 = open("/proc/net/udp6", flags);
 	}
diff --git a/fwd.h b/fwd.h
index 7f52f76e..6d657ddc 100644
--- a/fwd.h
+++ b/fwd.h
@@ -68,14 +68,6 @@ struct fwd_listen_ref {
 	unsigned	rule :FWD_RULE_BITS;
 };
 
-enum fwd_ports_mode {
-	FWD_UNSET = 0,
-	FWD_SPEC = 1,
-	FWD_NONE,
-	FWD_AUTO,
-	FWD_ALL,
-};
-
 #define PORT_BITMAP_SIZE	DIV_ROUND_UP(NUM_PORTS, 8)
 
 /* Maximum number of listening sockets (per pif & protocol)
@@ -87,7 +79,6 @@ enum fwd_ports_mode {
 
 /**
  * fwd_ports() - Describes port forwarding for one protocol and direction
- * @mode:	Overall mode (all, none, auto, specific ports)
  * @scan4:	/proc/net fd to scan for IPv4 ports when in AUTO mode
  * @scan6:	/proc/net fd to scan for IPv6 ports when in AUTO mode
  * @count:	Number of forwarding rules
@@ -97,7 +88,6 @@ enum fwd_ports_mode {
  * @socks:	Listening sockets for forwarding
  */
 struct fwd_ports {
-	enum fwd_ports_mode mode;
 	int scan4;
 	int scan6;
 	unsigned count;
-- 
2.53.0


  reply	other threads:[~2026-03-11 12:03 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-11 12:03 [PATCH v2 0/9] Unify TCP and UDP forwarding tables David Gibson
2026-03-11 12:03 ` David Gibson [this message]
2026-03-11 12:03 ` [PATCH v2 2/9] tcp: Remove stale description of port_to_tap field David Gibson
2026-03-11 12:03 ` [PATCH v2 3/9] fwd: Don't initialise unused port bitmaps David Gibson
2026-03-11 12:03 ` [PATCH v2 4/9] Fix misnamed field in struct ctx comments David Gibson
2026-03-11 12:03 ` [PATCH v2 5/9] fwd: Split forwarding table from port scanning state David Gibson
2026-03-11 12:03 ` [PATCH v2 6/9] fwd: Unify TCP and UDP forwarding tables David Gibson
2026-03-11 12:03 ` [PATCH v2 7/9] fwd: Always open /proc/net{tcp,tcp6,udp,udp6} in pasta mode David Gibson
2026-03-11 12:03 ` [PATCH v2 8/9] conf: Don't defer handling of --dns option David Gibson
2026-03-11 12:03 ` [PATCH v2 9/9] conf: Parse all forwarding options at the same time David Gibson
2026-03-11 21:12 ` [PATCH v2 0/9] Unify TCP and UDP forwarding tables Stefano Brivio
2026-03-11 23:33   ` 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=20260311120314.933546-2-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    --cc=sbrivio@redhat.com \
    /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).