Skip to content

Commit 3132dac

Browse files
harshit-agheraedtanous
authored andcommitted
Fabric: add support for PCIe Switch Port URI
This patch enable support for following properties for Port of a PCIe Switch. [1] - PortProtocol - PortType - CurrentSpeedGbps - ActiveWidth One of the devices that gets enabled with this patch is Nvidia ConnectX devices, which are network cards featuring an integrated PCIe switch. These devices combine both PCIe ports and network ports in a single unit. Since such devices don't strictly qualify as Fabric Adapters, the Switch URI is used instead of the FabricAdapter URI. Port schema only allows certain URIs as Port URI. URI /redfish/v1/Fabrics/{FabricId}/Switches/{SwitchId}/Ports/{PortId} seems most appropriate choice for PCIe Switch Port. [1] The Fabric resource is modeled similarly to the System resource, meaning that only one Fabric resource will exist for each BMC. Route handler for collections and each individual components are added in this patch for each URI resource under /redfish/v1/Fabrics. DBus Interface "xyz.openbmc_project.Inventory.Item.PCIeSwitch" is used to identify the Switch resources. Association between Switch and Port is `connecting` and `connected_to`. Feature like Port Metrics properties (for PCIe Error Counters) can be added in future at Port Metric URI. dbus-sensors patches - https://gerrit.openbmc.org/c/openbmc/dbus-sensors/+/84079 https://gerrit.openbmc.org/c/openbmc/dbus-sensors/+/83202 Tested: Build an image for nvl32-obmc machine with the following patch cherry picked. https://gerrit.openbmc.org/c/openbmc/dbus-sensors/+/84079 https://gerrit.openbmc.org/c/openbmc/openbmc/+/85490 The openbmc patch cherry-picks the following patches that are currently under review. ``` 1. device tree https://lore.kernel.org/all/aRbLqH8pLWCQryhu@molberding.nvidia.com/ 2. mctpd patches CodeConstruct/mctp#85 3. u-boot changes https://lore.kernel.org/openbmc/20251121-msx4-v1-0-fc0118b666c1@nvidia.com/T/#t 4. kernel changes as specified in the openbmc patch (for espi) 5. entity-manager changes https://gerrit.openbmc.org/c/openbmc/entity-manager/+/85455 6. platform-init changes https://gerrit.openbmc.org/c/openbmc/platform-init/+/85456 7. spi changes https://lore.kernel.org/all/20251121-w25q01jv_fixup-v1-1-3d175050db73@nvidia.com/ ``` redfish service validator is passing. ``` $ curl -k -u 'root:0penBmc' https://${bmc_ip}/redfish/v1/Fabrics/ { "@odata.id": "/redfish/v1/Fabrics", "@odata.type": "#FabricCollection.FabricCollection", "Members": [ { "@odata.id": "/redfish/v1/Fabrics/fabric" } ], "Members@odata.count": 1, "Name": "Fabric Collection" }% $ curl -k -u 'root:0penBmc' https://${bmc_ip}/redfish/v1/Fabrics/fabric/ { "@odata.id": "/redfish/v1/Fabrics/fabric", "@odata.type": "#Fabric.v1_2_0.Fabric", "Id": "fabric", "Name": "fabric Fabric", "Switches": { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches" } }% $ curl -k -u 'root:0penBmc' https://${bmc_ip}/redfish/v1/Fabrics/fabric/Switches/ { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches", "@odata.type": "#SwitchCollection.SwitchCollection", "Members": [ { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0" }, { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_1" }, { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_2" }, { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_3" } ], "Members@odata.count": 4, "Name": "fabric Switch Collection" }% $ curl -k -u 'root:0penBmc' https://${bmc_ip}/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0 { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0", "@odata.type": "#Switch.v1_7_0.Switch", "Id": "Nvidia_ConnectX_0", "Name": "Nvidia_ConnectX_0", "Ports": { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports" }, "Status": { "Health": "OK", "State": "Enabled" } }% $ curl -k -u 'root:0penBmc' https://${bmc_ip}/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports/ { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports", "@odata.type": "#PortCollection.PortCollection", "Members": [ { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports/DOWN_0" }, { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports/DOWN_1" }, { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports/UP_0" } ], "Members@odata.count": 3, "Name": "Nvidia_ConnectX_0 Port Collection" }% $ curl -k -u 'root:0penBmc' https://${bmc_ip}/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports/UP_0/ { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports/UP_0", "@odata.type": "#Port.v1_4_0.Port", "ActiveWidth": 8, "CurrentSpeedGbps": 32.0, "Id": "UP_0", "Metrics": { "@odata.id": "/redfish/v1/Fabrics/fabric/Switches/Nvidia_ConnectX_0/Ports/UP_0/Metrics" }, "Name": "Nvidia_ConnectX_0 UP_0 Port", "PortProtocol": "PCIe", "PortType": "UpstreamPort", "Status": { "Health": "OK", "State": "Enabled" } }% ``` [1]: https://redfish.dmtf.org/schemas/v1/Port_v1.xml Change-Id: I52f4ca62b4953f6196c589e340602a0d7885d9c1 Signed-off-by: Harshit Aghera <haghera@nvidia.com>
1 parent 64fe802 commit 3132dac

