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 v4 11/17] pesto: Expose list of pifs to pesto and optionally display
Date: Tue, 21 Apr 2026 14:42:11 +1000	[thread overview]
Message-ID: <20260421044217.2500314-12-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <20260421044217.2500314-1-david@gibson.dropbear.id.au>

Extend the dynamic update protocol to expose the pif indices and names
from a running passt/pasta to the pesto tool.  pesto records that data
and, if requested with a new --show flag, prints it out.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 Makefile    |   1 +
 common.h    |   2 +
 conf.c      |  41 ++++++++++++++++
 pesto.c     | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 pesto.h     |  19 +++++++-
 pif.h       |   4 +-
 serialise.c |   4 ++
 serialise.h |   1 +
 util.h      |   2 -
 9 files changed, 200 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 1718ddbf..6da76b44 100644
--- a/Makefile
+++ b/Makefile
@@ -223,6 +223,7 @@ cppcheck: passt.cppcheck passt-repair.cppcheck pesto.cppcheck qrap.cppcheck
 	$(CPPCHECK) $(CPPCHECK_FLAGS) $(BASE_CPPFLAGS) $^
 
 passt.cppcheck: BASE_CPPFLAGS += -UPESTO
+passt.cppcheck: CPPCHECK_FLAGS += --suppress=unusedFunction:serialise.c
 passt.cppcheck: $(PASST_SRCS) $(PASST_HEADERS) seccomp.h
 
 passt-repair.cppcheck: $(PASST_REPAIR_SRCS) $(PASST_REPAIR_HEADERS) seccomp_repair.h
diff --git a/common.h b/common.h
index 2f2e6f1e..45f66ea6 100644
--- a/common.h
+++ b/common.h
@@ -53,4 +53,6 @@ static inline const char *strerror_(int errnum)
 
 #define strerror(x) @ "Don't call strerror() directly, use strerror_() instead"
 
+#define ARRAY_SIZE(a)		((int)(sizeof(a) / sizeof((a)[0])))
+
 #endif /* _COMMON_H */
diff --git a/conf.c b/conf.c
index 75d816ac..2ea97839 100644
--- a/conf.c
+++ b/conf.c
@@ -1923,6 +1923,43 @@ void conf(struct ctx *c, int argc, char **argv)
 		conf_print(c);
 }
 
