main, vmm: add explicit PCI BDF support for Rng device

This was missing in [0] but is required for proper explicit PCI BDF
management, e.g., when a VM is created via libvirt and each device has
an explicit BDF.

[0] https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7965

On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
This commit is contained in:
Philipp Schuster
2026-05-07 15:53:51 +02:00
committed by Rob Bradford
parent 18bbc71b59
commit bad10f3026
7 changed files with 68 additions and 35 deletions

View File

@@ -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=<entropy_source_path>,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,

View File

@@ -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,

View File

@@ -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:

View File

@@ -1750,23 +1750,30 @@ impl NetConfig {
}
impl RngConfig {
pub const SYNTAX: &'static str = "Random number generator parameters \"\
src=<entropy_source_path>,iommu=on|off,pci_segment=<segment_id>,\
pci_device_id=<pci_slot>\"";
pub fn parse(rng: &str) -> Result<Self> {
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::<Toggle>("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,

View File

@@ -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<Mutex<dyn virtio_devices::VirtioDevice>>,
pci_common: PciDeviceCommonConfig {
id: Some(id.clone()),
iommu: rng_config.iommu,
..Default::default()
},
pci_common: rng_config.pci_common.clone(),
dma_handler: None,
});

View File

@@ -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,

View File

@@ -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(),
}
}
}