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
afterGetFabricPortLocation(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::string & value)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
getFabricPortLocation(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & portPath,const std::string & serviceName)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
afterGetFabricPortState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,bool present)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
getFabricPortState(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & portPath,const std::string & serviceName)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
afterGetFabricPortHealth(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,bool functional)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
getFabricPortHealth(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & portPath,const std::string & serviceName)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
getFabricPortProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & adapterId,const std::string & portId,const std::string & portPath,const std::string & serviceName)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
afterGetValidFabricPortPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & portId,std::function<void (const std::string & portPath,const std::string & portServiceName)> & callback,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & portSubTreePaths)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
getValidFabricPortPath(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & adapterId,const std::string & portId,std::function<void (const std::string & portPath,const std::string & portServiceName)> && callback)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
handleFabricPortHead(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & adapterId,const std::string & portId)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
handleFabricPortGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & adapterId,const std::string & portId)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
afterHandleFabricPortCollectionHead(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & adapterId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse &)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
handleFabricPortCollectionHead(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & adapterId)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
doHandleFabricPortCollectionGet(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & adapterId,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & portSubTreePaths)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
handleFabricPortCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & adapterId)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
afterHandlePortPatch(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & portId,const bool locationIndicatorActive,const std::string & portPath,const std::string &)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
handlePortPatch(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName,const std::string & adapterId,const std::string & portId)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
requestRoutesFabricPort(App & app)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