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 v5 05/14] fwd: Make space to store listening sockets in forward table
Date: Fri, 16 Jan 2026 11:59:17 +1100	[thread overview]
Message-ID: <20260116005926.616085-6-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260116005926.616085-1-david@gibson.dropbear.id.au>

At present, we don't keep track of the fds for listening sockets (except
for "auto" ones).  Since the fd is stored in the epoll reference, we didn't
need an alternative source of it for the various handlers.

However, we're intending to allow dynamic changes to forwarding
configuration in future.  That means we need a way to enumerate sockets so
we can close them on removal of a forward.

Extend our forwarding table data structure to make space for all the
listening sockets.  To avoid allocation, this imposes another limit:
we could run out of space for socket fds before we run out of slots
for forwarding rules.

We don't actually do anything with the allocate spaced yet.  For
"auto" forwards it's redundant with existing arrays.  We'll fix both
of those in later patches.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 fwd.c | 10 +++++++++-
 fwd.h | 17 +++++++++++++++--
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/fwd.c b/fwd.c
index da4c3139..30b8a25b 100644
--- a/fwd.c
+++ b/fwd.c
@@ -346,6 +346,7 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags,
 {
 	/* Flags which can be set from the caller */
 	const uint8_t allowed_flags = FWD_WEAK | FWD_SCAN;
+	unsigned num = (unsigned)last - first + 1;
 	struct fwd_rule *new;
 	unsigned port;
 
@@ -353,6 +354,8 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags,
 
 	if (fwd->count >= ARRAY_SIZE(fwd->rules))
 		die("Too many port forwarding ranges");
+	if ((fwd->sock_count + num) > ARRAY_SIZE(fwd->socks))
+		die("Too many listening sockets");
 
 	new = &fwd->rules[fwd->count++];
 	new->flags = flags;
@@ -379,8 +382,13 @@ void fwd_rule_add(struct fwd_ports *fwd, uint8_t flags,
 
 	new->to = to;
 
+	new->socks = &fwd->socks[fwd->sock_count];
+	fwd->sock_count += num;
+
 	for (port = new->first; port <= new->last; port++) {
-		/* Fill in the legacy data structures to match the table */
+		new->socks[port - new->first] = -1;
+
+		/* Fill in the legacy forwarding data structures to match the table */
 		if (!(new->flags & FWD_SCAN))
 			bitmap_set(fwd->map, port);
 		fwd->delta[port] = new->to - new->first;
diff --git a/fwd.h b/fwd.h
index cc7e0aca..f971fff7 100644
--- a/fwd.h
+++ b/fwd.h
@@ -23,6 +23,7 @@ bool fwd_port_is_ephemeral(in_port_t port);
  * @first:	First port number to forward
  * @last:	Last port number to forward
  * @to:		Target port for @first, port n goes to @to + (n - @first)
+ * @socks:	Array of listening sockets for this entry
  * @flags:	Flag mask
  * 	FWD_DUAL_STACK_ANY - match any IPv4 or IPv6 address (@addr should be ::)
  *	FWD_WEAK - Don't give an error if binds fail for some forwards
@@ -36,6 +37,7 @@ struct fwd_rule {
 	in_port_t first;
 	in_port_t last;
 	in_port_t to;
+	int *socks;
 #define FWD_DUAL_STACK_ANY	BIT(0)
 #define FWD_WEAK		BIT(1)
 #define FWD_SCAN		BIT(2)
@@ -68,15 +70,24 @@ enum fwd_ports_mode {
 
 #define PORT_BITMAP_SIZE	DIV_ROUND_UP(NUM_PORTS, 8)
 
+/* Maximum number of listening sockets (per pif & protocol)
+ *
+ * Rationale: This lets us listen on every port for two addresses (which we need
+ * for -T auto without SO_BINDTODEVICE), plus a comfortable number of extras.
+ */
+#define MAX_LISTEN_SOCKS	(NUM_PORTS * 3)
+
 /**
  * fwd_ports() - Describes port forwarding for one protocol and direction
- * @mode:	Overall forwarding mode (all, none, auto, specific ports)
+ * @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
  * @rules:	Array of forwarding rules
  * @map:	Bitmap describing which ports are forwarded
- * @delta:	Offset between the original destination and mapped port number
+ * @delta:	Offset between the original mapped port number
+ * @sock_count:	Number of entries used in @socks
+ * @socks:	Listening sockets for forwarding
  */
 struct fwd_ports {
 	enum fwd_ports_mode mode;
@@ -86,6 +97,8 @@ struct fwd_ports {
 	struct fwd_rule rules[MAX_FWD_RULES];
 	uint8_t map[PORT_BITMAP_SIZE];
 	in_port_t delta[NUM_PORTS];
+	unsigned sock_count;
+	int socks[MAX_LISTEN_SOCKS];
 };
 
 #define FWD_PORT_SCAN_INTERVAL		1000	/* ms */
-- 
2.52.0


  parent reply	other threads:[~2026-01-16  0:59 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-16  0:59 [PATCH v5 00/14] Introduce forwarding table David Gibson
2026-01-16  0:59 ` [PATCH v5 01/14] inany: Extend inany_ntop() to treat NULL as a fully unspecified address David Gibson
2026-01-16  0:59 ` [PATCH v5 02/14] conf, fwd: Keep a table of our port forwarding configuration David Gibson
2026-01-16  0:59 ` [PATCH v5 03/14] conf: Accurately record ifname and address for outbound forwards David Gibson
2026-01-16  0:59 ` [PATCH v5 04/14] conf, fwd: Record "auto" port forwards in forwarding table David Gibson
2026-01-16  0:59 ` David Gibson [this message]
2026-01-16  0:59 ` [PATCH v5 06/14] ip: Add ipproto_name() function David Gibson
2026-01-16  0:59 ` [PATCH v5 07/14] fwd, tcp, udp: Set up listening sockets based on forward table David Gibson
2026-01-16  0:59 ` [PATCH v5 08/14] tcp, udp: Remove old auto-forwarding socket arrays David Gibson
2026-01-16  0:59 ` [PATCH v5 09/14] conf, fwd: Check forwarding table for conflicting rules David Gibson
2026-01-16  0:59 ` [PATCH v5 10/14] fwd: Generate auto-forward exclusions from socket fd tables David Gibson
2026-01-16  0:59 ` [PATCH v5 11/14] flow, fwd: Consult rules table when forwarding a new flow from socket David Gibson
2026-01-16  0:59 ` [PATCH v5 12/14] fwd: Remap ports based directly on forwarding rule David Gibson
2026-01-16  0:59 ` [PATCH v5 13/14] fwd, tcp, udp: Add forwarding rule to listening socket epoll references David Gibson
2026-01-16  0:59 ` [PATCH v5 14/14] flow, fwd: Optimise forwarding rule lookup using epoll ref when possible David Gibson
2026-01-18 13:49 ` [PATCH v5 00/14] Introduce forwarding table Stefano Brivio

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=20260116005926.616085-6-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).