[PATCH v3 1/3] tools/router: use socket activation
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. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v3: • use anyhow::bail • set sockets to non-blocking in router v2: https://spectrum-os.org/lists/archives/spectrum-devel/20251209110503.674499-... host/rootfs/file-list.mk | 1 + .../service/spectrum-router/notification-fd | 1 + .../spectrum-router/notification-fd.license | 2 + .../template/data/service/spectrum-router/run | 21 ++- tools/router/Cargo.lock | 148 ++++++++++++------ tools/router/Cargo.toml | 2 +- tools/router/src/main.rs | 40 +++-- 7 files changed, 141 insertions(+), 74 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 df22bce8..5a043b7b 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 00000000..7ed6ff82 --- /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 00000000..0d3d47ca --- /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 3ba35def..dc1ef900 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,7 @@ 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 60d7657b..d0d105aa 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 0b969113..cfdf3527 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 e3aca65a..3b26ddb0 100644 --- a/tools/router/src/main.rs +++ b/tools/router/src/main.rs @@ -1,47 +1,45 @@ // 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::bail; 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 { + bail!("not activated with driver socket"); + }; + let Some(app_listener) = listenfd.take_unix_listener(1)? else { + bail!("not activated with app socket"); + }; + + driver_listener.set_nonblocking(true)?; + app_listener.set_nonblocking(true)?; + + let driver_listener = UnixListener::from_std(driver_listener)?; + let app_listener = UnixListener::from_std(app_listener)?; let mut router = Router::<GuestMemoryMmap>::new(InterfaceId::Upstream); -- 2.51.0
When we have different Cloud Hypervisor instances running as different users, it makes sense not to permit them to see into each other's /run/vm directories. That means we'll need somewhere else to store router app sockets, which should be accessible by VMs other than the driver VM associated with the router. Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v3: no change host/rootfs/Makefile | 1 + .../template/data/service/spectrum-router/run | 2 +- tools/start-vmm/lib.rs | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 7bec1259..831fdc10 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -14,6 +14,7 @@ DIRS = \ dev \ etc/s6-linux-init/env \ etc/s6-linux-init/run-image/configs \ + etc/s6-linux-init/run-image/router \ etc/s6-linux-init/run-image/sd-notify-wrapper \ etc/s6-linux-init/run-image/service/serial-getty/instance \ etc/s6-linux-init/run-image/service/serial-getty/instances \ 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 dc1ef900..ec26b76f 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 @@ -8,7 +8,7 @@ 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 +s6-ipcserver-socketbinder -a 0770 /run/router/${VM} fdmove -c 4 0 # Notify readiness. diff --git a/tools/start-vmm/lib.rs b/tools/start-vmm/lib.rs index b44e0375..2ee87bd9 100644 --- a/tools/start-vmm/lib.rs +++ b/tools/start-vmm/lib.rs @@ -1,5 +1,5 @@ // SPDX-License-Identifier: EUPL-1.2+ -// SPDX-FileCopyrightText: 2022-2024 Alyssa Ross <hi@alyssa.is> +// SPDX-FileCopyrightText: 2022-2025 Alyssa Ross <hi@alyssa.is> // SPDX-FileCopyrightText: 2025 Yureka Lilian <yureka@cyberchaos.dev> mod ch; @@ -117,6 +117,16 @@ pub fn vm_config(vm_dir: &Path) -> Result<VmConfig, String> { )); } + let provider_path = Path::new("/run/vm/by-name").join(&provider_name); + let provider_target = provider_path + .read_link() + .map_err(|e| format!("dereferencing {provider_path:?}: {e}"))?; + let provider_id = provider_target + .file_name() + .ok_or_else(|| format!("{provider_path:?} target has no file name"))? + .to_str() + .ok_or_else(|| format!("{provider_target:?} has non-UTF-8 basename"))?; + let mut hasher = std::hash::DefaultHasher::new(); vm_name.hash(&mut hasher); let id_hashed = hasher.finish(); @@ -132,7 +142,7 @@ pub fn vm_config(vm_dir: &Path) -> Result<VmConfig, String> { Ok(NetConfig { vhost_user: true, - vhost_socket: format!("/run/vm/by-name/{provider_name}/router-app.sock"), + vhost_socket: format!("/run/router/{provider_id}"), id: provider_name, mac, }) -- 2.51.0
This patch has been committed as b30db1e510f2890449c7983c56c04ef520a0fd8c, which can be viewed online at https://spectrum-os.org/git/spectrum/commit/?id=b30db1e510f2890449c7983c56c0.... This is an automated message. Send comments/questions/requests to: Alyssa Ross <hi@alyssa.is>
Signed-off-by: Alyssa Ross <hi@alyssa.is> --- v3: no change host/rootfs/image/etc/group | 1 + host/rootfs/image/etc/passwd | 1 + .../vm-services/template/data/service/spectrum-router/run | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/host/rootfs/image/etc/group b/host/rootfs/image/etc/group index e3ade468..299ea68a 100644 --- a/host/rootfs/image/etc/group +++ b/host/rootfs/image/etc/group @@ -13,3 +13,4 @@ disk:x:11: cdrom:x:12: tape:x:13: kvm:x:14: +router:x:15:router diff --git a/host/rootfs/image/etc/passwd b/host/rootfs/image/etc/passwd index 29f3b252..8c579ce8 100644 --- a/host/rootfs/image/etc/passwd +++ b/host/rootfs/image/etc/passwd @@ -1 +1,2 @@ root:x:0:0:System administrator:/:/bin/sh +router:x:15:15::/:/bin/nologin 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 ec26b76f..2c6626e3 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 @@ -11,13 +11,15 @@ fdmove -c 3 0 s6-ipcserver-socketbinder -a 0770 /run/router/${VM} fdmove -c 4 0 +redirfd -r 0 /dev/null + # Notify readiness. if { fdmove -c 5 1 echo } -redirfd -r 0 /dev/null +s6-setuidgid router bwrap --unshare-all -- 2.51.0
This patch has been committed as f30ad35eaf6df9ed8056abde360128a8f97d9f99, which can be viewed online at https://spectrum-os.org/git/spectrum/commit/?id=f30ad35eaf6df9ed8056abde3601.... This is an automated message. Send comments/questions/requests to: Alyssa Ross <hi@alyssa.is>
This patch has been committed as a3a2c018f5f335f81bb60a913be36106c35b11ae, which can be viewed online at https://spectrum-os.org/git/spectrum/commit/?id=a3a2c018f5f335f81bb60a913be3.... This is an automated message. Send comments/questions/requests to: Alyssa Ross <hi@alyssa.is>
participants (2)
-
Alyssa Ross -
Alyssa Ross