8 files changed

Lines changed: 729 additions & 1 deletion

File tree

config/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ string_options = [
5050
'mutual-tls-common-name-parsing-default',
5151
'redfish-manager-uri-name',
5252
'redfish-system-uri-name',
53+
'redfish-fabric-uri-name',
5354
'redfish-eventlog-location',
5455
]
5556

docs/Redfish.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Fields common to all schemas
4848
- TelemetryService
4949
- UUID
5050
- UpdateService
51+
- Fabrics
5152

5253
### /redfish/v1/AccountService/
5354

@@ -1194,6 +1195,84 @@ functions the same like the default implementation under the System resource.
11941195
- Updateable
11951196
- Version
11961197

1198+
### /redfish/v1/Fabrics/
1199+
1200+
#### FabricCollection
1201+
1202+
- Description
1203+
- Members
1204+
- `Members@odata.count`
1205+
- Name
1206+
1207+
### /redfish/v1/Fabrics/{FabricId}/
1208+
1209+
#### Fabric
1210+
1211+
- @odata.id
1212+
- @odata.type
1213+
- Id
1214+
- Name
1215+
- Switches
1216+
1217+
### /redfish/v1/Fabrics/{FabricId}/Switches/
1218+
1219+
#### SwitchCollection
1220+
1221+
- @odata.id
1222+
- @odata.type
1223+
- Members
1224+
- `Members@odata.count`
1225+
- Name
1226+
1227+
### /redfish/v1/Fabrics/{FabricId}/Switches/{SwitchId}/
1228+
1229+
#### Switch
1230+
1231+
- @odata.id
1232+
- @odata.type
1233+
- Id
1234+
- Name
1235+
- Ports
1236+
- Status
1237+
- Health
1238+
- State
1239+
1240+
### /redfish/v1/Fabrics/{FabricId}/Switches/{SwitchId}/Ports/
1241+
1242+
#### PortCollection
1243+
1244+
- @odata.id
1245+
- @odata.type
1246+
- Members
1247+
- `Members@odata.count`
1248+
- Name
1249+
1250+
### /redfish/v1/Fabrics/{FabricId}/Switches/{SwitchId}/Ports/{PortId}/
1251+
1252+
#### Port
1253+
1254+
- @odata.id
1255+
- @odata.type
1256+
- ActiveWidth
1257+
- CurrentSpeedGbps
1258+
- Id
1259+
- Metrics
1260+
- Name
1261+
- PortProtocol
1262+
- PortType
1263+
- Status
1264+
- Health
1265+
- State
1266+
1267+
### /redfish/v1/Fabrics/{FabricId}/Switches/{SwitchId}/Ports/{PortId}/Metrics
1268+
1269+
#### PortMetrics
1270+
1271+
- @odata.id
1272+
- @odata.type
1273+
- Id
1274+
- Name
1275+
11971276
[1]: https://www.dmtf.org/standards/redfish
11981277
[2]: https://github.com/DMTF/Redfish-Service-Validator
11991278
[3]: https://redfish.dmtf.org/schemas/

