Skip to content

Commit 92baf12

Browse files
JocelynBerrendonnersprt
authored andcommitted
openvmm: add cold-plug VFIO PCI pass-through support
Cold-plug VFIO devices (GPUs, NVSwitches, InfiniBand VFs) are now wired into the OpenVMM Config before launch: - Reserve 16 PCIe root ports named vfio0..vfio15 with hotplug=false in the root complex. - In start_vm, process pending DeviceType::Vfio by opening /dev/vfio/<group>, building a VfioDeviceHandle { pci_id, group } per HostDevice in the IOMMU group, and pushing a PcieDeviceConfig on a pre-reserved port. - Reject post-launch VFIO add_device with an explicit cold-plug-only error. - Add vfio_assigned_device_resources git dep at the existing openvmm rev.
1 parent 8b161e8 commit 92baf12

5 files changed

Lines changed: 94 additions & 0 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ virtio_resources = { git = "https://github.com/microsoft/openvmm", rev = "14ad21
118118
vm_resource = { git = "https://github.com/microsoft/openvmm", rev = "14ad213b739a2ca7976f00ea090b475ceddd4592" }
119119
disk_backend_resources = { git = "https://github.com/microsoft/openvmm", rev = "14ad213b739a2ca7976f00ea090b475ceddd4592" }
120120
disk_blockdevice = { git = "https://github.com/microsoft/openvmm", rev = "14ad213b739a2ca7976f00ea090b475ceddd4592" }
121+
vfio_assigned_device_resources = { git = "https://github.com/microsoft/openvmm", rev = "14ad213b739a2ca7976f00ea090b475ceddd4592" }
121122
ovmm_vmm_core_defs = { git = "https://github.com/microsoft/openvmm", rev = "14ad213b739a2ca7976f00ea090b475ceddd4592", package = "vmm_core_defs" }
122123
ovmm_guid = { git = "https://github.com/microsoft/openvmm", rev = "14ad213b739a2ca7976f00ea090b475ceddd4592", package = "guid" }
123124
ovmm_memory_range = { git = "https://github.com/microsoft/openvmm", rev = "14ad213b739a2ca7976f00ea090b475ceddd4592", package = "memory_range" }

src/runtime-rs/crates/hypervisor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ virtio_resources = { workspace = true, optional = true }
8888
vm_resource = { workspace = true, optional = true }
8989
disk_backend_resources = { workspace = true, optional = true }
9090
disk_blockdevice = { workspace = true, optional = true }
91+
vfio_assigned_device_resources = { workspace = true, optional = true }
9192
ovmm_vmm_core_defs = { workspace = true, optional = true }
9293
ovmm_guid = { workspace = true, optional = true }
9394
ovmm_memory_range = { workspace = true, optional = true }
@@ -123,6 +124,7 @@ openvmm = [
123124
"dep:vm_resource",
124125
"dep:disk_backend_resources",
125126
"dep:disk_blockdevice",
127+
"dep:vfio_assigned_device_resources",
126128
"dep:ovmm_vmm_core_defs",
127129
"dep:ovmm_guid",
128130
"dep:ovmm_memory_range",

src/runtime-rs/crates/hypervisor/src/openvmm/inner_device.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ impl OpenVmmInner {
117117
Ok(DeviceType::Block(block))
118118
}
119119
other => {
120+
if matches!(other, DeviceType::Vfio(_)) {
121+
return Err(anyhow!(
122+
"openvmm: VFIO devices are cold-plug only and must be \
123+
added before start_vm; got {} after VMM start",
124+
other
125+
));
126+
}
120127
warn!(sl!(), "openvmm: add_device stub for {}", other);
121128
Ok(other)
122129
}

src/runtime-rs/crates/hypervisor/src/openvmm/inner_hypervisor.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use super::vmm_instance::DeferredNetworkDevice;
1616
use super::{
1717
OPENVMM_BLOCK_HOTPLUG_PORT_COUNT, OPENVMM_BLOCK_HOTPLUG_PORT_PREFIX, OPENVMM_CONSOLE_PCI_PORT,
1818
OPENVMM_NET_PCI_PORT, OPENVMM_ROOTFS_PCI_PORT, OPENVMM_SHAREFS_PCI_PORT,
19+
OPENVMM_VFIO_COLDPLUG_PORT_COUNT, OPENVMM_VFIO_COLDPLUG_PORT_PREFIX,
1920
};
2021
use crate::kernel_param::KernelParams;
2122
use crate::utils::{get_jailer_root, get_sandbox_path};
@@ -194,6 +195,17 @@ impl OpenVmmInner {
194195
});
195196
}
196197

