1 #pragma once 2 3 #include "app.hpp" 4 #include "dbus_utility.hpp" 5 #include "query.hpp" 6 #include "registries/privilege_registry.hpp" 7 #include "utils/collection.hpp" 8 #include "utils/json_utils.hpp" 9 10 #include <boost/system/error_code.hpp> 11 12 #include <array> 13 #include <functional> 14 #include <memory> 15 #include <string> 16 #include <string_view> 17 18 namespace redfish 19 { 20 21 inline void handleAdapterError(const boost::system::error_code& ec, 22 crow::Response& res, 23 const std::string& adapterId) 24 { 25 26 if (ec.value() == boost::system::errc::io_error) 27 { 28 messages::resourceNotFound(res, "#FabricAdapter.v1_4_0.FabricAdapter", 29 adapterId); 30 return; 31 } 32 33 BMCWEB_LOG_ERROR << "DBus method call failed with error " << ec.value(); 34 messages::internalError(res); 35 } 36 37 inline void 38 getFabricAdapterLocation(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 39 const std::string& serviceName, 40 const std::string& fabricAdapterPath) 41 { 42 sdbusplus::asio::getProperty<std::string>( 43 *crow::connections::systemBus, serviceName, fabricAdapterPath, 44 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 45 [aResp](const boost::system::error_code ec, 46 const std::string& property) { 47 if (ec) 48 { 49 if (ec.value() != EBADR) 50 { 51 BMCWEB_LOG_ERROR << "DBUS response error for Location"; 52 messages::internalError(aResp->res); 53 } 54 return; 55 } 56 57 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 58 property; 59 }); 60 } 61 62 inline void doAdapterGet(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 63 const std::string& systemName, 64 const std::string& adapterId, 65 const std::string& fabricAdapterPath, 66 const std::string& serviceName) 67 { 68 aResp->res.addHeader( 69 boost::beast::http::field::link, 70 "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby"); 71 aResp->res.jsonValue["@odata.type"] = "#FabricAdapter.v1_4_0.FabricAdapter"; 72 aResp->res.jsonValue["Name"] = "Fabric Adapter"; 73 aResp->res.jsonValue["Id"] = adapterId; 74 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 75 "redfish", "v1", "Systems", systemName, "FabricAdapters", adapterId); 76 77 getFabricAdapterLocation(aResp, serviceName, fabricAdapterPath); 78 } 79 80 inline bool checkFabricAdapterId(const std::string& adapterPath, 81 const std::string& adapterId) 82 { 83 std::string fabricAdapterName = 84 sdbusplus::message::object_path(adapterPath).filename(); 85 86 return !(fabricAdapterName.empty() || fabricAdapterName != adapterId); 87 } 88 89 inline void getValidFabricAdapterPath( 90 const std::string& adapterId, const std::string& systemName, 91 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 92 std::function<void(const std::string& fabricAdapterPath, 93 const std::string& serviceName)>&& callback) 94 { 95 if (systemName != "system") 96 { 97 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 98 return; 99 } 100 constexpr std::array<std::string_view, 1> interfaces{ 101 "xyz.openbmc_project.Inventory.Item.FabricAdapter"}; 102 103 dbus::utility::getSubTree( 104 "/xyz/openbmc_project/inventory", 0, interfaces, 105 [adapterId, aResp, 106 callback](const boost::system::error_code& ec, 107 const dbus::utility::MapperGetSubTreeResponse& subtree) { 108 if (ec) 109 { 110 handleAdapterError(ec, aResp->res, adapterId); 111 return; 112 } 113 for (const auto& [adapterPath, serviceMap] : subtree) 114 { 115 if (checkFabricAdapterId(adapterPath, adapterId)) 116 { 117 callback(adapterPath, serviceMap.begin()->first); 118 return; 119 } 120 } 121 BMCWEB_LOG_WARNING << "Adapter not found"; 122 messages::resourceNotFound(aResp->res, "FabricAdapter", adapterId); 123 }); 124 } 125 126 inline void 127 handleFabricAdapterGet(App& app, const crow::Request& req, 128 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 129 const std::string& systemName, 130 const std::string& adapterId) 131 { 132 if (!redfish::setUpRedfishRoute(app, req, aResp)) 133 { 134 return; 135 } 136 137 getValidFabricAdapterPath( 138 adapterId, systemName, aResp, 139 [aResp, systemName, adapterId](const std::string& fabricAdapterPath, 140 const std::string& serviceName) { 141 doAdapterGet(aResp, systemName, adapterId, fabricAdapterPath, 142 serviceName); 143 }); 144 } 145 146 inline void handleFabricAdapterCollectionGet( 147 crow::App& app, const crow::Request& req, 148 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 149 const std::string& systemName) 150 { 151 if (!redfish::setUpRedfishRoute(app, req, aResp)) 152 { 153 return; 154 } 155 if (systemName != "system") 156 { 157 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 158 return; 159 } 160 161 aResp->res.addHeader( 162 boost::beast::http::field::link, 163 "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby"); 164 aResp->res.jsonValue["@odata.type"] = 165 "#FabricAdapterCollection.FabricAdapterCollection"; 166 aResp->res.jsonValue["Name"] = "Fabric Adapter Collection"; 167 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 168 "redfish", "v1", "Systems", systemName, "FabricAdapters"); 169 170 constexpr std::array<std::string_view, 1> interfaces{ 171 "xyz.openbmc_project.Inventory.Item.FabricAdapter"}; 172 collection_util::getCollectionMembers( 173 aResp, boost::urls::url("/redfish/v1/Systems/system/FabricAdapters"), 174 interfaces); 175 } 176 177 inline void handleFabricAdapterCollectionHead( 178 crow::App& app, const crow::Request& req, 179 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 180 const std::string& systemName) 181 { 182 if (!redfish::setUpRedfishRoute(app, req, aResp)) 183 { 184 return; 185 } 186 if (systemName != "system") 187 { 188 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 189 return; 190 } 191 aResp->res.addHeader( 192 boost::beast::http::field::link, 193 "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby"); 194 } 195 196 inline void 197 handleFabricAdapterHead(crow::App& app, const crow::Request& req, 198 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 199 const std::string& systemName, 200 const std::string& adapterId) 201 { 202 if (!redfish::setUpRedfishRoute(app, req, aResp)) 203 { 204 return; 205 } 206 207 getValidFabricAdapterPath( 208 adapterId, systemName, aResp, 209 [aResp, systemName, adapterId](const std::string&, const std::string&) { 210 aResp->res.addHeader( 211 boost::beast::http::field::link, 212 "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby"); 213 }); 214 } 215 216 inline void requestRoutesFabricAdapterCollection(App& app) 217 { 218 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/") 219 .privileges(redfish::privileges::getFabricAdapterCollection) 220 .methods(boost::beast::http::verb::get)( 221 std::bind_front(handleFabricAdapterCollectionGet, std::ref(app))); 222 223 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/") 224 .privileges(redfish::privileges::headFabricAdapterCollection) 225 .methods(boost::beast::http::verb::head)( 226 std::bind_front(handleFabricAdapterCollectionHead, std::ref(app))); 227 } 228 229 inline void requestRoutesFabricAdapters(App& app) 230 { 231 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/") 232 .privileges(redfish::privileges::getFabricAdapter) 233 .methods(boost::beast::http::verb::get)( 234 std::bind_front(handleFabricAdapterGet, std::ref(app))); 235 236 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/") 237 .privileges(redfish::privileges::headFabricAdapter) 238 .methods(boost::beast::http::verb::head)( 239 std::bind_front(handleFabricAdapterHead, std::ref(app))); 240 } 241 } // namespace redfish 242