diff --git a/crates/api-model/src/site_explorer/mod.rs b/crates/api-model/src/site_explorer/mod.rs index 32e0e51b5b..438b18e3bb 100644 --- a/crates/api-model/src/site_explorer/mod.rs +++ b/crates/api-model/src/site_explorer/mod.rs @@ -307,10 +307,28 @@ impl ExploredEndpoint { } impl EndpointExplorationReport { + /// The boot interface MAC for this endpoint's explored default -- the boot + /// interface site-explorer records before any machine owns the endpoint. + /// + /// A declared `ExpectedHostNic.primary` wins when this report has that NIC, + /// whatever its type (an integrated NIC as readily as a DPU host-PF), so the + /// explored default agrees with the managed store's declared primary across + /// the ownership handoff. Absent a declaration, it falls back to the + /// automatic pick: the lowest-PCI DPU host-PF interface. pub fn fetch_host_primary_interface_mac( &self, explored_dpus: &[ExploredDpu], + declared_primary: Option, ) -> Option { + // A declared primary wins as long as the report has it as a full pair + // (`find_interface_id_for_mac` scans every system ethernet interface, + // integrated NICs included). + if let Some(declared) = declared_primary + && self.find_interface_id_for_mac(declared).is_some() + { + return Some(declared); + } + let system = self.systems.first()?; // Gather explored DPUs mac. diff --git a/crates/site-explorer/src/lib.rs b/crates/site-explorer/src/lib.rs index 30fbd68458..29a75d9a1c 100644 --- a/crates/site-explorer/src/lib.rs +++ b/crates/site-explorer/src/lib.rs @@ -1323,9 +1323,15 @@ impl SiteExplorer { // If we know the booting interface of the host, we should use this for deciding // primary interface. let mut is_sorted = false; + // A declared `ExpectedHostNic.primary` (when the matched expected + // machine sets one) wins over the automatic DPU-PF pick, so the + // explored default names the same NIC the managed store will. + let declared_primary = expected_explored_endpoint_index + .matched_expected_machine(&ep.address) + .and_then(|expected| expected.data.declared_primary_mac()); if let Some(mac_address) = ep .report - .fetch_host_primary_interface_mac(&dpus_explored_for_host) + .fetch_host_primary_interface_mac(&dpus_explored_for_host, declared_primary) { // Capture the boot interface's [stable] Redfish interface id // alongside its MAC. Only persist when both resolve from the diff --git a/crates/site-explorer/tests/site_explorer.rs b/crates/site-explorer/tests/site_explorer.rs index f62f085d8e..295855e744 100644 --- a/crates/site-explorer/tests/site_explorer.rs +++ b/crates/site-explorer/tests/site_explorer.rs @@ -2252,11 +2252,55 @@ async fn test_fetch_host_primary_interface_mac( }); } + // No declaration: the automatic pick stands -- the lowest-PCI DPU host-PF + // (the second mock DPU, given the device paths set above). let expected_mac: MacAddress = mock_dpus[1].host_mac_address; let mac = host_report - .fetch_host_primary_interface_mac(&explored_dpus) + .fetch_host_primary_interface_mac(&explored_dpus, None) .unwrap(); assert_eq!(mac, expected_mac); + + // A declared primary on a DPU host-PF wins over the automatic pick -- here + // the first DPU, which the PCI ordering would NOT have chosen. + let declared_dpu_pf = mock_dpus[0].host_mac_address; + assert_eq!( + host_report + .fetch_host_primary_interface_mac(&explored_dpus, Some(declared_dpu_pf)) + .unwrap(), + declared_dpu_pf, + ); + + // The headline case: a declared *integrated* NIC -- which the DPU-only + // automatic pick can never name -- becomes the explored default. + let integrated_nic = host_report + .systems + .first() + .unwrap() + .ethernet_interfaces + .iter() + .filter_map(|e| e.mac_address) + .find(|mac| { + !explored_dpus + .iter() + .any(|d| d.host_pf_mac_address == Some(*mac)) + }) + .expect("the fixture host should have a non-DPU integrated NIC"); + assert_eq!( + host_report + .fetch_host_primary_interface_mac(&explored_dpus, Some(integrated_nic)) + .unwrap(), + integrated_nic, + ); + + // A declared MAC absent from this report is ignored -- the automatic pick + // stands. + let absent_mac: MacAddress = "de:ad:be:ef:00:01".parse().unwrap(); + assert_eq!( + host_report + .fetch_host_primary_interface_mac(&explored_dpus, Some(absent_mac)) + .unwrap(), + expected_mac, + ); Ok(()) }