From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: passt-dev@passt.top
Subject: Re: [PATCH 06/18] fwd: Better split forwarding rule specification from associated sockets
Date: Wed, 08 Apr 2026 01:14:46 +0200 (CEST) [thread overview]
Message-ID: <20260408011445.275ff479@elisabeth> (raw)
In-Reply-To: <20260407031630.2457081-7-david@gibson.dropbear.id.au>
On Tue, 7 Apr 2026 13:16:18 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:
> 6dad076df037 ("fwd: Split forwarding rule specification from its
> implementation state") created struct fwd_rule_state with a forwarding rule
> plus the table of sockets used for its implementation. It turns out this
> is quite awkward for sharing rule parsing code between passt and the
> upcoming configuration client.
Indeed, I hated it, in that short moment I had to fiddle with it. Thanks
for coming up with a cleaner solution.
>
> Instead keep the index of listening sockets in a parallel array in
> struct fwd_table.
>
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
> fwd.c | 73 ++++++++++++++++++++++++++++++-----------------------------
> fwd.h | 16 ++++---------
> 2 files changed, 41 insertions(+), 48 deletions(-)
>
> diff --git a/fwd.c b/fwd.c
> index e09b42fe..7e0edc38 100644
> --- a/fwd.c
> +++ b/fwd.c
> @@ -363,7 +363,7 @@ void fwd_rule_add(struct fwd_table *fwd, uint8_t proto, uint8_t flags,
> /* Flags which can be set from the caller */
> const uint8_t allowed_flags = FWD_WEAK | FWD_SCAN | FWD_DUAL_STACK_ANY;
> unsigned num = (unsigned)last - first + 1;
> - struct fwd_rule_state *new;
> + struct fwd_rule *new;
> unsigned i, port;
>
> assert(!(flags & ~allowed_flags));
> @@ -379,7 +379,7 @@ void fwd_rule_add(struct fwd_table *fwd, uint8_t proto, uint8_t flags,
> /* Check for any conflicting entries */
> for (i = 0; i < fwd->count; i++) {
> char newstr[INANY_ADDRSTRLEN], rulestr[INANY_ADDRSTRLEN];
> - const struct fwd_rule *rule = &fwd->rules[i].rule;
> + const struct fwd_rule *rule = &fwd->rules[i];
>
> if (proto != rule->proto)
> /* Non-conflicting protocols */
> @@ -399,38 +399,38 @@ void fwd_rule_add(struct fwd_table *fwd, uint8_t proto, uint8_t flags,
> rule->first, rule->last);
> }
>
> - new = &fwd->rules[fwd->count++];
> - new->rule.proto = proto;
> - new->rule.flags = flags;
> + new = &fwd->rules[fwd->count];
> + new->proto = proto;
> + new->flags = flags;
>
> if (addr) {
> - new->rule.addr = *addr;
> + new->addr = *addr;
> } else {
> - new->rule.addr = inany_any6;
> - new->rule.flags |= FWD_DUAL_STACK_ANY;
> + new->addr = inany_any6;
> + new->flags |= FWD_DUAL_STACK_ANY;
> }
>
> - memset(new->rule.ifname, 0, sizeof(new->rule.ifname));
> + memset(new->ifname, 0, sizeof(new->ifname));
> if (ifname) {
> int ret;
>
> - ret = snprintf(new->rule.ifname, sizeof(new->rule.ifname),
> + ret = snprintf(new->ifname, sizeof(new->ifname),
> "%s", ifname);
> - if (ret <= 0 || (size_t)ret >= sizeof(new->rule.ifname))
> + if (ret <= 0 || (size_t)ret >= sizeof(new->ifname))
> die("Invalid interface name: %s", ifname);
> }
>
> assert(first <= last);
> - new->rule.first = first;
> - new->rule.last = last;
> + new->first = first;
> + new->last = last;
> + new->to = to;
>
> - new->rule.to = to;
> + fwd->rulesocks[fwd->count] = &fwd->socks[fwd->sock_count];
> + for (port = new->first; port <= new->last; port++)
> + fwd->rulesocks[fwd->count][port - new->first] = -1;
>
> - new->socks = &fwd->socks[fwd->sock_count];
> + fwd->count++;
> fwd->sock_count += num;
> -
> - for (port = new->rule.first; port <= new->rule.last; port++)
> - new->socks[port - new->rule.first] = -1;
> }
>
> /**
> @@ -466,7 +466,7 @@ const struct fwd_rule *fwd_rule_search(const struct fwd_table *fwd,
>
> if (hint >= 0) {
> char ostr[INANY_ADDRSTRLEN], rstr[INANY_ADDRSTRLEN];
> - const struct fwd_rule *rule = &fwd->rules[hint].rule;
> + const struct fwd_rule *rule = &fwd->rules[hint];
>
> assert((unsigned)hint < fwd->count);
> if (fwd_rule_match(rule, ini, proto))
> @@ -480,8 +480,8 @@ const struct fwd_rule *fwd_rule_search(const struct fwd_table *fwd,
> }
>
> for (i = 0; i < fwd->count; i++) {
> - if (fwd_rule_match(&fwd->rules[i].rule, ini, proto))
> - return &fwd->rules[i].rule;
> + if (fwd_rule_match(&fwd->rules[i], ini, proto))
> + return &fwd->rules[i];
> }
>
> return NULL;
> @@ -496,7 +496,7 @@ void fwd_rules_print(const struct fwd_table *fwd)
> unsigned i;
>
> for (i = 0; i < fwd->count; i++) {
> - const struct fwd_rule *rule = &fwd->rules[i].rule;
> + const struct fwd_rule *rule = &fwd->rules[i];
> const char *percent = *rule->ifname ? "%" : "";
> const char *weak = "", *scan = "";
> char addr[INANY_ADDRSTRLEN];
> @@ -533,9 +533,9 @@ void fwd_rules_print(const struct fwd_table *fwd)
> static int fwd_sync_one(const struct ctx *c, uint8_t pif, unsigned idx,
> const uint8_t *tcp, const uint8_t *udp)
> {
> - const struct fwd_rule_state *rs = &c->fwd[pif]->rules[idx];
> - const struct fwd_rule *rule = &rs->rule;
> + const struct fwd_rule *rule = &c->fwd[pif]->rules[idx];
> const union inany_addr *addr = fwd_rule_addr(rule);
> + int *socks = c->fwd[pif]->rulesocks[idx];
> const char *ifname = rule->ifname;
> const uint8_t *map = NULL;
> bool bound_one = false;
> @@ -555,7 +555,7 @@ static int fwd_sync_one(const struct ctx *c, uint8_t pif, unsigned idx,
> }
>
> for (port = rule->first; port <= rule->last; port++) {
> - int fd = rs->socks[port - rule->first];
> + int fd = socks[port - rule->first];
>
> if (map && !bitmap_isset(map, port)) {
> /* We don't want to listen on this port */
> @@ -563,7 +563,7 @@ static int fwd_sync_one(const struct ctx *c, uint8_t pif, unsigned idx,
> /* We already are, so stop */
> epoll_del(c->epollfd, fd);
> close(fd);
> - rs->socks[port - rule->first] = -1;
> + socks[port - rule->first] = -1;
> }
> continue;
> }
> @@ -595,7 +595,7 @@ static int fwd_sync_one(const struct ctx *c, uint8_t pif, unsigned idx,
> continue;
> }
>
> - rs->socks[port - rule->first] = fd;
> + socks[port - rule->first] = fd;
> bound_one = true;
> }
>
> @@ -685,11 +685,12 @@ void fwd_listen_close(const struct fwd_table *fwd)
> unsigned i;
>
> for (i = 0; i < fwd->count; i++) {
> - const struct fwd_rule_state *rs = &fwd->rules[i];
> + const struct fwd_rule *rule = &fwd->rules[i];
> + int *socks = fwd->rulesocks[i];
> unsigned port;
>
> - for (port = rs->rule.first; port <= rs->rule.last; port++) {
> - int *fdp = &rs->socks[port - rs->rule.first];
> + for (port = rule->first; port <= rule->last; port++) {
> + int *fdp = &socks[port - rule->first];
> if (*fdp >= 0) {
> close(*fdp);
> *fdp = -1;
> @@ -769,8 +770,8 @@ static bool has_scan_rules(const struct fwd_table *fwd, uint8_t proto)
> unsigned i;
>
> for (i = 0; i < fwd->count; i++) {
> - if (fwd->rules[i].rule.proto == proto &&
> - fwd->rules[i].rule.flags & FWD_SCAN)
> + if (fwd->rules[i].proto == proto &&
> + fwd->rules[i].flags & FWD_SCAN)
> return true;
> }
> return false;
> @@ -838,14 +839,14 @@ static void current_listen_map(uint8_t *map, const struct fwd_table *fwd,
> memset(map, 0, PORT_BITMAP_SIZE);
>
> for (i = 0; i < fwd->count; i++) {
> - const struct fwd_rule_state *rs = &fwd->rules[i];
> + const struct fwd_rule *rule = &fwd->rules[i];
> unsigned port;
>
> - if (rs->rule.proto != proto)
> + if (rule->proto != proto)
> continue;
>
> - for (port = rs->rule.first; port <= rs->rule.last; port++) {
> - if (rs->socks[port - rs->rule.first] >= 0)
> + for (port = rule->first; port <= rule->last; port++) {
> + if (fwd->rulesocks[i][port - rule->first] >= 0)
> bitmap_set(map, port);
> }
> }
> diff --git a/fwd.h b/fwd.h
> index 33600cbf..83ee9b2e 100644
> --- a/fwd.h
> +++ b/fwd.h
> @@ -26,16 +26,6 @@ struct flowside;
> void fwd_probe_ephemeral(void);
> void fwd_port_map_ephemeral(uint8_t *map);
>
> -/**
> - * struct fwd_rule_state - Forwarding rule and associated state
> - * @rule: Rule specification
> - * @socks: Array of listening sockets for this entry
> - */
> -struct fwd_rule_state {
> - struct fwd_rule rule;
> - int *socks;
> -};
> -
> #define FWD_RULE_BITS 8
> #define MAX_FWD_RULES MAX_FROM_BITS(FWD_RULE_BITS)
> #define FWD_NO_HINT (-1)
> @@ -61,15 +51,17 @@ struct fwd_listen_ref {
> #define MAX_LISTEN_SOCKS (NUM_PORTS * 5)
>
> /**
> - * struct fwd_table - Table of forwarding rules (per initiating pif)
> + * struct fwd_table - Forwarding state (per initiating pif)
> * @count: Number of forwarding rules
> * @rules: Array of forwarding rules
> + * @rulesocks: Pointers to socket arrays per-rule
I don't see this as particularly descriptive (which sockets? What's
the array size?). I'm thinking of something like:
@socks_ref: Per-rule pointers to associated @socks, @sock_count of them
> * @sock_count: Number of entries used in @socks
> * @socks: Listening sockets for forwarding
> */
> struct fwd_table {
> unsigned count;
> - struct fwd_rule_state rules[MAX_FWD_RULES];
> + struct fwd_rule rules[MAX_FWD_RULES];
> + int *rulesocks[MAX_FWD_RULES];
> unsigned sock_count;
> int socks[MAX_LISTEN_SOCKS];
> };
--
Stefano
next prev parent reply other threads:[~2026-04-07 23:16 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 [this message]
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
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=20260408011445.275ff479@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).