mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
tests: Add integration test for FD-based VFIO device
This also covers the usage of pre-opened iommufd FD. Signed-off-by: Bo Chen <bchen@crusoe.ai> Assisted-by: Claude:Opus-4.7
This commit is contained in:
@@ -11128,6 +11128,8 @@ mod windows {
|
|||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
mod vfio {
|
mod vfio {
|
||||||
|
use std::io;
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
const NVIDIA_VFIO_DEVICE: &str = "/sys/bus/pci/devices/0002:00:01.0";
|
const NVIDIA_VFIO_DEVICE: &str = "/sys/bus/pci/devices/0002:00:01.0";
|
||||||
@@ -11393,6 +11395,92 @@ mod vfio {
|
|||||||
test_nvidia_card_reboot_common(true);
|
test_nvidia_card_reboot_common(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass the NVIDIA card to the guest via an externally-opened
|
||||||
|
// /dev/vfio/devices/<n> FD instead of a sysfs path, and verify it
|
||||||
|
// survives a guest reboot. Mirrors `_test_tap_from_fd` for VFIO.
|
||||||
|
#[test]
|
||||||
|
fn test_iommufd_nvidia_card_reboot_from_fd() {
|
||||||
|
let disk_config = UbuntuDiskConfig::new(JAMMY_VFIO_IMAGE_NAME.to_string());
|
||||||
|
let guest = Guest::new(Box::new(disk_config));
|
||||||
|
let api_socket = temp_api_path(&guest.tmp_dir);
|
||||||
|
|
||||||
|
// Discover the cdev for the NVIDIA card. The directory has a
|
||||||
|
// single entry whose name (e.g. "vfio0") is also the basename
|
||||||
|
// of the corresponding /dev/vfio/devices/<n> node.
|
||||||
|
let vfio_dev_dir = format!("{NVIDIA_VFIO_DEVICE}/vfio-dev");
|
||||||
|
let cdev_name = fs::read_dir(&vfio_dev_dir)
|
||||||
|
.unwrap_or_else(|e| panic!("read_dir({vfio_dev_dir}) failed: {e}"))
|
||||||
|
.next()
|
||||||
|
.expect("no vfio-dev entry")
|
||||||
|
.unwrap()
|
||||||
|
.file_name();
|
||||||
|
let cdev_path = PathBuf::from("/dev/vfio/devices").join(&cdev_name);
|
||||||
|
|
||||||
|
let cdev_file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.open(&cdev_path)
|
||||||
|
.unwrap_or_else(|e| panic!("open({cdev_path:?}) failed: {e}"));
|
||||||
|
let iommufd_file = OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.write(true)
|
||||||
|
.open("/dev/iommu")
|
||||||
|
.unwrap_or_else(|e| panic!("open(/dev/iommu) failed: {e}"));
|
||||||
|
// OpenOptions sets FD_CLOEXEC by default; clear it for both fds
|
||||||
|
// so they're inherited by the VMM child via spawn().
|
||||||
|
for f in [&cdev_file, &iommufd_file] {
|
||||||
|
// SAFETY: FFI call to fcntl on a valid fd we own.
|
||||||
|
let ret = unsafe { libc::fcntl(f.as_raw_fd(), libc::F_SETFD, 0) };
|
||||||
|
assert!(
|
||||||
|
ret >= 0,
|
||||||
|
"fcntl(F_SETFD, 0) failed: {}",
|
||||||
|
io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let platform = format!(
|
||||||
|
"{},iommufd_fd={}",
|
||||||
|
platform_cfg(true),
|
||||||
|
iommufd_file.as_raw_fd()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut child = GuestCommand::new(&guest)
|
||||||
|
.args(["--cpus", "boot=4"])
|
||||||
|
.args(["--memory", "size=1G"])
|
||||||
|
.args(["--platform", &platform])
|
||||||
|
.args(["--kernel", fw_path(FwType::RustHypervisorFirmware).as_str()])
|
||||||
|
.args([
|
||||||
|
"--device",
|
||||||
|
format!("fd={},iommu=on", cdev_file.as_raw_fd()).as_str(),
|
||||||
|
])
|
||||||
|
.args(["--api-socket", &api_socket])
|
||||||
|
.default_disks()
|
||||||
|
.default_net()
|
||||||
|
.capture_output()
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
guest.wait_vm_boot().unwrap();
|
||||||
|
|
||||||
|
// VFIO device works after boot from an externally-opened FD.
|
||||||
|
assert!(guest.check_nvidia_gpu());
|
||||||
|
|
||||||
|
guest.reboot_linux(0);
|
||||||
|
|
||||||
|
// Both FDs survive a VM reboot
|
||||||
|
assert!(guest.check_nvidia_gpu());
|
||||||
|
});
|
||||||
|
|
||||||
|
drop(cdev_file);
|
||||||
|
drop(iommufd_file);
|
||||||
|
|
||||||
|
let _ = child.kill();
|
||||||
|
let output = child.wait_with_output().unwrap();
|
||||||
|
|
||||||
|
handle_child_output(r, &output);
|
||||||
|
}
|
||||||
|
|
||||||
fn test_nvidia_card_iommu_address_width_common(iommufd: bool) {
|
fn test_nvidia_card_iommu_address_width_common(iommufd: bool) {
|
||||||
let disk_config = UbuntuDiskConfig::new(JAMMY_VFIO_IMAGE_NAME.to_string());
|
let disk_config = UbuntuDiskConfig::new(JAMMY_VFIO_IMAGE_NAME.to_string());
|
||||||
let guest = Guest::new(Box::new(disk_config));
|
let guest = Guest::new(Box::new(disk_config));
|
||||||
|
|||||||
Reference in New Issue
Block a user