+/**
+ * conf_send_rules() - Send current forwarding rules to config client (pesto)
+ * @c:		Execution context
+ * @fd:		Socket to the client
+ *
+ * Return: 0 on success, -1 on failure
+ *
+ * FIXME: So far only sends pif ids and names
+ */
+static int conf_send_rules(const struct ctx *c, int fd)
+{
+	unsigned pif;
+
+	for (pif = 0; pif < PIF_NUM_TYPES; pif++) {
+		struct pesto_pif_info info;
+		int rc;
+
+		if (!c->fwd[pif])
+			continue;
+
+		assert(pif != PIF_NONE);
+
+		rc = snprintf(info.name, sizeof(info.name), "%s", pif_name(pif));
+		assert(rc >= 0 && (size_t)rc < sizeof(info.name));
+
+		if (write_u8(fd, pif) < 0)
+			return -1;
+		if (write_all_buf(fd, &info, sizeof(info)) < 0)
+			return -1;
+	}
+
+	if (write_u8(fd, PIF_NONE) < 0)
+		return -1;
+
+	return 0;
+}
+
 /**
  * conf_close() - Close configuration / control socket and clean up
  * @c:		Execution context
@@ -1945,6 +1982,7 @@ void conf_listen_handler(struct ctx *c, uint32_t events)
 	struct pesto_hello hello = {
 		.magic = PESTO_SERVER_MAGIC,
 		.version = htonl(PESTO_PROTOCOL_VERSION),
+		.pif_name_size = htonl(PIF_NAME_SIZE),
 	};
 	union epoll_ref ref = { .type = EPOLL_TYPE_CONF };
 	struct ucred uc = { 0 };
@@ -1990,6 +2028,9 @@ void conf_listen_handler(struct ctx *c, uint32_t events)
 "Warning: Using experimental unsupported configuration protocol");
 	}
 
+	if (conf_send_rules(c, fd) < 0)
+		goto fail;
+
 	return;
 
 fail:
diff --git a/pesto.c b/pesto.c
index 5e191283..3e34bbac 100644
--- a/pesto.c
+++ b/pesto.c
@@ -60,6 +60,125 @@ static void usage(const char *name, FILE *f, int status)
 	exit(status);
 }
 
+/* Maximum number of pifs with rule tables */
+#define MAX_PIFS	3
+
+struct pif_configuration {
+	uint8_t pif;
+	char name[PIF_NAME_SIZE];
+};
+
+struct configuration {
+	uint32_t npifs;
+	struct pif_configuration pif[MAX_PIFS];
+};
+
+/**
+ * pif_conf_by_num() - Find a pif's configuration by pif id
+ * @conf:	Configuration description
+ * @pif:	pif id
+ *
+ * Return: pointer to the pif_configuration for @pif, or NULL if not found
+ */
+static struct pif_configuration *pif_conf_by_num(struct configuration *conf,
+						 uint8_t pif)
+{
+	unsigned i;
+
+	for (i = 0; i < conf->npifs; i++) {
+		if (conf->pif[i].pif == pif)
+			return &conf->pif[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * pif_conf_by_name() - Find a pif's configuration by name
+ * @conf:	Configuration description
+ * @name:	Interface name
+ *
+ * Return: pif_configuration for pif named @name, or NULL if not found
+ */
+static struct pif_configuration *pif_conf_by_name(struct configuration *conf,
+						  const char *name)
+{
+	unsigned i;
+
+	for (i = 0; i < conf->npifs; i++) {
+		if (strcmp(conf->pif[i].name, name) == 0)
+			return &conf->pif[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * pesto_read_rules() - Read rulestate from passt/pasta
+ * @fd:		Control socket
+ * @conf:	Configuration description to update
+ */
+static bool read_pif_conf(int fd, struct configuration *conf)
+{
+	struct pif_configuration *pc;
+	struct pesto_pif_info info;
+	uint8_t pif;
+
+	if (read_u8(fd, &pif) < 0)
+		die("Error reading from control socket");
+
+	if (pif == PIF_NONE)
+		return false;
+
+	debug("Receiving config for PIF %"PRIu8, pif);
+
+	if (conf->npifs >= ARRAY_SIZE(conf->pif)) {
+		die("passt has more pifs than pesto can manage (max %d)",
+		    ARRAY_SIZE(conf->pif));
+	}
+
+	pc = &conf->pif[conf->npifs];
+	pc->pif = pif;
+
+	if (read_all_buf(fd, &info, sizeof(info)) < 0)
+		die("Error reading from control socket");
+
+	if (info.name[sizeof(info.name)-1])
+		die("Interface name was not NULL terminated");
+
+	static_assert(sizeof(info.name) == sizeof(pc->name),
+		      "Mismatching pif name lengths");
+	memcpy(pc->name, info.name, sizeof(pc->name));
+
+	debug("PIF %"PRIu8": %s", pc->pif, pc->name);
+
+	/* O(n^2), but n is bounded by MAX_PIFS */
+	if (pif_conf_by_num(conf, pc->pif))
+		die("Received duplicate interface identifier");
+
+	/* O(n^2), but n is bounded by MAX_PIFS */
+	if (pif_conf_by_name(conf, pc->name))
+		die("Received duplicate interface name");
+
+	conf->npifs++;
+	return true;
+}
+
+/**
+ * show_conf() - Show current configuration obtained from passt/pasta
+ * @conf:	Configuration description
+ */
+static void show_conf(const struct configuration *conf)
+{
+	unsigned i;
+
+	for (i = 0; i < conf->npifs; i++) {
+		const struct pif_configuration *pc = &conf->pif[i];
+		printf("  %s\n", pc->name);
+		printf("    TBD\n");
+	}
+}
+
 /**
  * main() - Dynamic reconfiguration client main program
  * @argc:	Argument count
@@ -80,6 +199,7 @@ int main(int argc, char **argv)
 		{ 0 },
 	};
 	struct sockaddr_un a = { AF_UNIX, "" };
+	struct configuration conf = { 0 };
 	const char *optstring = "dh";
 	struct pesto_hello hello;
 	struct sock_fprog prog;
@@ -162,6 +282,18 @@ int main(int argc, char **argv)
 "Warning: Using experimental protocol version, client and server must match\n");
 	}
 
+	if (ntohl(hello.pif_name_size) != PIF_NAME_SIZE) {
+		die("Server has unexpected pif name size (%"
+		    PRIu32" not %"PRIu32"\n",
+		    ntohl(hello.pif_name_size), PIF_NAME_SIZE);
+	}
+
+	while (read_pif_conf(s, &conf))
+		;
+
+	printf("passt/pasta configuration (%s)\n", a.sun_path);
+	show_conf(&conf);
+
 	if (shutdown(s, SHUT_RDWR) < 0 || close(s) < 0)
 		die_perror("Error shutting down control socket");
 
diff --git a/pesto.h b/pesto.h
index 92d4df3a..ac4c2b58 100644
--- a/pesto.h
+++ b/pesto.h
@@ -17,18 +17,33 @@
 /* Version 0 is reserved for unreleased / unsupported experimental versions */
 #define PESTO_PROTOCOL_VERSION	0
 
+/* Maxmimum size of a pif name, including \0 */
+#define	PIF_NAME_SIZE	(128)
+#define PIF_NONE	0
+
 /**
  * struct pesto_hello - Server introduction message
- * @magic:	PESTO_SERVER_MAGIC
- * @version:	Version number
+ * @magic:		PESTO_SERVER_MAGIC
+ * @version:		Version number
+ * @pif_name_size:	Server's value for PIF_NAME_SIZE
  */
 struct pesto_hello {
 	char magic[8];
 	uint32_t version;
+	uint32_t pif_name_size;
 } __attribute__ ((__packed__));
 
 static_assert(sizeof(PESTO_SERVER_MAGIC)
 	      == sizeof(((struct pesto_hello *)0)->magic),
 	      "PESTO_SERVER_MAGIC has wrong size");
 
+/**
+ * struct pesto_pif_info - Message with basic metadata about a pif
+ * @resv_:	Alignment gap (must be 0)
+ * @name:	Name (\0 terminated)
+ */
+struct pesto_pif_info {
+	char name[PIF_NAME_SIZE];
+} __attribute__ ((__packed__));
+
 #endif /* PESTO_H */
diff --git a/pif.h b/pif.h
index 90dd3a32..d7708603 100644
--- a/pif.h
+++ b/pif.h
@@ -11,6 +11,7 @@
 
 #include <netinet/in.h>
 
+#include "pesto.h"
 #include "epoll_type.h"
 
 union inany_addr;
@@ -24,7 +25,7 @@ union sockaddr_inany;
  */
 enum pif_type {
 	/* Invalid or not present pif */
-	PIF_NONE = 0,
+	PIF_NONE_ = PIF_NONE,
 	/* Host socket interface */
 	PIF_HOST,
 	/* Qemu socket or namespace tuntap interface */
@@ -36,7 +37,6 @@ enum pif_type {
 };
 
 /* Maxmimum size of a pif name, including \0 */
-#define	PIF_NAME_SIZE	(128)
 extern const char pif_type_str[][PIF_NAME_SIZE];
 
 static inline const char *pif_type(enum pif_type pt)
diff --git a/serialise.c b/serialise.c
index 346df998..e083112e 100644
--- a/serialise.c
+++ b/serialise.c
@@ -121,6 +121,10 @@ int write_all_buf(int fd, const void *buf, size_t len)
 		return write_all_buf(fd, &beval, sizeof(beval));	\
 	}
 
+#define	be8toh(x)	(x)
+#define	htobe8(x)	(x)
+
+SERIALISE_UINT(8)
 SERIALISE_UINT(32)
 
 #undef SERIALISE_UINT
diff --git a/serialise.h b/serialise.h
index a88f3dee..4714f4c9 100644
--- a/serialise.h
+++ b/serialise.h
@@ -16,6 +16,7 @@ int write_all_buf(int fd, const void *buf, size_t len);
 	int read_u##bits(int fd, uint##bits##_t *val);			\
 	int write_u##bits(int fd, uint##bits##_t val);
 
+SERIALISE_UINT_DECL(8)
 SERIALISE_UINT_DECL(32)
 
 #endif /* SERIALISE_H */
diff --git a/util.h b/util.h
index e90be47d..c7883824 100644
--- a/util.h
+++ b/util.h
@@ -87,8 +87,6 @@ void abort_with_msg(const char *fmt, ...)
 #define V6		1
 #define IP_VERSIONS	2
 
-#define ARRAY_SIZE(a)		((int)(sizeof(a) / sizeof((a)[0])))
-
 #define foreach(item, array)						\
 	for ((item) = (array); (item) - (array) < ARRAY_SIZE(array); (item)++)
 
-- 
2.53.0


  parent reply	other threads:[~2026-04-21  4:42 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-21  4:42 [PATCH v4 00/17] RFC: Dynamic configuration update implementation David Gibson
2026-04-21  4:42 ` [PATCH v4 01/17] conf, fwd: Stricter rule checking in fwd_rule_add() David Gibson
2026-04-21  4:42 ` [PATCH v4 02/17] fwd_rule: Move ephemeral port probing to fwd_rule.c David Gibson
2026-04-21  4:42 ` [PATCH v4 03/17] fwd, conf: Move rule parsing code to fwd_rule.[ch] David Gibson
2026-04-21  4:42 ` [PATCH v4 04/17] fwd_rule: Move conflict checking back within fwd_rule_add() David Gibson
2026-04-21  4:42 ` [PATCH v4 05/17] fwd: Generalise fwd_rules_info() David Gibson
2026-04-21  4:42 ` [PATCH v4 06/17] pif: Limit pif names to 128 bytes David Gibson
2026-04-21  4:42 ` [PATCH v4 07/17] fwd_rule: Fix some format specifiers David Gibson
2026-04-21  4:42 ` [PATCH v4 08/17] pesto: Introduce stub configuration tool David Gibson
2026-04-21  4:42 ` [PATCH v4 09/17] pesto, log: Share log.h (but not log.c) with pesto tool David Gibson
2026-04-21  4:42 ` [PATCH v4 10/17] pesto, conf: Have pesto connect to passt and check versions David Gibson
2026-04-21  4:42 ` David Gibson [this message]
2026-04-21  4:42 ` [PATCH v4 12/17] ip: Prepare ip.[ch] for sharing with pesto tool David Gibson
2026-04-21  4:42 ` [PATCH v4 13/17] inany: Prepare inany.[ch] " David Gibson
2026-04-21  4:42 ` [PATCH v4 14/17] pesto: Read current ruleset from passt/pasta and optionally display it David Gibson
2026-04-21  4:42 ` [PATCH v4 15/17] pesto: Parse and add new rules from command line David Gibson
2026-04-21  4:42 ` [PATCH v4 16/17] pesto, conf: Send updated rules from pesto back to passt/pasta David Gibson
2026-04-21  4:42 ` [PATCH v4 17/17] conf, fwd: Allow switching to new rules received from pesto David Gibson
2026-04-21  6:26 ` [PATCH v4 00/17] IGNORE RFC: Dynamic configuration update implementation 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=20260421044217.2500314-12-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).