diff --git a/cloud-hypervisor/src/main.rs b/cloud-hypervisor/src/main.rs index a607309f8..055d64981 100644 --- a/cloud-hypervisor/src/main.rs +++ b/cloud-hypervisor/src/main.rs @@ -34,7 +34,7 @@ use vmm::vm_config::IvshmemConfig; use vmm::vm_config::{ BalloonConfig, DeviceConfig, DiskConfig, FsConfig, GenericVhostUserConfig, LandlockConfig, NetConfig, NumaConfig, PciSegmentConfig, PlatformConfig, PmemConfig, RateLimiterGroupConfig, - TpmConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, + RngConfig, TpmConfig, UserDeviceConfig, VdpaConfig, VmConfig, VsockConfig, }; use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::signal::block_signal; @@ -174,7 +174,7 @@ fn default_memory() -> String { } fn default_rng() -> String { - format!("src={}", vm_config::DEFAULT_RNG_SOURCE) + format!("src={}", RngConfig::DEFAULT_RNG_SOURCE) } /// Returns all [`Arg`]s in alphabetical order. This is the order used in the @@ -426,7 +426,7 @@ fn get_cli_options_sorted( .group("vmm-config"), Arg::new("rng") .long("rng") - .help("Random number generator parameters \"src=,iommu=on|off\"") + .help(RngConfig::SYNTAX) .default_value(default_rng) .group("vm-config"), Arg::new("seccomp") @@ -953,7 +953,7 @@ mod unit_tests { use vmm::vm_config::DebugConsoleConfig; use vmm::vm_config::{ ConsoleConfig, ConsoleOutputMode, CoreScheduling, CpuFeatures, CpusConfig, HotplugMethod, - MemoryConfig, PayloadConfig, RngConfig, VmConfig, + MemoryConfig, PayloadConfig, PciDeviceCommonConfig, RngConfig, VmConfig, }; use crate::test_util::assert_args_sorted; @@ -1036,7 +1036,7 @@ mod unit_tests { net: None, rng: RngConfig { src: PathBuf::from("/dev/urandom"), - iommu: false, + pci_common: PciDeviceCommonConfig::default(), }, balloon: None, fs: None, diff --git a/fuzz/fuzz_targets/http_api.rs b/fuzz/fuzz_targets/http_api.rs index b7128a167..79b8fe215 100644 --- a/fuzz/fuzz_targets/http_api.rs +++ b/fuzz/fuzz_targets/http_api.rs @@ -165,7 +165,7 @@ impl RequestHandler for StubApiRequestHandler { net: None, rng: RngConfig { src: PathBuf::from("/dev/urandom"), - iommu: false, + pci_common: PciDeviceCommonConfig::default(), }, balloon: None, fs: None, diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index f7428cf77..2637e1580 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -1073,11 +1073,19 @@ components: - src type: object properties: - src: + id: type: string + pci_segment: + type: integer + format: int16 + pci_device_id: + type: integer + format: uint8 iommu: type: boolean default: false + src: + type: string BalloonConfig: required: diff --git a/vmm/src/config.rs b/vmm/src/config.rs index fedf8882b..b3a35c8f8 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -1750,23 +1750,30 @@ impl NetConfig { } impl RngConfig { + pub const SYNTAX: &'static str = "Random number generator parameters \"\ + src=,iommu=on|off,pci_segment=,\ + pci_device_id=\""; + pub fn parse(rng: &str) -> Result { let mut parser = OptionParser::new(); - parser.add("src").add("iommu"); + parser + .add("src") + .add_all(PciDeviceCommonConfig::OPTIONS_IOMMU); parser.parse(rng).map_err(Error::ParseRng)?; let src = PathBuf::from( parser .get("src") - .unwrap_or_else(|| DEFAULT_RNG_SOURCE.to_owned()), + .unwrap_or_else(|| Self::DEFAULT_RNG_SOURCE.to_owned()), ); - let iommu = parser - .convert::("iommu") - .map_err(Error::ParseRng)? - .unwrap_or(Toggle(false)) - .0; - Ok(RngConfig { src, iommu }) + let pci_common = PciDeviceCommonConfig::parse(rng)?; + + Ok(RngConfig { src, pci_common }) + } + + pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> { + self.pci_common.validate(vm_config) } } @@ -2972,6 +2979,8 @@ impl VmConfig { } } + self.rng.validate(self)?; + if let Some(nets) = &self.net { for net in nets { if net.vhost_user && !self.backed_by_shared_memory() { @@ -3018,7 +3027,7 @@ impl VmConfig { } } - self.iommu |= self.rng.iommu; + self.iommu |= self.rng.pci_common.iommu; self.iommu |= self.console.iommu; if let Some(t) = &self.cpus.topology { @@ -4184,16 +4193,26 @@ mod unit_tests { } ); assert_eq!( - RngConfig::parse("src=/dev/random,iommu=on")?, + RngConfig::parse("src=/dev/random,iommu=on,pci_segment=1,pci_device_id=7")?, RngConfig { src: PathBuf::from("/dev/random"), - iommu: true, + pci_common: PciDeviceCommonConfig { + id: None, + iommu: true, + pci_segment: 1, + pci_device_id: Some(7), + }, } ); assert_eq!( RngConfig::parse("iommu=on")?, RngConfig { - iommu: true, + pci_common: PciDeviceCommonConfig { + id: None, + iommu: true, + pci_segment: 0, + pci_device_id: None, + }, ..Default::default() } ); @@ -5010,7 +5029,7 @@ id=\"{id}\",pci_segment={pci_segment},queue_sizes={queue_sizes}" net: None, rng: RngConfig { src: PathBuf::from("/dev/urandom"), - iommu: false, + pci_common: PciDeviceCommonConfig::default(), }, balloon: None, fs: None, diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 2d145fa99..83a3e64a8 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -3006,16 +3006,24 @@ impl DeviceManager { fn make_virtio_rng_devices(&mut self) -> DeviceManagerResult<()> { // Add virtio-rng if required - let rng_config = self.config.lock().unwrap().rng.clone(); + let mut rng_config = self.config.lock().unwrap().rng.clone(); if let Some(rng_path) = rng_config.src.to_str() { info!("Creating virtio-rng device: {rng_config:?}"); - let id = String::from(RNG_DEVICE_NAME); + + let id = match rng_config.pci_common.id.as_ref() { + Some(id) => id.clone(), + None => rng_config + .pci_common + .id + .insert(RNG_DEVICE_NAME.to_string()) + .clone(), + }; let virtio_rng_device = Arc::new(Mutex::new( virtio_devices::Rng::new( id.clone(), rng_path, - self.force_access_platform | rng_config.iommu, + self.force_access_platform | rng_config.pci_common.iommu, self.seccomp_action.clone(), self.exit_evt .try_clone() @@ -3028,11 +3036,7 @@ impl DeviceManager { self.virtio_devices.push(MetaVirtioDevice { virtio_device: Arc::clone(&virtio_rng_device) as Arc>, - pci_common: PciDeviceCommonConfig { - id: Some(id.clone()), - iommu: rng_config.iommu, - ..Default::default() - }, + pci_common: rng_config.pci_common.clone(), dma_handler: None, }); diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 8ae2eb4c5..5ebcf250e 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -2654,7 +2654,7 @@ mod unit_tests { use crate::vm_config::DebugConsoleConfig; use crate::vm_config::{ ConsoleConfig, ConsoleOutputMode, CoreScheduling, CpuFeatures, CpusConfig, HotplugMethod, - MemoryConfig, PayloadConfig, RngConfig, + MemoryConfig, PayloadConfig, PciDeviceCommonConfig, RngConfig, }; fn create_dummy_vmm() -> Vmm { @@ -2716,7 +2716,7 @@ mod unit_tests { net: None, rng: RngConfig { src: PathBuf::from("/dev/urandom"), - iommu: false, + pci_common: PciDeviceCommonConfig::default(), }, balloon: None, fs: None, diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index 09a78a750..349fac613 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -432,18 +432,20 @@ where #[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct RngConfig { + #[serde(flatten)] + pub pci_common: PciDeviceCommonConfig, pub src: PathBuf, - #[serde(default)] - pub iommu: bool, } -pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom"; +impl RngConfig { + pub const DEFAULT_RNG_SOURCE: &str = "/dev/urandom"; +} impl Default for RngConfig { fn default() -> Self { RngConfig { - src: PathBuf::from(DEFAULT_RNG_SOURCE), - iommu: false, + src: PathBuf::from(Self::DEFAULT_RNG_SOURCE), + pci_common: PciDeviceCommonConfig::default(), } } }