mirror of
https://github.com/kata-containers/kata-containers.git
synced 2026-08-08 23:54:51 +00:00
runtime-rs: align ch API models with CLH v51.1
Align the local runtime-rs API models with the shared field definitions in Cloud Hypervisor v51.1. Update CPU configuration, topology, affinity, NUMA CPU ID, VM resize, and vsock CID types. This also preserves Kata's supported 256-vCPU value during VM creation and resize. Remove the unused MAX_NUM_PCI_SEGMENTS constant and add regression coverage. Fixes: #13449 Assisted-By: GitHub Copilot Signed-off-by: Sudipta Pandit <sudpandit@microsoft.com>
This commit is contained in:
@@ -31,7 +31,7 @@ const PMEM_ALIGN_BYTES: u64 = 2 * MIB;
|
||||
|
||||
const DEFAULT_CH_MAX_PHYS_BITS: u8 = 46;
|
||||
|
||||
const DEFAULT_VSOCK_CID: u64 = 3;
|
||||
const DEFAULT_VSOCK_CID: u32 = 3;
|
||||
|
||||
pub const DEFAULT_NUM_PCI_SEGMENTS: u16 = 1;
|
||||
|
||||
@@ -226,10 +226,10 @@ impl TryFrom<NamedHypervisorConfig> for VmConfig {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(String, u64)> for VsockConfig {
|
||||
impl TryFrom<(String, u32)> for VsockConfig {
|
||||
type Error = VsockConfigError;
|
||||
|
||||
fn try_from(args: (String, u64)) -> Result<Self, Self::Error> {
|
||||
fn try_from(args: (String, u32)) -> Result<Self, Self::Error> {
|
||||
let vsock_socket_path = args.0;
|
||||
let cid = args.1;
|
||||
|
||||
@@ -380,17 +380,13 @@ impl TryFrom<(CpuInfo, GuestProtection)> for CpusConfig {
|
||||
return Err(CpusConfigError::BootVCPUsTooSmall);
|
||||
}
|
||||
|
||||
let default_vcpus = u8::try_from(cpu.default_vcpus.ceil() as u32)
|
||||
.map_err(CpusConfigError::BootVCPUsTooBig)?;
|
||||
let default_vcpus = cpu.default_vcpus.ceil() as u32;
|
||||
|
||||
// This can only happen if runtime-rs fails to set default values.
|
||||
if cpu.default_maxvcpus == 0 {
|
||||
return Err(CpusConfigError::MaxVCPUsTooSmall);
|
||||
}
|
||||
|
||||
let default_max_vcpus =
|
||||
u8::try_from(cpu.default_maxvcpus).map_err(CpusConfigError::MaxVCPUsTooBig)?;
|
||||
|
||||
let boot_vcpus = default_vcpus;
|
||||
|
||||
let max_vcpus = if guest_protection_is_tdx(guest_protection_to_use.clone()) {
|
||||
@@ -398,15 +394,18 @@ impl TryFrom<(CpuInfo, GuestProtection)> for CpusConfig {
|
||||
// cpus.
|
||||
default_vcpus
|
||||
} else {
|
||||
default_max_vcpus
|
||||
cpu.default_maxvcpus
|
||||
};
|
||||
|
||||
if boot_vcpus > max_vcpus {
|
||||
return Err(CpusConfigError::BootVPUsGtThanMaxVCPUs);
|
||||
}
|
||||
|
||||
let cores_per_die =
|
||||
u16::try_from(max_vcpus).map_err(CpusConfigError::MaxVCPUsTooBigForTopology)?;
|
||||
|
||||
let topology = CpuTopology {
|
||||
cores_per_die: max_vcpus,
|
||||
cores_per_die,
|
||||
threads_per_core: 1,
|
||||
dies_per_package: 1,
|
||||
packages: 1,
|
||||
@@ -643,6 +642,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use kata_sys_util::protection::SevSnpDetails;
|
||||
use kata_types::config::default::MAX_CH_VCPUS;
|
||||
use kata_types::config::hypervisor::{
|
||||
BlockDeviceInfo, Hypervisor as HypervisorConfig, SecurityInfo,
|
||||
};
|
||||
@@ -692,12 +692,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_cpu_objects(cpu_default: u8, cpu_max: u8, tdx: bool) -> (CpuInfo, CpusConfig) {
|
||||
let default_maxvcpus = if tdx {
|
||||
cpu_default as u32
|
||||
} else {
|
||||
cpu_max as u32
|
||||
};
|
||||
fn make_cpu_objects(cpu_default: u32, cpu_max: u32, tdx: bool) -> (CpuInfo, CpusConfig) {
|
||||
let default_maxvcpus = if tdx { cpu_default } else { cpu_max };
|
||||
|
||||
let cpu_info = CpuInfo {
|
||||
default_vcpus: cpu_default as f32,
|
||||
@@ -706,18 +702,14 @@ mod tests {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let max_vcpus = if tdx {
|
||||
cpu_default
|
||||
} else {
|
||||
default_maxvcpus as u8
|
||||
};
|
||||
let max_vcpus = if tdx { cpu_default } else { default_maxvcpus };
|
||||
|
||||
let cpus_config = CpusConfig {
|
||||
boot_vcpus: cpu_default,
|
||||
max_vcpus,
|
||||
nested: cpu_nested_config(),
|
||||
topology: Some(CpuTopology {
|
||||
cores_per_die: max_vcpus,
|
||||
cores_per_die: u16::try_from(max_vcpus).unwrap(),
|
||||
|
||||
..make_bare_topology()
|
||||
}),
|
||||
@@ -1320,6 +1312,27 @@ mod tests {
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
TestData {
|
||||
cpu_info: CpuInfo {
|
||||
default_vcpus: 1.0,
|
||||
default_maxvcpus: 256,
|
||||
..Default::default()
|
||||
},
|
||||
guest_protection: GuestProtection::NoProtection,
|
||||
result: Ok(CpusConfig {
|
||||
boot_vcpus: 1,
|
||||
max_vcpus: 256,
|
||||
nested: cpu_nested_config(),
|
||||
topology: Some(CpuTopology {
|
||||
cores_per_die: 256,
|
||||
|
||||
..topology
|
||||
}),
|
||||
max_phys_bits: DEFAULT_CH_MAX_PHYS_BITS,
|
||||
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
TestData {
|
||||
cpu_info: CpuInfo {
|
||||
default_vcpus: 1.0,
|
||||
@@ -1707,7 +1720,7 @@ mod tests {
|
||||
#[derive(Debug)]
|
||||
struct TestData<'a> {
|
||||
vsock_socket_path: &'a str,
|
||||
cid: u64,
|
||||
cid: u32,
|
||||
result: Result<VsockConfig, VsockConfigError>,
|
||||
}
|
||||
|
||||
@@ -1790,8 +1803,8 @@ mod tests {
|
||||
let valid_vsock =
|
||||
VsockConfig::try_from((vsock_socket_path.to_string(), DEFAULT_VSOCK_CID)).unwrap();
|
||||
|
||||
let (cpu_info, cpus_config) = make_cpu_objects(7, u8::MAX, false);
|
||||
let (cpu_info_tdx, cpus_config_tdx) = make_cpu_objects(7, u8::MAX, true);
|
||||
let (cpu_info, cpus_config) = make_cpu_objects(7, MAX_CH_VCPUS, false);
|
||||
let (cpu_info_tdx, cpus_config_tdx) = make_cpu_objects(7, MAX_CH_VCPUS, true);
|
||||
|
||||
let (memory_info_std, mem_config_std) =
|
||||
make_memory_objects(79, usable_max_mem_bytes, false);
|
||||
|
||||
@@ -70,14 +70,11 @@ pub enum CpusConfigError {
|
||||
#[error("Boot vCPUs cannot be zero or negative")]
|
||||
BootVCPUsTooSmall,
|
||||
|
||||
#[error("Too many boot vCPUs specified: {0}")]
|
||||
BootVCPUsTooBig(<u8 as TryFrom<i32>>::Error),
|
||||
|
||||
#[error("Max vCPUs cannot be zero or negative")]
|
||||
MaxVCPUsTooSmall,
|
||||
|
||||
#[error("Too many max vCPUs specified: {0}")]
|
||||
MaxVCPUsTooBig(<u8 as TryFrom<u32>>::Error),
|
||||
#[error("Max vCPUs cannot be represented in CPU topology: {0}")]
|
||||
MaxVCPUsTooBigForTopology(<u16 as TryFrom<u32>>::Error),
|
||||
|
||||
#[error("Boot vCPUs cannot be larger than max vCPUs")]
|
||||
BootVPUsGtThanMaxVCPUs,
|
||||
|
||||
@@ -15,8 +15,6 @@ use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
||||
use kata_types::config::hypervisor::RateLimiterConfig;
|
||||
pub use net_util::MacAddr;
|
||||
|
||||
pub const MAX_NUM_PCI_SEGMENTS: u16 = 16;
|
||||
|
||||
mod errors;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
@@ -62,14 +60,14 @@ pub enum ConsoleOutputMode {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct CpuAffinity {
|
||||
pub vcpu: u8,
|
||||
pub host_cpus: Vec<u8>,
|
||||
pub vcpu: u32,
|
||||
pub host_cpus: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct CpusConfig {
|
||||
pub boot_vcpus: u8,
|
||||
pub max_vcpus: u8,
|
||||
pub boot_vcpus: u32,
|
||||
pub max_vcpus: u32,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub topology: Option<CpuTopology>,
|
||||
@@ -96,10 +94,10 @@ pub struct CpuFeatures {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct CpuTopology {
|
||||
pub threads_per_core: u8,
|
||||
pub cores_per_die: u8,
|
||||
pub dies_per_package: u8,
|
||||
pub packages: u8,
|
||||
pub threads_per_core: u16,
|
||||
pub cores_per_die: u16,
|
||||
pub dies_per_package: u16,
|
||||
pub packages: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
@@ -338,7 +336,7 @@ pub struct NumaConfig {
|
||||
#[serde(default)]
|
||||
pub guest_numa_id: u32,
|
||||
#[serde(default)]
|
||||
pub cpus: Option<Vec<u8>>,
|
||||
pub cpus: Option<Vec<u32>>,
|
||||
#[serde(default)]
|
||||
pub distances: Option<Vec<NumaDistance>>,
|
||||
#[serde(default)]
|
||||
@@ -503,7 +501,7 @@ pub struct VmConfig {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct VsockConfig {
|
||||
pub cid: u64,
|
||||
pub cid: u32,
|
||||
pub socket: PathBuf,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
@@ -555,7 +553,7 @@ pub struct NamedHypervisorConfig {
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, Default)]
|
||||
pub struct VmResize {
|
||||
pub desired_vcpus: Option<u8>,
|
||||
pub desired_vcpus: Option<u32>,
|
||||
pub desired_ram: Option<u64>,
|
||||
pub desired_balloon: Option<u64>,
|
||||
}
|
||||
@@ -589,6 +587,23 @@ mod tests {
|
||||
use super::*;
|
||||
use kata_sys_util::protection::SevSnpDetails;
|
||||
|
||||
#[test]
|
||||
fn test_vm_resize_serialization_preserves_256_vcpus() {
|
||||
let resize = VmResize {
|
||||
desired_vcpus: Some(256),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(resize).unwrap(),
|
||||
serde_json::json!({
|
||||
"desired_vcpus": 256,
|
||||
"desired_ram": null,
|
||||
"desired_balloon": null,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_guest_protection_is_tdx() {
|
||||
let sev_snp_details = SevSnpDetails {
|
||||
|
||||
@@ -264,7 +264,7 @@ impl CloudHypervisorInner {
|
||||
let hvsock_config = device.config.clone();
|
||||
|
||||
let vsock_config = VsockConfig {
|
||||
cid: hvsock_config.guest_cid.into(),
|
||||
cid: hvsock_config.guest_cid,
|
||||
socket: hvsock_config.uds_path.into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -935,7 +935,7 @@ impl CloudHypervisorInner {
|
||||
}
|
||||
|
||||
let vmresize = VmResize {
|
||||
desired_vcpus: Some(new_vcpus as u8),
|
||||
desired_vcpus: Some(new_vcpus),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user