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