xref: /openbmc/bmcweb/features/redfish/lib/fabric_ports.hpp (revision 7842c99f138b209a19c2d24387406060a4be47f4)
137937d51SGeorge Liu // SPDX-License-Identifier: Apache-2.0
237937d51SGeorge Liu // SPDX-FileCopyrightText: Copyright OpenBMC Authors
337937d51SGeorge Liu #pragma once
437937d51SGeorge Liu 
537937d51SGeorge Liu #include "bmcweb_config.h"
637937d51SGeorge Liu 
737937d51SGeorge Liu #include "app.hpp"
837937d51SGeorge Liu #include "async_resp.hpp"
9*7842c99fSMyung Bae #include "dbus_singleton.hpp"
1037937d51SGeorge Liu #include "dbus_utility.hpp"
1137937d51SGeorge Liu #include "error_messages.hpp"
1237937d51SGeorge Liu #include "http_request.hpp"
1337937d51SGeorge Liu #include "human_sort.hpp"
1437937d51SGeorge Liu #include "logging.hpp"
1537937d51SGeorge Liu #include "query.hpp"
1637937d51SGeorge Liu #include "registries/privilege_registry.hpp"
1737937d51SGeorge Liu 
18*7842c99fSMyung Bae #include <asm-generic/errno.h>
19*7842c99fSMyung Bae 
2037937d51SGeorge Liu #include <boost/beast/http/field.hpp>
2137937d51SGeorge Liu #include <boost/beast/http/verb.hpp>
2237937d51SGeorge Liu #include <boost/system/error_code.hpp>
2337937d51SGeorge Liu #include <boost/url/format.hpp>
24*7842c99fSMyung Bae #include <sdbusplus/asio/property.hpp>
2537937d51SGeorge Liu 
2637937d51SGeorge Liu #include <algorithm>
2737937d51SGeorge Liu #include <array>
2837937d51SGeorge Liu #include <functional>
2937937d51SGeorge Liu #include <memory>
3037937d51SGeorge Liu #include <ranges>
3137937d51SGeorge Liu #include <string>
3237937d51SGeorge Liu #include <string_view>
3337937d51SGeorge Liu #include <utility>
3437937d51SGeorge Liu #include <vector>
3537937d51SGeorge Liu 
3637937d51SGeorge Liu namespace redfish
3737937d51SGeorge Liu {
3837937d51SGeorge Liu static constexpr std::array<std::string_view, 1> fabricInterfaces{
3937937d51SGeorge Liu     "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
4037937d51SGeorge Liu static constexpr std::array<std::string_view, 1> portInterfaces{
4137937d51SGeorge Liu     "xyz.openbmc_project.Inventory.Connector.Port"};
4237937d51SGeorge Liu 
43*7842c99fSMyung Bae inline void afterGetFabricPortLocation(
44*7842c99fSMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
45*7842c99fSMyung Bae     const boost::system::error_code& ec, const std::string& value)
46*7842c99fSMyung Bae {
47*7842c99fSMyung Bae     if (ec)
48*7842c99fSMyung Bae     {
49*7842c99fSMyung Bae         if (ec.value() != EBADR)
50*7842c99fSMyung Bae         {
51*7842c99fSMyung Bae             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
52*7842c99fSMyung Bae             messages::internalError(asyncResp->res);
53*7842c99fSMyung Bae         }
54*7842c99fSMyung Bae         return;
55*7842c99fSMyung Bae     }
56*7842c99fSMyung Bae     asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
57*7842c99fSMyung Bae         value;
58*7842c99fSMyung Bae }
59*7842c99fSMyung Bae 
60*7842c99fSMyung Bae inline void getFabricPortLocation(
61*7842c99fSMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
62*7842c99fSMyung Bae     const std::string& portPath, const std::string& serviceName)
63*7842c99fSMyung Bae {
64*7842c99fSMyung Bae     dbus::utility::getProperty<std::string>(
65*7842c99fSMyung Bae         serviceName, portPath,
66*7842c99fSMyung Bae         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
67*7842c99fSMyung Bae         std::bind_front(afterGetFabricPortLocation, asyncResp));
68*7842c99fSMyung Bae }
69*7842c99fSMyung Bae 
7037937d51SGeorge Liu inline void getFabricPortProperties(
7137937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7237937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
73*7842c99fSMyung Bae     const std::string& portId, const std::string& portPath,
74*7842c99fSMyung Bae     const std::string& serviceName)
7537937d51SGeorge Liu {
7637937d51SGeorge Liu     if (portPath.empty())
7737937d51SGeorge Liu     {
7837937d51SGeorge Liu         BMCWEB_LOG_WARNING("Port not found");
7937937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Port", portId);
8037937d51SGeorge Liu         return;
8137937d51SGeorge Liu     }
8237937d51SGeorge Liu 
8337937d51SGeorge Liu     asyncResp->res.addHeader(
8437937d51SGeorge Liu         boost::beast::http::field::link,
8537937d51SGeorge Liu         "</redfish/v1/JsonSchemas/Port/Port.json>; rel=describedby");
8637937d51SGeorge Liu 
8737937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] = "#Port.v1_11_0.Port";
8837937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] =
8937937d51SGeorge Liu         boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters/{}/Ports/{}",
9037937d51SGeorge Liu                             systemName, adapterId, portId);
9137937d51SGeorge Liu     asyncResp->res.jsonValue["Id"] = portId;
9237937d51SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Fabric Port";
93*7842c99fSMyung Bae     getFabricPortLocation(asyncResp, portPath, serviceName);
9437937d51SGeorge Liu }
9537937d51SGeorge Liu 
9637937d51SGeorge Liu inline void afterGetValidFabricPortPath(
9737937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9837937d51SGeorge Liu     const std::string& portId,
99*7842c99fSMyung Bae     std::function<void(const std::string& portPath,
100*7842c99fSMyung Bae                        const std::string& portServiceName)>& callback,
10137937d51SGeorge Liu     const boost::system::error_code& ec,
10237937d51SGeorge Liu     const dbus::utility::MapperGetSubTreePathsResponse& portSubTreePaths)
10337937d51SGeorge Liu {
10437937d51SGeorge Liu     if (ec)
10537937d51SGeorge Liu     {
10637937d51SGeorge Liu         if (ec.value() != boost::system::errc::io_error)
10737937d51SGeorge Liu         {
10837937d51SGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
10937937d51SGeorge Liu             messages::internalError(asyncResp->res);
11037937d51SGeorge Liu             return;
11137937d51SGeorge Liu         }
11237937d51SGeorge Liu         // Port not found
113*7842c99fSMyung Bae         callback(std::string(), std::string());
11437937d51SGeorge Liu         return;
11537937d51SGeorge Liu     }
11637937d51SGeorge Liu     const auto& it =
11737937d51SGeorge Liu         std::ranges::find_if(portSubTreePaths, [portId](const auto& portPath) {
11837937d51SGeorge Liu             return portId ==
11937937d51SGeorge Liu                    sdbusplus::message::object_path(portPath).filename();
12037937d51SGeorge Liu         });
12137937d51SGeorge Liu     if (it == portSubTreePaths.end())
12237937d51SGeorge Liu     {
12337937d51SGeorge Liu         // Port not found
124*7842c99fSMyung Bae         callback(std::string(), std::string());
12537937d51SGeorge Liu         return;
12637937d51SGeorge Liu     }
12737937d51SGeorge Liu 
12837937d51SGeorge Liu     const std::string& portPath = *it;
12937937d51SGeorge Liu     dbus::utility::getDbusObject(
13037937d51SGeorge Liu         portPath, portInterfaces,
13137937d51SGeorge Liu         [asyncResp, portPath, callback{std::move(callback)}](
13237937d51SGeorge Liu             const boost::system::error_code& ec1,
13337937d51SGeorge Liu             const dbus::utility::MapperGetObject& object) {
13437937d51SGeorge Liu             if (ec1 || object.empty())
13537937d51SGeorge Liu             {
13637937d51SGeorge Liu                 BMCWEB_LOG_ERROR("DBUS response error on getDbusObject {}",
13737937d51SGeorge Liu                                  ec1.value());
13837937d51SGeorge Liu                 messages::internalError(asyncResp->res);
13937937d51SGeorge Liu                 return;
14037937d51SGeorge Liu             }
141*7842c99fSMyung Bae             callback(portPath, object.begin()->first);
14237937d51SGeorge Liu         });
14337937d51SGeorge Liu }
14437937d51SGeorge Liu 
14537937d51SGeorge Liu inline void getValidFabricPortPath(
14637937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
14737937d51SGeorge Liu     const std::string& adapterId, const std::string& portId,
148*7842c99fSMyung Bae     std::function<void(const std::string& portPath,
149*7842c99fSMyung Bae                        const std::string& portServiceName)>&& callback)
15037937d51SGeorge Liu {
15137937d51SGeorge Liu     dbus::utility::getAssociatedSubTreePathsById(
15237937d51SGeorge Liu         adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces,
15337937d51SGeorge Liu         "connecting", portInterfaces,
15437937d51SGeorge Liu         std::bind_front(afterGetValidFabricPortPath, asyncResp, portId,
15537937d51SGeorge Liu                         std::move(callback)));
15637937d51SGeorge Liu }
15737937d51SGeorge Liu 
15837937d51SGeorge Liu inline void handleFabricPortHead(
15937937d51SGeorge Liu     crow::App& app, const crow::Request& req,
16037937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16137937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
16237937d51SGeorge Liu     const std::string& portId)
16337937d51SGeorge Liu {
16437937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
16537937d51SGeorge Liu     {
16637937d51SGeorge Liu         return;
16737937d51SGeorge Liu     }
16837937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
16937937d51SGeorge Liu     {
17037937d51SGeorge Liu         // Option currently returns no systems.  TBD
17137937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
17237937d51SGeorge Liu                                    systemName);
17337937d51SGeorge Liu         return;
17437937d51SGeorge Liu     }
17537937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
17637937d51SGeorge Liu     {
17737937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
17837937d51SGeorge Liu                                    systemName);
17937937d51SGeorge Liu         return;
18037937d51SGeorge Liu     }
18137937d51SGeorge Liu 
18237937d51SGeorge Liu     getValidFabricPortPath(
18337937d51SGeorge Liu         asyncResp, adapterId, portId,
184*7842c99fSMyung Bae         [asyncResp, portId](const std::string& portPath, const std::string&) {
18537937d51SGeorge Liu             if (portPath.empty())
18637937d51SGeorge Liu             {
18737937d51SGeorge Liu                 BMCWEB_LOG_WARNING("Port not found");
18837937d51SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "Port", portId);
18937937d51SGeorge Liu                 return;
19037937d51SGeorge Liu             }
19137937d51SGeorge Liu             asyncResp->res.addHeader(
19237937d51SGeorge Liu                 boost::beast::http::field::link,
19337937d51SGeorge Liu                 "</redfish/v1/JsonSchemas/Port/Port.json>; rel=describedby");
19437937d51SGeorge Liu         });
19537937d51SGeorge Liu }
19637937d51SGeorge Liu 
19737937d51SGeorge Liu inline void handleFabricPortGet(
19837937d51SGeorge Liu     App& app, const crow::Request& req,
19937937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
20037937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
20137937d51SGeorge Liu     const std::string& portId)
20237937d51SGeorge Liu {
20337937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
20437937d51SGeorge Liu     {
20537937d51SGeorge Liu         return;
20637937d51SGeorge Liu     }
20737937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
20837937d51SGeorge Liu     {
20937937d51SGeorge Liu         // Option currently returns no systems.  TBD
21037937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
21137937d51SGeorge Liu                                    systemName);
21237937d51SGeorge Liu         return;
21337937d51SGeorge Liu     }
21437937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
21537937d51SGeorge Liu     {
21637937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
21737937d51SGeorge Liu                                    systemName);
21837937d51SGeorge Liu         return;
21937937d51SGeorge Liu     }
22037937d51SGeorge Liu     getValidFabricPortPath(asyncResp, adapterId, portId,
22137937d51SGeorge Liu                            std::bind_front(getFabricPortProperties, asyncResp,
22237937d51SGeorge Liu                                            systemName, adapterId, portId));
22337937d51SGeorge Liu }
22437937d51SGeorge Liu 
22537937d51SGeorge Liu inline void afterHandleFabricPortCollectionHead(
22637937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22737937d51SGeorge Liu     const std::string& adapterId, const boost::system::error_code& ec,
22837937d51SGeorge Liu     const dbus::utility::MapperGetSubTreePathsResponse& /* portSubTreePaths */)
22937937d51SGeorge Liu {
23037937d51SGeorge Liu     if (ec)
23137937d51SGeorge Liu     {
23237937d51SGeorge Liu         if (ec.value() != boost::system::errc::io_error)
23337937d51SGeorge Liu         {
23437937d51SGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
23537937d51SGeorge Liu             messages::internalError(asyncResp->res);
23637937d51SGeorge Liu             return;
23737937d51SGeorge Liu         }
23837937d51SGeorge Liu         BMCWEB_LOG_WARNING("Adapter not found");
23937937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Adapter", adapterId);
24037937d51SGeorge Liu         return;
24137937d51SGeorge Liu     }
24237937d51SGeorge Liu     asyncResp->res.addHeader(
24337937d51SGeorge Liu         boost::beast::http::field::link,
24437937d51SGeorge Liu         "</redfish/v1/JsonSchemas/PortCollection/PortCollection.json>; rel=describedby");
24537937d51SGeorge Liu }
24637937d51SGeorge Liu 
24737937d51SGeorge Liu inline void handleFabricPortCollectionHead(
24837937d51SGeorge Liu     crow::App& app, const crow::Request& req,
24937937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
25037937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId)
25137937d51SGeorge Liu {
25237937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
25337937d51SGeorge Liu     {
25437937d51SGeorge Liu         return;
25537937d51SGeorge Liu     }
25637937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
25737937d51SGeorge Liu     {
25837937d51SGeorge Liu         // Option currently returns no systems.  TBD
25937937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
26037937d51SGeorge Liu                                    systemName);
26137937d51SGeorge Liu         return;
26237937d51SGeorge Liu     }
26337937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
26437937d51SGeorge Liu     {
26537937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
26637937d51SGeorge Liu                                    systemName);
26737937d51SGeorge Liu         return;
26837937d51SGeorge Liu     }
26937937d51SGeorge Liu 
27037937d51SGeorge Liu     dbus::utility::getAssociatedSubTreePathsById(
27137937d51SGeorge Liu         adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces,
27237937d51SGeorge Liu         "connecting", portInterfaces,
27337937d51SGeorge Liu         std::bind_front(afterHandleFabricPortCollectionHead, asyncResp,
27437937d51SGeorge Liu                         adapterId));
27537937d51SGeorge Liu }
27637937d51SGeorge Liu 
27737937d51SGeorge Liu inline void doHandleFabricPortCollectionGet(
27837937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
27937937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
28037937d51SGeorge Liu     const boost::system::error_code& ec,
28137937d51SGeorge Liu     const dbus::utility::MapperGetSubTreePathsResponse& portSubTreePaths)
28237937d51SGeorge Liu {
28337937d51SGeorge Liu     if (ec)
28437937d51SGeorge Liu     {
28537937d51SGeorge Liu         if (ec.value() != boost::system::errc::io_error)
28637937d51SGeorge Liu         {
28737937d51SGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
28837937d51SGeorge Liu             messages::internalError(asyncResp->res);
28937937d51SGeorge Liu             return;
29037937d51SGeorge Liu         }
29137937d51SGeorge Liu         BMCWEB_LOG_WARNING("Adapter not found");
29237937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Adapter", adapterId);
29337937d51SGeorge Liu         return;
29437937d51SGeorge Liu     }
29537937d51SGeorge Liu     asyncResp->res.addHeader(
29637937d51SGeorge Liu         boost::beast::http::field::link,
29737937d51SGeorge Liu         "</redfish/v1/JsonSchemas/PortCollection/PortCollection.json>; rel=describedby");
29837937d51SGeorge Liu 
29937937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] = "#PortCollection.PortCollection";
30037937d51SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Port Collection";
30137937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] =
30237937d51SGeorge Liu         boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters/{}/Ports",
30337937d51SGeorge Liu                             systemName, adapterId);
30437937d51SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
30537937d51SGeorge Liu 
30637937d51SGeorge Liu     std::vector<std::string> portIdNames;
30737937d51SGeorge Liu     for (const std::string& portPath : portSubTreePaths)
30837937d51SGeorge Liu     {
30937937d51SGeorge Liu         std::string portId =
31037937d51SGeorge Liu             sdbusplus::message::object_path(portPath).filename();
31137937d51SGeorge Liu         if (!portId.empty())
31237937d51SGeorge Liu         {
31337937d51SGeorge Liu             portIdNames.emplace_back(std::move(portId));
31437937d51SGeorge Liu         }
31537937d51SGeorge Liu     }
31637937d51SGeorge Liu 
31737937d51SGeorge Liu     std::ranges::sort(portIdNames, AlphanumLess<std::string>());
31837937d51SGeorge Liu 
31937937d51SGeorge Liu     nlohmann::json& members = asyncResp->res.jsonValue["Members"];
32037937d51SGeorge Liu     for (const std::string& portId : portIdNames)
32137937d51SGeorge Liu     {
32237937d51SGeorge Liu         nlohmann::json item;
32337937d51SGeorge Liu         item["@odata.id"] = boost::urls::format(
32437937d51SGeorge Liu             "/redfish/v1/Systems/{}/FabricAdapters/{}/Ports/{}", systemName,
32537937d51SGeorge Liu             adapterId, portId);
32637937d51SGeorge Liu         members.emplace_back(std::move(item));
32737937d51SGeorge Liu     }
32837937d51SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = members.size();
32937937d51SGeorge Liu }
33037937d51SGeorge Liu 
33137937d51SGeorge Liu inline void handleFabricPortCollectionGet(
33237937d51SGeorge Liu     App& app, const crow::Request& req,
33337937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
33437937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId)
33537937d51SGeorge Liu {
33637937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
33737937d51SGeorge Liu     {
33837937d51SGeorge Liu         return;
33937937d51SGeorge Liu     }
34037937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
34137937d51SGeorge Liu     {
34237937d51SGeorge Liu         // Option currently returns no systems.  TBD
34337937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
34437937d51SGeorge Liu                                    systemName);
34537937d51SGeorge Liu         return;
34637937d51SGeorge Liu     }
34737937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
34837937d51SGeorge Liu     {
34937937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
35037937d51SGeorge Liu                                    systemName);
35137937d51SGeorge Liu         return;
35237937d51SGeorge Liu     }
35337937d51SGeorge Liu 
35437937d51SGeorge Liu     dbus::utility::getAssociatedSubTreePathsById(
35537937d51SGeorge Liu         adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces,
35637937d51SGeorge Liu         "connecting", portInterfaces,
35737937d51SGeorge Liu         std::bind_front(doHandleFabricPortCollectionGet, asyncResp, systemName,
35837937d51SGeorge Liu                         adapterId));
35937937d51SGeorge Liu }
36037937d51SGeorge Liu inline void requestRoutesFabricPort(App& app)
36137937d51SGeorge Liu {
36237937d51SGeorge Liu     BMCWEB_ROUTE(app,
36337937d51SGeorge Liu                  "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/<str>/")
36437937d51SGeorge Liu         .privileges(redfish::privileges::headPort)
36537937d51SGeorge Liu         .methods(boost::beast::http::verb::head)(
36637937d51SGeorge Liu             std::bind_front(handleFabricPortHead, std::ref(app)));
36737937d51SGeorge Liu 
36837937d51SGeorge Liu     BMCWEB_ROUTE(app,
36937937d51SGeorge Liu                  "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/<str>/")
37037937d51SGeorge Liu         .privileges(redfish::privileges::getPort)
37137937d51SGeorge Liu         .methods(boost::beast::http::verb::get)(
37237937d51SGeorge Liu             std::bind_front(handleFabricPortGet, std::ref(app)));
37337937d51SGeorge Liu 
37437937d51SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/")
37537937d51SGeorge Liu         .privileges(redfish::privileges::headPortCollection)
37637937d51SGeorge Liu         .methods(boost::beast::http::verb::head)(
37737937d51SGeorge Liu             std::bind_front(handleFabricPortCollectionHead, std::ref(app)));
37837937d51SGeorge Liu 
37937937d51SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/")
38037937d51SGeorge Liu         .privileges(redfish::privileges::getPortCollection)
38137937d51SGeorge Liu         .methods(boost::beast::http::verb::get)(
38237937d51SGeorge Liu             std::bind_front(handleFabricPortCollectionGet, std::ref(app)));
38337937d51SGeorge Liu }
38437937d51SGeorge Liu 
38537937d51SGeorge Liu } // namespace redfish
386