From f5de0d221678c55fa717686757f99a244b782c8f Mon Sep 17 00:00:00 2001 From: iximeow Date: Tue, 3 Nov 2026 22:40:26 +0000 Subject: [PATCH] Dedupe compatible_sled_cpu_families across {Instance,Vmm}CpuPlatform Both of these had versions of `compatible_sled_cpu_families()`, and one was right, while the other was stale, resulting in #11668. Now and for the future an instance's CPU platform, if explicitly chosen, is represented by exactly one VMM CPU platform. Because of that, we can convert the instance's CPU platform to the VMM CPU platform for it and have a single authoritative `compatible_sled_cpu_families()`. --- nexus/db-model/src/instance_cpu_platform.rs | 22 ++++----------- nexus/db-model/src/vmm_cpu_platform.rs | 31 ++++++++++++++------- nexus/src/app/sagas/instance_migrate.rs | 6 ++-- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/nexus/db-model/src/instance_cpu_platform.rs b/nexus/db-model/src/instance_cpu_platform.rs index b794c75d2f4..3a55293d920 100644 --- a/nexus/db-model/src/instance_cpu_platform.rs +++ b/nexus/db-model/src/instance_cpu_platform.rs @@ -29,24 +29,12 @@ impl_enum_type!( ); impl InstanceCpuPlatform { - /// Returns a slice containing the set of sled CPU families that can - /// accommodate an instance with this CPU platform. + /// A convenience helper for the set of sled CPU families which support this + /// instance CPU platform, without callers having to convert to a matching + /// VMM CPU platform first. pub fn compatible_sled_cpu_families(&self) -> &'static [SledCpuFamily] { - match self { - // Turin-based sleds have a superset of the features made available - // in a guest's Milan CPU platform - Self::AmdMilan => &[ - SledCpuFamily::AmdMilan, - SledCpuFamily::AmdTurin, - SledCpuFamily::AmdTurinDense, - ], - Self::AmdTurin => { - &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] - } - Self::AmdTurinV2 => { - &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] - } - } + let vmm_platform: crate::VmmCpuPlatform = (*self).into(); + vmm_platform.compatible_sled_cpu_families() } } diff --git a/nexus/db-model/src/vmm_cpu_platform.rs b/nexus/db-model/src/vmm_cpu_platform.rs index 0bd146f9afd..56a0fe6fb88 100644 --- a/nexus/db-model/src/vmm_cpu_platform.rs +++ b/nexus/db-model/src/vmm_cpu_platform.rs @@ -30,36 +30,47 @@ impl_enum_type!( ); impl VmmCpuPlatform { - /// If this VMM has a well-known CPU platform, returns a `Some` containing - /// the set of sled CPU families that can host that the VMM. Returns `None` - /// if there is insufficient information to determine what CPU families - /// could host this VMM. - pub fn compatible_sled_cpu_families(&self) -> Option<&[SledCpuFamily]> { + /// If this VMM has a well-known CPU platform, returns a set of sled CPU + /// families that can host the VMM. Otherwise, returns an empty set to + /// indicate that a VMM CPU platform of "the target sled's defaults" cannot + /// be generalized to any `SledCpuFamily`. + pub fn compatible_sled_cpu_families(&self) -> &'static [SledCpuFamily] { match self { // Milan-based instances can run on both Milan and Turin processors. // Turin and Turin Dense are equally viable from a features // perspective. - Self::AmdMilan => Some(&[ + Self::AmdMilan => &[ SledCpuFamily::AmdMilan, SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense, - ]), + ], Self::AmdTurin => { - Some(&[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense]) + &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] } Self::AmdTurinV2 => { - Some(&[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense]) + &[SledCpuFamily::AmdTurin, SledCpuFamily::AmdTurinDense] } // VMMs get the "sled default" CPU platform when an instance starts // up on a sled that hasn't reported a well-known CPU family. Assume // that nothing is known about the VM's compatible CPU platforms in // this case. - Self::SledDefault => None, + Self::SledDefault => &[], } } } +// An InstanceCpuPlatform is an instance's request for how it wants vCPUs to +// look, whereas a VmmCpuPlatform is the actual chosen platform at the point +// that instance was incarnated. A critical difference is that VmmCpuPlatform +// has an escape hatch in the form of `SledDefault` if an instance is to be run +// on a kind of hardware the control plane does not yet know about - this is +// only a possible value if both the instance did not have an explicit CPU +// platform *and* it was placed on a sled whose family we don't know. +// +// While this means we can convert between Instance and VMM CPU platforms, in +// practice Instance->VMM is the only useful direction. Since that is expected +// to be injective, `From` suffices. impl From for VmmCpuPlatform { fn from(value: InstanceCpuPlatform) -> Self { match value { diff --git a/nexus/src/app/sagas/instance_migrate.rs b/nexus/src/app/sagas/instance_migrate.rs index 471ad262231..c943cf269cf 100644 --- a/nexus/src/app/sagas/instance_migrate.rs +++ b/nexus/src/app/sagas/instance_migrate.rs @@ -208,9 +208,9 @@ async fn sim_reserve_sled_resources( let params = sagactx.saga_params::()?; let propolis_id = sagactx.lookup::("dst_propolis_id")?; - let Some(compatible_sled_families) = - params.src_vmm.cpu_platform.compatible_sled_cpu_families() - else { + let compatible_sled_families = + params.src_vmm.cpu_platform.compatible_sled_cpu_families(); + if compatible_sled_families.is_empty() { // If we're here there are no compatible sled families for the VMM's CPU // platform. That means the VMM's CPU platform is "SledDefault" and we // just don't know what sleds might be compatible with the CPU platform