From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=none (p=none dis=none) header.from=gibson.dropbear.id.au Authentication-Results: passt.top; dkim=pass (2048-bit key; secure) header.d=gibson.dropbear.id.au header.i=@gibson.dropbear.id.au header.a=rsa-sha256 header.s=202512 header.b=p0pgOVQD; dkim-atps=neutral Received: from mail.ozlabs.org (gandalf.ozlabs.org [150.107.74.76]) by passt.top (Postfix) with ESMTPS id EA7725A0625 for ; Thu, 15 Jan 2026 09:50:57 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202512; t=1768467049; bh=yJ+Dyr8rAYZrlTe9x6XSy7tP/RkId4Ushm5CeHeScSY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=p0pgOVQDCxiN1N8TWVXXFT2GqKixFq1Ytq60oTQeQRKKMYBtoweXazUs4PpsMOCIY tFpVY2qhSr3w/7qy/dkjGBvQUUCQTyv6IKIZR2Qgg94veDNQ2hHjKxS51RoOztyEfm o7F+TB4gIUzWkOg5hFnLoTMHTpu45vNuAGwU/WneLp5NM2oScJ+KQB88N/HIJK9vQ0 fr0dRuv9c7C1r1Dg8+C/eQjAjuXzgqgveaTDUz4JXPgIB1Hc2DLSuTieA1g5o5GzhB ytbjw4ZljNw9KgLt2uaQ8xDmctB1t+ETj6Wk+jyOcan3Rcge+/HmxsdGc0LWld7vmU u6P51F4d5K6Pg== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4dsGsj3NMmz4wMH; Thu, 15 Jan 2026 19:50:49 +1100 (AEDT) From: David Gibson To: Stefano Brivio , passt-dev@passt.top Subject: [PATCH v4 05/14] fwd: Make space to store listening sockets in forward table Date: Thu, 15 Jan 2026 19:50:36 +1100 Message-ID: <20260115085045.3309818-6-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260115085045.3309818-1-david@gibson.dropbear.id.au> References: <20260115085045.3309818-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: HAKST5HQM36I6TNMWO3PBWG3TOCNSK33 X-Message-ID-Hash: HAKST5HQM36I6TNMWO3PBWG3TOCNSK33 X-MailFrom: dgibson@gandalf.ozlabs.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: David Gibson X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: 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 --- fwd.c | 10 +++++++++- fwd.h | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/fwd.c b/fwd.c index 588bf24a..4e82d2dd 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; @@ -377,8 +380,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