198+
// Cold-plug ports for VFIO PCI pass-through (GPUs, NVSwitches,
199+
// InfiniBand VFs). These are always created so the OpenVMM
200+
// root-complex layout is stable; unused ones simply appear
201+
// empty in the guest.
202+
for index in 0..OPENVMM_VFIO_COLDPLUG_PORT_COUNT {
203+
ports.push(PcieRootPortConfig {
204+
name: format!("{}{}", OPENVMM_VFIO_COLDPLUG_PORT_PREFIX, index),
205+
hotplug: false,
206+
});
207+
}
208+
197209
ports
198210
},
199211
}];
@@ -221,6 +233,7 @@ impl OpenVmmInner {
221233
Vec::new();
222234
let mut deferred_block_devices = Vec::new();
223235
let mut deferred_network_devices = Vec::new();
236+
let mut next_vfio_port: u8 = 0;
224237

225238
for dev in &pending {
226239
match dev {
@@ -338,6 +351,72 @@ impl OpenVmmInner {
338351
deferred_block_devices.push(dev.clone());
339352
}
340353
}
354+
crate::DeviceType::Vfio(vfio_dev) => {
355+
// Cold-plug VFIO PCI pass-through. Each HostDevice in the
356+
// IOMMU group becomes its own PcieDeviceConfig on a
357+
// pre-reserved root port. The /dev/vfio/<group> fd is
358+
// opened here (one open per device, which the kernel
359+
// allows for the same group).
360+
let host_path = &vfio_dev.config.host_path;
361+
info!(
362+
sl!(),
363+
"openvmm: cold-plug VFIO group {} ({} device(s))",
364+
host_path,
365+
vfio_dev.devices.len()
366+
);
367+
368+
for hostdev in &vfio_dev.devices {
369+
if hostdev.bus_slot_func.is_empty() {
370+
warn!(
371+
sl!(),
372+
"openvmm: skipping VFIO device with empty BDF in group {}",
373+
host_path
374+
);
375+
continue;
376+
}
377+
378+
if next_vfio_port >= OPENVMM_VFIO_COLDPLUG_PORT_COUNT {
379+
return Err(anyhow!(
380+
"openvmm: too many VFIO devices (limit {}), cannot cold-plug BDF {}",
381+
OPENVMM_VFIO_COLDPLUG_PORT_COUNT,
382+
hostdev.bus_slot_func
383+
));
384+
}
385+
386+
let group_fd = std::fs::OpenOptions::new()
387+
.read(true)
388+
.write(true)
389+
.open(host_path)
390+
.with_context(|| {
391+
format!(
392+
"openvmm: failed to open VFIO group {} for BDF {}",
393+
host_path, hostdev.bus_slot_func
394+
)
395+
})?;
396+
397+
let port_name = format!(
398+
"{}{}",
399+
OPENVMM_VFIO_COLDPLUG_PORT_PREFIX, next_vfio_port
400+
);
401+
next_vfio_port += 1;
402+
403+
info!(
404+
sl!(),
405+
"openvmm: assigning VFIO BDF {} to port {}",
406+
hostdev.bus_slot_func,
407+
port_name
408+
);
409+
410+
pcie_devices.push(PcieDeviceConfig {
411+
port_name,
412+
resource: vfio_assigned_device_resources::VfioDeviceHandle {
413+
pci_id: hostdev.bus_slot_func.clone(),
414+
group: group_fd,
415+
}
416+
.into_resource(),
417+
});
418+
}
419+
}
341420
other => {
342421
warn!(sl!(), "openvmm: unsupported pending device type: {}", other);
343422
}

src/runtime-rs/crates/hypervisor/src/openvmm/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ pub(crate) const OPENVMM_CONSOLE_PCI_PORT: &str = "rp4";
3838
pub(crate) const OPENVMM_STATIC_PCI_PORT_COUNT: u8 = 5;
3939
pub(crate) const OPENVMM_BLOCK_HOTPLUG_PORT_PREFIX: &str = "hp";
4040
pub(crate) const OPENVMM_BLOCK_HOTPLUG_PORT_COUNT: u8 = 24;
41+
/// Number of pre-reserved PCIe root ports for cold-plug VFIO pass-through
42+
/// devices (e.g., GPUs, NVSwitches). These ports are created with
43+
/// `hotplug: false` so the guest sees the assigned devices at boot.
44+
pub(crate) const OPENVMM_VFIO_COLDPLUG_PORT_PREFIX: &str = "vfio";
45+
pub(crate) const OPENVMM_VFIO_COLDPLUG_PORT_COUNT: u8 = 16;
4146

4247
/// The OpenVMM hypervisor struct, wrapping inner state behind a lock.
4348
pub struct OpenVmm {

0 commit comments

Comments
 (0)