mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
vmm: config: Validate IOMMU configuration
Ensure devices that are specified to be on a PCI segment that is behind the IOMMU are IOMMU enabled if possible or error out for those devices that do not support it. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
6d2224f1ba
commit
0834eca8d4
@ -2130,7 +2130,13 @@ mod parallel {
|
||||
let (cmd_success, cmd_output) = remote_command_w_output(
|
||||
&api_socket,
|
||||
"add-disk",
|
||||
Some(format!("path={},id=test0,pci_segment=1", test_disk_path.as_str()).as_str()),
|
||||
Some(
|
||||
format!(
|
||||
"path={},id=test0,pci_segment=1,iommu=on",
|
||||
test_disk_path.as_str()
|
||||
)
|
||||
.as_str(),
|
||||
),
|
||||
);
|
||||
assert!(cmd_success);
|
||||
assert!(String::from_utf8_lossy(&cmd_output)
|
||||
|
@ -164,6 +164,10 @@ pub enum ValidationError {
|
||||
InvalidPciSegment(u16),
|
||||
/// Balloon too big
|
||||
BalloonLargerThanRam(u64, u64),
|
||||
/// On a IOMMU segment but not behind IOMMU
|
||||
OnIommuSegment(u16),
|
||||
// On a IOMMU segment but IOMMU not suported
|
||||
IommuNotSupported(u16),
|
||||
}
|
||||
|
||||
type ValidationResult<T> = std::result::Result<T, ValidationError>;
|
||||
@ -236,6 +240,20 @@ impl fmt::Display for ValidationError {
|
||||
balloon_size, ram_size
|
||||
)
|
||||
}
|
||||
OnIommuSegment(pci_segment) => {
|
||||
write!(
|
||||
f,
|
||||
"Device is on an IOMMU PCI segment ({}) but not placed behind IOMMU",
|
||||
pci_segment
|
||||
)
|
||||
}
|
||||
IommuNotSupported(pci_segment) => {
|
||||
write!(
|
||||
f,
|
||||
"Device is on an IOMMU PCI segment ({}) but does support being placed behind IOMMU",
|
||||
pci_segment
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1091,6 +1109,12 @@ impl DiskConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) && !self.iommu {
|
||||
return Err(ValidationError::OnIommuSegment(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1381,6 +1405,12 @@ impl NetConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) && !self.iommu {
|
||||
return Err(ValidationError::OnIommuSegment(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1597,6 +1627,12 @@ impl FsConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) {
|
||||
return Err(ValidationError::IommuNotSupported(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1678,6 +1714,12 @@ impl PmemConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) && !self.iommu {
|
||||
return Err(ValidationError::OnIommuSegment(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1810,6 +1852,12 @@ impl DeviceConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) && !self.iommu {
|
||||
return Err(ValidationError::OnIommuSegment(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1855,6 +1903,12 @@ impl UserDeviceConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) {
|
||||
return Err(ValidationError::IommuNotSupported(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1916,6 +1970,12 @@ impl VdpaConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) {
|
||||
return Err(ValidationError::IommuNotSupported(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1980,6 +2040,12 @@ impl VsockConfig {
|
||||
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() {
|
||||
if iommu_segments.contains(&self.pci_segment) && !self.iommu {
|
||||
return Err(ValidationError::OnIommuSegment(self.pci_segment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -3333,11 +3399,165 @@ mod tests {
|
||||
});
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut invalid_config = valid_config;
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![17, 18]),
|
||||
});
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
still_valid_config.disks = Some(vec![DiskConfig {
|
||||
iommu: true,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
still_valid_config.net = Some(vec![NetConfig {
|
||||
iommu: true,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
still_valid_config.pmem = Some(vec![PmemConfig {
|
||||
iommu: true,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
still_valid_config.devices = Some(vec![DeviceConfig {
|
||||
iommu: true,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut still_valid_config = valid_config.clone();
|
||||
still_valid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
still_valid_config.vsock = Some(VsockConfig {
|
||||
iommu: true,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
});
|
||||
assert!(still_valid_config.validate().is_ok());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.disks = Some(vec![DiskConfig {
|
||||
iommu: false,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.net = Some(vec![NetConfig {
|
||||
iommu: false,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.pmem = Some(vec![PmemConfig {
|
||||
iommu: false,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.devices = Some(vec![DeviceConfig {
|
||||
iommu: false,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.vsock = Some(VsockConfig {
|
||||
iommu: false,
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
});
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.memory.shared = true;
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.user_devices = Some(vec![UserDeviceConfig {
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut invalid_config = valid_config.clone();
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.vdpa = Some(vec![VdpaConfig {
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
|
||||
let mut invalid_config = valid_config;
|
||||
invalid_config.platform = Some(PlatformConfig {
|
||||
num_pci_segments: 16,
|
||||
iommu_segments: Some(vec![1, 2, 3]),
|
||||
});
|
||||
invalid_config.fs = Some(vec![FsConfig {
|
||||
pci_segment: 1,
|
||||
..Default::default()
|
||||
}]);
|
||||
assert!(invalid_config.validate().is_err());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user