diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c7abd4007f..7c74fddd21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -271,6 +271,8 @@ jobs: if: matrix.arch == 'x86_64' - run: cargo clean working-directory: . + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package vsock qemu ${{ matrix.qemu_flags }} --sudo --devices virtio-vsock-pci + if: matrix.arch != 'riscv64' && matrix.arch != 'aarch64_be' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package httpd --features ci,hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.qemu_flags }} --devices virtio-net-pci if: matrix.arch != 'riscv64' # FIXME: this is broken on QEMU 8.2.2 diff --git a/Cargo.lock b/Cargo.lock index 83c0cfa89e..a75ff359ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,6 +313,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.44" @@ -1067,7 +1073,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1ccb0bdc9cefc5772ebc23d9bd94aabf408ab6753735f1936ac6ed7e714c8c6" dependencies = [ "cfg-if", - "nix", + "nix 0.28.0", ] [[package]] @@ -1213,6 +1219,15 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + [[package]] name = "memory_addresses" version = "0.2.3" @@ -1249,10 +1264,23 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.11.0", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "libc", ] +[[package]] +name = "nix" +version = "0.31.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", + "memoffset", +] + [[package]] name = "nom" version = "7.1.3" @@ -2148,6 +2176,16 @@ dependencies = [ "syn", ] +[[package]] +name = "vsock" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b82aeb12ad864eb8cd26a6c21175d0bdc66d398584ee6c93c76964c3bcfc78ff" +dependencies = [ + "libc", + "nix 0.31.2", +] + [[package]] name = "wait-timeout" version = "0.2.1" @@ -2512,6 +2550,7 @@ dependencies = [ "ovmf-prebuilt", "sysinfo", "ureq", + "vsock", "wait-timeout", "xshell", ] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 3965e1cee7..d0e3a59379 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [features] default = ["ci"] -ci = ["dep:ovmf-prebuilt", "dep:sysinfo", "dep:ureq", "dep:wait-timeout"] +ci = ["dep:ovmf-prebuilt", "dep:sysinfo", "dep:ureq", "dep:vsock", "dep:wait-timeout"] [dependencies] anyhow = "1.0" @@ -15,5 +15,6 @@ home = "0.5" ovmf-prebuilt = { version = "0.2", optional = true } sysinfo = { version = "0.38", optional = true } ureq = { version = "3", default-features = false, features = ["rustls"], optional = true } +vsock = { version = "0.5", optional = true } wait-timeout = { version = "0.2", optional = true } xshell = "0.2" diff --git a/xtask/src/ci/qemu.rs b/xtask/src/ci/qemu.rs index 17bc6284dd..1dc119c621 100644 --- a/xtask/src/ci/qemu.rs +++ b/xtask/src/ci/qemu.rs @@ -9,6 +9,7 @@ use std::{env, fs, thread}; use anyhow::{Context, Result, bail, ensure}; use clap::{Args, ValueEnum}; use sysinfo::{CpuRefreshKind, System}; +use vsock::VsockStream; use wait_timeout::ChildExt; use xshell::cmd; @@ -79,6 +80,12 @@ pub enum Device { /// virtio-net via PCI. VirtioNetPci, + + /// virtio-vsock via MMIO. + VirtioVsockMmio, + + /// virtio-vsock via PCI. + VirtioVsockPci, } impl Qemu { @@ -152,12 +159,13 @@ impl Qemu { "mioudp" => test_mioudp(guest_ip)?, "poll" => test_poll(guest_ip)?, "stdin" => test_stdin(&mut qemu.0)?, + "vsock" => test_vsock()?, _ => {} } if matches!( image_name, - "axum-example" | "http_server" | "http_server_poll" | "http_server_select" + "axum-example" | "http_server" | "http_server_poll" | "http_server_select" | "vsock" ) || self.devices.contains(&Device::CadenceGem) // sifive_u, on which we test CadenceGem, does not support software shutdowns, so we have to kill the machine ourselves. { @@ -430,6 +438,16 @@ impl Qemu { "virtconsole,chardev=char0".to_owned(), ] } + device @ (Device::VirtioVsockMmio | Device::VirtioVsockPci) => { + let device_arg = match device { + Device::VirtioVsockMmio => "vhost-vsock-device", + Device::VirtioVsockPci => "vhost-vsock-pci,disable-legacy=on", + _ => unreachable!(), + }; + let device_arg = format!("{device_arg},guest-cid=3"); + + vec!["-device".to_owned(), device_arg] + } }) .collect() } @@ -545,6 +563,26 @@ fn test_stdin(child: &mut Child) -> Result<()> { Ok(()) } +fn test_vsock() -> Result<()> { + thread::sleep(Duration::from_secs(10)); + let messages = ["Hello, there!", "Hello, again!", "Bye-bye!"]; + + let mut stream = VsockStream::connect_with_cid_port(3, 9975)?; + for message in messages { + writeln!(&mut stream, "{message}")?; + thread::sleep(Duration::from_secs(1)); + } + + const BUF_SIZE: usize = 8 * 1024; + let mut buf = vec![0; BUF_SIZE]; + let n = stream.read(&mut buf)?; + let s = str::from_utf8(&buf[0..n])?; + let received_messages = s.trim().split('\n').collect::>(); + assert_eq!(received_messages, messages); + + Ok(()) +} + fn test_http_server(guest_ip: IpAddr) -> Result<()> { thread::sleep(Duration::from_secs(10)); let url = format!("http://{guest_ip}:9975");