xref: /openbmc/bmcweb/features/redfish/lib/fabric_ports.hpp (revision ae16a89913b06505551738bc0d33e3a1c188c12b)
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"
97842c99fSMyung Bae #include "dbus_singleton.hpp"
1037937d51SGeorge Liu #include "dbus_utility.hpp"
1137937d51SGeorge Liu #include "error_messages.hpp"
12*ae16a899SMyung Bae #include "generated/enums/resource.hpp"
1337937d51SGeorge Liu #include "http_request.hpp"
1437937d51SGeorge Liu #include "human_sort.hpp"
1537937d51SGeorge Liu #include "logging.hpp"
1637937d51SGeorge Liu #include "query.hpp"
1737937d51SGeorge Liu #include "registries/privilege_registry.hpp"
1837937d51SGeorge Liu 
197842c99fSMyung Bae #include <asm-generic/errno.h>
207842c99fSMyung Bae 
2137937d51SGeorge Liu #include <boost/beast/http/field.hpp>
2237937d51SGeorge Liu #include <boost/beast/http/verb.hpp>
2337937d51SGeorge Liu #include <boost/system/error_code.hpp>
2437937d51SGeorge Liu #include <boost/url/format.hpp>
257842c99fSMyung Bae #include <sdbusplus/asio/property.hpp>
2637937d51SGeorge Liu 
2737937d51SGeorge Liu #include <algorithm>
2837937d51SGeorge Liu #include <array>
2937937d51SGeorge Liu #include <functional>
3037937d51SGeorge Liu #include <memory>
3137937d51SGeorge Liu #include <ranges>
3237937d51SGeorge Liu #include <string>
3337937d51SGeorge Liu #include <string_view>
3437937d51SGeorge Liu #include <utility>
3537937d51SGeorge Liu #include <vector>
3637937d51SGeorge Liu 
3737937d51SGeorge Liu namespace redfish
3837937d51SGeorge Liu {
3937937d51SGeorge Liu static constexpr std::array<std::string_view, 1> fabricInterfaces{
4037937d51SGeorge Liu     "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
4137937d51SGeorge Liu static constexpr std::array<std::string_view, 1> portInterfaces{
4237937d51SGeorge Liu     "xyz.openbmc_project.Inventory.Connector.Port"};
4337937d51SGeorge Liu 
447842c99fSMyung Bae inline void afterGetFabricPortLocation(
457842c99fSMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
467842c99fSMyung Bae     const boost::system::error_code& ec, const std::string& value)
477842c99fSMyung Bae {
487842c99fSMyung Bae     if (ec)
497842c99fSMyung Bae     {
507842c99fSMyung Bae         if (ec.value() != EBADR)
517842c99fSMyung Bae         {
527842c99fSMyung Bae             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
537842c99fSMyung Bae             messages::internalError(asyncResp->res);
547842c99fSMyung Bae         }
557842c99fSMyung Bae         return;
567842c99fSMyung Bae     }
577842c99fSMyung Bae     asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
587842c99fSMyung Bae         value;
597842c99fSMyung Bae }
607842c99fSMyung Bae 
617842c99fSMyung Bae inline void getFabricPortLocation(
627842c99fSMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
637842c99fSMyung Bae     const std::string& portPath, const std::string& serviceName)
647842c99fSMyung Bae {
657842c99fSMyung Bae     dbus::utility::getProperty<std::string>(
667842c99fSMyung Bae         serviceName, portPath,
677842c99fSMyung Bae         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
687842c99fSMyung Bae         std::bind_front(afterGetFabricPortLocation, asyncResp));
697842c99fSMyung Bae }
707842c99fSMyung Bae 
71*ae16a899SMyung Bae inline void afterGetFabricPortState(
72*ae16a899SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
73*ae16a899SMyung Bae     const boost::system::error_code& ec, bool present)
74*ae16a899SMyung Bae {
75*ae16a899SMyung Bae     if (ec)
76*ae16a899SMyung Bae     {
77*ae16a899SMyung Bae         if (ec.value() != EBADR)
78*ae16a899SMyung Bae         {
79*ae16a899SMyung Bae             BMCWEB_LOG_ERROR("DBUS response error for State, ec {}",
80*ae16a899SMyung Bae                              ec.value());
81*ae16a899SMyung Bae             messages::internalError(asyncResp->res);
82*ae16a899SMyung Bae         }
83*ae16a899SMyung Bae         return;
84*ae16a899SMyung Bae     }
85*ae16a899SMyung Bae     if (!present)
86*ae16a899SMyung Bae     {
87*ae16a899SMyung Bae         asyncResp->res.jsonValue["Status"]["State"] = resource::State::Absent;
88*ae16a899SMyung Bae     }
89*ae16a899SMyung Bae }
90*ae16a899SMyung Bae 
91*ae16a899SMyung Bae inline void getFabricPortState(
92*ae16a899SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
93*ae16a899SMyung Bae     const std::string& portPath, const std::string& serviceName)
94*ae16a899SMyung Bae {
95*ae16a899SMyung Bae     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
96*ae16a899SMyung Bae     dbus::utility::getProperty<bool>(
97*ae16a899SMyung Bae         serviceName, portPath, "xyz.openbmc_project.Inventory.Item", "Present",
98*ae16a899SMyung Bae         std::bind_front(afterGetFabricPortState, asyncResp));
99*ae16a899SMyung Bae }
100*ae16a899SMyung Bae 
101*ae16a899SMyung Bae inline void afterGetFabricPortHealth(
102*ae16a899SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
103*ae16a899SMyung Bae     const boost::system::error_code& ec, bool functional)
104*ae16a899SMyung Bae {
105*ae16a899SMyung Bae     if (ec)
106*ae16a899SMyung Bae     {
107*ae16a899SMyung Bae         if (ec.value() != EBADR)
108*ae16a899SMyung Bae         {
109*ae16a899SMyung Bae             BMCWEB_LOG_ERROR("DBUS response error for Health, ec {}",
110*ae16a899SMyung Bae                              ec.value());
111*ae16a899SMyung Bae             messages::internalError(asyncResp->res);
112*ae16a899SMyung Bae         }
113*ae16a899SMyung Bae         return;
114*ae16a899SMyung Bae     }
115*ae16a899SMyung Bae 
116*ae16a899SMyung Bae     if (!functional)
117*ae16a899SMyung Bae     {
118*ae16a899SMyung Bae         asyncResp->res.jsonValue["Status"]["Health"] =
119*ae16a899SMyung Bae             resource::Health::Critical;
120*ae16a899SMyung Bae     }
121*ae16a899SMyung Bae }
122*ae16a899SMyung Bae 
123*ae16a899SMyung Bae inline void getFabricPortHealth(
124*ae16a899SMyung Bae     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
125*ae16a899SMyung Bae     const std::string& portPath, const std::string& serviceName)
126*ae16a899SMyung Bae {
127*ae16a899SMyung Bae     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
128*ae16a899SMyung Bae     dbus::utility::getProperty<bool>(
129*ae16a899SMyung Bae         serviceName, portPath,
130*ae16a899SMyung Bae         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional",
131*ae16a899SMyung Bae         std::bind_front(afterGetFabricPortHealth, asyncResp));
132*ae16a899SMyung Bae }
133*ae16a899SMyung Bae 
13437937d51SGeorge Liu inline void getFabricPortProperties(
13537937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
13637937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
1377842c99fSMyung Bae     const std::string& portId, const std::string& portPath,
1387842c99fSMyung Bae     const std::string& serviceName)
13937937d51SGeorge Liu {
14037937d51SGeorge Liu     if (portPath.empty())
14137937d51SGeorge Liu     {
14237937d51SGeorge Liu         BMCWEB_LOG_WARNING("Port not found");
14337937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Port", portId);
14437937d51SGeorge Liu         return;
14537937d51SGeorge Liu     }
14637937d51SGeorge Liu 
14737937d51SGeorge Liu     asyncResp->res.addHeader(
14837937d51SGeorge Liu         boost::beast::http::field::link,
14937937d51SGeorge Liu         "</redfish/v1/JsonSchemas/Port/Port.json>; rel=describedby");
15037937d51SGeorge Liu 
15137937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] = "#Port.v1_11_0.Port";
15237937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] =
15337937d51SGeorge Liu         boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters/{}/Ports/{}",
15437937d51SGeorge Liu                             systemName, adapterId, portId);
15537937d51SGeorge Liu     asyncResp->res.jsonValue["Id"] = portId;
15637937d51SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Fabric Port";
157*ae16a899SMyung Bae 
1587842c99fSMyung Bae     getFabricPortLocation(asyncResp, portPath, serviceName);
159*ae16a899SMyung Bae     getFabricPortState(asyncResp, portPath, serviceName);
160*ae16a899SMyung Bae     getFabricPortHealth(asyncResp, portPath, serviceName);
16137937d51SGeorge Liu }
16237937d51SGeorge Liu 
16337937d51SGeorge Liu inline void afterGetValidFabricPortPath(
16437937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
16537937d51SGeorge Liu     const std::string& portId,
1667842c99fSMyung Bae     std::function<void(const std::string& portPath,
1677842c99fSMyung Bae                        const std::string& portServiceName)>& callback,
16837937d51SGeorge Liu     const boost::system::error_code& ec,
16937937d51SGeorge Liu     const dbus::utility::MapperGetSubTreePathsResponse& portSubTreePaths)
17037937d51SGeorge Liu {
17137937d51SGeorge Liu     if (ec)
17237937d51SGeorge Liu     {
17337937d51SGeorge Liu         if (ec.value() != boost::system::errc::io_error)
17437937d51SGeorge Liu         {
17537937d51SGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
17637937d51SGeorge Liu             messages::internalError(asyncResp->res);
17737937d51SGeorge Liu             return;
17837937d51SGeorge Liu         }
17937937d51SGeorge Liu         // Port not found
1807842c99fSMyung Bae         callback(std::string(), std::string());
18137937d51SGeorge Liu         return;
18237937d51SGeorge Liu     }
18337937d51SGeorge Liu     const auto& it =
18437937d51SGeorge Liu         std::ranges::find_if(portSubTreePaths, [portId](const auto& portPath) {
18537937d51SGeorge Liu             return portId ==
18637937d51SGeorge Liu                    sdbusplus::message::object_path(portPath).filename();
18737937d51SGeorge Liu         });
18837937d51SGeorge Liu     if (it == portSubTreePaths.end())
18937937d51SGeorge Liu     {
19037937d51SGeorge Liu         // Port not found
1917842c99fSMyung Bae         callback(std::string(), std::string());
19237937d51SGeorge Liu         return;
19337937d51SGeorge Liu     }
19437937d51SGeorge Liu 
19537937d51SGeorge Liu     const std::string& portPath = *it;
19637937d51SGeorge Liu     dbus::utility::getDbusObject(
19737937d51SGeorge Liu         portPath, portInterfaces,
19837937d51SGeorge Liu         [asyncResp, portPath, callback{std::move(callback)}](
19937937d51SGeorge Liu             const boost::system::error_code& ec1,
20037937d51SGeorge Liu             const dbus::utility::MapperGetObject& object) {
20137937d51SGeorge Liu             if (ec1 || object.empty())
20237937d51SGeorge Liu             {
20337937d51SGeorge Liu                 BMCWEB_LOG_ERROR("DBUS response error on getDbusObject {}",
20437937d51SGeorge Liu                                  ec1.value());
20537937d51SGeorge Liu                 messages::internalError(asyncResp->res);
20637937d51SGeorge Liu                 return;
20737937d51SGeorge Liu             }
2087842c99fSMyung Bae             callback(portPath, object.begin()->first);
20937937d51SGeorge Liu         });
21037937d51SGeorge Liu }
21137937d51SGeorge Liu 
21237937d51SGeorge Liu inline void getValidFabricPortPath(
21337937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
21437937d51SGeorge Liu     const std::string& adapterId, const std::string& portId,
2157842c99fSMyung Bae     std::function<void(const std::string& portPath,
2167842c99fSMyung Bae                        const std::string& portServiceName)>&& callback)
21737937d51SGeorge Liu {
21837937d51SGeorge Liu     dbus::utility::getAssociatedSubTreePathsById(
21937937d51SGeorge Liu         adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces,
22037937d51SGeorge Liu         "connecting", portInterfaces,
22137937d51SGeorge Liu         std::bind_front(afterGetValidFabricPortPath, asyncResp, portId,
22237937d51SGeorge Liu                         std::move(callback)));
22337937d51SGeorge Liu }
22437937d51SGeorge Liu 
22537937d51SGeorge Liu inline void handleFabricPortHead(
22637937d51SGeorge Liu     crow::App& app, const crow::Request& req,
22737937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
22837937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
22937937d51SGeorge Liu     const std::string& portId)
23037937d51SGeorge Liu {
23137937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
23237937d51SGeorge Liu     {
23337937d51SGeorge Liu         return;
23437937d51SGeorge Liu     }
23537937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
23637937d51SGeorge Liu     {
23737937d51SGeorge Liu         // Option currently returns no systems.  TBD
23837937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
23937937d51SGeorge Liu                                    systemName);
24037937d51SGeorge Liu         return;
24137937d51SGeorge Liu     }
24237937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
24337937d51SGeorge Liu     {
24437937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
24537937d51SGeorge Liu                                    systemName);
24637937d51SGeorge Liu         return;
24737937d51SGeorge Liu     }
24837937d51SGeorge Liu 
24937937d51SGeorge Liu     getValidFabricPortPath(
25037937d51SGeorge Liu         asyncResp, adapterId, portId,
2517842c99fSMyung Bae         [asyncResp, portId](const std::string& portPath, const std::string&) {
25237937d51SGeorge Liu             if (portPath.empty())
25337937d51SGeorge Liu             {
25437937d51SGeorge Liu                 BMCWEB_LOG_WARNING("Port not found");
25537937d51SGeorge Liu                 messages::resourceNotFound(asyncResp->res, "Port", portId);
25637937d51SGeorge Liu                 return;
25737937d51SGeorge Liu             }
25837937d51SGeorge Liu             asyncResp->res.addHeader(
25937937d51SGeorge Liu                 boost::beast::http::field::link,
26037937d51SGeorge Liu                 "</redfish/v1/JsonSchemas/Port/Port.json>; rel=describedby");
26137937d51SGeorge Liu         });
26237937d51SGeorge Liu }
26337937d51SGeorge Liu 
26437937d51SGeorge Liu inline void handleFabricPortGet(
26537937d51SGeorge Liu     App& app, const crow::Request& req,
26637937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
26737937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
26837937d51SGeorge Liu     const std::string& portId)
26937937d51SGeorge Liu {
27037937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
27137937d51SGeorge Liu     {
27237937d51SGeorge Liu         return;
27337937d51SGeorge Liu     }
27437937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
27537937d51SGeorge Liu     {
27637937d51SGeorge Liu         // Option currently returns no systems.  TBD
27737937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
27837937d51SGeorge Liu                                    systemName);
27937937d51SGeorge Liu         return;
28037937d51SGeorge Liu     }
28137937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
28237937d51SGeorge Liu     {
28337937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
28437937d51SGeorge Liu                                    systemName);
28537937d51SGeorge Liu         return;
28637937d51SGeorge Liu     }
28737937d51SGeorge Liu     getValidFabricPortPath(asyncResp, adapterId, portId,
28837937d51SGeorge Liu                            std::bind_front(getFabricPortProperties, asyncResp,
28937937d51SGeorge Liu                                            systemName, adapterId, portId));
29037937d51SGeorge Liu }
29137937d51SGeorge Liu 
29237937d51SGeorge Liu inline void afterHandleFabricPortCollectionHead(
29337937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
29437937d51SGeorge Liu     const std::string& adapterId, const boost::system::error_code& ec,
29537937d51SGeorge Liu     const dbus::utility::MapperGetSubTreePathsResponse& /* portSubTreePaths */)
29637937d51SGeorge Liu {
29737937d51SGeorge Liu     if (ec)
29837937d51SGeorge Liu     {
29937937d51SGeorge Liu         if (ec.value() != boost::system::errc::io_error)
30037937d51SGeorge Liu         {
30137937d51SGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
30237937d51SGeorge Liu             messages::internalError(asyncResp->res);
30337937d51SGeorge Liu             return;
30437937d51SGeorge Liu         }
30537937d51SGeorge Liu         BMCWEB_LOG_WARNING("Adapter not found");
30637937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Adapter", adapterId);
30737937d51SGeorge Liu         return;
30837937d51SGeorge Liu     }
30937937d51SGeorge Liu     asyncResp->res.addHeader(
31037937d51SGeorge Liu         boost::beast::http::field::link,
31137937d51SGeorge Liu         "</redfish/v1/JsonSchemas/PortCollection/PortCollection.json>; rel=describedby");
31237937d51SGeorge Liu }
31337937d51SGeorge Liu 
31437937d51SGeorge Liu inline void handleFabricPortCollectionHead(
31537937d51SGeorge Liu     crow::App& app, const crow::Request& req,
31637937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
31737937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId)
31837937d51SGeorge Liu {
31937937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
32037937d51SGeorge Liu     {
32137937d51SGeorge Liu         return;
32237937d51SGeorge Liu     }
32337937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
32437937d51SGeorge Liu     {
32537937d51SGeorge Liu         // Option currently returns no systems.  TBD
32637937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
32737937d51SGeorge Liu                                    systemName);
32837937d51SGeorge Liu         return;
32937937d51SGeorge Liu     }
33037937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
33137937d51SGeorge Liu     {
33237937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
33337937d51SGeorge Liu                                    systemName);
33437937d51SGeorge Liu         return;
33537937d51SGeorge Liu     }
33637937d51SGeorge Liu 
33737937d51SGeorge Liu     dbus::utility::getAssociatedSubTreePathsById(
33837937d51SGeorge Liu         adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces,
33937937d51SGeorge Liu         "connecting", portInterfaces,
34037937d51SGeorge Liu         std::bind_front(afterHandleFabricPortCollectionHead, asyncResp,
34137937d51SGeorge Liu                         adapterId));
34237937d51SGeorge Liu }
34337937d51SGeorge Liu 
34437937d51SGeorge Liu inline void doHandleFabricPortCollectionGet(
34537937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
34637937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId,
34737937d51SGeorge Liu     const boost::system::error_code& ec,
34837937d51SGeorge Liu     const dbus::utility::MapperGetSubTreePathsResponse& portSubTreePaths)
34937937d51SGeorge Liu {
35037937d51SGeorge Liu     if (ec)
35137937d51SGeorge Liu     {
35237937d51SGeorge Liu         if (ec.value() != boost::system::errc::io_error)
35337937d51SGeorge Liu         {
35437937d51SGeorge Liu             BMCWEB_LOG_ERROR("DBUS response error {}", ec.value());
35537937d51SGeorge Liu             messages::internalError(asyncResp->res);
35637937d51SGeorge Liu             return;
35737937d51SGeorge Liu         }
35837937d51SGeorge Liu         BMCWEB_LOG_WARNING("Adapter not found");
35937937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "Adapter", adapterId);
36037937d51SGeorge Liu         return;
36137937d51SGeorge Liu     }
36237937d51SGeorge Liu     asyncResp->res.addHeader(
36337937d51SGeorge Liu         boost::beast::http::field::link,
36437937d51SGeorge Liu         "</redfish/v1/JsonSchemas/PortCollection/PortCollection.json>; rel=describedby");
36537937d51SGeorge Liu 
36637937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.type"] = "#PortCollection.PortCollection";
36737937d51SGeorge Liu     asyncResp->res.jsonValue["Name"] = "Port Collection";
36837937d51SGeorge Liu     asyncResp->res.jsonValue["@odata.id"] =
36937937d51SGeorge Liu         boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters/{}/Ports",
37037937d51SGeorge Liu                             systemName, adapterId);
37137937d51SGeorge Liu     asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
37237937d51SGeorge Liu 
37337937d51SGeorge Liu     std::vector<std::string> portIdNames;
37437937d51SGeorge Liu     for (const std::string& portPath : portSubTreePaths)
37537937d51SGeorge Liu     {
37637937d51SGeorge Liu         std::string portId =
37737937d51SGeorge Liu             sdbusplus::message::object_path(portPath).filename();
37837937d51SGeorge Liu         if (!portId.empty())
37937937d51SGeorge Liu         {
38037937d51SGeorge Liu             portIdNames.emplace_back(std::move(portId));
38137937d51SGeorge Liu         }
38237937d51SGeorge Liu     }
38337937d51SGeorge Liu 
38437937d51SGeorge Liu     std::ranges::sort(portIdNames, AlphanumLess<std::string>());
38537937d51SGeorge Liu 
38637937d51SGeorge Liu     nlohmann::json& members = asyncResp->res.jsonValue["Members"];
38737937d51SGeorge Liu     for (const std::string& portId : portIdNames)
38837937d51SGeorge Liu     {
38937937d51SGeorge Liu         nlohmann::json item;
39037937d51SGeorge Liu         item["@odata.id"] = boost::urls::format(
39137937d51SGeorge Liu             "/redfish/v1/Systems/{}/FabricAdapters/{}/Ports/{}", systemName,
39237937d51SGeorge Liu             adapterId, portId);
39337937d51SGeorge Liu         members.emplace_back(std::move(item));
39437937d51SGeorge Liu     }
39537937d51SGeorge Liu     asyncResp->res.jsonValue["Members@odata.count"] = members.size();
39637937d51SGeorge Liu }
39737937d51SGeorge Liu 
39837937d51SGeorge Liu inline void handleFabricPortCollectionGet(
39937937d51SGeorge Liu     App& app, const crow::Request& req,
40037937d51SGeorge Liu     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
40137937d51SGeorge Liu     const std::string& systemName, const std::string& adapterId)
40237937d51SGeorge Liu {
40337937d51SGeorge Liu     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
40437937d51SGeorge Liu     {
40537937d51SGeorge Liu         return;
40637937d51SGeorge Liu     }
40737937d51SGeorge Liu     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
40837937d51SGeorge Liu     {
40937937d51SGeorge Liu         // Option currently returns no systems.  TBD
41037937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
41137937d51SGeorge Liu                                    systemName);
41237937d51SGeorge Liu         return;
41337937d51SGeorge Liu     }
41437937d51SGeorge Liu     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
41537937d51SGeorge Liu     {
41637937d51SGeorge Liu         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
41737937d51SGeorge Liu                                    systemName);
41837937d51SGeorge Liu         return;
41937937d51SGeorge Liu     }
42037937d51SGeorge Liu 
42137937d51SGeorge Liu     dbus::utility::getAssociatedSubTreePathsById(
42237937d51SGeorge Liu         adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces,
42337937d51SGeorge Liu         "connecting", portInterfaces,
42437937d51SGeorge Liu         std::bind_front(doHandleFabricPortCollectionGet, asyncResp, systemName,
42537937d51SGeorge Liu                         adapterId));
42637937d51SGeorge Liu }
42737937d51SGeorge Liu inline void requestRoutesFabricPort(App& app)
42837937d51SGeorge Liu {
42937937d51SGeorge Liu     BMCWEB_ROUTE(app,
43037937d51SGeorge Liu                  "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/<str>/")
43137937d51SGeorge Liu         .privileges(redfish::privileges::headPort)
43237937d51SGeorge Liu         .methods(boost::beast::http::verb::head)(
43337937d51SGeorge Liu             std::bind_front(handleFabricPortHead, std::ref(app)));
43437937d51SGeorge Liu 
43537937d51SGeorge Liu     BMCWEB_ROUTE(app,
43637937d51SGeorge Liu                  "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/<str>/")
43737937d51SGeorge Liu         .privileges(redfish::privileges::getPort)
43837937d51SGeorge Liu         .methods(boost::beast::http::verb::get)(
43937937d51SGeorge Liu             std::bind_front(handleFabricPortGet, std::ref(app)));
44037937d51SGeorge Liu 
44137937d51SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/")
44237937d51SGeorge Liu         .privileges(redfish::privileges::headPortCollection)
44337937d51SGeorge Liu         .methods(boost::beast::http::verb::head)(
44437937d51SGeorge Liu             std::bind_front(handleFabricPortCollectionHead, std::ref(app)));
44537937d51SGeorge Liu 
44637937d51SGeorge Liu     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/")
44737937d51SGeorge Liu         .privileges(redfish::privileges::getPortCollection)
44837937d51SGeorge Liu         .methods(boost::beast::http::verb::get)(
44937937d51SGeorge Liu             std::bind_front(handleFabricPortCollectionGet, std::ref(app)));
45037937d51SGeorge Liu }
45137937d51SGeorge Liu 
45237937d51SGeorge Liu } // namespace redfish
453