Re: [PATCH 1/3] tools/router: use socket activation

Demi Marie Obenour
2025-12-09T10:48:18Z

[-- Attachment #1.1.1: Type: text/plain, Size: 14820 bytes --]

On 12/8/25 19:38, Alyssa Ross wrote:
> This means we can use readiness notification to wait until the sockets
> are created without having to add special functionality for that to
> the router program, and also means we can do extra system-specific
> setup to the sockets, like changing their owners, outside of the
> router.
>
> Since the socket paths were the only arguments taken by the router,
> this also lets us drop the clap dependency entirely.

I strongly recommend open-coding the file descriptor stuff instead
of using a third-party library for it. It's just a two calls to
getsockopt() (SO_DOMAIN and SO_TYPE) per socket, and listenfd pulls
in wasm-bindgen and js-sys!

> Signed-off-by: Alyssa Ross <hi@alyssa.is>
> ---
> host/rootfs/file-list.mk | 1 +
> .../service/spectrum-router/notification-fd | 1 +
> .../spectrum-router/notification-fd.license | 2 +
> .../template/data/service/spectrum-router/run | 19 +++
> tools/router/Cargo.lock | 148 ++++++++++++------
> tools/router/Cargo.toml | 2 +-
> tools/router/src/main.rs | 37 ++---
> 7 files changed, 138 insertions(+), 72 deletions(-)
> create mode 100644 host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd
> create mode 100644 host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd.license
>
> diff --git a/host/rootfs/file-list.mk b/host/rootfs/file-list.mk
> index df22bce..5a043b7 100644
> --- a/host/rootfs/file-list.mk
> +++ b/host/rootfs/file-list.mk
> @@ -28,6 +28,7 @@ FILES = \
> image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/notification-fd \
> image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/dbus/run \
> image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/down \
> + image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd \
> image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run \
> image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/notification-fd \
> image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/vhost-user-fs/run \
> diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd
> new file mode 100644
> index 0000000..7ed6ff8
> --- /dev/null
> +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd
> @@ -0,0 +1 @@
> +5
> diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd.license b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd.license
> new file mode 100644
> index 0000000..0d3d47c
> --- /dev/null
> +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/notification-fd.license
> @@ -0,0 +1,2 @@
> +SPDX-License-Identifier: CC0-1.0
> +SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
> diff --git a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run
> index 3ba35de..61375ca 100755
> --- a/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run
> +++ b/host/rootfs/image/etc/s6-linux-init/run-image/service/vm-services/template/data/service/spectrum-router/run
> @@ -1,14 +1,30 @@
> #!/bin/execlineb -P
> # SPDX-License-Identifier: EUPL-1.2+
> # SPDX-FileCopyrightText: 2025 Yureka Lilian <yureka@cyberchaos.dev>
> +# SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
>
> importas -i VM VM
>
> +s6-ipcserver-socketbinder -a 0770 /run/vm/by-id/${VM}/router-driver.sock
> +fdmove -c 3 0
> +
> +s6-ipcserver-socketbinder -a 0770 /run/vm/by-id/${VM}/router-app.sock
> +fdmove -c 4 0
> +
> +# Notify readiness.
> +if {
> + fdmove -c 5 1
> + echo
> +}
> +
> +redirfd -r 0 /dev/null
> +
> bwrap
> --unshare-all
> --unshare-user
> --dev-bind / /
> --setenv RUST_LOG spectrum-router=debug,info
> + --setenv LISTEN_FDS 2
> --tmpfs /tmp
> --dev /dev
> --tmpfs /dev/shm
> @@ -19,6 +35,9 @@ bwrap
> --ro-bind /lib /lib
> --bind /run/vm/by-id/${VM} /run/vm/by-id/${VM}
> --
> +
> +getpid LISTEN_PID
> +
> spectrum-router
> --app-listen-path /run/vm/by-id/${VM}/router-app.sock
> --driver-listen-path /run/vm/by-id/${VM}/router-driver.sock
> diff --git a/tools/router/Cargo.lock b/tools/router/Cargo.lock
> index 60d7657..d0d105a 100644
> --- a/tools/router/Cargo.lock
> +++ b/tools/router/Cargo.lock
> @@ -113,6 +113,12 @@ dependencies = [
> "wyz",
> ]
>
> +[[package]]
> +name = "bumpalo"
> +version = "3.19.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
> +
> [[package]]
> name = "bytes"
> version = "1.11.0"
> @@ -120,44 +126,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
> checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
>
> [[package]]
> -name = "clap"
> -version = "4.5.53"
> +name = "cfg-if"
> +version = "1.0.4"
> source = "registry+https://github.com/rust-lang/crates.io-index"
> -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
> -dependencies = [
> - "clap_builder",
> - "clap_derive",
> -]
> -
> -[[package]]
> -name = "clap_builder"
> -version = "4.5.53"
> -source = "registry+https://github.com/rust-lang/crates.io-index"
> -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
> -dependencies = [
> - "anstream",
> - "anstyle",
> - "clap_lex",
> - "strsim",
> -]
> -
> -[[package]]
> -name = "clap_derive"
> -version = "4.5.49"
> -source = "registry+https://github.com/rust-lang/crates.io-index"
> -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
> -dependencies = [
> - "heck",
> - "proc-macro2",
> - "quote",
> - "syn",
> -]
> -
> -[[package]]
> -name = "clap_lex"
> -version = "0.7.6"
> -source = "registry+https://github.com/rust-lang/crates.io-index"
> -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
> +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
>
> [[package]]
> name = "colorchoice"
> @@ -263,12 +235,6 @@ dependencies = [
> "slab",
> ]
>
> -[[package]]
> -name = "heck"
> -version = "0.5.0"
> -source = "registry+https://github.com/rust-lang/crates.io-index"
> -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
> -
> [[package]]
> name = "is_terminal_polyfill"
> version = "1.70.2"
> @@ -299,12 +265,33 @@ dependencies = [
> "syn",
> ]
>
> +[[package]]
> +name = "js-sys"
> +version = "0.3.83"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
> +dependencies = [
> + "once_cell",
> + "wasm-bindgen",
> +]
> +
> [[package]]
> name = "libc"
> version = "0.2.177"
> source = "registry+https://github.com/rust-lang/crates.io-index"
> checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
>
> +[[package]]
> +name = "listenfd"
> +version = "1.0.2"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b87bc54a4629b4294d0b3ef041b64c40c611097a677d9dc07b2c67739fe39dba"
> +dependencies = [
> + "libc",
> + "uuid",
> + "winapi",
> +]
> +
> [[package]]
> name = "log"
> version = "0.4.28"
> @@ -328,6 +315,12 @@ dependencies = [
> "windows-sys 0.61.2",
> ]
>
> +[[package]]
> +name = "once_cell"
> +version = "1.21.3"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
> +
> [[package]]
> name = "once_cell_polyfill"
> version = "1.70.2"
> @@ -420,6 +413,12 @@ version = "0.8.8"
> source = "registry+https://github.com/rust-lang/crates.io-index"
> checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
>
> +[[package]]
> +name = "rustversion"
> +version = "1.0.22"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
> +
> [[package]]
> name = "serde_core"
> version = "1.0.228"
> @@ -462,9 +461,9 @@ version = "0.1.0"
> dependencies = [
> "anyhow",
> "arrayvec",
> - "clap",
> "env_logger",
> "futures-util",
> + "listenfd",
> "log",
> "tokio",
> "tokio-stream",
> @@ -474,12 +473,6 @@ dependencies = [
> "zerocopy",
> ]
>
> -[[package]]
> -name = "strsim"
> -version = "0.11.1"
> -source = "registry+https://github.com/rust-lang/crates.io-index"
> -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
> -
> [[package]]
> name = "syn"
> version = "2.0.111"
> @@ -608,6 +601,16 @@ version = "0.2.2"
> source = "registry+https://github.com/rust-lang/crates.io-index"
> checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
>
> +[[package]]
> +name = "uuid"
> +version = "1.19.0"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
> +dependencies = [
> + "js-sys",
> + "wasm-bindgen",
> +]
> +
> [[package]]
> name = "vhost-device-net"
> version = "0.1.1"
> @@ -666,6 +669,51 @@ version = "0.11.1+wasi-snapshot-preview1"
> source = "registry+https://github.com/rust-lang/crates.io-index"
> checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
>
> +[[package]]
> +name = "wasm-bindgen"
> +version = "0.2.106"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
> +dependencies = [
> + "cfg-if",
> + "once_cell",
> + "rustversion",
> + "wasm-bindgen-macro",
> + "wasm-bindgen-shared",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen-macro"
> +version = "0.2.106"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
> +dependencies = [
> + "quote",
> + "wasm-bindgen-macro-support",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen-macro-support"
> +version = "0.2.106"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
> +dependencies = [
> + "bumpalo",
> + "proc-macro2",
> + "quote",
> + "syn",
> + "wasm-bindgen-shared",
> +]
> +
> +[[package]]
> +name = "wasm-bindgen-shared"
> +version = "0.2.106"
> +source = "registry+https://github.com/rust-lang/crates.io-index"
> +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
> +dependencies = [
> + "unicode-ident",
> +]
> +
> [[package]]
> name = "winapi"
> version = "0.3.9"
> diff --git a/tools/router/Cargo.toml b/tools/router/Cargo.toml
> index 0b96911..cfdf352 100644
> --- a/tools/router/Cargo.toml
> +++ b/tools/router/Cargo.toml
> @@ -8,7 +8,6 @@ edition = "2024"
>
> [dependencies]
> anyhow = "1.0.100"
> -clap = { version = "4.5.45", features = ["derive"] }
> env_logger = "0.11.8"
> log = { version = "0.4.27", features = ["release_max_level_debug"] }
> vhost-device-net = "0.1.0"
> @@ -19,3 +18,4 @@ tokio-stream = "0.1.17"
> arrayvec = "0.7.6"
> vm-memory = "0.16"
> tokio-util = "0.7.17"
> +listenfd = "1.0.2"
> diff --git a/tools/router/src/main.rs b/tools/router/src/main.rs
> index e3aca65..a96d511 100644
> --- a/tools/router/src/main.rs
> +++ b/tools/router/src/main.rs
> @@ -1,47 +1,42 @@
> // SPDX-License-Identifier: EUPL-1.2+
> // SPDX-FileCopyrightText: 2025 Yureka Lilian <yureka@cyberchaos.dev>
> +// SPDX-FileCopyrightText: 2025 Alyssa Ross <hi@alyssa.is>
>
> pub(crate) mod packet;
> pub(crate) mod protocol;
> mod router;
> mod upstream;
>
> -use std::path::PathBuf;
> -
> use packet::*;
> use router::{InterfaceId, Router};
> use upstream::Upstream;
>
> -use clap::Parser;
> +use anyhow::anyhow;
> use futures_util::{SinkExt, TryStreamExt};
> +use listenfd::ListenFd;
> use log::{error, info};
> use tokio::net::UnixListener;
> use vhost_device_net::{IncomingPacket, VhostDeviceNet};
> use vm_memory::GuestMemoryMmap;
>
> -#[derive(Parser, Debug)]
> -#[command()] //version = None, about = None, long_about = None)]
> -struct Args {
> - #[arg(long)]
> - driver_listen_path: PathBuf,
> - #[arg(long)]
> - app_listen_path: PathBuf,
> -}
> -
> fn main() -> anyhow::Result<()> {
> env_logger::init();
> - let args = Args::parse();
>
> - for path in [&args.driver_listen_path, &args.app_listen_path] {
> - let _ = std::fs::remove_file(path);
> - }
> -
> - run_router(args)
> + run_router()
> }
> #[tokio::main(flavor = "current_thread")]
> -async fn run_router(args: Args) -> anyhow::Result<()> {
> - let app_listener = UnixListener::bind(&args.app_listen_path)?;
> - let driver_listener = UnixListener::bind(&args.driver_listen_path)?;
> +async fn run_router() -> anyhow::Result<()> {
> + let mut listenfd = ListenFd::from_env();
> +
> + let Some(driver_listener) = listenfd.take_unix_listener(0)? else {
> + return Err(anyhow!("not activated with driver socket"));
> + };
> + let Some(app_listener) = listenfd.take_unix_listener(1)? else {
> + return Err(anyhow!("not activated with app socket"));
> + };
> +
> + let driver_listener = UnixListener::from_std(driver_listener)?;
> + let app_listener = UnixListener::from_std(app_listener)?;
>
> let mut router = Router::<GuestMemoryMmap>::new(InterfaceId::Upstream);
>
>
> base-commit: 04b6183cbbb624996cf848ee248be6dd719ace23

--
Sincerely,
Demi Marie Obenour (she/her/hers)

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 7253 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]