public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: passt-dev@passt.top
Subject: Re: [PATCH 12/18] conf: Don't be strict about exclusivity of forwarding mode
Date: Wed, 08 Apr 2026 23:40:16 +0200 (CEST)	[thread overview]
Message-ID: <20260408234015.242166e9@elisabeth> (raw)
In-Reply-To: <20260407031630.2457081-13-david@gibson.dropbear.id.au>

On Tue,  7 Apr 2026 13:16:24 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:

> Currently as well as building the forwarding tables, conf() maintains a
> "forwarding mode" value for each protocol and direction.  This prevents,
> for example "-t all" and "-t 40000" being given on the same command line.
> 
> This restriction predates the forwarding table and is no longer really
> necessary.  Remove the restriction, instead doing our best to apply all the
> given options simultaneously.
> 
>  * Many combinations previously disallowed will still be disallowed because
>    of conflicts between the specific generated rules, e.g.
>         -t all -t 8888
>    (because -t all already listens on port 8888)
>  * Some new combinations are now allowed and will work, e.g.
>         -t all -t 40000
>    because 'all' excludes ephemeral ports (which includes 40000 on default
>    Linux configurations).

This is slightly confusing though:

$ ./pasta -t auto -t 31337
Forwarding configuration conflict: TCP [*]:31337  =>  31337  versus TCP [*]:1-32767  =>  1-32767  (best effort) (auto-scan)

but I don't see a practical way to "fix" it for the moment being, and
overall I'd say the new behaviour is better than the original one, so I
don't really care.

