[PATCH v4 02/17] fwd_rule: Move ephemeral port probing to fwd_rule.c

David Gibson
2026-04-21T04:42:21Z

We want to move parsing of forward rule options to fwd_rule.c so it can
eventually be shared with a configuration client. As a preliminary step,
move the ephemeral port probing there, which that will need to use.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Laurent Vivier <lvivier@redhat.com>
---
fwd.c | 73 --------------------------------------------------
fwd.h | 6 -----
fwd_rule.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
fwd_rule.h | 6 +++++
4 files changed, 84 insertions(+), 79 deletions(-)

diff --git a/fwd.c b/fwd.c
index 979c1494..a6d75b74 100644
--- a/fwd.c
+++ b/fwd.c
@@ -34,12 +34,6 @@
#include "arp.h"
#include "ndp.h"

-/* Ephemeral port range: values from RFC 6335 */
-static in_port_t fwd_ephemeral_min = (1 << 15) + (1 << 14);
-static in_port_t fwd_ephemeral_max = NUM_PORTS - 1;
-
-#define PORT_RANGE_SYSCTL "/proc/sys/net/ipv4/ip_local_port_range"
-
#define NEIGH_TABLE_SLOTS 1024
#define NEIGH_TABLE_SIZE (NEIGH_TABLE_SLOTS / 2)
static_assert((NEIGH_TABLE_SLOTS & (NEIGH_TABLE_SLOTS - 1)) == 0,
@@ -249,73 +243,6 @@ void fwd_neigh_table_init(const struct ctx *c)
fwd_neigh_table_update(c, &mga, c->our_tap_mac, true);
}

-/** fwd_probe_ephemeral() - Determine what ports this host considers ephemeral
- *
- * Work out what ports the host thinks are emphemeral and record it for later
- * use by fwd_port_is_ephemeral(). If we're unable to probe, assume the range
- * recommended by RFC 6335.
- */
-void fwd_probe_ephemeral(void)
-{
- char *line, *tab, *end;
- struct lineread lr;
- long min, max;
- ssize_t len;
- int fd;
-
- fd = open(PORT_RANGE_SYSCTL, O_RDONLY | O_CLOEXEC);
- if (fd < 0) {
- warn_perror("Unable to open %s", PORT_RANGE_SYSCTL);
- return;
- }
-
- lineread_init(&lr, fd);
- len = lineread_get(&lr, &line);
- close(fd);
-
- if (len < 0)
- goto parse_err;
-
- tab = strchr(line, '\t');
- if (!tab)
- goto parse_err;
- *tab = '\0';
-
- errno = 0;
- min = strtol(line, &end, 10);
- if (*end || errno)
- goto parse_err;
-
- errno = 0;
- max = strtol(tab + 1, &end, 10);
- if (*end || errno)
- goto parse_err;
-
- if (min < 0 || min >= (long)NUM_PORTS ||
- max < 0 || max >= (long)NUM_PORTS)
- goto parse_err;
-
- fwd_ephemeral_min = min;
- fwd_ephemeral_max = max;
-
- return;
-
-parse_err:
- warn("Unable to parse %s", PORT_RANGE_SYSCTL);
-}
-
-/**
- * fwd_port_map_ephemeral() - Mark ephemeral ports in a bitmap
- * @map: Bitmap to update
- */
-void fwd_port_map_ephemeral(uint8_t *map)
-{
- unsigned port;
-
- for (port = fwd_ephemeral_min; port <= fwd_ephemeral_max; port++)
- bitmap_set(map, port);
-}
-
/* Forwarding table storage, generally accessed via pointers in struct ctx */
static struct fwd_table fwd_in;
static struct fwd_table fwd_out;
diff --git a/fwd.h b/fwd.h
index 3e365d35..e664d1d0 100644
--- a/fwd.h
+++ b/fwd.h
@@ -20,12 +20,6 @@

struct flowside;

