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=202602 header.b=VuPfzsvV; dkim-atps=neutral Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id 6E6005A0262 for ; Tue, 17 Mar 2026 01:49:00 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202602; t=1773708536; bh=ocUhzdjtw8LmstvHEsW5OEHD0mry46a943VZ6+Z4vf0=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=VuPfzsvVKJLZx9Z/LNb5xrRJdug9yUTLsatj2As1u/6PgVSrgn+yKK0QSMcoFupzB UNO1O3Fp2GRObRurfze9lXrEi7u6LR2bvmJ8gdoP47sxJF/YNt4W3DG1u265b8b2Km lRFoYeX7V/fd09d3aSpmAh9OL3X2/1+2htcx4vRB0XOlTvneaJ73TCWbVsU/j9YQU3 z5LF7VShbPXgROlziJeKIUX9EMi1nQ05xqDdG/D+g4ZVCaKvwb7CQB3ISegVc629oM W1P8UY4GWXhUKG12DunN6vXzKiJ2ir+uJo2Z+lljfeQIq9Tkr7UVQt6KCG3+kMFgmL zzOrmSjMZte2A== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4fZYHX5n46z4wD3; Tue, 17 Mar 2026 11:48:56 +1100 (AEDT) Date: Tue, 17 Mar 2026 11:48:50 +1100 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH 5/5] pesto: Introduce stub configuration interface and tool Message-ID: References: <20260316054629.239002-1-david@gibson.dropbear.id.au> <20260316054629.239002-6-david@gibson.dropbear.id.au> <20260317010245.4f5a8f33@elisabeth> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="s5avtmCPf5kc7xGO" Content-Disposition: inline In-Reply-To: <20260317010245.4f5a8f33@elisabeth> Message-ID-Hash: 3I3W45XBCSL5FYY7KT2R44QX4N3LZWDA X-Message-ID-Hash: 3I3W45XBCSL5FYY7KT2R44QX4N3LZWDA 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: passt-dev@passt.top 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: --s5avtmCPf5kc7xGO Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Tue, Mar 17, 2026 at 01:02:46AM +0100, Stefano Brivio wrote: > On Mon, 16 Mar 2026 16:46:29 +1100 > David Gibson wrote: >=20 > > Add a control socket to passt/pasta for updating configuration at runti= me. > > Add a tool (pesto) for communicating with the control socket. > >=20 > > For now this is a stub implementation that forms the connection and sen= ds > > some version information, but nothing more. > > Example: > > ./pasta --debug --config-net -c /tmp/pasta.conf -t none > > ./pesto /tmp/pasta.conf > >=20 > > Signed-off-by: Stefano Brivio > > [dwg: Based on an early draft from Stefano] > > Signed-off-by: David Gibson > > --- > > .gitignore | 2 + > > Makefile | 32 +++++++---- > > conf.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++- > > conf.h | 2 + > > epoll_type.h | 4 ++ > > passt.1 | 5 ++ > > passt.c | 8 +++ > > passt.h | 6 +++ > > pesto.1 | 47 ++++++++++++++++ > > pesto.c | 111 ++++++++++++++++++++++++++++++++++++++ > > pesto.h | 34 ++++++++++++ > > pesto_util.c | 62 +++++++++++++++++++++ > > pesto_util.h | 19 +++++++ > > util.c | 38 ------------- > > util.h | 5 +- > > 15 files changed, 469 insertions(+), 54 deletions(-) > > create mode 100644 pesto.1 > > create mode 100644 pesto.c > > create mode 100644 pesto.h > > create mode 100644 pesto_util.c > > create mode 100644 pesto_util.h > >=20 > > diff --git a/.gitignore b/.gitignore > > index 3c16adc7..3e40d9f7 100644 > > --- a/.gitignore > > +++ b/.gitignore > > @@ -4,9 +4,11 @@ > > /pasta > > /pasta.avx2 > > /passt-repair > > +/pesto > > /qrap > > /pasta.1 > > /seccomp.h > > +/seccomp_pesto.h > > /seccomp_repair.h > > /c*.json > > README.plain.md > > diff --git a/Makefile b/Makefile > > index fe016f30..a528b34a 100644 > > --- a/Makefile > > +++ b/Makefile > > @@ -39,21 +39,25 @@ FLAGS +=3D -DDUAL_STACK_SOCKETS=3D$(DUAL_STACK_SOCK= ETS) > > =20 > > PASST_SRCS =3D arch.c arp.c checksum.c conf.c dhcp.c dhcpv6.c epoll_ct= l.c \ > > flow.c fwd.c icmp.c igmp.c inany.c iov.c ip.c isolation.c lineread.c \ > > - log.c mld.c ndp.c netlink.c migrate.c packet.c passt.c pasta.c pcap.c= \ > > - pif.c repair.c tap.c tcp.c tcp_buf.c tcp_splice.c tcp_vu.c udp.c \ > > - udp_flow.c udp_vu.c util.c vhost_user.c virtio.c vu_common.c > > + log.c mld.c ndp.c netlink.c migrate.c packet.c passt.c pasta.c \ > > + pesto_util.c pcap.c pif.c repair.c tap.c tcp.c tcp_buf.c tcp_splice.c= \ > > + tcp_vu.c udp.c udp_flow.c udp_vu.c util.c vhost_user.c virtio.c \ > > + vu_common.c > > QRAP_SRCS =3D qrap.c > > PASST_REPAIR_SRCS =3D passt-repair.c > > -SRCS =3D $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) > > +PESTO_SRCS =3D pesto.c pesto_util.c > > +SRCS =3D $(PASST_SRCS) $(QRAP_SRCS) $(PASST_REPAIR_SRCS) $(PESTO_SRCS) > > =20 > > -MANPAGES =3D passt.1 pasta.1 qrap.1 passt-repair.1 > > +MANPAGES =3D passt.1 pasta.1 pesto.1 qrap.1 passt-repair.1 > > =20 > > +PESTO_HEADERS =3D pesto.h pesto_util.h > > PASST_HEADERS =3D 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 inany.h iov.h ip.h \ > > isolation.h lineread.h log.h migrate.h ndp.h netlink.h packet.h \ > > passt.h pasta.h pcap.h pif.h repair.h siphash.h tap.h tcp.h tcp_buf.h= \ > > tcp_conn.h tcp_internal.h tcp_splice.h tcp_vu.h udp.h udp_flow.h \ > > - udp_internal.h udp_vu.h util.h vhost_user.h virtio.h vu_common.h > > + udp_internal.h udp_vu.h util.h vhost_user.h virtio.h vu_common.h \ > > + $(PESTO_HEADERS) > > HEADERS =3D $(PASST_HEADERS) seccomp.h > > =20 > > C :=3D \#include \nint main(){int a=3Dgetrandom(0, 0, 0)= ;} > > @@ -74,9 +78,9 @@ mandir ?=3D $(datarootdir)/man > > man1dir ?=3D $(mandir)/man1 > > =20 > > ifeq ($(TARGET_ARCH),x86_64) > > -BIN :=3D passt passt.avx2 pasta pasta.avx2 qrap passt-repair > > +BIN :=3D passt passt.avx2 pasta pasta.avx2 qrap passt-repair pesto > > else > > -BIN :=3D passt pasta qrap passt-repair > > +BIN :=3D passt pasta qrap passt-repair pesto > > endif > > =20 > > all: $(BIN) $(MANPAGES) docs > > @@ -90,6 +94,9 @@ seccomp.h: seccomp.sh $(PASST_SRCS) $(PASST_HEADERS) > > seccomp_repair.h: seccomp.sh $(PASST_REPAIR_SRCS) > > @ ARCH=3D"$(TARGET_ARCH)" CC=3D"$(CC)" ./seccomp.sh seccomp_repair.h = $(PASST_REPAIR_SRCS) > > =20 > > +seccomp_pesto.h: seccomp.sh $(PESTO_SRCS) > > + @ ARCH=3D"$(TARGET_ARCH)" CC=3D"$(CC)" ./seccomp.sh seccomp_pesto.h $= (PESTO_SRCS) > > + > > passt: $(PASST_SRCS) $(HEADERS) > > $(CC) $(FLAGS) $(CFLAGS) $(CPPFLAGS) $(PASST_SRCS) -o passt $(LDFLAGS) > > =20 > > @@ -109,6 +116,9 @@ qrap: $(QRAP_SRCS) passt.h > > passt-repair: $(PASST_REPAIR_SRCS) seccomp_repair.h > > $(CC) $(FLAGS) $(CFLAGS) $(CPPFLAGS) $(PASST_REPAIR_SRCS) -o passt-re= pair $(LDFLAGS) > > =20 > > +pesto: $(PESTO_SRCS) $(PESTO_HEADERS) seccomp_pesto.h > > + $(CC) $(FLAGS) $(CFLAGS) $(CPPFLAGS) $(PESTO_SRCS) -o pesto $(LDFLAGS) > > + > > valgrind: EXTRA_SYSCALLS +=3D rt_sigprocmask rt_sigtimedwait rt_sigact= ion \ > > rt_sigreturn getpid gettid kill clock_gettime \ > > mmap|mmap2 munmap open unlink gettimeofday futex \ > > @@ -118,7 +128,7 @@ valgrind: all > > =20 > > .PHONY: clean > > clean: > > - $(RM) $(BIN) *~ *.o seccomp.h seccomp_repair.h pasta.1 \ > > + $(RM) $(BIN) *~ *.o seccomp.h seccomp_repair.h seccomp_pesto.h pasta.= 1 \ > > passt.tar passt.tar.gz *.deb *.rpm \ > > passt.pid README.plain.md > > =20 > > @@ -172,11 +182,11 @@ docs: README.md > > done < README.md; \ > > ) > README.plain.md > > =20 > > -clang-tidy: $(PASST_SRCS) > > +clang-tidy: $(PASST_SRCS) $(PESTO_SRCS) > > clang-tidy $^ -- $(filter-out -pie,$(FLAGS) $(CFLAGS) $(CPPFLAGS)) \ > > -DCLANG_TIDY_58992 > > =20 > > -cppcheck: $(PASST_SRCS) $(HEADERS) > > +cppcheck: $(PASST_SRCS) $(PESTO_SRCS) $(HEADERS) > > if cppcheck --check-level=3Dexhaustive /dev/null > /dev/null 2>&1; th= en \ > > CPPCHECK_EXHAUSTIVE=3D"--check-level=3Dexhaustive"; \ > > else \ > > diff --git a/conf.c b/conf.c > > index 940fb9e9..04f65b30 100644 > > --- a/conf.c > > +++ b/conf.c > > @@ -47,6 +47,9 @@ > > #include "isolation.h" > > #include "log.h" > > #include "vhost_user.h" > > +#include "epoll_ctl.h" > > +#include "conf.h" > > +#include "pesto.h" > > =20 > > #define NETNS_RUN_DIR "/run/netns" > > =20 > > @@ -894,6 +897,7 @@ static void usage(const char *name, FILE *f, int st= atus) > > " --runas UID|UID:GID Run as given UID, GID, which can be\n" > > " numeric, or login and group names\n" > > " default: drop to user \"nobody\"\n" > > + " -c, --conf-PATH PATH Configuration socket path\n" >=20 > --conf-path Oops, fixed. >=20 > > " -h, --help Display this help message and exit\n" > > " --version Show version and exit\n"); > > =20 > > @@ -1425,6 +1429,17 @@ static void conf_open_files(struct ctx *c) > > if (c->pidfile_fd < 0) > > die_perror("Couldn't open PID file %s", c->pidfile); > > } > > + > > + c->fd_conf =3D -1; >=20 > Note: we should remember to tackle your own comments from > , eventually (not necessarily now, but fd_conf > just reminded me). Uh, don't remember what that mail was and I'm not immediately sure how to search for it based on message-id. > > + if (*c->conf_path) { > > + c->fd_conf_listen =3D sock_unix(c->conf_path); > > + if (c->fd_conf_listen < 0) { > > + die_perror("Couldn't open control socket %s", > > + c->conf_path); > > + } > > + } else { > > + c->fd_conf_listen =3D -1; > > + } > > } > > =20 > > /** > > @@ -1460,6 +1475,25 @@ fail: > > die("Invalid MAC address: %s", str); > > } > > =20 > > +/** > > + * conf_sock_listen() - Start listening for connections on configurati= on socket > > + * @c: Execution context > > + */ > > +static void conf_sock_listen(const struct ctx *c) > > +{ > > + union epoll_ref ref =3D { .type =3D EPOLL_TYPE_CONF_LISTEN }; > > + > > + if (c->fd_conf_listen < 0) > > + return; > > + > > + if (listen(c->fd_conf_listen, 0)) > > + die_perror("Couldn't listen on configuration socket"); > > + > > + ref.fd =3D c->fd_conf_listen; > > + if (epoll_add(c->epollfd, EPOLLIN | EPOLLET, ref)) > > + die_perror("Couldn't add configuration socket to epoll"); > > +} > > + > > /** > > * conf() - Process command-line arguments and set configuration > > * @c: Execution context > > @@ -1542,9 +1576,10 @@ void conf(struct ctx *c, int argc, char **argv) > > {"migrate-exit", no_argument, NULL, 29 }, > > {"migrate-no-linger", no_argument, NULL, 30 }, > > {"stats", required_argument, NULL, 31 }, > > + {"conf-path", required_argument, NULL, 'c' }, > > { 0 }, > > }; > > - const char *optstring =3D "+dqfel:hs:F:I:p:P:m:a:n:M:g:i:o:D:S:H:461t= :u:T:U:"; > > + const char *optstring =3D "+dqfel:hs:c:F:I:p:P:m:a:n:M:g:i:o:D:S:H:46= 1t:u:T:U:"; > > const char *logname =3D (c->mode =3D=3D MODE_PASTA) ? "pasta" : "pass= t"; > > char userns[PATH_MAX] =3D { 0 }, netns[PATH_MAX] =3D { 0 }; > > bool copy_addrs_opt =3D false, copy_routes_opt =3D false; > > @@ -1808,6 +1843,13 @@ void conf(struct ctx *c, int argc, char **argv) > > =20 > > c->fd_tap =3D -1; > > break; > > + case 'c': > > + ret =3D snprintf(c->conf_path, sizeof(c->conf_path), "%s", > > + optarg); > > + if (ret <=3D 0 || ret >=3D (int)sizeof(c->sock_path)) > > + die("Invalid configuration path: %s", optarg); > > + c->fd_conf_listen =3D c->fd_conf =3D -1; > > + break; > > case 'F': > > errno =3D 0; > > fd_tap_opt =3D strtol(optarg, NULL, 0); > > @@ -2242,4 +2284,108 @@ void conf(struct ctx *c, int argc, char **argv) > > =20 > > if (!c->quiet) > > conf_print(c); > > + > > + conf_sock_listen(c); > > +} > > + > > +/** > > + * conf_listen_handler() - Handle events on configuration listening so= cket > > + * @c: Execution context > > + * @events: epoll events > > + */ > > +void conf_listen_handler(struct ctx *c, uint32_t events) > > +{ > > + struct pesto_hello hello =3D { > > + .magic =3D PESTO_SERVER_MAGIC, > > + .version =3D htonl(PESTO_PROTOCOL_VERSION), > > + }; > > + union epoll_ref ref =3D { .type =3D EPOLL_TYPE_CONF }; > > + struct ucred uc =3D { 0 }; > > + socklen_t len =3D sizeof(uc); > > + int fd, rc; > > + > > + if (events !=3D EPOLLIN) { > > + err("Unexpected event 0x%04x on configuration socket", events); > > + return; > > + } > > + > > + fd =3D accept4(c->fd_conf_listen, NULL, NULL, SOCK_NONBLOCK); > > + if (fd < 0) { > > + warn_perror("accept4() on configuration listening socket"); > > + return; > > + } > > + > > + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) < 0) > > + warn_perror("Can't get configuration client credentials"); > > + > > + /* Another client is already connected: accept and close right away. = */ > > + if (c->fd_conf !=3D -1) { > > + info("Discarding configuration client, PID %i", uc.pid); > > + goto fail; > > + } > > + > > + ref.fd =3D fd; > > + rc =3D epoll_add(c->epollfd, EPOLLIN | EPOLLET, ref); > > + if (rc < 0) { > > + warn_perror("epoll_ctl() on configuration socket"); > > + goto fail; > > + } > > + > > + rc =3D write_all_buf(fd, &hello, sizeof(hello)); > > + if (rc < 0) { > > + warn_perror("Error writing configuration protocol hello"); > > + goto fail; > > + } > > + > > + c->fd_conf =3D fd; > > + info("Accepted configuration client, PID %i", uc.pid); > > + if (!PESTO_PROTOCOL_VERSION) { > > + warn( > > +"Warning: Using experimental unsupported configuration protocol"); > > + } > > + > > + return; > > + > > +fail: > > + close(fd); > > +} > > + > > +/** > > + * conf_handler() - Handle events on configuration socket > > + * @c: Execution context > > + * @events: epoll events > > + */ > > +void conf_handler(struct ctx *c, uint32_t events) > > +{ > > + if (events & EPOLLIN) { > > + char discard[BUFSIZ]; > > + ssize_t n; > > + > > + do { > > + n =3D read(c->fd_conf, discard, sizeof(discard)); > > + if (n > 0) > > + debug("Discarded %zd bytes of config data", n); > > + } while (n > 0); > > + if (n =3D=3D 0) { > > + debug("Configuration client EOF"); > > + goto close; > > + } > > + if (errno !=3D EAGAIN && errno !=3D EWOULDBLOCK) { > > + err_perror("Error reading config data"); > > + goto close; > > + } > > + } > > + > > + if (events & EPOLLHUP) { > > + debug("Configuration client hangup"); > > + goto close; > > + } > > + > > + return; > > + > > +close: > > + debug("Closing configuration socket"); > > + epoll_ctl(c->epollfd, EPOLL_CTL_DEL, c->fd_conf, NULL); > > + close(c->fd_conf); > > + c->fd_conf =3D -1; > > } > > diff --git a/conf.h b/conf.h > > index b45ad746..16f97189 100644 > > --- a/conf.h > > +++ b/conf.h > > @@ -8,5 +8,7 @@ > > =20 > > enum passt_modes conf_mode(int argc, char *argv[]); > > void conf(struct ctx *c, int argc, char **argv); > > +void conf_listen_handler(struct ctx *c, uint32_t events); > > +void conf_handler(struct ctx *c, uint32_t events); > > =20 > > #endif /* CONF_H */ > > diff --git a/epoll_type.h b/epoll_type.h > > index a90ffb67..061325aa 100644 > > --- a/epoll_type.h > > +++ b/epoll_type.h > > @@ -46,6 +46,10 @@ enum epoll_type { > > EPOLL_TYPE_REPAIR, > > /* Netlink neighbour subscription socket */ > > EPOLL_TYPE_NL_NEIGH, > > + /* Configuration listening socket */ > > + EPOLL_TYPE_CONF_LISTEN, > > + /* Configuration socket */ > > + EPOLL_TYPE_CONF, > > =20 > > EPOLL_NUM_TYPES, > > }; > > diff --git a/passt.1 b/passt.1 > > index 13e8df9d..32d70c8d 100644 > > --- a/passt.1 > > +++ b/passt.1 > > @@ -127,6 +127,11 @@ login name and group name can be passed. This requ= ires privileges (either > > initial effective UID 0 or CAP_SETUID capability) to work. > > Default is to change to user \fInobody\fR if started as root. > > =20 > > +.TP > > +.BR \-c ", " \-\-conf-path " " \fIpath " " (EXPERIMENTAL) >=20 > I wouldn't even mention (EXPERIMENTAL). Pretty much all the options we > added so far were. Well, my plan was to remove that once we had a v1 of the update protocol. > > +Path for configuration and control socket used by \fBpesto\fR(1) to > > +dynamically update passt or pasta's configuration. > > + > > .TP > > .BR \-h ", " \-\-help > > Display a help message and exit. > > diff --git a/passt.c b/passt.c > > index f84419c7..bc42ea33 100644 > > --- a/passt.c > > +++ b/passt.c > > @@ -80,6 +80,8 @@ char *epoll_type_str[] =3D { > > [EPOLL_TYPE_REPAIR_LISTEN] =3D "TCP_REPAIR helper listening socket", > > [EPOLL_TYPE_REPAIR] =3D "TCP_REPAIR helper socket", > > [EPOLL_TYPE_NL_NEIGH] =3D "netlink neighbour notifier socket", > > + [EPOLL_TYPE_CONF_LISTEN] =3D "configuration listening socket", > > + [EPOLL_TYPE_CONF] =3D "configuration socket", > > }; > > static_assert(ARRAY_SIZE(epoll_type_str) =3D=3D EPOLL_NUM_TYPES, > > "epoll_type_str[] doesn't match enum epoll_type"); > > @@ -303,6 +305,12 @@ static void passt_worker(void *opaque, int nfds, s= truct epoll_event *events) > > case EPOLL_TYPE_NL_NEIGH: > > nl_neigh_notify_handler(c); > > break; > > + case EPOLL_TYPE_CONF_LISTEN: > > + conf_listen_handler(c, eventmask); > > + break; > > + case EPOLL_TYPE_CONF: > > + conf_handler(c, eventmask); > > + break; > > default: > > /* Can't happen */ > > assert(0); > > diff --git a/passt.h b/passt.h > > index b614bdf0..a49fbe1d 100644 > > --- a/passt.h > > +++ b/passt.h > > @@ -158,6 +158,7 @@ struct ip6_ctx { > > * @foreground: Run in foreground, don't log to stderr by default > > * @nofile: Maximum number of open files (ulimit -n) > > * @sock_path: Path for UNIX domain socket > > + * @conf_path: Path for configuration UNIX domain socket > > * @repair_path: TCP_REPAIR helper path, can be "none", empty for defa= ult > > * @pcap: Path for packet capture file > > * @pidfile: Path to PID file, empty string if not configured > > @@ -169,6 +170,8 @@ struct ip6_ctx { > > * @epollfd: File descriptor for epoll instance > > * @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any > > * @fd_tap: AF_UNIX socket, tuntap device, or pre-opened socket > > + * @fd_conf_listen: Listening configuration socket, if any > > + * @fd_conf: Configuration socket, if any > > * @fd_repair_listen: File descriptor for listening TCP_REPAIR socket,= if any > > * @fd_repair: Connected AF_UNIX socket for TCP_REPAIR helper > > * @our_tap_mac: Pasta/passt's MAC on the tap link > > @@ -224,6 +227,7 @@ struct ctx { > > int foreground; > > int nofile; > > char sock_path[UNIX_PATH_MAX]; > > + char conf_path[UNIX_PATH_MAX]; > > char repair_path[UNIX_PATH_MAX]; > > char pcap[PATH_MAX]; > > =20 > > @@ -241,6 +245,8 @@ struct ctx { > > int epollfd; > > int fd_tap_listen; > > int fd_tap; > > + int fd_conf_listen; > > + int fd_conf; > > int fd_repair_listen; > > int fd_repair; > > unsigned char our_tap_mac[ETH_ALEN]; > > diff --git a/pesto.1 b/pesto.1 > > new file mode 100644 > > index 00000000..fe2072f5 > > --- /dev/null > > +++ b/pesto.1 > > @@ -0,0 +1,47 @@ > > +.\" SPDX-License-Identifier: GPL-2.0-or-later > > +.\" Copyright Red Hat > > +.\" Author: David Gibson > > +.TH pesto 1 > > + > > +.SH NAME > > +.B pesto > > +\- View or alter configuration of a running \fBpasst\fR(1) or > > +\fBpasta\fR(1). >=20 > ...process/instance? I had that initially, but I was trying to keep it to one line. > > + > > +.SH SYNOPSIS > > +.B pesto > > +\fIPATH\fR > > + > > +.SH DESCRIPTION > > + > > +.B pesto > > +is an experimental client to view and update the port forwarding >=20 > I'd drop "experimental" from here as well, otherwise we'll never drop > it until somebody asks if there's a "stable" solution in two years. Again, my plan was to remove that once we have a series that implements a suitable-for-release version of the protocol. This man page to require a bunch of updates as we add options, so I'm hoping that will be enough not to forget. > > +configuration of a running \fBpasst\fR(1) or \fBpasta\fR(1) instance. > > + > > +\fIPATH\fR gives the path to the UNIX domain socket created by > > +\fBpasst\fR or \fBpasta\fR. It should match the \fB-c\fR command line > > +option given to that instance. > > + > > +.SH AUTHOR >=20 > Should be AUTHORS (just like in passt(1) -- I checked, back then, both > section names seem to be common and they aren't really standardised > anywhere). Fixed. >=20 > > + > > +Stefano Brivio , > > +David Gibson . > > + > > +.SH REPORTING BUGS > > + > > +Please report issues on the bug tracker at https://bugs.passt.top/, or > > +send a message to the passt-user@passt.top mailing list, see > > +https://lists.passt.top/. > > + > > +.SH COPYRIGHT > > + > > +Copyright Red Hat > > + > > +\fBpesto\fR is free software: you can redistribute them and/or modify > > +them under the terms of the GNU General Public License as published by > > +the Free Software Foundation, either version 2 of the License, or (at > > +your option) any later version. > > + > > +.SH SEE ALSO > > + > > +\fBpasst\fR(1), \fBpasta\fR(1), \fBunix\fR(7). > > diff --git a/pesto.c b/pesto.c > > new file mode 100644 > > index 00000000..a158eadf > > --- /dev/null > > +++ b/pesto.c > > @@ -0,0 +1,111 @@ > > +// SPDX-License-Identifier: GPL-2.0-or-later > > + > > +/* PESTO - Programmable Extensible Socket Translation Orchestrator > > + * front-end for passt(1) and pasta(1) forwarding configuration > > + * > > + * pesto.c - Main program (it's not actually extensible) > > + * > > + * Copyright (c) 2026 Red Hat GmbH > > + * Author: Stefano Brivio > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > + > > +#include "seccomp_pesto.h" > > +#include "pesto_util.h" > > +#include "pesto.h" > > + > > +#define die(...) \ > > + do { \ > > + FPRINTF(stderr, __VA_ARGS__); \ > > + FPRINTF(stderr, "\n"); \ > > + exit(EXIT_FAILURE); \ > > + } while (0) > > + > > +/** > > + * main() - Entry point and whole program with loop > > + * @argc: Argument count > > + * @argv: Arguments: socket path, operation, port specifiers > > + * > > + * Return: 0 on success, won't return on failure > > + * > > + * #syscalls:pesto connect write close exit_group fstat brk > > + * #syscalls:pesto socket s390x:socketcall i686:socketcall > > + * #syscalls:pesto recvfrom recvmsg arm:recv ppc64le:recv > > + * #syscalls:pesto sendto sendmsg arm:send ppc64le:send > > + */ > > +int main(int argc, char **argv) > > +{ > > + struct sockaddr_un a =3D { AF_UNIX, "" }; > > + struct pesto_hello hello; > > + struct sock_fprog prog; > > + uint32_t s_version; > > + int ret, s; > > + > > + prctl(PR_SET_DUMPABLE, 0); > > + > > + prog.len =3D (unsigned short)sizeof(filter_pesto) / > > + sizeof(filter_pesto[0]); > > + prog.filter =3D filter_pesto; > > + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) || > > + prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) > > + die("Failed to apply seccomp filter"); > > + > > + if (argc < 2) > > + die("Usage: %s CONTROLPATH", argv[0]); >=20 > While CONTROLPATH is a bit more descriptive, I think it's also harder > to read compared to PATH, and after all it's not adding much. Fair enough, done. > > + > > + if ((s =3D socket(AF_UNIX, SOCK_STREAM, 0)) < 0) > > + die("Failed to create AF_UNIX socket: %s", strerror(errno)); > > + > > + ret =3D snprintf(a.sun_path, sizeof(a.sun_path), "%s", argv[1]); > > + if (ret <=3D 0 || ret >=3D (int)sizeof(a.sun_path)) > > + die("Invalid socket path \"%s\"", argv[1]); > > + > > + ret =3D connect(s, (struct sockaddr *)&a, sizeof(a)); > > + if (ret < 0) { > > + die("Failed to connect to %s: %s", > > + a.sun_path, strerror(errno)); > > + } > > + > > + ret =3D read_all_buf(s, &hello, sizeof(hello)); > > + if (ret < 0) > > + die("Couldn't read server greeting: %s", strerror(errno)); > > + > > + if (memcmp(hello.magic, PESTO_SERVER_MAGIC, sizeof(hello.magic))) > > + die("Bad magic number from server"); > > + > > + s_version =3D ntohl(hello.version); > > + > > + if (s_version > PESTO_PROTOCOL_VERSION) { > > + die("Unknown server protocol version %"PRIu32" > %"PRIu32"\n", > > + s_version, PESTO_PROTOCOL_VERSION); > > + } > > + > > + if (!s_version) { > > + if (PESTO_PROTOCOL_VERSION) > > + die("Unsupported experimental server protocol"); > > + fprintf(stderr, > > +"Warning: Using experimental protocol version, client and server must = match\n"); > > + } > > + > > + return 0; > > +} > > diff --git a/pesto.h b/pesto.h > > new file mode 100644 > > index 00000000..92d4df3a > > --- /dev/null > > +++ b/pesto.h > > @@ -0,0 +1,34 @@ > > +/* SPDX-License-Identifier: GPL-2.0-or-later > > + * Copyright Red Hat > > + * Author: David Gibson > > + * > > + * Definitions and functions used by both client and server of the con= figuration > > + * update protocol (pesto). >=20 > The answer is probably not obvious now, but eventually we should figure > out what we want to call "pesto": for me it was just the client, from > this description it sounds like the protocol as well (or Bad Acronym > Sounds Indeed Logical?). Maybe we'll never need to name the protocol > though. Yeah, I've been using it a bit sloppily for both. Or "pesto" (client) versus "pesto protocol". > > + */ > > + > > +#ifndef PESTO_H > > +#define PESTO_H > > + > > +#include > > +#include > > + > > +#define PESTO_SERVER_MAGIC "pesto:s" >=20 > Regardless of the consideration above, shouldn't this be "basil:s"? I really don't care :). > > + > > +/* Version 0 is reserved for unreleased / unsupported experimental ver= sions */ > > +#define PESTO_PROTOCOL_VERSION 0 > > + > > +/** > > + * struct pesto_hello - Server introduction message > > + * @magic: PESTO_SERVER_MAGIC > > + * @version: Version number > > + */ > > +struct pesto_hello { > > + char magic[8]; > > + uint32_t version; > > +} __attribute__ ((__packed__)); > > + > > +static_assert(sizeof(PESTO_SERVER_MAGIC) > > + =3D=3D sizeof(((struct pesto_hello *)0)->magic), > > + "PESTO_SERVER_MAGIC has wrong size"); > > + > > +#endif /* PESTO_H */ > > diff --git a/pesto_util.c b/pesto_util.c > > new file mode 100644 > > index 00000000..8e6b43d4 > > --- /dev/null > > +++ b/pesto_util.c > > @@ -0,0 +1,62 @@ > > +// SPDX-License-Identifier: GPL-2.0-or-later > > + > > +/* ASST - Plug A Simple Socket Transport >=20 > :) Oops, fixed. > > + * for qemu/UNIX domain socket mode > > + * > > + * PASTA - Pack A Subtle Tap Abstraction > > + * for network namespace/tap device mode > > + * > > + * PESTO - Programmable Extensible Socket Translation Orchestrator > > + * front-end for passt(1) and pasta(1) forwarding configuration > > + * > > + * pesto_util.c - Helpers used by both passt/pasta and pesto >=20 > Maybe we should call this common.c? It's a bit counter-intuitive to > look for read_all_buf() as used by passt into pesto_util.c. I'm not > fond of common.c either, it's less descriptive, but also potentially > less misleading. Maybe? I thought about common.c, but I wan't to distinguish (a) that this is shared specifically between pesto and passt, not with, e.g. passt-repair and (b) these are shared utility functions, rather than shared logic specifically regarding the protocol (that's in pesto.h). I'll keep it for now, but I'm open to better suggestions if either of us comes up with one. > > + * Copyright Red Hat > > + * Author: Stefano Brivio > > + * Author: David Gibson > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > + > > +#include "pesto_util.h" > > + > > +/** > > + * read_all_buf() - Fill a whole buffer from a file descriptor > > + * @fd: File descriptor > > + * @buf: Pointer to base of buffer > > + * @len: Length of buffer > > + * > > + * Return: 0 on success, -1 on error (with errno set) > > + * > > + * #syscalls read > > + */ > > +int read_all_buf(int fd, void *buf, size_t len) > > +{ > > + size_t left =3D len; > > + char *p =3D buf; > > + > > + while (left) { > > + ssize_t rc; > > + > > + assert(left <=3D len); > > + > > + do > > + rc =3D read(fd, p, left); > > + while ((rc < 0) && errno =3D=3D EINTR); > > + > > + if (rc < 0) > > + return -1; > > + > > + if (rc =3D=3D 0) { > > + errno =3D ENODATA; > > + return -1; > > + } > > + > > + p +=3D rc; > > + left -=3D rc; > > + } > > + return 0; > > +} > > diff --git a/pesto_util.h b/pesto_util.h > > new file mode 100644 > > index 00000000..1fc5d9fd > > --- /dev/null > > +++ b/pesto_util.h > > @@ -0,0 +1,19 @@ > > +/* SPDX-License-Identifier: GPL-2.0-or-later > > + * Copyright Red Hat > > + * Author: David Gibson > > + * > > + * Helper functions used by both passt/pasta and pesto (the configurat= ion update > > + * client). > > + */ > > + > > +#ifndef PESTO_UTIL_H > > +#define PESTO_UTIL_H > > + > > +#include > > + > > +/* FPRINTF() intentionally silences cert-err33-c clang-tidy warnings */ > > +#define FPRINTF(f, ...) (void)fprintf(f, __VA_ARGS__) > > + > > +int read_all_buf(int fd, void *buf, size_t len); > > + > > +#endif /* PESTO_UTIL_H */ > > diff --git a/util.c b/util.c > > index 22318c00..1571850b 100644 > > --- a/util.c > > +++ b/util.c > > @@ -866,44 +866,6 @@ int write_remainder(int fd, const struct iovec *io= v, size_t iovcnt, size_t skip) > > return 0; > > } > > =20 > > -/** > > - * read_all_buf() - Fill a whole buffer from a file descriptor > > - * @fd: File descriptor > > - * @buf: Pointer to base of buffer > > - * @len: Length of buffer > > - * > > - * Return: 0 on success, -1 on error (with errno set) > > - * > > - * #syscalls read > > - */ > > -int read_all_buf(int fd, void *buf, size_t len) > > -{ > > - size_t left =3D len; > > - char *p =3D buf; > > - > > - while (left) { > > - ssize_t rc; > > - > > - assert(left <=3D len); > > - > > - do > > - rc =3D read(fd, p, left); > > - while ((rc < 0) && errno =3D=3D EINTR); > > - > > - if (rc < 0) > > - return -1; > > - > > - if (rc =3D=3D 0) { > > - errno =3D ENODATA; > > - return -1; > > - } > > - > > - p +=3D rc; > > - left -=3D rc; > > - } > > - return 0; > > -} > > - > > /** > > * read_remainder() - Read the tail of an IO vector from a file descri= ptor > > * @fd: File descriptor > > diff --git a/util.h b/util.h > > index dcb79afe..74227a68 100644 > > --- a/util.h > > +++ b/util.h > > @@ -20,6 +20,7 @@ > > #include > > =20 > > #include "log.h" > > +#include "pesto_util.h" > > =20 > > #define VERSION_BLOB \ > > VERSION "\n" \ > > @@ -242,7 +243,6 @@ int write_file(const char *path, const char *buf); > > intmax_t read_file_integer(const char *path, intmax_t fallback); > > int write_all_buf(int fd, const void *buf, size_t len); > > int write_remainder(int fd, const struct iovec *iov, size_t iovcnt, si= ze_t skip); > > -int read_all_buf(int fd, void *buf, size_t len); > > int read_remainder(int fd, const struct iovec *iov, size_t cnt, size_t= skip); > > void close_open_files(int argc, char **argv); > > bool snprintf_check(char *str, size_t size, const char *format, ...); > > @@ -314,9 +314,6 @@ static inline bool mod_between(unsigned x, unsigned= i, unsigned j, unsigned m) > > return mod_sub(x, i, m) < mod_sub(j, i, m); > > } > > =20 > > -/* FPRINTF() intentionally silences cert-err33-c clang-tidy warnings */ > > -#define FPRINTF(f, ...) (void)fprintf(f, __VA_ARGS__) > > - > > void raw_random(void *buf, size_t buflen); > > =20 > > /* >=20 > The rest looks good to me, maybe we could just keep it like it is while > building stuff on top of this patch and address the comments later, no > particular preference (not a big effort either way). >=20 > --=20 > Stefano >=20 --=20 David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson --s5avtmCPf5kc7xGO Content-Type: application/pgp-signature; name=signature.asc -----BEGIN PGP SIGNATURE----- iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmm4pPEACgkQzQJF27ox 2GcJ4w/9HvbNtxBJCFUQJvm3NTIWBLtKCKK0saAISDDt8u4NDVdlyxzy4s9ao8th GaBcvRW1cMMPibCoh3k3RVA8ZHi8PWdkJZUVsrvJa7QU+XQn4P0AtXzFh7DvRaDE tIo7F4s360jllX+clEU5CO3AobNrnxDQTLJtCgmQF7P5EVxutigwEVmEiZG2gG6+ 46T7vlTpdKkZg1xbSgrOAwmxbkdhPuckpmNbv9yrKBuWD9BalljDFGUIjmA2+ZvO Pv/rrJg/q01a+VXI0GJ1SRKi17wgwxOAx3EjxAgwL39OUjPGF+ZL9tLaxzR3rgXD wgABIrsfcmsyya/bwk7JFJpePmw2EUDf6tJVyFspMTGI7Gn1jA38/dvPAe2ETHuI NOYuxRQlak9SYGm5djj40DsyqvgTPfiHzfrg2c6PvNtBizuo7qirwiDz4TRJir85 UwP2G0cRKzdbl5UekerYZvqUdrqwJsj+zqdowbwKEBRIAUD9sksFMWnL6jRgBK6O gIP6oTZuu5j3YynASz7LjuWH2uK0DCTNzH89E7Z2Lqwn8lDZUgA1d4IVuq9kM7Dy V8boG5s3gA/CWbQovLohwxSgV+uCWX/XAIpZpNBqkJ8oKr0+YxpElDMzTrEZvYlN FcZ2FPT2xf7yMQLzLurjzELY36iLywx8t0uUnZGRcnrEmjjkZn8= =nDP6 -----END PGP SIGNATURE----- --s5avtmCPf5kc7xGO--