From: David Gibson <david@gibson.dropbear.id.au>
To: Stefano Brivio <sbrivio@redhat.com>, passt-dev@passt.top
Cc: David Gibson <david@gibson.dropbear.id.au>
Subject: [PATCH v3 18/25] fwd: Split forwading rule specification from its implementation state
Date: Mon, 23 Mar 2026 18:37:25 +1100 [thread overview]
Message-ID: <20260323073732.3158468-19-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260323073732.3158468-1-david@gibson.dropbear.id.au>
Most of the fields in struct fwd_rule give the parameters of the forwarding
rule itself. The @socks field gives the list of listening sockets we use
to implement it. In order to share code with the configuraiton update tool
pesto, we want to split these. Move the rule specification itself into
fwd_rule.h, which can be shared with pesto.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
Makefile | 2 +-
fwd.c | 77 ++++++++++++++++++++++++++++--------------------------
fwd.h | 31 +++++-----------------
fwd_rule.h | 45 +++++++++++++++++++++++++++++++
util.h | 1 -
5 files changed, 92 insertions(+), 64 deletions(-)
create mode 100644 fwd_rule.h
diff --git a/Makefile b/Makefile
index 92809813..bc325482 100644
--- a/Makefile
+++ b/Makefile
@@ -49,7 +49,7 @@ SRCS = $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS)
MANPAGES = passt.1 pasta.1 pesto.1 qrap.1 passt-repair.1
-PESTO_HEADERS = common.h inany.h ip.h pesto.h serialise.h
+PESTO_HEADERS = common.h fwd_rule.h inany.h ip.h pesto.h serialise.h
PASST_HEADERS = arch.h arp.h checksum.h conf.h dhcp.h dhcpv6.h epoll_ctl.h \
flow.h fwd.h flow_table.h icmp.h icmp_flow.h iov.h isolation.h \
lineread.h log.h migrate.h ndp.h netlink.h packet.h passt.h pasta.h \
diff --git a/fwd.c b/fwd.c
index 05c8e378..a32d0a20 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 *new;
+ struct fwd_rule_state *new;
unsigned i, port;
assert(!(flags & ~allowed_flags));
@@ -379,57 +379,59 @@ 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];
- struct fwd_rule *rule = &fwd->rules[i];
+ struct fwd_rule_state *rule = &fwd->rules[i];
- if (proto != rule->proto)
+ if (proto != rule->rule.proto)
/* Non-conflicting protocols */
continue;
- if (!inany_matches(addr, fwd_rule_addr(rule)))
+ if (!inany_matches(addr, fwd_rule_addr(&rule->rule)))
/* Non-conflicting addresses */
continue;
- if (last < rule->first || rule->last < first)
+ if (last < rule->rule.first || rule->rule.last < first)
/* Port ranges don't overlap */
continue;
die("Forwarding configuration conflict: %s/%u-%u versus %s/%u-%u",
inany_ntop(addr, newstr, sizeof(newstr)), first, last,
- inany_ntop(fwd_rule_addr(rule), rulestr, sizeof(rulestr)),
- rule->first, rule->last);
+ inany_ntop(fwd_rule_addr(&rule->rule),
+ rulestr, sizeof(rulestr)),
+ rule->rule.first, rule->rule.last);
}
new = &fwd->rules[fwd->count++];
- new->proto = proto;
- new->flags = flags;
+ new->rule.proto = proto;
+ new->rule.flags = flags;
if (addr) {
- new->addr = *addr;
+ new->rule.addr = *addr;
} else {
- new->addr = inany_any6;
- new->flags |= FWD_DUAL_STACK_ANY;
+ new->rule.addr = inany_any6;
+ new->rule.flags |= FWD_DUAL_STACK_ANY;
}
- memset(new->ifname, 0, sizeof(new->ifname));
+ memset(new->rule.ifname, 0, sizeof(new->rule.ifname));
if (ifname) {
int ret;
- ret = snprintf(new->ifname, sizeof(new->ifname), "%s", ifname);
- if (ret <= 0 || (size_t)ret >= sizeof(new->ifname))
+ ret = snprintf(new->rule.ifname, sizeof(new->rule.ifname),
+ "%s", ifname);
+ if (ret <= 0 || (size_t)ret >= sizeof(new->rule.ifname))
die("Invalid interface name: %s", ifname);
}
assert(first <= last);
- new->first = first;
- new->last = last;
+ new->rule.first = first;
+ new->rule.last = last;
- new->to = to;
+ new->rule.to = to;
new->socks = &fwd->socks[fwd->sock_count];
fwd->sock_count += num;
- for (port = new->first; port <= new->last; port++)
- new->socks[port - new->first] = -1;
+ for (port = new->rule.first; port <= new->rule.last; port++)
+ new->socks[port - new->rule.first] = -1;
}
/**
@@ -465,7 +467,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];
+ const struct fwd_rule *rule = &fwd->rules[hint].rule;
assert((unsigned)hint < fwd->count);
if (fwd_rule_match(rule, ini, proto))
@@ -479,8 +481,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], ini, proto))
- return &fwd->rules[i];
+ if (fwd_rule_match(&fwd->rules[i].rule, ini, proto))
+ return &fwd->rules[i].rule;
}
return NULL;
@@ -495,7 +497,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];
+ const struct fwd_rule *rule = &fwd->rules[i].rule;
const char *percent = *rule->ifname ? "%" : "";
const char *weak = "", *scan = "";
char addr[INANY_ADDRSTRLEN];
@@ -532,7 +534,8 @@ 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 *rule = &c->fwd[pif]->rules[idx];
+ const struct fwd_rule_state *rs = &c->fwd[pif]->rules[idx];
+ const struct fwd_rule *rule = &rs->rule;
const union inany_addr *addr = fwd_rule_addr(rule);
const char *ifname = rule->ifname;
const uint8_t *map = NULL;
@@ -553,7 +556,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 = rule->socks[port - rule->first];
+ int fd = rs->socks[port - rule->first];
if (map && !bitmap_isset(map, port)) {
/* We don't want to listen on this port */
@@ -561,7 +564,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);
- rule->socks[port - rule->first] = -1;
+ rs->socks[port - rule->first] = -1;
}
continue;
}
@@ -593,7 +596,7 @@ static int fwd_sync_one(const struct ctx *c, uint8_t pif, unsigned idx,
continue;
}
- rule->socks[port - rule->first] = fd;
+ rs->socks[port - rule->first] = fd;
bound_one = true;
}
@@ -683,11 +686,11 @@ void fwd_listen_close(const struct fwd_table *fwd)
unsigned i;
for (i = 0; i < fwd->count; i++) {
- const struct fwd_rule *rule = &fwd->rules[i];
+ const struct fwd_rule_state *rs = &fwd->rules[i];
unsigned port;
- for (port = rule->first; port <= rule->last; port++) {
- int *fdp = &rule->socks[port - rule->first];
+ for (port = rs->rule.first; port <= rs->rule.last; port++) {
+ int *fdp = &rs->socks[port - rs->rule.first];
if (*fdp >= 0) {
close(*fdp);
*fdp = -1;
@@ -767,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].proto == proto &&
- fwd->rules[i].flags & FWD_SCAN)
+ if (fwd->rules[i].rule.proto == proto &&
+ fwd->rules[i].rule.flags & FWD_SCAN)
return true;
}
return false;
@@ -836,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 *rule = &fwd->rules[i];
+ const struct fwd_rule_state *rs = &fwd->rules[i];
unsigned port;
- if (rule->proto != proto)
+ if (rs->rule.proto != proto)
continue;
- for (port = rule->first; port <= rule->last; port++) {
- if (rule->socks[port - rule->first] >= 0)
+ for (port = rs->rule.first; port <= rs->rule.last; port++) {
+ if (rs->socks[port - rs->rule.first] >= 0)
bitmap_set(map, port);
}
}
diff --git a/fwd.h b/fwd.h
index f111e139..d37f2cdc 100644
--- a/fwd.h
+++ b/fwd.h
@@ -15,6 +15,7 @@
#include <netinet/in.h>
#include "inany.h"
+#include "fwd_rule.h"
struct flowside;
@@ -25,32 +26,12 @@ void fwd_probe_ephemeral(void);
void fwd_port_map_ephemeral(uint8_t *map);
/**
- * struct fwd_rule - Forwarding rule governing a range of ports
- * @addr: Address to forward from
- * @ifname: Interface to forward from
- * @first: First port number to forward
- * @last: Last port number to forward
- * @to: Target port for @first, port n goes to @to + (n - @first)
- * @proto: Protocol to forward
- * @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
- * FWD_SCAN - Only forward if the matching port in the target is listening
+ * struct fwd_rule_state - Forwarding rule and associated state
+ * @rule: Rule specification
* @socks: Array of listening sockets for this entry
- *
- * FIXME: @addr and @ifname currently ignored for outbound tables
*/
-struct fwd_rule {
- union inany_addr addr;
- char ifname[IFNAMSIZ];
- in_port_t first;
- in_port_t last;
- in_port_t to;
- uint8_t proto;
-#define FWD_DUAL_STACK_ANY BIT(0)
-#define FWD_WEAK BIT(1)
-#define FWD_SCAN BIT(2)
- uint8_t flags;
+struct fwd_rule_state {
+ struct fwd_rule rule;
int *socks;
};
@@ -87,7 +68,7 @@ struct fwd_listen_ref {
*/
struct fwd_table {
unsigned count;
- struct fwd_rule rules[MAX_FWD_RULES];
+ struct fwd_rule_state rules[MAX_FWD_RULES];
unsigned sock_count;
int socks[MAX_LISTEN_SOCKS];
};
diff --git a/fwd_rule.h b/fwd_rule.h
new file mode 100644
index 00000000..84ec5cbe
--- /dev/null
+++ b/fwd_rule.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright Red Hat
+ * Author: Stefano Brivio <sbrivio@redhat.com>
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ *
+ * Forwarding rule definitions shared between passt/pasta and pesto
+ */
+
+#ifndef FWD_RULE_H
+#define FWD_RULE_H
+
+#include <stdint.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "common.h"
+#include "inany.h"
+
+/**
+ * struct fwd_rule - Forwarding rule governing a range of ports
+ * @addr: Address to forward from
+ * @ifname: Interface to forward from
+ * @first: First port number to forward
+ * @last: Last port number to forward
+ * @to: Target port for @first, port n goes to @to + (n - @first)
+ * @proto: Protocol to forward
+ * @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
+ * FWD_SCAN - Only forward if the matching port in the target is listening
+ */
+struct fwd_rule {
+ union inany_addr addr;
+ char ifname[IFNAMSIZ];
+ in_port_t first;
+ in_port_t last;
+ in_port_t to;
+ uint8_t proto;
+#define FWD_DUAL_STACK_ANY BIT(0)
+#define FWD_WEAK BIT(1)
+#define FWD_SCAN BIT(2)
+ uint8_t flags;
+};
+
+#endif /* FWD_RULE_H */
diff --git a/util.h b/util.h
index 45792f46..8495ed9e 100644
--- a/util.h
+++ b/util.h
@@ -35,7 +35,6 @@
#define MAX_FROM_BITS(n) (((1U << (n)) - 1))
-#define BIT(n) (1UL << (n))
#define BITMAP_BIT(n) (BIT((n) % (sizeof(long) * 8)))
#define BITMAP_WORD(n) (n / (sizeof(long) * 8))
--
2.53.0
next prev parent reply other threads:[~2026-03-23 8:32 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 7:37 [PATCH v3 00/25] RFC: Read-only dynamic update implementation David Gibson
2026-03-23 7:37 ` [PATCH v3 01/25] conf: runas can be const David Gibson
2026-03-23 7:37 ` [PATCH v3 02/25] vhost_user: Fix assorted minor cppcheck warnings David Gibson
2026-03-23 7:37 ` [PATCH v3 03/25] serialise: Split functions user for serialisation from util.c David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-25 1:50 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 04/25] serialise: Add helpers for serialising unsigned integers David Gibson
2026-03-23 7:37 ` [PATCH v3 05/25] fwd: Move selecting correct scan bitmap into fwd_sync_one() David Gibson
2026-03-23 7:37 ` [PATCH v3 06/25] fwd: Look up rule index in fwd_sync_one() David Gibson
2026-03-23 7:37 ` [PATCH v3 07/25] fwd: Store forwarding tables indexed by (origin) pif David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-25 4:04 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 08/25] fwd: Allow FWD_DUAL_STACK_ANY flag to be passed directly to fwd_rule_add() David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-25 4:07 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 09/25] fwd, conf: Expose ephemeral ports as bitmap rather than function David Gibson
2026-03-23 7:37 ` [PATCH v3 10/25] conf: Don't bother complaining about overlapping excluded ranges David Gibson
2026-03-23 7:37 ` [PATCH v3 11/25] conf: Move check for mapping port 0 to caller David Gibson
2026-03-23 7:37 ` [PATCH v3 12/25] conf: Move check for disabled interfaces earlier David Gibson
2026-03-23 7:37 ` [PATCH v3 13/25] pesto: Introduce stub configuration interface and tool David Gibson
2026-03-25 0:54 ` Stefano Brivio
2026-03-23 7:37 ` [PATCH v3 14/25] pesto: Add command line option parsing and debug messages David Gibson
2026-03-25 0:55 ` Stefano Brivio
2026-03-25 4:27 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 15/25] pesto: Expose list of pifs to pesto David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 4:34 ` David Gibson
2026-03-25 8:18 ` Stefano Brivio
2026-03-25 8:31 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 16/25] ip: Prepare ip.[ch] for sharing with pesto tool David Gibson
2026-03-23 7:37 ` [PATCH v3 17/25] inany: Prepare inany.[ch] " David Gibson
2026-03-23 7:37 ` David Gibson [this message]
2026-03-23 7:37 ` [PATCH v3 19/25] ip: Define a bound for the string returned by ipproto_name() David Gibson
2026-03-23 7:37 ` [PATCH v3 20/25] fwd_rule: Move forwarding rule text formatting to common code David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 4:42 ` David Gibson
2026-03-25 8:18 ` Stefano Brivio
2026-03-25 23:54 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 21/25] pesto: Read current ruleset from passt/pasta and display it David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 4:43 ` David Gibson
2026-03-23 7:37 ` [PATCH v3 22/25] conf: Move port parsing functions to own file, ports.c David Gibson
2026-03-23 7:37 ` [PATCH v3 23/25] conf, fwd, ports, util: Move things around for pesto David Gibson
2026-03-23 7:37 ` [PATCH v3 24/25] pesto, conf: Parse, send and receive new rules David Gibson
2026-03-23 7:37 ` [PATCH v3 25/25] conf, fwd: Allow switching to new rules received from pesto David Gibson
2026-03-23 8:38 ` [PATCH v3 00/25] RFC: Read-only dynamic update implementation David Gibson
2026-03-25 0:56 ` Stefano Brivio
2026-03-25 1:00 ` Stefano Brivio
2026-03-25 4:44 ` 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=20260323073732.3158468-19-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).