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" 12ae16a899SMyung Bae #include "generated/enums/resource.hpp" 1337937d51SGeorge Liu #include "http_request.hpp" 1437937d51SGeorge Liu #include "human_sort.hpp" 15*fc1342c5SMyung Bae #include "led.hpp" 1637937d51SGeorge Liu #include "logging.hpp" 1737937d51SGeorge Liu #include "query.hpp" 1837937d51SGeorge Liu #include "registries/privilege_registry.hpp" 19*fc1342c5SMyung Bae #include "utils/json_utils.hpp" 2037937d51SGeorge Liu 217842c99fSMyung Bae #include <asm-generic/errno.h> 227842c99fSMyung Bae 2337937d51SGeorge Liu #include <boost/beast/http/field.hpp> 2437937d51SGeorge Liu #include <boost/beast/http/verb.hpp> 2537937d51SGeorge Liu #include <boost/system/error_code.hpp> 2637937d51SGeorge Liu #include <boost/url/format.hpp> 277842c99fSMyung Bae #include <sdbusplus/asio/property.hpp> 2837937d51SGeorge Liu 2937937d51SGeorge Liu #include <algorithm> 3037937d51SGeorge Liu #include <array> 3137937d51SGeorge Liu #include <functional> 3237937d51SGeorge Liu #include <memory> 33*fc1342c5SMyung Bae #include <optional> 3437937d51SGeorge Liu #include <ranges> 3537937d51SGeorge Liu #include <string> 3637937d51SGeorge Liu #include <string_view> 3737937d51SGeorge Liu #include <utility> 3837937d51SGeorge Liu #include <vector> 3937937d51SGeorge Liu 4037937d51SGeorge Liu namespace redfish 4137937d51SGeorge Liu { 4237937d51SGeorge Liu static constexpr std::array<std::string_view, 1> fabricInterfaces{ 4337937d51SGeorge Liu "xyz.openbmc_project.Inventory.Item.FabricAdapter"}; 4437937d51SGeorge Liu static constexpr std::array<std::string_view, 1> portInterfaces{ 4537937d51SGeorge Liu "xyz.openbmc_project.Inventory.Connector.Port"}; 4637937d51SGeorge Liu 477842c99fSMyung Bae inline void afterGetFabricPortLocation( 487842c99fSMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 497842c99fSMyung Bae const boost::system::error_code& ec, const std::string& value) 507842c99fSMyung Bae { 517842c99fSMyung Bae if (ec) 527842c99fSMyung Bae { 537842c99fSMyung Bae if (ec.value() != EBADR) 547842c99fSMyung Bae { 557842c99fSMyung Bae BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 567842c99fSMyung Bae messages::internalError(asyncResp->res); 577842c99fSMyung Bae } 587842c99fSMyung Bae return; 597842c99fSMyung Bae } 607842c99fSMyung Bae asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 617842c99fSMyung Bae value; 627842c99fSMyung Bae } 637842c99fSMyung Bae 647842c99fSMyung Bae inline void getFabricPortLocation( 657842c99fSMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 667842c99fSMyung Bae const std::string& portPath, const std::string& serviceName) 677842c99fSMyung Bae { 687842c99fSMyung Bae dbus::utility::getProperty<std::string>( 697842c99fSMyung Bae serviceName, portPath, 707842c99fSMyung Bae "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 717842c99fSMyung Bae std::bind_front(afterGetFabricPortLocation, asyncResp)); 727842c99fSMyung Bae } 737842c99fSMyung Bae 74ae16a899SMyung Bae inline void afterGetFabricPortState( 75ae16a899SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 76ae16a899SMyung Bae const boost::system::error_code& ec, bool present) 77ae16a899SMyung Bae { 78ae16a899SMyung Bae if (ec) 79ae16a899SMyung Bae { 80ae16a899SMyung Bae if (ec.value() != EBADR) 81ae16a899SMyung Bae { 82ae16a899SMyung Bae BMCWEB_LOG_ERROR("DBUS response error for State, ec {}", 83ae16a899SMyung Bae ec.value()); 84ae16a899SMyung Bae messages::internalError(asyncResp->res); 85ae16a899SMyung Bae } 86ae16a899SMyung Bae return; 87ae16a899SMyung Bae } 88ae16a899SMyung Bae if (!present) 89ae16a899SMyung Bae { 90ae16a899SMyung Bae asyncResp->res.jsonValue["Status"]["State"] = resource::State::Absent; 91ae16a899SMyung Bae } 92ae16a899SMyung Bae } 93ae16a899SMyung Bae 94ae16a899SMyung Bae inline void getFabricPortState( 95ae16a899SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 96ae16a899SMyung Bae const std::string& portPath, const std::string& serviceName) 97ae16a899SMyung Bae { 98ae16a899SMyung Bae asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 99ae16a899SMyung Bae dbus::utility::getProperty<bool>( 100ae16a899SMyung Bae serviceName, portPath, "xyz.openbmc_project.Inventory.Item", "Present", 101ae16a899SMyung Bae std::bind_front(afterGetFabricPortState, asyncResp)); 102ae16a899SMyung Bae } 103ae16a899SMyung Bae 104ae16a899SMyung Bae inline void afterGetFabricPortHealth( 105ae16a899SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 106ae16a899SMyung Bae const boost::system::error_code& ec, bool functional) 107ae16a899SMyung Bae { 108ae16a899SMyung Bae if (ec) 109ae16a899SMyung Bae { 110ae16a899SMyung Bae if (ec.value() != EBADR) 111ae16a899SMyung Bae { 112ae16a899SMyung Bae BMCWEB_LOG_ERROR("DBUS response error for Health, ec {}", 113ae16a899SMyung Bae ec.value()); 114ae16a899SMyung Bae messages::internalError(asyncResp->res); 115ae16a899SMyung Bae } 116ae16a899SMyung Bae return; 117ae16a899SMyung Bae } 118ae16a899SMyung Bae 119ae16a899SMyung Bae if (!functional) 120ae16a899SMyung Bae { 121ae16a899SMyung Bae asyncResp->res.jsonValue["Status"]["Health"] = 122ae16a899SMyung Bae resource::Health::Critical; 123ae16a899SMyung Bae } 124ae16a899SMyung Bae } 125ae16a899SMyung Bae 126ae16a899SMyung Bae inline void getFabricPortHealth( 127ae16a899SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 128ae16a899SMyung Bae const std::string& portPath, const std::string& serviceName) 129ae16a899SMyung Bae { 130ae16a899SMyung Bae asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 131ae16a899SMyung Bae dbus::utility::getProperty<bool>( 132ae16a899SMyung Bae serviceName, portPath, 133ae16a899SMyung Bae "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 134ae16a899SMyung Bae std::bind_front(afterGetFabricPortHealth, asyncResp)); 135ae16a899SMyung Bae } 136ae16a899SMyung Bae 13737937d51SGeorge Liu inline void getFabricPortProperties( 13837937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 13937937d51SGeorge Liu const std::string& systemName, const std::string& adapterId, 1407842c99fSMyung Bae const std::string& portId, const std::string& portPath, 1417842c99fSMyung Bae const std::string& serviceName) 14237937d51SGeorge Liu { 14337937d51SGeorge Liu if (portPath.empty()) 14437937d51SGeorge Liu { 14537937d51SGeorge Liu BMCWEB_LOG_WARNING("Port not found"); 14637937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "Port", portId); 14737937d51SGeorge Liu return; 14837937d51SGeorge Liu } 14937937d51SGeorge Liu 15037937d51SGeorge Liu asyncResp->res.addHeader( 15137937d51SGeorge Liu boost::beast::http::field::link, 15237937d51SGeorge Liu "</redfish/v1/JsonSchemas/Port/Port.json>; rel=describedby"); 15337937d51SGeorge Liu 15437937d51SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = "#Port.v1_11_0.Port"; 15537937d51SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = 15637937d51SGeorge Liu boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters/{}/Ports/{}", 15737937d51SGeorge Liu systemName, adapterId, portId); 15837937d51SGeorge Liu asyncResp->res.jsonValue["Id"] = portId; 15937937d51SGeorge Liu asyncResp->res.jsonValue["Name"] = "Fabric Port"; 160ae16a899SMyung Bae 1617842c99fSMyung Bae getFabricPortLocation(asyncResp, portPath, serviceName); 162ae16a899SMyung Bae getFabricPortState(asyncResp, portPath, serviceName); 163ae16a899SMyung Bae getFabricPortHealth(asyncResp, portPath, serviceName); 164*fc1342c5SMyung Bae getLocationIndicatorActive(asyncResp, portPath); 16537937d51SGeorge Liu } 16637937d51SGeorge Liu 16737937d51SGeorge Liu inline void afterGetValidFabricPortPath( 16837937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 16937937d51SGeorge Liu const std::string& portId, 1707842c99fSMyung Bae std::function<void(const std::string& portPath, 1717842c99fSMyung Bae const std::string& portServiceName)>& callback, 17237937d51SGeorge Liu const boost::system::error_code& ec, 17337937d51SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& portSubTreePaths) 17437937d51SGeorge Liu { 17537937d51SGeorge Liu if (ec) 17637937d51SGeorge Liu { 17737937d51SGeorge Liu if (ec.value() != boost::system::errc::io_error) 17837937d51SGeorge Liu { 17937937d51SGeorge Liu BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 18037937d51SGeorge Liu messages::internalError(asyncResp->res); 18137937d51SGeorge Liu return; 18237937d51SGeorge Liu } 18337937d51SGeorge Liu // Port not found 1847842c99fSMyung Bae callback(std::string(), std::string()); 18537937d51SGeorge Liu return; 18637937d51SGeorge Liu } 18737937d51SGeorge Liu const auto& it = 18837937d51SGeorge Liu std::ranges::find_if(portSubTreePaths, [portId](const auto& portPath) { 18937937d51SGeorge Liu return portId == 19037937d51SGeorge Liu sdbusplus::message::object_path(portPath).filename(); 19137937d51SGeorge Liu }); 19237937d51SGeorge Liu if (it == portSubTreePaths.end()) 19337937d51SGeorge Liu { 19437937d51SGeorge Liu // Port not found 1957842c99fSMyung Bae callback(std::string(), std::string()); 19637937d51SGeorge Liu return; 19737937d51SGeorge Liu } 19837937d51SGeorge Liu 19937937d51SGeorge Liu const std::string& portPath = *it; 20037937d51SGeorge Liu dbus::utility::getDbusObject( 20137937d51SGeorge Liu portPath, portInterfaces, 20237937d51SGeorge Liu [asyncResp, portPath, callback{std::move(callback)}]( 20337937d51SGeorge Liu const boost::system::error_code& ec1, 20437937d51SGeorge Liu const dbus::utility::MapperGetObject& object) { 20537937d51SGeorge Liu if (ec1 || object.empty()) 20637937d51SGeorge Liu { 20737937d51SGeorge Liu BMCWEB_LOG_ERROR("DBUS response error on getDbusObject {}", 20837937d51SGeorge Liu ec1.value()); 20937937d51SGeorge Liu messages::internalError(asyncResp->res); 21037937d51SGeorge Liu return; 21137937d51SGeorge Liu } 2127842c99fSMyung Bae callback(portPath, object.begin()->first); 21337937d51SGeorge Liu }); 21437937d51SGeorge Liu } 21537937d51SGeorge Liu 21637937d51SGeorge Liu inline void getValidFabricPortPath( 21737937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21837937d51SGeorge Liu const std::string& adapterId, const std::string& portId, 2197842c99fSMyung Bae std::function<void(const std::string& portPath, 2207842c99fSMyung Bae const std::string& portServiceName)>&& callback) 22137937d51SGeorge Liu { 22237937d51SGeorge Liu dbus::utility::getAssociatedSubTreePathsById( 22337937d51SGeorge Liu adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces, 22437937d51SGeorge Liu "connecting", portInterfaces, 22537937d51SGeorge Liu std::bind_front(afterGetValidFabricPortPath, asyncResp, portId, 22637937d51SGeorge Liu std::move(callback))); 22737937d51SGeorge Liu } 22837937d51SGeorge Liu 22937937d51SGeorge Liu inline void handleFabricPortHead( 23037937d51SGeorge Liu crow::App& app, const crow::Request& req, 23137937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 23237937d51SGeorge Liu const std::string& systemName, const std::string& adapterId, 23337937d51SGeorge Liu const std::string& portId) 23437937d51SGeorge Liu { 23537937d51SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 23637937d51SGeorge Liu { 23737937d51SGeorge Liu return; 23837937d51SGeorge Liu } 23937937d51SGeorge Liu if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 24037937d51SGeorge Liu { 24137937d51SGeorge Liu // Option currently returns no systems. TBD 24237937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 24337937d51SGeorge Liu systemName); 24437937d51SGeorge Liu return; 24537937d51SGeorge Liu } 24637937d51SGeorge Liu if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 24737937d51SGeorge Liu { 24837937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 24937937d51SGeorge Liu systemName); 25037937d51SGeorge Liu return; 25137937d51SGeorge Liu } 25237937d51SGeorge Liu 25337937d51SGeorge Liu getValidFabricPortPath( 25437937d51SGeorge Liu asyncResp, adapterId, portId, 2557842c99fSMyung Bae [asyncResp, portId](const std::string& portPath, const std::string&) { 25637937d51SGeorge Liu if (portPath.empty()) 25737937d51SGeorge Liu { 25837937d51SGeorge Liu BMCWEB_LOG_WARNING("Port not found"); 25937937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "Port", portId); 26037937d51SGeorge Liu return; 26137937d51SGeorge Liu } 26237937d51SGeorge Liu asyncResp->res.addHeader( 26337937d51SGeorge Liu boost::beast::http::field::link, 26437937d51SGeorge Liu "</redfish/v1/JsonSchemas/Port/Port.json>; rel=describedby"); 26537937d51SGeorge Liu }); 26637937d51SGeorge Liu } 26737937d51SGeorge Liu 26837937d51SGeorge Liu inline void handleFabricPortGet( 26937937d51SGeorge Liu App& app, const crow::Request& req, 27037937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 27137937d51SGeorge Liu const std::string& systemName, const std::string& adapterId, 27237937d51SGeorge Liu const std::string& portId) 27337937d51SGeorge Liu { 27437937d51SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 27537937d51SGeorge Liu { 27637937d51SGeorge Liu return; 27737937d51SGeorge Liu } 27837937d51SGeorge Liu if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 27937937d51SGeorge Liu { 28037937d51SGeorge Liu // Option currently returns no systems. TBD 28137937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 28237937d51SGeorge Liu systemName); 28337937d51SGeorge Liu return; 28437937d51SGeorge Liu } 28537937d51SGeorge Liu if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 28637937d51SGeorge Liu { 28737937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 28837937d51SGeorge Liu systemName); 28937937d51SGeorge Liu return; 29037937d51SGeorge Liu } 29137937d51SGeorge Liu getValidFabricPortPath(asyncResp, adapterId, portId, 29237937d51SGeorge Liu std::bind_front(getFabricPortProperties, asyncResp, 29337937d51SGeorge Liu systemName, adapterId, portId)); 29437937d51SGeorge Liu } 29537937d51SGeorge Liu 29637937d51SGeorge Liu inline void afterHandleFabricPortCollectionHead( 29737937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 29837937d51SGeorge Liu const std::string& adapterId, const boost::system::error_code& ec, 29937937d51SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& /* portSubTreePaths */) 30037937d51SGeorge Liu { 30137937d51SGeorge Liu if (ec) 30237937d51SGeorge Liu { 30337937d51SGeorge Liu if (ec.value() != boost::system::errc::io_error) 30437937d51SGeorge Liu { 30537937d51SGeorge Liu BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 30637937d51SGeorge Liu messages::internalError(asyncResp->res); 30737937d51SGeorge Liu return; 30837937d51SGeorge Liu } 30937937d51SGeorge Liu BMCWEB_LOG_WARNING("Adapter not found"); 31037937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "Adapter", adapterId); 31137937d51SGeorge Liu return; 31237937d51SGeorge Liu } 31337937d51SGeorge Liu asyncResp->res.addHeader( 31437937d51SGeorge Liu boost::beast::http::field::link, 31537937d51SGeorge Liu "</redfish/v1/JsonSchemas/PortCollection/PortCollection.json>; rel=describedby"); 31637937d51SGeorge Liu } 31737937d51SGeorge Liu 31837937d51SGeorge Liu inline void handleFabricPortCollectionHead( 31937937d51SGeorge Liu crow::App& app, const crow::Request& req, 32037937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 32137937d51SGeorge Liu const std::string& systemName, const std::string& adapterId) 32237937d51SGeorge Liu { 32337937d51SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 32437937d51SGeorge Liu { 32537937d51SGeorge Liu return; 32637937d51SGeorge Liu } 32737937d51SGeorge Liu if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 32837937d51SGeorge Liu { 32937937d51SGeorge Liu // Option currently returns no systems. TBD 33037937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33137937d51SGeorge Liu systemName); 33237937d51SGeorge Liu return; 33337937d51SGeorge Liu } 33437937d51SGeorge Liu if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 33537937d51SGeorge Liu { 33637937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 33737937d51SGeorge Liu systemName); 33837937d51SGeorge Liu return; 33937937d51SGeorge Liu } 34037937d51SGeorge Liu 34137937d51SGeorge Liu dbus::utility::getAssociatedSubTreePathsById( 34237937d51SGeorge Liu adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces, 34337937d51SGeorge Liu "connecting", portInterfaces, 34437937d51SGeorge Liu std::bind_front(afterHandleFabricPortCollectionHead, asyncResp, 34537937d51SGeorge Liu adapterId)); 34637937d51SGeorge Liu } 34737937d51SGeorge Liu 34837937d51SGeorge Liu inline void doHandleFabricPortCollectionGet( 34937937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 35037937d51SGeorge Liu const std::string& systemName, const std::string& adapterId, 35137937d51SGeorge Liu const boost::system::error_code& ec, 35237937d51SGeorge Liu const dbus::utility::MapperGetSubTreePathsResponse& portSubTreePaths) 35337937d51SGeorge Liu { 35437937d51SGeorge Liu if (ec) 35537937d51SGeorge Liu { 35637937d51SGeorge Liu if (ec.value() != boost::system::errc::io_error) 35737937d51SGeorge Liu { 35837937d51SGeorge Liu BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 35937937d51SGeorge Liu messages::internalError(asyncResp->res); 36037937d51SGeorge Liu return; 36137937d51SGeorge Liu } 36237937d51SGeorge Liu BMCWEB_LOG_WARNING("Adapter not found"); 36337937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "Adapter", adapterId); 36437937d51SGeorge Liu return; 36537937d51SGeorge Liu } 36637937d51SGeorge Liu asyncResp->res.addHeader( 36737937d51SGeorge Liu boost::beast::http::field::link, 36837937d51SGeorge Liu "</redfish/v1/JsonSchemas/PortCollection/PortCollection.json>; rel=describedby"); 36937937d51SGeorge Liu 37037937d51SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = "#PortCollection.PortCollection"; 37137937d51SGeorge Liu asyncResp->res.jsonValue["Name"] = "Port Collection"; 37237937d51SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = 37337937d51SGeorge Liu boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters/{}/Ports", 37437937d51SGeorge Liu systemName, adapterId); 37537937d51SGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 37637937d51SGeorge Liu 37737937d51SGeorge Liu std::vector<std::string> portIdNames; 37837937d51SGeorge Liu for (const std::string& portPath : portSubTreePaths) 37937937d51SGeorge Liu { 38037937d51SGeorge Liu std::string portId = 38137937d51SGeorge Liu sdbusplus::message::object_path(portPath).filename(); 38237937d51SGeorge Liu if (!portId.empty()) 38337937d51SGeorge Liu { 38437937d51SGeorge Liu portIdNames.emplace_back(std::move(portId)); 38537937d51SGeorge Liu } 38637937d51SGeorge Liu } 38737937d51SGeorge Liu 38837937d51SGeorge Liu std::ranges::sort(portIdNames, AlphanumLess<std::string>()); 38937937d51SGeorge Liu 39037937d51SGeorge Liu nlohmann::json& members = asyncResp->res.jsonValue["Members"]; 39137937d51SGeorge Liu for (const std::string& portId : portIdNames) 39237937d51SGeorge Liu { 39337937d51SGeorge Liu nlohmann::json item; 39437937d51SGeorge Liu item["@odata.id"] = boost::urls::format( 39537937d51SGeorge Liu "/redfish/v1/Systems/{}/FabricAdapters/{}/Ports/{}", systemName, 39637937d51SGeorge Liu adapterId, portId); 39737937d51SGeorge Liu members.emplace_back(std::move(item)); 39837937d51SGeorge Liu } 39937937d51SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = members.size(); 40037937d51SGeorge Liu } 40137937d51SGeorge Liu 40237937d51SGeorge Liu inline void handleFabricPortCollectionGet( 40337937d51SGeorge Liu App& app, const crow::Request& req, 40437937d51SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 40537937d51SGeorge Liu const std::string& systemName, const std::string& adapterId) 40637937d51SGeorge Liu { 40737937d51SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 40837937d51SGeorge Liu { 40937937d51SGeorge Liu return; 41037937d51SGeorge Liu } 41137937d51SGeorge Liu if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 41237937d51SGeorge Liu { 41337937d51SGeorge Liu // Option currently returns no systems. TBD 41437937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 41537937d51SGeorge Liu systemName); 41637937d51SGeorge Liu return; 41737937d51SGeorge Liu } 41837937d51SGeorge Liu if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 41937937d51SGeorge Liu { 42037937d51SGeorge Liu messages::resourceNotFound(asyncResp->res, "ComputerSystem", 42137937d51SGeorge Liu systemName); 42237937d51SGeorge Liu return; 42337937d51SGeorge Liu } 42437937d51SGeorge Liu 42537937d51SGeorge Liu dbus::utility::getAssociatedSubTreePathsById( 42637937d51SGeorge Liu adapterId, "/xyz/openbmc_project/inventory", fabricInterfaces, 42737937d51SGeorge Liu "connecting", portInterfaces, 42837937d51SGeorge Liu std::bind_front(doHandleFabricPortCollectionGet, asyncResp, systemName, 42937937d51SGeorge Liu adapterId)); 43037937d51SGeorge Liu } 431*fc1342c5SMyung Bae 432*fc1342c5SMyung Bae inline void afterHandlePortPatch( 433*fc1342c5SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 434*fc1342c5SMyung Bae const std::string& portId, const bool locationIndicatorActive, 435*fc1342c5SMyung Bae const std::string& portPath, const std::string& /*serviceName*/) 436*fc1342c5SMyung Bae { 437*fc1342c5SMyung Bae if (portPath.empty()) 438*fc1342c5SMyung Bae { 439*fc1342c5SMyung Bae BMCWEB_LOG_WARNING("Port not found"); 440*fc1342c5SMyung Bae messages::resourceNotFound(asyncResp->res, "Port", portId); 441*fc1342c5SMyung Bae return; 442*fc1342c5SMyung Bae } 443*fc1342c5SMyung Bae 444*fc1342c5SMyung Bae setLocationIndicatorActive(asyncResp, portPath, locationIndicatorActive); 445*fc1342c5SMyung Bae } 446*fc1342c5SMyung Bae 447*fc1342c5SMyung Bae inline void handlePortPatch(App& app, const crow::Request& req, 448*fc1342c5SMyung Bae const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 449*fc1342c5SMyung Bae const std::string& systemName, 450*fc1342c5SMyung Bae const std::string& adapterId, 451*fc1342c5SMyung Bae const std::string& portId) 452*fc1342c5SMyung Bae { 453*fc1342c5SMyung Bae if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 454*fc1342c5SMyung Bae { 455*fc1342c5SMyung Bae return; 456*fc1342c5SMyung Bae } 457*fc1342c5SMyung Bae if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 458*fc1342c5SMyung Bae { 459*fc1342c5SMyung Bae // Option currently returns no systems. TBD 460*fc1342c5SMyung Bae messages::resourceNotFound(asyncResp->res, "ComputerSystem", 461*fc1342c5SMyung Bae systemName); 462*fc1342c5SMyung Bae return; 463*fc1342c5SMyung Bae } 464*fc1342c5SMyung Bae if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 465*fc1342c5SMyung Bae { 466*fc1342c5SMyung Bae messages::resourceNotFound(asyncResp->res, "ComputerSystem", 467*fc1342c5SMyung Bae systemName); 468*fc1342c5SMyung Bae return; 469*fc1342c5SMyung Bae } 470*fc1342c5SMyung Bae 471*fc1342c5SMyung Bae std::optional<bool> locationIndicatorActive; 472*fc1342c5SMyung Bae if (!json_util::readJsonPatch(req, asyncResp->res, 473*fc1342c5SMyung Bae "LocationIndicatorActive", 474*fc1342c5SMyung Bae locationIndicatorActive)) 475*fc1342c5SMyung Bae { 476*fc1342c5SMyung Bae return; 477*fc1342c5SMyung Bae } 478*fc1342c5SMyung Bae if (locationIndicatorActive) 479*fc1342c5SMyung Bae { 480*fc1342c5SMyung Bae getValidFabricPortPath( 481*fc1342c5SMyung Bae asyncResp, adapterId, portId, 482*fc1342c5SMyung Bae std::bind_front(afterHandlePortPatch, asyncResp, portId, 483*fc1342c5SMyung Bae *locationIndicatorActive)); 484*fc1342c5SMyung Bae } 485*fc1342c5SMyung Bae } 486*fc1342c5SMyung Bae 48737937d51SGeorge Liu inline void requestRoutesFabricPort(App& app) 48837937d51SGeorge Liu { 48937937d51SGeorge Liu BMCWEB_ROUTE(app, 49037937d51SGeorge Liu "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/<str>/") 49137937d51SGeorge Liu .privileges(redfish::privileges::headPort) 49237937d51SGeorge Liu .methods(boost::beast::http::verb::head)( 49337937d51SGeorge Liu std::bind_front(handleFabricPortHead, std::ref(app))); 49437937d51SGeorge Liu 49537937d51SGeorge Liu BMCWEB_ROUTE(app, 49637937d51SGeorge Liu "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/<str>/") 49737937d51SGeorge Liu .privileges(redfish::privileges::getPort) 49837937d51SGeorge Liu .methods(boost::beast::http::verb::get)( 49937937d51SGeorge Liu std::bind_front(handleFabricPortGet, std::ref(app))); 50037937d51SGeorge Liu 50137937d51SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/") 50237937d51SGeorge Liu .privileges(redfish::privileges::headPortCollection) 50337937d51SGeorge Liu .methods(boost::beast::http::verb::head)( 50437937d51SGeorge Liu std::bind_front(handleFabricPortCollectionHead, std::ref(app))); 50537937d51SGeorge Liu 50637937d51SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/") 50737937d51SGeorge Liu .privileges(redfish::privileges::getPortCollection) 50837937d51SGeorge Liu .methods(boost::beast::http::verb::get)( 50937937d51SGeorge Liu std::bind_front(handleFabricPortCollectionGet, std::ref(app))); 510*fc1342c5SMyung Bae 511*fc1342c5SMyung Bae BMCWEB_ROUTE(app, 512*fc1342c5SMyung Bae "/redfish/v1/Systems/<str>/FabricAdapters/<str>/Ports/<str>/") 513*fc1342c5SMyung Bae .privileges(redfish::privileges::patchPort) 514*fc1342c5SMyung Bae .methods(boost::beast::http::verb::patch)( 515*fc1342c5SMyung Bae std::bind_front(handlePortPatch, std::ref(app))); 51637937d51SGeorge Liu } 51737937d51SGeorge Liu 51837937d51SGeorge Liu } // namespace redfish 519