-/* Number of ports for both TCP and UDP */
-#define NUM_PORTS (1U << 16)
-
-void fwd_probe_ephemeral(void);
-void fwd_port_map_ephemeral(uint8_t *map);
-
#define FWD_RULE_BITS 8
#define MAX_FWD_RULES MAX_FROM_BITS(FWD_RULE_BITS)
#define FWD_NO_HINT (-1)
diff --git a/fwd_rule.c b/fwd_rule.c
index 47d8df1c..9d489827 100644
--- a/fwd_rule.c
+++ b/fwd_rule.c
@@ -15,9 +15,87 @@
* Author: David Gibson <david@gibson.dropbear.id.au>
*/

+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
+#include <unistd.h>

#include "fwd_rule.h"
+#include "lineread.h"
+#include "log.h"
+
+/* Ephemeral port range: values from RFC 6335 */
+static in_port_t fwd_ephemeral_min = (1 << 15) + (1 << 14);
+static in_port_t fwd_ephemeral_max = NUM_PORTS - 1;
+
+#define PORT_RANGE_SYSCTL "/proc/sys/net/ipv4/ip_local_port_range"
+
+/** fwd_probe_ephemeral() - Determine what ports this host considers ephemeral
+ *
+ * Work out what ports the host thinks are emphemeral and record it for later
+ * use by fwd_port_is_ephemeral(). If we're unable to probe, assume the range
+ * recommended by RFC 6335.
+ */
+void fwd_probe_ephemeral(void)
+{
+ char *line, *tab, *end;
+ struct lineread lr;
+ long min, max;
+ ssize_t len;
+ int fd;
+
+ fd = open(PORT_RANGE_SYSCTL, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ warn_perror("Unable to open %s", PORT_RANGE_SYSCTL);
+ return;
+ }
+
+ lineread_init(&lr, fd);
+ len = lineread_get(&lr, &line);
+ close(fd);
+
+ if (len < 0)
+ goto parse_err;
+
+ tab = strchr(line, '\t');
+ if (!tab)
+ goto parse_err;
+ *tab = '\0';
+
+ errno = 0;
+ min = strtol(line, &end, 10);
+ if (*end || errno)
+ goto parse_err;
+
+ errno = 0;
+ max = strtol(tab + 1, &end, 10);
+ if (*end || errno)
+ goto parse_err;
+
+ if (min < 0 || min >= (long)NUM_PORTS ||
+ max < 0 || max >= (long)NUM_PORTS)
+ goto parse_err;
+
+ fwd_ephemeral_min = min;
+ fwd_ephemeral_max = max;
+
+ return;
+
+parse_err:
+ warn("Unable to parse %s", PORT_RANGE_SYSCTL);
+}
+
+/**
+ * fwd_port_map_ephemeral() - Mark ephemeral ports in a bitmap
+ * @map: Bitmap to update
+ */
+void fwd_port_map_ephemeral(uint8_t *map)
+{
+ unsigned port;
+
+ for (port = fwd_ephemeral_min; port <= fwd_ephemeral_max; port++)
+ bitmap_set(map, port);
+}

/**
* fwd_rule_addr() - Return match address for a rule
diff --git a/fwd_rule.h b/fwd_rule.h
index edba6782..5c7b67aa 100644
--- a/fwd_rule.h
+++ b/fwd_rule.h
@@ -17,6 +17,9 @@
#include "inany.h"
#include "bitmap.h"

+/* Number of ports for both TCP and UDP */
+#define NUM_PORTS (1U << 16)
+
/* Forwarding capability bits */
#define FWD_CAP_IPV4 BIT(0)
#define FWD_CAP_IPV6 BIT(1)
@@ -51,6 +54,9 @@ struct fwd_rule {
uint8_t flags;
};

+void fwd_probe_ephemeral(void);
+void fwd_port_map_ephemeral(uint8_t *map);
+
#define FWD_RULE_STRLEN \
(IPPROTO_STRLEN - 1 \
+ INANY_ADDRSTRLEN - 1 \
--
2.53.0