Skip to content

Commit acc5f9c

Browse files
authored
feat(bmc-mock): add Dell R760 BF4 hardware scaffolding (#2902)
Adds BlueField-4 DPU mock support and a Dell PowerEdge R760 configuration with BF4 installed. Wires the new hardware type through machine info, Redfish config generation, discovery info, and DPU product handling. ## Related issues ## Type of Change - [x] **Add** - New feature or capability - [ ] **Change** - Changes in existing functionality - [ ] **Fix** - Bug fixes - [ ] **Remove** - Removed features or deprecated functionality - [x] **Internal** - Internal changes (refactoring, tests, docs, etc.) ## Breaking Changes - [ ] **This PR contains breaking changes** ## Testing - [ ] Unit tests added/updated - [ ] Integration tests added/updated - [ ] Manual testing performed - [x] No testing required (docs, internal refactor, etc.) ## Additional Notes Signed-off-by: Dmitry Porokh <dporokh@nvidia.com>
1 parent 6246e34 commit acc5f9c

5 files changed

Lines changed: 623 additions & 10 deletions

File tree

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
use std::borrow::Cow;
19+
use std::sync::Arc;
20+
21+
use mac_address::MacAddress;
22+
use rpc::machine_discovery::DiscoveryInfo;
23+
use serde_json::json;
24+
25+
use crate::{Callbacks, LogService, LogServices, hw, redfish};
26+
27+
pub struct Bluefield4<'a> {
28+
pub product_serial_number: Cow<'a, str>,
29+
pub host_mac_address: MacAddress,
30+
pub bmc_mac_address: MacAddress,
31+
}
32+
33+
impl Bluefield4<'_> {
34+
fn sensor_layout() -> redfish::sensor::Layout {
35+
// BF4 Card1 dump contains 96 sensors total. The generic mock
36+
// layout currently models Temperature, Fan, Power, Current,
37+
// and Voltage. Missing BF4 ReadingType counts: Percent=64,
38+
// Frequency=2, EnergyJoules=1.
39+
redfish::sensor::Layout {
40+
temperature: 5,
41+
fan: 0,
42+
power: 6,
43+
current: 0,
44+
voltage: 18,
45+
}
46+
}
47+
48+
pub fn chassis_config(&self) -> redfish::chassis::ChassisConfig {
49+
redfish::chassis::ChassisConfig {
50+
chassis: vec![
51+
redfish::chassis::SingleChassisConfig {
52+
id: "Bluefield_BMC".into(),
53+
chassis_type: "Component".into(),
54+
manufacturer: Some("Nvidia".into()),
55+
model: Some("B4240".into()),
56+
part_number: Some(self.part_number().into()),
57+
pcie_devices: Some(vec![]),
58+
sensors: Some(vec![]),
59+
serial_number: Some(self.product_serial_number.to_string().into()),
60+
..redfish::chassis::SingleChassisConfig::defaults()
61+
},
62+
redfish::chassis::SingleChassisConfig {
63+
id: "Bluefield_BMC_ERoT".into(),
64+
chassis_type: "Component".into(),
65+
manufacturer: Some(Cow::Borrowed("NVIDIA")),
66+
serial_number: Some("".into()),
67+
..redfish::chassis::SingleChassisConfig::defaults()
68+
},
69+
redfish::chassis::SingleChassisConfig {
70+
id: "Bluefield_CPU_ERoT".into(),
71+
chassis_type: "Component".into(),
72+
manufacturer: Some(Cow::Borrowed("NVIDIA")),
73+
serial_number: Some("".into()),
74+
..redfish::chassis::SingleChassisConfig::defaults()
75+
},
76+
redfish::chassis::SingleChassisConfig {
77+
id: "Bluefield_NIC".into(),
78+
chassis_type: "Component".into(),
79+
manufacturer: Some(Cow::Borrowed("NVIDIA")),
80+
serial_number: Some("".into()),
81+
..redfish::chassis::SingleChassisConfig::defaults()
82+
},
83+
redfish::chassis::SingleChassisConfig {
84+
id: "Card1".into(),
85+
chassis_type: "Card".into(),
86+
pcie_devices: Some(vec![]),
87+
sensors: Some(redfish::sensor::generate_chassis_sensors(
88+
"Card1",
89+
Self::sensor_layout(),
90+
)),
91+
..redfish::chassis::SingleChassisConfig::defaults()
92+
},
93+
redfish::chassis::SingleChassisConfig {
94+
id: "MCTP_SPI_DEV".into(),
95+
chassis_type: "".into(),
96+
pcie_devices: Some(vec![]),
97+
sensors: Some(vec![]),
98+
..redfish::chassis::SingleChassisConfig::defaults()
99+
},
100+
],
101+
}
102+
}
103+
104+
pub fn system_config(&self, callbacks: Arc<dyn Callbacks>) -> redfish::computer_system::Config {
105+
let system_id = "Bluefield";
106+
redfish::computer_system::Config {
107+
systems: vec![redfish::computer_system::SingleSystemConfig {
108+
id: Cow::Borrowed("Bluefield"),
109+
manufacturer: None,
110+
model: None,
111+
eth_interfaces: Some(vec![]),
112+
chassis: vec!["Bluefield_BMC".into()],
113+
serial_number: None,
114+
boot_order_mode: redfish::computer_system::BootOrderMode::ViaSettings,
115+
callbacks: Some(callbacks),
116+
boot_options: Some(vec![]),
117+
bios_mode: redfish::computer_system::BiosMode::Generic,
118+
oem: redfish::computer_system::Oem::NvidiaBluefield,
119+
base_bios: Some(
120+
redfish::bios::builder(&redfish::bios::resource(system_id))
121+
.attributes(json!({}))
122+
.build(),
123+
),
124+
log_services: Some(Arc::new(Bf4LogServices {
125+
event_log: DpuEventLog { entries: vec![] },
126+
})),
127+
storage: Some(vec![]),
128+
processors: Some(vec![]),
129+
secure_boot_available: true,
130+
}],
131+
}
132+
}
133+
134+
pub fn manager_config(&self) -> redfish::manager::Config {
135+
redfish::manager::Config {
136+
managers: vec![redfish::manager::SingleConfig {
137+
id: "Bluefield_BMC",
138+
eth_interfaces: Some(vec![
139+
redfish::ethernet_interface::builder(
140+
&redfish::ethernet_interface::manager_resource("Bluefield_BMC", "eth0"),
141+
)
142+
.mac_address(self.bmc_mac_address)
143+
.interface_enabled(true)
144+
.build(),
145+
]),
146+
host_interfaces: None,
147+
firmware_version: Some("BF4-26.01-2"),
148+
oem: None,
149+
}],
150+
}
151+
}
152+
153+
pub fn update_service_config(&self) -> redfish::update_service::UpdateServiceConfig {
154+
redfish::update_service::UpdateServiceConfig {
155+
firmware_inventory: vec![],
156+
}
157+
}
158+
159+
pub fn host_nic(&self) -> hw::nic::Nic<'static> {
160+
hw::nic::Nic {
161+
mac_address: self.host_mac_address,
162+
serial_number: Some(format!("{}", self.product_serial_number).into()),
163+
manufacturer: Some("Mellanox Technologies".into()),
164+
model: Some("B4240".into()),
165+
description: Some("CX9 Family [ConnectX-9]".into()),
166+
part_number: Some(self.part_number().into()),
167+
firmware_version: Some("82.48.0802".into()),
168+
is_mat_dpu: true,
169+
}
170+
}
171+
172+
pub fn discovery_info(&self) -> DiscoveryInfo {
173+
DiscoveryInfo::default()
174+
}
175+
176+
fn part_number(&self) -> &'static str {
177+
"900-9D4B4-CWAA-TSA"
178+
}
179+
}
180+
181+
struct DpuEventLog {
182+
entries: Vec<String>,
183+
}
184+
185+
impl LogService for DpuEventLog {
186+
fn id(&self) -> &str {
187+
"EventLog"
188+
}
189+
190+
fn entries(&self, collection: &redfish::Collection<'_>) -> Vec<serde_json::Value> {
191+
self.entries
192+
.iter()
193+
.enumerate()
194+
.map(|(idx, entry)| {
195+
redfish::log_service::event_entry(collection, &idx.to_string())
196+
.message(entry)
197+
// These are not required by specification but
198+
// required by libredfish. Making it happy. However, in future
199+
// we may want to simulate these fields as well.
200+
.severity("OK")
201+
.created("2026-02-12T02:06:58+00:00")
202+
.build()
203+
})
204+
.collect()
205+
}
206+
}
207+
208+
struct Bf4LogServices {
209+
event_log: DpuEventLog,
210+
}
211+
212+
impl LogServices for Bf4LogServices {
213+
fn services(&self) -> Vec<&(dyn LogService + '_)> {
214+
vec![&self.event_log as &dyn LogService]
215+
}
216+
}

0 commit comments

Comments
 (0)