vmm: config: Validate that vCPUs is sufficient for MQ queue count

Fixes: #2563

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-04-29 12:10:44 +01:00 committed by Sebastien Boeuf
parent 2ad615cd32
commit 7e0ccce225
2 changed files with 53 additions and 12 deletions

View File

@ -984,11 +984,13 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--cpus", "boot=2",
"--net", "--net",
"mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=4", "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=4",
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"cpus": {"boot_vcpus": 2, "max_vcpus": 2},
"net": [ "net": [
{"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 4} {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 4}
] ]
@ -998,11 +1000,13 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--cpus", "boot=2",
"--net", "--net",
"mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=4,queue_size=128", "mac=12:34:56:78:90:ab,host_mac=34:56:78:90:ab:cd,tap=tap0,ip=1.2.3.4,mask=5.6.7.8,num_queues=4,queue_size=128",
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"cpus": {"boot_vcpus": 2, "max_vcpus": 2},
"net": [ "net": [
{"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 4, "queue_size": 128} {"mac": "12:34:56:78:90:ab", "host_mac": "34:56:78:90:ab:cd", "tap": "tap0", "ip": "1.2.3.4", "mask": "5.6.7.8", "num_queues": 4, "queue_size": 128}
] ]
@ -1163,13 +1167,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true", "--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4", "tag=virtiofs1,socket=/path/to/sock1,num_queues=4",
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4}
] ]
@ -1179,13 +1184,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true", "--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
] ]
@ -1195,13 +1201,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true", "--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,dax=on" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,dax=on"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
] ]
@ -1211,13 +1218,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true", "--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,dax=on" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,dax=on"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true}
] ]
@ -1227,13 +1235,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true", "--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true}
] ]
@ -1243,13 +1252,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true", "--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=8589934592" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=8589934592"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
] ]
@ -1259,13 +1269,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true", "--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 8589934592} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 8589934592}
] ]
@ -1275,13 +1286,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true","--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 4294967296} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 4294967296}
] ]
@ -1291,13 +1303,14 @@ mod unit_tests {
( (
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true","--cpus", "boot=4",
"--fs", "--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296" "tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296"
], ],
r#"{ r#"{
"kernel": {"path": "/path/to/kernel"}, "kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 }, "memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [ "fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128} {"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
] ]

View File

@ -126,6 +126,8 @@ pub enum ValidationError {
// CPU Hotplug not permitted with TDX // CPU Hotplug not permitted with TDX
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
TdxNoCpuHotplug, TdxNoCpuHotplug,
// Insuffient vCPUs for queues
TooManyQueues,
} }
type ValidationResult<T> = std::result::Result<T, ValidationError>; type ValidationResult<T> = std::result::Result<T, ValidationError>;
@ -166,6 +168,9 @@ impl fmt::Display for ValidationError {
TdxNoCpuHotplug => { TdxNoCpuHotplug => {
write!(f, "CPU hotplug not possible with TDX") write!(f, "CPU hotplug not possible with TDX")
} }
TooManyQueues => {
write!(f, "Number of vCPUs is insufficient for number of queues")
}
} }
} }
} }
@ -863,6 +868,14 @@ impl DiskConfig {
disable_io_uring, disable_io_uring,
}) })
} }
pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> {
if self.num_queues > vm_config.cpus.boot_vcpus as usize {
return Err(ValidationError::TooManyQueues);
}
Ok(())
}
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
@ -1075,11 +1088,10 @@ impl NetConfig {
fds, fds,
rate_limiter_config, rate_limiter_config,
}; };
config.validate().map_err(Error::Validation)?;
Ok(config) Ok(config)
} }
pub fn validate(&self) -> ValidationResult<()> { pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> {
if self.num_queues < 2 { if self.num_queues < 2 {
return Err(ValidationError::VnetQueueLowerThan2); return Err(ValidationError::VnetQueueLowerThan2);
} }
@ -1096,6 +1108,10 @@ impl NetConfig {
} }
} }
if (self.num_queues / 2) > vm_config.cpus.boot_vcpus as usize {
return Err(ValidationError::TooManyQueues);
}
Ok(()) Ok(())
} }
} }
@ -1264,6 +1280,14 @@ impl FsConfig {
id, id,
}) })
} }
pub fn validate(&self, vm_config: &VmConfig) -> ValidationResult<()> {
if self.num_queues > vm_config.cpus.boot_vcpus as usize {
return Err(ValidationError::TooManyQueues);
}
Ok(())
}
} }
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
@ -1719,6 +1743,7 @@ impl VmConfig {
if disk.vhost_user && disk.vhost_socket.is_none() { if disk.vhost_user && disk.vhost_socket.is_none() {
return Err(ValidationError::VhostUserMissingSocket); return Err(ValidationError::VhostUserMissingSocket);
} }
disk.validate(self)?;
} }
} }
@ -1727,7 +1752,7 @@ impl VmConfig {
if net.vhost_user && !self.memory.shared { if net.vhost_user && !self.memory.shared {
return Err(ValidationError::VhostUserRequiresSharedMemory); return Err(ValidationError::VhostUserRequiresSharedMemory);
} }
net.validate()?; net.validate(self)?;
} }
} }
@ -1735,6 +1760,9 @@ impl VmConfig {
if !fses.is_empty() && !self.memory.shared { if !fses.is_empty() && !self.memory.shared {
return Err(ValidationError::VhostUserRequiresSharedMemory); return Err(ValidationError::VhostUserRequiresSharedMemory);
} }
for fs in fses {
fs.validate(self)?;
}
} }
if let Some(t) = &self.cpus.topology { if let Some(t) = &self.cpus.topology {