Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion phd-tests/framework/src/test_vm/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -56,6 +56,7 @@ pub struct VmConfig<'dr> {
disks: Vec<DiskRequest<'dr>>,
migration_failure: Option<MigrationFailureInjector>,
guest_hv_interface: Option<GuestHypervisorInterface>,
vsock: Option<VirtioSocket>,
}

impl<'dr> VmConfig<'dr> {
Expand All @@ -76,6 +77,7 @@ impl<'dr> VmConfig<'dr> {
disks: Vec::new(),
migration_failure: None,
guest_hv_interface: None,
vsock: None,
};

config.boot_disk(
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -218,6 +226,7 @@ impl<'dr> VmConfig<'dr> {
disks,
migration_failure,
guest_hv_interface,
vsock,
} = self;
let framework = &ctx.framework;
let bootrom_path = framework
Expand Down Expand Up @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions phd-tests/tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ mod migrate;
mod server_state_machine;
mod smoke;
mod stats;
mod vsock;
44 changes: 44 additions & 0 deletions phd-tests/tests/src/vsock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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);
cfg.cpus(4);

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) {
let mut cfg = ctx.vm_config_builder("vsock_get_cid");
cfg.vsock(GUEST_CID, PCI_DEV_NUM);
cfg.cpus(4);

let mut vm = ctx.spawn_vm(&cfg, None).await?;
vm.launch().await?;
vm.wait_to_boot().await?;

// TODO: Remove the dependency on python
if vm.run_shell_command("test -e /usr/bin/python3").await.is_err() {
phd_skip!("guest doesn't have python3 installed");
}

// We don't really want to have to deal with python in a test but this is
// an easy way to get the cid until we support custom VM test images or
// tool block devices.
const GET_CID: &str = r#"python3 -c "import struct,fcntl;f=open('/dev/vsock','rb');print(struct.unpack('I',fcntl.ioctl(f,0x7b9,bytes(4)))[0])""#;

let cid = vm.run_shell_command(GET_CID).await?.parse::<u64>()?;
assert_eq!(cid, GUEST_CID, "guest cid matches what was configured");
}