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)