From 0d3080e036c479e7791cc201f44239f0b0686f7b Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 3 Apr 2026 11:59:42 -0700 Subject: [PATCH] vmm: config: Switch GenericVhostUserConfig to use PciDeviceCommonConfig Switch GenericVhostUserConfig 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 generic vhost-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 | 37 +++++++++++++------------------------ vmm/src/device_manager.rs | 8 ++++---- vmm/src/vm_config.rs | 6 ++---- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/vmm/src/config.rs b/vmm/src/config.rs index a447b89f3..d3aad9d93 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -1861,11 +1861,7 @@ impl GenericVhostUserConfig { } _ => {} } - let id = parser.get("id"); - let pci_segment = parser - .convert("pci_segment") - .map_err(Error::ParseGenericVhostUser)? - .unwrap_or_default(); + let pci_common = PciDeviceCommonConfig::parse(vhost_user)?; let mut converted_queue_sizes: Vec = Vec::new(); for (offset, &queue_size) in queue_sizes.iter().enumerate() { match queue_size.try_into() { @@ -1879,30 +1875,19 @@ impl GenericVhostUserConfig { } Ok(GenericVhostUserConfig { + pci_common, socket: socket.into(), device_type, - id, - pci_segment, queue_sizes: converted_queue_sizes, }) } 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) } } @@ -3054,7 +3039,7 @@ impl VmConfig { for generic_vhost_user_device in generic_vhost_user_devices { generic_vhost_user_device.validate(self)?; - Self::validate_identifier(&mut id_list, &generic_vhost_user_device.id)?; + Self::validate_identifier(&mut id_list, &generic_vhost_user_device.pci_common.id)?; } } @@ -3521,7 +3506,8 @@ impl VmConfig { // Remove if generic vhost-user device if let Some(generic_vhost_user) = self.generic_vhost_user.as_mut() { let len = generic_vhost_user.len(); - generic_vhost_user.retain(|dev| dev.id.as_ref().map(|id| id.as_ref()) != Some(id)); + generic_vhost_user + .retain(|dev| dev.pci_common.id.as_ref().map(|id| id.as_ref()) != Some(id)); removed |= generic_vhost_user.len() != len; } @@ -4292,10 +4278,13 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" assert_eq!( config.unwrap(), GenericVhostUserConfig { + pci_common: PciDeviceCommonConfig { + id: Some(id.to_owned()), + pci_segment: u16::try_from(pci_segment).unwrap(), + ..Default::default() + }, socket: socket.into(), - id: Some(id.to_owned()), device_type: u32::try_from(virtio_id).unwrap(), - pci_segment: u16::try_from(pci_segment).unwrap(), queue_sizes: queue_sizes .0 .iter() diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index c431fc756..cb3f7c0ef 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -3150,11 +3150,11 @@ impl DeviceManager { &mut self, generic_vhost_user_cfg: &mut GenericVhostUserConfig, ) -> DeviceManagerResult { - let id = if let Some(id) = &generic_vhost_user_cfg.id { + let id = if let Some(id) = &generic_vhost_user_cfg.pci_common.id { id.clone() } else { let id = self.next_device_name(GENERIC_VHOST_USER_DEVICE_NAME_PREFIX)?; - generic_vhost_user_cfg.id = Some(id.clone()); + generic_vhost_user_cfg.pci_common.id = Some(id.clone()); id }; @@ -3191,7 +3191,7 @@ impl DeviceManager { as Arc>, iommu: false, id, - pci_segment: generic_vhost_user_cfg.pci_segment, + pci_segment: generic_vhost_user_cfg.pci_common.pci_segment, dma_handler: None, }) } else { @@ -5049,7 +5049,7 @@ impl DeviceManager { &mut self, generic_vhost_user_cfg: &mut GenericVhostUserConfig, ) -> DeviceManagerResult { - self.validate_identifier(&generic_vhost_user_cfg.id)?; + self.validate_identifier(&generic_vhost_user_cfg.pci_common.id)?; let device = self.make_generic_vhost_user_device(generic_vhost_user_cfg)?; self.hotplug_virtio_pci_device(device) diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index 847a79bda..b9b660988 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -498,12 +498,10 @@ impl ApplyLandlock for FsConfig { #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct GenericVhostUserConfig { + #[serde(flatten)] + pub pci_common: PciDeviceCommonConfig, pub socket: PathBuf, pub queue_sizes: Vec, - #[serde(default)] - pub id: Option, - #[serde(default)] - pub pci_segment: u16, pub device_type: u32, }