meson.options

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,18 @@ option(
187187
/redfish/v1/Systems/system''',
188188
)
189189

190+
# BMCWEB_REDFISH_FABRIC_URI_NAME
191+
option(
192+
'redfish-fabric-uri-name',
193+
type: 'string',
194+
value: 'fabric',
195+
description: '''The static Redfish Fabric ID representing the host
196+
instance. This option will appear in the Redfish tree at
197+
/redfish/v1/Fabrics/<redfish-fabric-uri-name>.
198+
Defaults to \'fabric\' which resolves to
199+
/redfish/v1/Fabrics/fabric''',
200+
)
201+
190202
# BMCWEB_LOGGING_LEVEL
191203
option(
192204
'bmcweb-logging',

redfish-core/lib/fabric.hpp

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3+
#pragma once
4+
5+
#include "app.hpp"
6+
#include "async_resp.hpp"
7+
#include "dbus_utility.hpp"
8+
#include "error_messages.hpp"
9+
#include "generated/enums/resource.hpp"
10+
#include "http_request.hpp"
11+
#include "logging.hpp"
12+
#include "query.hpp"
13+
#include "registries/privilege_registry.hpp"
14+
#include "utils/collection.hpp"
15+
16+
#include <boost/beast/http/verb.hpp>
17+
#include <boost/system/error_code.hpp>
18+
#include <boost/url/url.hpp>
19+
20+
#include <array>
21+
#include <format>
22+
#include <functional>
23+
#include <memory>
24+
#include <string>
25+
#include <string_view>
26+
#include <utility>
27+
28+
static constexpr std::array<std::string_view, 1> switchInterfaces = {
29+
"xyz.openbmc_project.Inventory.Item.PCIeSwitch"};
30+
31+
namespace redfish
32+
{
33+
34+
inline void handleFabricSwitchPathSwitchGet(
35+
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
36+
const std::string& fabricId, const std::string& switchId,
37+
[[maybe_unused]] const std::string& switchPath)
38+
{
39+
asyncResp->res.jsonValue["@odata.type"] = "#Switch.v1_7_0.Switch";
40+
asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
41+
"/redfish/v1/Fabrics/{}/Switches/{}", fabricId, switchId);
42+
asyncResp->res.jsonValue["Id"] = switchId;
43+
asyncResp->res.jsonValue["Name"] = switchId;
44+
45+
nlohmann::json& status = asyncResp->res.jsonValue["Status"];
46+
status["Health"] = resource::Health::OK;
47+
status["State"] = resource::State::Enabled;
48+
49+
asyncResp->res.jsonValue["Ports"]["@odata.id"] = boost::urls::format(
50+
"/redfish/v1/Fabrics/{}/Switches/{}/Ports", fabricId, switchId);
51+
}
52+
53+
inline void handleFabricSwitchPaths(
54+
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
55+
const std::string& switchId,
56+
const std::function<void(const std::string& switchPath)>& callback,
57+
const boost::system::error_code& ec,
58+
const dbus::utility::MapperGetSubTreePathsResponse& object)
59+
{
60+
if (ec)
61+
{
62+
if (ec.value() == boost::system::errc::io_error || ec.value() == EBADR)
63+
{
64+
BMCWEB_LOG_DEBUG("Switch resource {} not found", switchId);
65+
messages::resourceNotFound(asyncResp->res, "Switch", switchId);
66+
return;
67+
}
68+
69+
BMCWEB_LOG_ERROR("DBus response error on GetSubTreePaths {}", ec);
70+
messages::internalError(asyncResp->res);
71+
return;
72+
}
73+
74+
std::string switchPath;
75+
76+
for (const auto& path : object)
77+
{
78+
std::string switchName =
79+
sdbusplus::message::object_path(path).filename();
80+
if (switchName == switchId)
81+
{
82+
if (!switchPath.empty())
83+
{
84+
BMCWEB_LOG_ERROR("Multiple Switch resources found for {}",
85+
switchId);
86+
messages::internalError(asyncResp->res);
87+
return;
88+
}
89+
90+
switchPath = path;
91+
}
92+
}
93+
94+
if (!switchPath.empty())
95+
{
96+
callback(switchPath);
97+
return;
98+
}
99+
100+
messages::resourceNotFound(asyncResp->res, "Switch", switchId);
101+
}
102+
103+
inline void getFabricSwitchPath(
104+
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
105+
const std::string& fabricId, const std::string& switchId,
106+
std::function<void(const std::string& switchPath)>&& callback)
107+
{
108+
if (fabricId != BMCWEB_REDFISH_FABRIC_URI_NAME)
109+
{
110+
messages::resourceNotFound(asyncResp->res, "Fabric", fabricId);
111+
return;
112+
}
113+
114+
dbus::utility::getSubTreePaths(
115+
"/xyz/openbmc_project/inventory", 0, switchInterfaces,
116+
std::bind_front(handleFabricSwitchPaths, asyncResp, switchId,
117+
std::move(callback)));
118+
}
119+
120+
inline void handleFabricSwitchGet(
121+
crow::App& app, const crow::Request& req,
122+
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
123+
const std::string& fabricId, const std::string& switchId)
124+
{
125+
if (!redfish::setUpRedfishRoute(app, req, asyncResp))
126+
{
127+
return;
128+
}
129+
130+
getFabricSwitchPath(asyncResp, fabricId, switchId,
131+
std::bind_front(handleFabricSwitchPathSwitchGet,
132+
asyncResp, fabricId, switchId));
133+
}
134+
135+
inline void handleFabricSwitchCollectionGet(
136+
crow::App& app, const crow::Request& req,
137+
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
138+
const std::string& fabricId)
139+
{
140+
if (!redfish::setUpRedfishRoute(app, req, asyncResp))
141+
{
142+
return;
143+
}
144+
145+
if (fabricId != BMCWEB_REDFISH_FABRIC_URI_NAME)
146+
{
147+
messages::resourceNotFound(asyncResp->res, "Fabric", fabricId);
148+
return;
149+
}
150+
151+
const auto switchUrl =
152+
boost::urls::format("/redfish/v1/Fabrics/{}/Switches", fabricId);
153+
154+
asyncResp->res.jsonValue["@odata.id"] = switchUrl;
155+
asyncResp->res.jsonValue["@odata.type"] =
156+
"#SwitchCollection.SwitchCollection";
157+
asyncResp->res.jsonValue["Name"] = fabricId + " Switch Collection";
158+
159+
asyncResp->res.jsonValue["@odata.id"] =
160+
boost::urls::format("/redfish/v1/Fabrics/{}/Switches", fabricId);
161+
asyncResp->res.jsonValue["@odata.type"] =
162+
"#SwitchCollection.SwitchCollection";
163+
asyncResp->res.jsonValue["Name"] = fabricId + " Switch Collection";
164+
165+
collection_util::getCollectionMembers(
166+
asyncResp, switchUrl, switchInterfaces,
167+
"/xyz/openbmc_project/inventory");
168+
}
169+
170+
inline void handleFabricGet(crow::App& app, const crow::Request& req,
171+
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
172+
const std::string& fabricId)
173+
{
174+
if (!redfish::setUpRedfishRoute(app, req, asyncResp))
175+
{
176+
return;
177+
}
178+
179+
if (fabricId != BMCWEB_REDFISH_FABRIC_URI_NAME)
180+
{
181+
messages::resourceNotFound(asyncResp->res, "Fabric", fabricId);
182+
return;
183+
}
184+
185+
asyncResp->res.jsonValue["@odata.type"] = "#Fabric.v1_2_0.Fabric";
186+
asyncResp->res.jsonValue["@odata.id"] =
187+
boost::urls::format("/redfish/v1/Fabrics/{}", fabricId);
188+
asyncResp->res.jsonValue["Id"] = fabricId;
189+
asyncResp->res.jsonValue["Name"] = fabricId + " Fabric";
190+
191+
asyncResp->res.jsonValue["Switches"]["@odata.id"] =
192+
boost::urls::format("/redfish/v1/Fabrics/{}/Switches", fabricId);
193+
}
194+
195+
inline void handleFabricCollectionGet(
196+
crow::App& app, const crow::Request& req,
197+
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
198+
{
199+
if (!redfish::setUpRedfishRoute(app, req, asyncResp))
200+
{
201+
return;
202+
}
203+
204+
asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Fabrics";
205+
asyncResp->res.jsonValue["@odata.type"] =
206+
"#FabricCollection.FabricCollection";
207+
208+
asyncResp->res.jsonValue["Name"] = "Fabric Collection";
209+
210+
asyncResp->res.jsonValue["Members@odata.count"] = 1;
211+
212+
nlohmann::json::array_t members;
213+
nlohmann::json::object_t member;
214+
member["@odata.id"] = boost::urls::format("/redfish/v1/Fabrics/{}",
215+
BMCWEB_REDFISH_FABRIC_URI_NAME);
216+
members.emplace_back(std::move(member));
217+
218+
asyncResp->res.jsonValue["Members"] = std::move(members);
219+
}
220+
221+
inline void requestRoutesFabrics(App& app)
222+
{
223+
// The Fabric resource is designed so that each BMC will have only one
224+
// Fabric resource.
225+
BMCWEB_ROUTE(app, "/redfish/v1/Fabrics/")
226+
.privileges(redfish::privileges::getFabricCollection)
227+
.methods(boost::beast::http::verb::get)(
228+
std::bind_front(handleFabricCollectionGet, std::ref(app)));
229+
230+
BMCWEB_ROUTE(app, "/redfish/v1/Fabrics/<str>/")
231+
.privileges(redfish::privileges::getFabric)
232+
.methods(boost::beast::http::verb::get)(
233+
std::bind_front(handleFabricGet, std::ref(app)));
234+
235+
BMCWEB_ROUTE(app, "/redfish/v1/Fabrics/<str>/Switches/")
236+
.privileges(redfish::privileges::getSwitchCollection)
237+
.methods(boost::beast::http::verb::get)(
238+
std::bind_front(handleFabricSwitchCollectionGet, std::ref(app)));
239+
240+
BMCWEB_ROUTE(app, "/redfish/v1/Fabrics/<str>/Switches/<str>/")
241+
.privileges(redfish::privileges::getSwitch)
242+
.methods(boost::beast::http::verb::get)(
243+
std::bind_front(handleFabricSwitchGet, std::ref(app)));
244+
}
245+
} // namespace redfish

redfish-core/lib/service_root.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ inline void handleServiceRootGetImpl(
6969
asyncResp->res.jsonValue["SessionService"]["@odata.id"] =
7070
"/redfish/v1/SessionService";
7171
asyncResp->res.jsonValue["Systems"]["@odata.id"] = "/redfish/v1/Systems";
72+
asyncResp->res.jsonValue["Fabrics"]["@odata.id"] = "/redfish/v1/Fabrics";
7273
asyncResp->res.jsonValue["Registries"]["@odata.id"] =
7374
"/redfish/v1/Registries";
7475
asyncResp->res.jsonValue["UpdateService"]["@odata.id"] =

0 commit comments

Comments
 (0)