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
next prev parent 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).