@@ -224,13 +224,12 @@ pub trait Redfish: Send + Sync + 'static {
224224
225225 /// Sets up a reasonable UEFI configuration.
226226 /// remember to call lockdown() afterwards to secure the server
227- /// - boot_interface: identifies the NIC you wish to boot from. Either a
228- /// `BootInterfaceRef::Mac` (existing behavior: vendor impl looks up
229- /// the partition by MAC via its BMC enumeration) or a
230- /// `BootInterfaceRef::InterfaceId` (vendor-native Redfish
231- /// `EthernetInterface.Id` — used when we already know the interface
232- /// partition ID (and don't need to look it up by MAC). One case
233- /// being if we flip a DPU to NIC mode.
227+ /// - boot_interface: identifies the NIC you wish to boot from. A
228+ /// `BootInterfaceRef::Mac` uses the existing vendor lookup by MAC, while
229+ /// `BootInterfaceRef::InterfaceId` uses a vendor-native Redfish
230+ /// `EthernetInterface.Id`. `BootInterfaceRef::Pair` supplies both so each
231+ /// vendor can use its native identifier without resolving one from the
232+ /// other.
234233 /// If not given we look for a Mellanox Bluefield DPU and use that.
235234 /// Not applicable to Supermicro and the DPU itself.
236235 /// bios_profiles: Map of vendor/model (with spaces replaced by underscores)/profile/type
@@ -537,11 +536,11 @@ pub trait Redfish: Send + Sync + 'static {
537536
538537 /// Change the boot order so the system will boot from the chosen NIC first.
539538 ///
540- /// `boot_interface` selects the target NIC. A `BootInterfaceRef::Mac` is the
541- /// classic path: the vendor impl looks the NIC up via its BMC enumeration
542- /// by MAC. A `BootInterfaceRef::InterfaceId` is the vendor-native Redfish
543- /// `EthernetInterface.Id` -- used when the caller already knows the
544- /// partition ID .
539+ /// `boot_interface` selects the target NIC. A `BootInterfaceRef::Mac` uses
540+ /// the existing vendor lookup by MAC, while `BootInterfaceRef::InterfaceId`
541+ /// uses a vendor-native Redfish `EthernetInterface.Id`.
542+ /// `BootInterfaceRef::Pair` supplies both so the vendor can use its native
543+ /// identifier directly .
545544 fn set_boot_order_dpu_first < ' a > (
546545 & ' a self ,
547546 boot_interface : BootInterfaceRef < ' a > ,
@@ -772,8 +771,7 @@ impl Status {
772771}
773772
774773/// How a caller identifies a boot interface to [`Redfish::machine_setup`]
775- /// and supporting query methods. Callers can pass either form; vendor
776- /// impls handle both.
774+ /// and supporting query methods.
777775#[ derive( Debug , Clone , Copy ) ]
778776pub enum BootInterfaceRef < ' a > {
779777 /// MAC address of the boot interface. Vendor impl translates it into
@@ -783,25 +781,34 @@ pub enum BootInterfaceRef<'a> {
783781 /// interface (e.g. `"NIC.Slot.7-1-1"`). Vendor impl uses it
784782 /// directly.
785783 InterfaceId ( & ' a str ) ,
784+ /// Complete identity for one boot interface. Both fields must identify the
785+ /// same interface; this is one target, not an instruction to try both.
786+ /// MAC-oriented vendor paths use `mac_address`, while interface-ID-oriented
787+ /// paths use `interface_id`.
788+ Pair {
789+ mac_address : mac_address:: MacAddress ,
790+ interface_id : & ' a str ,
791+ } ,
786792}
787793
788794impl BootInterfaceRef < ' _ > {
789- /// Returns the MAC if this is the [`BootInterfaceRef::Mac`] variant.
790- /// Returns `None` if this is the [`BootInterfaceRef::InterfaceId`]
791- /// variant.
795+ /// Returns the supplied MAC when this selector contains one.
792796 pub fn mac ( & self ) -> Option < mac_address:: MacAddress > {
793797 match self {
794- BootInterfaceRef :: Mac ( mac) => Some ( * mac) ,
798+ BootInterfaceRef :: Mac ( mac)
799+ | BootInterfaceRef :: Pair {
800+ mac_address : mac, ..
801+ } => Some ( * mac) ,
795802 BootInterfaceRef :: InterfaceId ( _) => None ,
796803 }
797804 }
798805}
799806
800807/// Returns the MAC address for a [`BootInterfaceRef`].
801- /// [`BootInterfaceRef::Mac`] is a pass-through; [`BootInterfaceRef::InterfaceId`]
802- /// is resolved by fetching `Systems/{}/EthernetInterfaces/{id}` via the
803- /// Redfish-standard `EthernetInterface` resource (every vendor
804- /// implements it).
808+ /// [`BootInterfaceRef::Mac`] and [`BootInterfaceRef::Pair`] pass through their
809+ /// supplied MAC. [`BootInterfaceRef::InterfaceId`] is resolved by fetching
810+ /// `Systems/{}/EthernetInterfaces/{id}` via the Redfish-standard
811+ /// `EthernetInterface` resource (every vendor implements it).
805812///
806813/// Used by methods that compare against a MAC (verification paths that
807814/// walk boot options by MAC substring, etc.) so the caller can pass
@@ -811,7 +818,10 @@ pub async fn resolve_boot_interface_mac<R: Redfish + ?Sized>(
811818 boot_interface : BootInterfaceRef < ' _ > ,
812819) -> Result < String , RedfishError > {
813820 match boot_interface {
814- BootInterfaceRef :: Mac ( mac) => Ok ( mac. to_string ( ) ) ,
821+ BootInterfaceRef :: Mac ( mac)
822+ | BootInterfaceRef :: Pair {
823+ mac_address : mac, ..
824+ } => Ok ( mac. to_string ( ) ) ,
815825 BootInterfaceRef :: InterfaceId ( id) => {
816826 let eif = redfish. get_system_ethernet_interface ( id) . await ?;
817827 extract_resolved_mac ( eif. mac_address . as_deref ( ) , id)
@@ -945,6 +955,37 @@ mod tests {
945955 assert ! ( r. mac( ) . is_none( ) ) ;
946956 }
947957
958+ #[ test]
959+ fn boot_interface_ref_pair_mac_returns_inner ( ) {
960+ let mac: mac_address:: MacAddress = "AA:BB:CC:DD:EE:01" . parse ( ) . unwrap ( ) ;
961+ let r = BootInterfaceRef :: Pair {
962+ mac_address : mac,
963+ interface_id : "NIC.Slot.7-1-1" ,
964+ } ;
965+ assert_eq ! ( r. mac( ) , Some ( mac) ) ;
966+ }
967+
968+ #[ tokio:: test]
969+ async fn resolve_boot_interface_mac_uses_pair_mac_without_lookup ( ) {
970+ let pool = RedfishClientPool :: builder ( ) . build ( ) . unwrap ( ) ;
971+ let redfish = pool
972+ . create_standard_client ( Endpoint :: default ( ) )
973+ . expect ( "test Redfish client should be constructed without a request" ) ;
974+ let mac: mac_address:: MacAddress = "AA:BB:CC:DD:EE:01" . parse ( ) . unwrap ( ) ;
975+
976+ let got = resolve_boot_interface_mac (
977+ redfish. as_ref ( ) ,
978+ BootInterfaceRef :: Pair {
979+ mac_address : mac,
980+ interface_id : "NIC.Slot.7-1-1" ,
981+ } ,
982+ )
983+ . await
984+ . expect ( "pair should use its MAC without querying the empty endpoint" ) ;
985+
986+ assert_eq ! ( got, mac. to_string( ) ) ;
987+ }
988+
948989 #[ test]
949990 fn extract_resolved_mac_passes_through_populated_mac ( ) {
950991 let got = super :: extract_resolved_mac ( Some ( "AA:BB:CC:DD:EE:01" ) , "NIC.Slot.7-1-1" )
0 commit comments