From 2c50be4753dbdb5d8b793ca2b7708c3a9fe935c7 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 3 Apr 2026 12:11:01 -0700 Subject: [PATCH] vmm: config: Switch UserDeviceConfig to use PciDeviceCommonConfig Switch UserDeviceConfig over to using the newly extracted struct members as used by all PCI based devices. The use of #[serde(flatten)] means that this change has no impact on the JSON format that the data is stored as. As VFIO user devices do not support being placed behind an IOMMU an error is now raised if iommu is set. This can't happen via the CLI but could via the JSON/API. Signed-off-by: Rob Bradford --- vmm/src/config.rs | 38 +++++++++++--------------------------- vmm/src/device_manager.rs | 11 ++++++----- vmm/src/vm_config.rs | 6 ++---- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/vmm/src/config.rs b/vmm/src/config.rs index c2c943020..b0d0de1e4 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -2244,39 +2244,21 @@ impl UserDeviceConfig { parser.add("socket").add("id").add("pci_segment"); parser.parse(user_device).map_err(Error::ParseUserDevice)?; + let pci_common = PciDeviceCommonConfig::parse(user_device)?; let socket = parser .get("socket") .map(PathBuf::from) .ok_or(Error::ParseUserDeviceSocketMissing)?; - let id = parser.get("id"); - let pci_segment = parser - .convert::("pci_segment") - .map_err(Error::ParseUserDevice)? - .unwrap_or_default(); - Ok(UserDeviceConfig { - socket, - id, - pci_segment, - }) + Ok(UserDeviceConfig { pci_common, socket }) } pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> { - if let Some(platform_config) = vm_config.platform.as_ref() { - if self.pci_segment >= platform_config.num_pci_segments { - return Err(ValidationError::InvalidPciSegment(self.pci_segment)); - } - - if let Some(iommu_segments) = platform_config.iommu_segments.as_ref() - && iommu_segments.contains(&self.pci_segment) - { - return Err(ValidationError::IommuNotSupportedOnSegment( - self.pci_segment, - )); - } + if self.pci_common.iommu { + return Err(ValidationError::IommuNotSupported); } - Ok(()) + self.pci_common.validate(vm_config) } } @@ -3052,7 +3034,7 @@ impl VmConfig { for user_device in user_devices { user_device.validate(self)?; - Self::validate_identifier(&mut id_list, &user_device.id)?; + Self::validate_identifier(&mut id_list, &user_device.pci_common.id)?; } } @@ -3439,7 +3421,7 @@ impl VmConfig { // Remove if VFIO user device if let Some(user_devices) = self.user_devices.as_mut() { let len = user_devices.len(); - user_devices.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + user_devices.retain(|dev| dev.pci_common.id.as_ref().map(|id| id.as_ref()) != Some(id)); removed |= user_devices.len() != len; } @@ -5409,9 +5391,11 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" ..platform_fixture() }); invalid_config.user_devices = Some(vec![UserDeviceConfig { - pci_segment: 1, + pci_common: PciDeviceCommonConfig { + pci_segment: 1, + ..Default::default() + }, socket: PathBuf::new(), - id: None, }]); assert_eq!( invalid_config.validate(), diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index da03c6b55..43eb7257c 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -4120,16 +4120,16 @@ impl DeviceManager { &mut self, device_cfg: &mut UserDeviceConfig, ) -> DeviceManagerResult<(PciBdf, String)> { - let vfio_user_name = if let Some(id) = &device_cfg.id { + let vfio_user_name = if let Some(id) = &device_cfg.pci_common.id { id.clone() } else { let id = self.next_device_name(VFIO_USER_DEVICE_NAME_PREFIX)?; - device_cfg.id = Some(id.clone()); + device_cfg.pci_common.id = Some(id.clone()); id }; let (pci_segment_id, pci_device_bdf, resources) = - self.pci_resources(&vfio_user_name, device_cfg.pci_segment)?; + self.pci_resources(&vfio_user_name, device_cfg.pci_common.pci_segment)?; let legacy_interrupt_group = if let Some(legacy_interrupt_manager) = &self.legacy_interrupt_manager { @@ -4653,12 +4653,13 @@ impl DeviceManager { &mut self, device_cfg: &mut UserDeviceConfig, ) -> DeviceManagerResult { - self.validate_identifier(&device_cfg.id)?; + self.validate_identifier(&device_cfg.pci_common.id)?; let (bdf, device_name) = self.add_vfio_user_device(device_cfg)?; // Update the PCIU bitmap - self.pci_segments[device_cfg.pci_segment as usize].pci_devices_up |= 1 << bdf.device(); + self.pci_segments[device_cfg.pci_common.pci_segment as usize].pci_devices_up |= + 1 << bdf.device(); Ok(PciDeviceInfo { id: device_name, diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index f6eb8af68..6afdb8f6c 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -633,11 +633,9 @@ impl ApplyLandlock for DeviceConfig { #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct UserDeviceConfig { + #[serde(flatten)] + pub pci_common: PciDeviceCommonConfig, pub socket: PathBuf, - #[serde(default)] - pub id: Option, - #[serde(default)] - pub pci_segment: u16, } impl ApplyLandlock for UserDeviceConfig {