>  * We remove our mode variables, but keep boolean variables to track if
>    any forwarding config option has been given.  This is needed in order to
>    correctly default to -t auto -T auto -u auto -U auto for pasta.
>  * -[tTuU] none after any other rules is still considered an error.
>    However -t none *before* other rules is allowed.  This is potentially
>    confusing, but is awkward to avoid for the time being.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  conf.c | 97 ++++++++++++++++------------------------------------------
>  1 file changed, 27 insertions(+), 70 deletions(-)
> 
> diff --git a/conf.c b/conf.c
> index cd30f2f8..1e456361 100644
> --- a/conf.c
> +++ b/conf.c
> @@ -232,22 +232,6 @@ fail:
>  	    fwd_rule_fmt(&rule, rulestr, sizeof(rulestr)));
>  }
>  
> -/**
> - * 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_spec() - Parse port range(s) specifier
>   * @c:		Execution context
> @@ -350,13 +334,12 @@ bad:
>   * @optname:	Short option name, t, T, u, or U
>   * @optarg:	Option argument (port specification)
>   * @fwd:	Forwarding table to be updated
> - * @mode:	Overall port forwarding mode (updated)
>   */
>  static void conf_ports(const struct ctx *c, char optname, const char *optarg,
> -		       struct fwd_table *fwd, enum fwd_mode *mode)
> +		       struct fwd_table *fwd)
>  {
>  	union inany_addr addr_buf = inany_any6, *addr = &addr_buf;
> -	char buf[BUFSIZ], *spec, *ifname = NULL, *p;
> +	char buf[BUFSIZ], *spec, *ifname = NULL;
>  	uint8_t proto;
>  
>  	if (optname == 't' || optname == 'T')
> @@ -367,10 +350,14 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
>  		assert(0);
>  
>  	if (!strcmp(optarg, "none")) {
> -		if (*mode)
> -			goto mode_conflict;
> +		unsigned i;
>  
> -		*mode = FWD_MODE_NONE;
> +		for (i = 0; i < fwd->count; i++) {
> +			if (fwd->rules[i].proto == proto) {
> +				die("-%c none conflicts with previous options",
> +					optname);
> +			}
> +		}
>  		return;
>  	}
>  
> @@ -380,14 +367,9 @@ 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 (*mode)
> -			goto mode_conflict;
> -
>  		if (c->mode != MODE_PASTA)
>  			die("'auto' port forwarding is only allowed for pasta");
>  
> -		*mode = FWD_MODE_AUTO;
> -
>  		conf_ports_range_except(c, optname, optarg, fwd,
>  					proto, NULL, NULL,
>  					1, NUM_PORTS - 1, NULL, 1, FWD_SCAN);
> @@ -398,11 +380,6 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
>  	if (!strcmp(optarg, "all")) {
>  		uint8_t exclude[PORT_BITMAP_SIZE] = { 0 };
>  
> -		if (*mode)
> -			goto mode_conflict;
> -
> -		*mode = FWD_MODE_ALL;
> -
>  		/* Exclude ephemeral ports */
>  		fwd_port_map_ephemeral(exclude);
>  
> @@ -413,11 +390,6 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
>  		return;
>  	}
>  
> -	if (*mode > FWD_MODE_SPEC)
> -		die("Specific ports cannot be specified together with all/none/auto");
> -
> -	*mode = FWD_MODE_SPEC;
> -
>  	strncpy(buf, optarg, sizeof(buf) - 1);
>  
>  	if ((spec = strchr(buf, '/'))) {
> @@ -445,7 +417,7 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
>  		if (ifname == buf + 1) {	/* Interface without address */
>  			addr = NULL;
>  		} else {
> -			p = buf;
> +			char *p = buf;
>  
>  			/* Allow square brackets for IPv4 too for convenience */
>  			if (*p == '[' && p[strlen(p) - 1] == ']') {
> @@ -482,10 +454,6 @@ static void conf_ports(const struct ctx *c, char optname, const char *optarg,
>  		ifname = "lo";
>  
>  	conf_ports_spec(c, optname, optarg, fwd, proto, addr, ifname, spec);
> -	return;
> -
> -mode_conflict:
> -	die("Port forwarding mode '%s' conflicts with previous mode", optarg);
>  }
>  
>  /**
> @@ -1594,12 +1562,9 @@ void conf(struct ctx *c, int argc, char **argv)
>  	};
>  	const char *optstring = "+dqfel:hs:F:I:p:P:m:a:n:M:g:i:o:D:S:H:461t:u:T:U:";
>  	const char *logname = (c->mode == MODE_PASTA) ? "pasta" : "passt";
> +	bool opt_t = false, opt_T = false, opt_u = false, opt_U = false;
>  	char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 };
>  	bool copy_addrs_opt = false, copy_routes_opt = false;
> -	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;
>  	bool v4_only = false, v6_only = false;
>  	unsigned dns4_idx = 0, dns6_idx = 0;
>  	unsigned long max_mtu = IP_MAX_MTU;
> @@ -2204,17 +2169,17 @@ 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->fwd[PIF_HOST],
> -				   &tcp_in_mode);
> +			opt_t = true;
> +			conf_ports(c, name, optarg, c->fwd[PIF_HOST]);
>  		} else if (name == 'u') {
> -			conf_ports(c, name, optarg, c->fwd[PIF_HOST],
> -				   &udp_in_mode);
> +			opt_u = true;
> +			conf_ports(c, name, optarg, c->fwd[PIF_HOST]);
>  		} else if (name == 'T') {
> -			conf_ports(c, name, optarg, c->fwd[PIF_SPLICE],
> -				   &tcp_out_mode);
> +			opt_T = true;
> +			conf_ports(c, name, optarg, c->fwd[PIF_SPLICE]);
>  		} else if (name == 'U') {
> -			conf_ports(c, name, optarg, c->fwd[PIF_SPLICE],
> -				   &udp_out_mode);
> +			opt_U = true;
> +			conf_ports(c, name, optarg, c->fwd[PIF_SPLICE]);
>  		}
>  	} while (name != -1);
>  
> @@ -2265,22 +2230,14 @@ void conf(struct ctx *c, int argc, char **argv)
>  	}
>  
>  	if (c->mode == MODE_PASTA) {
> -		if (!tcp_in_mode) {
> -			conf_ports(c, 't', "auto",
> -				   c->fwd[PIF_HOST], &tcp_in_mode);
> -		}
> -		if (!tcp_out_mode) {
> -			conf_ports(c, 'T', "auto",
> -				   c->fwd[PIF_SPLICE], &tcp_out_mode);
> -		}
> -		if (!udp_in_mode) {
> -			conf_ports(c, 'u', "auto",
> -				   c->fwd[PIF_HOST], &udp_in_mode);
> -		}
> -		if (!udp_out_mode) {
> -			conf_ports(c, 'U', "auto",
> -				   c->fwd[PIF_SPLICE], &udp_out_mode);
> -		}
> +		if (!opt_t)
> +			conf_ports(c, 't', "auto", c->fwd[PIF_HOST]);
> +		if (!opt_T)
> +			conf_ports(c, 'T', "auto", c->fwd[PIF_SPLICE]);
> +		if (!opt_u)
> +			conf_ports(c, 'u', "auto", c->fwd[PIF_HOST]);
> +		if (!opt_U)
> +			conf_ports(c, 'U', "auto", c->fwd[PIF_SPLICE]);
>  	}
>  
>  	if (!c->quiet)

-- 
Stefano


  reply	other threads:[~2026-04-08 21:40 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-07  3:16 [PATCH 00/18] Rework forwarding option parsing David Gibson
2026-04-07  3:16 ` [PATCH 01/18] conf: Split parsing of port specifiers from the rest of -[tuTU] parsing David Gibson
2026-04-07  3:16 ` [PATCH 02/18] conf: Simplify handling of default forwarding mode David Gibson
2026-04-07 23:14   ` Stefano Brivio
2026-04-08  1:10     ` David Gibson
2026-04-07  3:16 ` [PATCH 03/18] conf: Move first pass handling of -[TU] next to handling of -[tu] David Gibson
2026-04-07  3:16 ` [PATCH 04/18] doc: Consolidate -[tu] option descriptions for passt and pasta David Gibson
2026-04-07 23:14   ` Stefano Brivio
2026-04-08  1:23     ` David Gibson
2026-04-07  3:16 ` [PATCH 05/18] conf: Permit -[tTuU] all in pasta mode David Gibson
2026-04-07  3:16 ` [PATCH 06/18] fwd: Better split forwarding rule specification from associated sockets David Gibson
2026-04-07 23:14   ` Stefano Brivio
2026-04-08  1:30     ` David Gibson
2026-04-08 21:39       ` Stefano Brivio
2026-04-09  0:47         ` David Gibson
2026-04-07  3:16 ` [PATCH 07/18] fwd_rule: Move forwarding rule formatting David Gibson
2026-04-07  3:16 ` [PATCH 08/18] conf: Pass protocol explicitly to conf_ports_range_except() David Gibson
2026-04-07  3:16 ` [PATCH 09/18] fwd: Split rule building from rule adding David Gibson
2026-04-07  3:16 ` [PATCH 10/18] fwd_rule: Move rule conflict checking from fwd_rule_add() to caller David Gibson
2026-04-07 23:14   ` Stefano Brivio
2026-04-08  1:37     ` David Gibson
2026-04-08  4:42       ` David Gibson
2026-04-07  3:16 ` [PATCH 11/18] fwd: Improve error handling in fwd_rule_add() David Gibson
2026-04-08 21:40   ` Stefano Brivio
2026-04-09  0:10     ` David Gibson
2026-04-07  3:16 ` [PATCH 12/18] conf: Don't be strict about exclusivity of forwarding mode David Gibson
2026-04-08 21:40   ` Stefano Brivio [this message]
2026-04-09  0:12     ` David Gibson
2026-04-07  3:16 ` [PATCH 13/18] conf: Rework stepping through chunks of port specifiers David Gibson
2026-04-08 21:40   ` Stefano Brivio
2026-04-09  0:13     ` David Gibson
2026-04-07  3:16 ` [PATCH 14/18] conf: Rework checking for garbage after a range David Gibson
2026-04-08 21:40   ` Stefano Brivio
2026-04-09  0:15     ` David Gibson
2026-04-07  3:16 ` [PATCH 15/18] conf: Move "all" handling to port specifier David Gibson
2026-04-08 21:40   ` Stefano Brivio
2026-04-07  3:16 ` [PATCH 16/18] conf: Allow user-specified auto-scanned port forwarding ranges David Gibson
2026-04-08 21:40   ` Stefano Brivio
2026-04-07  3:16 ` [PATCH 17/18] conf: Move SO_BINDTODEVICE workaround to conf_ports() David Gibson
2026-04-07  3:16 ` [PATCH 18/18] conf: Don't pass raw commandline argument to conf_ports_spec() 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=20260408234015.242166e9@elisabeth \
    --to=sbrivio@redhat.com \
    --cc=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).