squib_api/schemas/
cpu_config.rs1use serde::{Deserialize, Serialize};
15
16pub const MAX_REG_MODIFIERS: usize = 256;
18
19#[derive(Debug, Clone, Default, Deserialize)]
21#[serde(deny_unknown_fields)]
22pub struct RawCpuConfig {
23 #[serde(default)]
25 pub reg_modifiers: Option<Vec<serde_json::Value>>,
26 #[serde(default)]
28 pub vcpu_features: Option<Vec<serde_json::Value>>,
29 #[serde(default)]
31 pub cpuid_modifiers: Option<Vec<serde_json::Value>>,
32 #[serde(default)]
34 pub msr_modifiers: Option<Vec<serde_json::Value>>,
35 #[serde(default)]
37 pub kvm_capabilities: Option<Vec<serde_json::Value>>,
38}
39
40#[derive(Debug, Clone, Default, Serialize)]
42#[non_exhaustive]
43pub struct CpuConfig {
44 pub reg_modifiers: Vec<serde_json::Value>,
46 pub vcpu_features: Vec<serde_json::Value>,
48 pub cpuid_modifiers: Vec<serde_json::Value>,
50 pub msr_modifiers: Vec<serde_json::Value>,
52 pub kvm_capabilities: Vec<serde_json::Value>,
54}
55
56fn cap_check<T>(field: &str, v: &[T]) -> Result<(), String> {
57 if v.len() > MAX_REG_MODIFIERS {
58 return Err(format!(
59 "Invalid cpu-config: {field} exceeds {MAX_REG_MODIFIERS} entries"
60 ));
61 }
62 Ok(())
63}
64
65impl TryFrom<RawCpuConfig> for CpuConfig {
66 type Error = String;
67
68 fn try_from(raw: RawCpuConfig) -> Result<Self, Self::Error> {
69 let reg_modifiers = raw.reg_modifiers.unwrap_or_default();
70 let vcpu_features = raw.vcpu_features.unwrap_or_default();
71 let cpuid_modifiers = raw.cpuid_modifiers.unwrap_or_default();
72 let msr_modifiers = raw.msr_modifiers.unwrap_or_default();
73 let kvm_capabilities = raw.kvm_capabilities.unwrap_or_default();
74 cap_check("reg_modifiers", ®_modifiers)?;
75 cap_check("vcpu_features", &vcpu_features)?;
76 cap_check("cpuid_modifiers", &cpuid_modifiers)?;
77 cap_check("msr_modifiers", &msr_modifiers)?;
78 cap_check("kvm_capabilities", &kvm_capabilities)?;
79 Ok(Self {
80 reg_modifiers,
81 vcpu_features,
82 cpuid_modifiers,
83 msr_modifiers,
84 kvm_capabilities,
85 })
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_should_accept_empty_cpu_config() {
95 let cfg = CpuConfig::try_from(RawCpuConfig::default()).unwrap();
96 assert!(cfg.reg_modifiers.is_empty());
97 }
98
99 #[test]
100 fn test_should_reject_oversize_reg_modifiers() {
101 let raw = RawCpuConfig {
102 reg_modifiers: Some(vec![serde_json::Value::Null; MAX_REG_MODIFIERS + 1]),
103 ..RawCpuConfig::default()
104 };
105 assert!(CpuConfig::try_from(raw).is_err());
106 }
107}