mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 02:55:45 +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(
|
let (cmd_success, cmd_output) = remote_command_w_output(
|
||||||
&api_socket,
|
&api_socket,
|
||||||
"add-disk",
|
"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!(cmd_success);
|
||||||
assert!(String::from_utf8_lossy(&cmd_output)
|
assert!(String::from_utf8_lossy(&cmd_output)
|
||||||
|
@ -164,6 +164,10 @@ pub enum ValidationError {
|
|||||||
InvalidPciSegment(u16),
|
InvalidPciSegment(u16),
|
||||||
/// Balloon too big
|
/// Balloon too big
|
||||||
BalloonLargerThanRam(u64, u64),
|
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>;
|
type ValidationResult<T> = std::result::Result<T, ValidationError>;
|
||||||
@ -236,6 +240,20 @@ impl fmt::Display for ValidationError {
|
|||||||
balloon_size, ram_size
|
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 {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -1381,6 +1405,12 @@ impl NetConfig {
|
|||||||
if self.pci_segment >= platform_config.num_pci_segments {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -1597,6 +1627,12 @@ impl FsConfig {
|
|||||||
if self.pci_segment >= platform_config.num_pci_segments {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -1678,6 +1714,12 @@ impl PmemConfig {
|
|||||||
if self.pci_segment >= platform_config.num_pci_segments {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -1810,6 +1852,12 @@ impl DeviceConfig {
|
|||||||
if self.pci_segment >= platform_config.num_pci_segments {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -1855,6 +1903,12 @@ impl UserDeviceConfig {
|
|||||||
if self.pci_segment >= platform_config.num_pci_segments {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -1916,6 +1970,12 @@ impl VdpaConfig {
|
|||||||
if self.pci_segment >= platform_config.num_pci_segments {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -1980,6 +2040,12 @@ impl VsockConfig {
|
|||||||
if self.pci_segment >= platform_config.num_pci_segments {
|
if self.pci_segment >= platform_config.num_pci_segments {
|
||||||
return Err(ValidationError::InvalidPciSegment(self.pci_segment));
|
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(())
|
Ok(())
|
||||||
@ -3333,11 +3399,165 @@ mod tests {
|
|||||||
});
|
});
|
||||||
assert!(still_valid_config.validate().is_ok());
|
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 {
|
invalid_config.platform = Some(PlatformConfig {
|
||||||
num_pci_segments: 16,
|
num_pci_segments: 16,
|
||||||
iommu_segments: Some(vec![17, 18]),
|
iommu_segments: Some(vec![17, 18]),
|
||||||
});
|
});
|
||||||
assert!(invalid_config.validate().is_err());
|
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