diff --git a/lib/propolis/src/vsock/poller.rs b/lib/propolis/src/vsock/poller.rs index 904598528..aa260def3 100644 --- a/lib/propolis/src/vsock/poller.rs +++ b/lib/propolis/src/vsock/poller.rs @@ -805,7 +805,7 @@ impl VsockGuestAddr { } #[cfg(test)] -mod tests { +mod test { use std::io::{Read, Write}; use std::net::TcpListener; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/phd-tests/framework/src/test_vm/config.rs b/phd-tests/framework/src/test_vm/config.rs index 819257de9..9412923b2 100644 --- a/phd-tests/framework/src/test_vm/config.rs +++ b/phd-tests/framework/src/test_vm/config.rs @@ -11,7 +11,7 @@ use propolis_client::{ Board, BootOrderEntry, BootSettings, Chipset, Component, Cpuid, CpuidEntry, CpuidVendor, GuestHypervisorInterface, InstanceMetadata, InstanceSpec, MigrationFailureInjector, NvmeDisk, PciPath, SerialPort, - SerialPortNumber, SpecKey, VirtioDisk, + SerialPortNumber, SpecKey, VirtioDisk, VirtioSocket, }, support::nvme_serial_from_str, }; @@ -56,6 +56,7 @@ pub struct VmConfig<'dr> { disks: Vec>, migration_failure: Option, guest_hv_interface: Option, + vsock: Option, } impl<'dr> VmConfig<'dr> { @@ -76,6 +77,7 @@ impl<'dr> VmConfig<'dr> { disks: Vec::new(), migration_failure: None, guest_hv_interface: None, + vsock: None, }; config.boot_disk( @@ -121,6 +123,12 @@ impl<'dr> VmConfig<'dr> { self } + pub fn vsock(&mut self, guest_cid: u64, pci_device_num: u8) -> &mut Self { + let pci_path = PciPath::new(0, pci_device_num, 0).unwrap(); + self.vsock = Some(VirtioSocket { guest_cid, pci_path }); + self + } + pub fn fail_migration_exports(&mut self, exports: u32) -> &mut Self { let injector = self.migration_failure.get_or_insert(MigrationFailureInjector { @@ -218,6 +226,7 @@ impl<'dr> VmConfig<'dr> { disks, migration_failure, guest_hv_interface, + vsock, } = self; let framework = &ctx.framework; let bootrom_path = framework @@ -369,6 +378,13 @@ impl<'dr> VmConfig<'dr> { assert!(_old.is_none()); } + if let Some(vsock) = vsock { + let _old = spec + .components + .insert("vsock".into(), Component::VirtioSocket(*vsock)); + assert!(_old.is_none()); + } + if let Some(mig) = migration_failure.as_ref() { let _old = spec.components.insert( "migration-failure".into(), diff --git a/phd-tests/tests/src/lib.rs b/phd-tests/tests/src/lib.rs index da2437a87..d70a4735b 100644 --- a/phd-tests/tests/src/lib.rs +++ b/phd-tests/tests/src/lib.rs @@ -15,3 +15,4 @@ mod migrate; mod server_state_machine; mod smoke; mod stats; +mod vsock; diff --git a/phd-tests/tests/src/vsock.rs b/phd-tests/tests/src/vsock.rs new file mode 100644 index 000000000..f7505ce7b --- /dev/null +++ b/phd-tests/tests/src/vsock.rs @@ -0,0 +1,44 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +use phd_testcase::*; + +const GUEST_CID: u64 = 16; +const PCI_DEV_NUM: u8 = 26; + +#[phd_testcase] +async fn vsock_smoke_test(ctx: &TestCtx) { + let mut cfg = ctx.vm_config_builder("vsock_smoke_test"); + cfg.vsock(GUEST_CID, PCI_DEV_NUM); + + let mut vm = ctx.spawn_vm(&cfg, None).await?; + vm.launch().await?; + vm.wait_to_boot().await?; + + // This doesn't tell the whole story since linux will sometimes make this + // device available even if the hypervisor does not present the virtio + // device itself. Either way, it would be an error if it's not present. + vm.run_shell_command("test -e /dev/vsock").await?; +} + +#[phd_testcase] +async fn vsock_get_cid(ctx: &TestCtx) { + const GET_CID: &str = "/usr/local/bin/getcid"; + + let mut cfg = ctx.vm_config_builder("vsock_get_cid"); + cfg.vsock(GUEST_CID, PCI_DEV_NUM); + + let mut vm = ctx.spawn_vm(&cfg, None).await?; + vm.launch().await?; + vm.wait_to_boot().await?; + + // If we are not using a modified alpine image with our additional tooling + // we should skip this test entirely. + if vm.run_shell_command(&format!("test -e {GET_CID}")).await.is_err() { + phd_skip!("guest doesn't have getcid installed"); + } + + let cid = vm.run_shell_command(GET_CID).await?.parse::()?; + assert_eq!(cid, GUEST_CID, "guest cid matches what was configured"); +}