vmm: Support device passthrough with vfio cdev and iommufd

When `--platform iommufd=on` is set, use the vfio cdev interface backed
by iommufd instead of the legacy vfio container/group interface for
device passthrough.

The cdev path opens '/dev/iommu' via IommuFd, allocates an IOAS, and
binds VFIO devices through VfioIommufd. The legacy container/group path
remains the default and is used when iommufd is not enabled.

Add iommufd-ioctls as a workspace dependency and enable the "vfio_cdev"
feature on vfio-ioctls for KVM builds.

Fixes: #6892

Signed-off-by: Bo Chen <bchen@crusoe.ai>
This commit is contained in:
Bo Chen
2026-04-09 04:50:54 +00:00
parent 13972a0edf
commit fe5f991c37
4 changed files with 62 additions and 3 deletions

View File

@@ -76,6 +76,8 @@ use event_monitor::event;
use hypervisor::IoEventAddress;
#[cfg(target_arch = "aarch64")]
use hypervisor::arch::aarch64::regs::AARCH64_PMU_IRQ;
#[cfg(feature = "kvm")]
use iommufd_ioctls::IommuFd;
use libc::{
MAP_NORESERVE, MAP_PRIVATE, MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE, TCSANOW, tcsetattr,
termios,
@@ -90,6 +92,8 @@ use seccompiler::SeccompAction;
use serde::{Deserialize, Serialize};
use thiserror::Error;
use tracer::trace_scoped;
#[cfg(feature = "kvm")]
use vfio_ioctls::VfioIommufd;
use vfio_ioctls::{VfioContainer, VfioDevice, VfioDeviceFd, VfioOps};
use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, VirtioTransport};
use virtio_devices::vhost_user::VhostUserConfig;
@@ -361,6 +365,15 @@ pub enum DeviceManagerError {
#[error("Error getting pty peer")]
GetPtyPeer(#[source] vmm_sys_util::errno::Error),
/// Cannot create iommufd
#[cfg(feature = "kvm")]
#[error("Cannot create iommufd")]
IommufdCreate(#[source] iommufd_ioctls::IommufdError),
/// iommufd is not supported
#[error("iommufd is not supported without the kvm feature")]
IommufdNotSupported,
/// Cannot create a VFIO device
#[error("Cannot create a VFIO device")]
VfioCreate(#[source] vfio_ioctls::VfioError),
@@ -3803,9 +3816,31 @@ impl DeviceManager {
.try_clone()
.map_err(DeviceManagerError::VfioCreate)?;
Ok(Arc::new(
VfioContainer::new(Some(Arc::new(dup))).map_err(DeviceManagerError::VfioCreate)?,
))
let iommufd = self
.config
.lock()
.unwrap()
.platform
.as_ref()
.is_some_and(|p| p.iommufd);
if iommufd {
#[cfg(feature = "kvm")]
{
info!("Using vfio cdev mode with iommufd.");
let iommufd = IommuFd::new().map_err(DeviceManagerError::IommufdCreate)?;
let vfio_iommufd = VfioIommufd::new(Arc::new(iommufd), None, Some(Arc::new(dup)))
.map_err(DeviceManagerError::VfioCreate)?;
Ok(Arc::new(vfio_iommufd))
}
#[cfg(not(feature = "kvm"))]
Err(DeviceManagerError::IommufdNotSupported)
} else {
info!("Using vfio legacy mode with vfio container/group.");
Ok(Arc::new(
VfioContainer::new(Some(Arc::new(dup))).map_err(DeviceManagerError::VfioCreate)?,
))
}
}
fn add_vfio_device(