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/dbus_utils.hpp" 9 #include "utils/json_utils.hpp" 10 11 #include <boost/system/error_code.hpp> 12 #include <sdbusplus/asio/property.hpp> 13 #include <sdbusplus/unpack_properties.hpp> 14 15 #include <array> 16 #include <functional> 17 #include <memory> 18 #include <string> 19 #include <string_view> 20 21 namespace redfish 22 { 23 24 inline void handleAdapterError(const boost::system::error_code& ec, 25 crow::Response& res, 26 const std::string& adapterId) 27 { 28 29 if (ec.value() == boost::system::errc::io_error) 30 { 31 messages::resourceNotFound(res, "#FabricAdapter.v1_4_0.FabricAdapter", 32 adapterId); 33 return; 34 } 35 36 BMCWEB_LOG_ERROR << "DBus method call failed with error " << ec.value(); 37 messages::internalError(res); 38 } 39 40 inline void 41 getFabricAdapterLocation(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 42 const std::string& serviceName, 43 const std::string& fabricAdapterPath) 44 { 45 sdbusplus::asio::getProperty<std::string>( 46 *crow::connections::systemBus, serviceName, fabricAdapterPath, 47 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 48 [aResp](const boost::system::error_code& ec, 49 const std::string& property) { 50 if (ec) 51 { 52 if (ec.value() != EBADR) 53 { 54 BMCWEB_LOG_ERROR << "DBUS response error for Location"; 55 messages::internalError(aResp->res); 56 } 57 return; 58 } 59 60 aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 61 property; 62 }); 63 } 64 65 inline void 66 getFabricAdapterAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 67 const std::string& serviceName, 68 const std::string& fabricAdapterPath) 69 { 70 sdbusplus::asio::getAllProperties( 71 *crow::connections::systemBus, serviceName, fabricAdapterPath, 72 "xyz.openbmc_project.Inventory.Decorator.Asset", 73 [fabricAdapterPath, 74 aResp{aResp}](const boost::system::error_code& ec, 75 const dbus::utility::DBusPropertiesMap& propertiesList) { 76 if (ec) 77 { 78 if (ec.value() != EBADR) 79 { 80 BMCWEB_LOG_ERROR << "DBUS response error for Properties"; 81 messages::internalError(aResp->res); 82 } 83 return; 84 } 85 86 const std::string* serialNumber = nullptr; 87 const std::string* model = nullptr; 88 const std::string* partNumber = nullptr; 89 const std::string* sparePartNumber = nullptr; 90 91 const bool success = sdbusplus::unpackPropertiesNoThrow( 92 dbus_utils::UnpackErrorPrinter(), propertiesList, "SerialNumber", 93 serialNumber, "Model", model, "PartNumber", partNumber, 94 "SparePartNumber", sparePartNumber); 95 96 if (!success) 97 { 98 messages::internalError(aResp->res); 99 return; 100 } 101 102 if (serialNumber != nullptr) 103 { 104 aResp->res.jsonValue["SerialNumber"] = *serialNumber; 105 } 106 107 if (model != nullptr) 108 { 109 aResp->res.jsonValue["Model"] = *model; 110 } 111 112 if (partNumber != nullptr) 113 { 114 aResp->res.jsonValue["PartNumber"] = *partNumber; 115 } 116 117 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 118 { 119 aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 120 } 121 }); 122 } 123 124 inline void 125 getFabricAdapterState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 126 const std::string& serviceName, 127 const std::string& fabricAdapterPath) 128 { 129 sdbusplus::asio::getProperty<bool>( 130 *crow::connections::systemBus, serviceName, fabricAdapterPath, 131 "xyz.openbmc_project.Inventory.Item", "Present", 132 [aResp](const boost::system::error_code& ec, const bool present) { 133 if (ec) 134 { 135 if (ec.value() != EBADR) 136 { 137 BMCWEB_LOG_ERROR << "DBUS response error for State"; 138 messages::internalError(aResp->res); 139 } 140 return; 141 } 142 143 if (!present) 144 { 145 aResp->res.jsonValue["Status"]["State"] = "Absent"; 146 } 147 }); 148 } 149 150 inline void 151 getFabricAdapterHealth(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 152 const std::string& serviceName, 153 const std::string& fabricAdapterPath) 154 { 155 sdbusplus::asio::getProperty<bool>( 156 *crow::connections::systemBus, serviceName, fabricAdapterPath, 157 "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 158 [aResp](const boost::system::error_code& ec, const bool functional) { 159 if (ec) 160 { 161 if (ec.value() != EBADR) 162 { 163 BMCWEB_LOG_ERROR << "DBUS response error for Health"; 164 messages::internalError(aResp->res); 165 } 166 return; 167 } 168 169 if (!functional) 170 { 171 aResp->res.jsonValue["Status"]["Health"] = "Critical"; 172 } 173 }); 174 } 175 176 inline void doAdapterGet(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 177 const std::string& systemName, 178 const std::string& adapterId, 179 const std::string& fabricAdapterPath, 180 const std::string& serviceName) 181 { 182 aResp->res.addHeader( 183 boost::beast::http::field::link, 184 "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby"); 185 aResp->res.jsonValue["@odata.type"] = "#FabricAdapter.v1_4_0.FabricAdapter"; 186 aResp->res.jsonValue["Name"] = "Fabric Adapter"; 187 aResp->res.jsonValue["Id"] = adapterId; 188 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 189 "redfish", "v1", "Systems", systemName, "FabricAdapters", adapterId); 190 191 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 192 aResp->res.jsonValue["Status"]["Health"] = "OK"; 193 194 getFabricAdapterLocation(aResp, serviceName, fabricAdapterPath); 195 getFabricAdapterAsset(aResp, serviceName, fabricAdapterPath); 196 getFabricAdapterState(aResp, serviceName, fabricAdapterPath); 197 getFabricAdapterHealth(aResp, serviceName, fabricAdapterPath); 198 } 199 200 inline bool checkFabricAdapterId(const std::string& adapterPath, 201 const std::string& adapterId) 202 { 203 std::string fabricAdapterName = 204 sdbusplus::message::object_path(adapterPath).filename(); 205 206 return !(fabricAdapterName.empty() || fabricAdapterName != adapterId); 207 } 208 209 inline void getValidFabricAdapterPath( 210 const std::string& adapterId, const std::string& systemName, 211 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 212 std::function<void(const std::string& fabricAdapterPath, 213 const std::string& serviceName)>&& callback) 214 { 215 if (systemName != "system") 216 { 217 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 218 return; 219 } 220 constexpr std::array<std::string_view, 1> interfaces{ 221 "xyz.openbmc_project.Inventory.Item.FabricAdapter"}; 222 223 dbus::utility::getSubTree( 224 "/xyz/openbmc_project/inventory", 0, interfaces, 225 [adapterId, aResp, 226 callback](const boost::system::error_code& ec, 227 const dbus::utility::MapperGetSubTreeResponse& subtree) { 228 if (ec) 229 { 230 handleAdapterError(ec, aResp->res, adapterId); 231 return; 232 } 233 for (const auto& [adapterPath, serviceMap] : subtree) 234 { 235 if (checkFabricAdapterId(adapterPath, adapterId)) 236 { 237 callback(adapterPath, serviceMap.begin()->first); 238 return; 239 } 240 } 241 BMCWEB_LOG_WARNING << "Adapter not found"; 242 messages::resourceNotFound(aResp->res, "FabricAdapter", adapterId); 243 }); 244 } 245 246 inline void 247 handleFabricAdapterGet(App& app, const crow::Request& req, 248 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 249 const std::string& systemName, 250 const std::string& adapterId) 251 { 252 if (!redfish::setUpRedfishRoute(app, req, aResp)) 253 { 254 return; 255 } 256 257 getValidFabricAdapterPath( 258 adapterId, systemName, aResp, 259 [aResp, systemName, adapterId](const std::string& fabricAdapterPath, 260 const std::string& serviceName) { 261 doAdapterGet(aResp, systemName, adapterId, fabricAdapterPath, 262 serviceName); 263 }); 264 } 265 266 inline void handleFabricAdapterCollectionGet( 267 crow::App& app, const crow::Request& req, 268 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 269 const std::string& systemName) 270 { 271 if (!redfish::setUpRedfishRoute(app, req, aResp)) 272 { 273 return; 274 } 275 if (systemName != "system") 276 { 277 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 278 return; 279 } 280 281 aResp->res.addHeader( 282 boost::beast::http::field::link, 283 "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby"); 284 aResp->res.jsonValue["@odata.type"] = 285 "#FabricAdapterCollection.FabricAdapterCollection"; 286 aResp->res.jsonValue["Name"] = "Fabric Adapter Collection"; 287 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 288 "redfish", "v1", "Systems", systemName, "FabricAdapters"); 289 290 constexpr std::array<std::string_view, 1> interfaces{ 291 "xyz.openbmc_project.Inventory.Item.FabricAdapter"}; 292 collection_util::getCollectionMembers( 293 aResp, boost::urls::url("/redfish/v1/Systems/system/FabricAdapters"), 294 interfaces); 295 } 296 297 inline void handleFabricAdapterCollectionHead( 298 crow::App& app, const crow::Request& req, 299 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 300 const std::string& systemName) 301 { 302 if (!redfish::setUpRedfishRoute(app, req, aResp)) 303 { 304 return; 305 } 306 if (systemName != "system") 307 { 308 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 309 return; 310 } 311 aResp->res.addHeader( 312 boost::beast::http::field::link, 313 "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby"); 314 } 315 316 inline void 317 handleFabricAdapterHead(crow::App& app, const crow::Request& req, 318 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 319 const std::string& systemName, 320 const std::string& adapterId) 321 { 322 if (!redfish::setUpRedfishRoute(app, req, aResp)) 323 { 324 return; 325 } 326 327 getValidFabricAdapterPath( 328 adapterId, systemName, aResp, 329 [aResp, systemName, adapterId](const std::string&, const std::string&) { 330 aResp->res.addHeader( 331 boost::beast::http::field::link, 332 "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby"); 333 }); 334 } 335 336 inline void requestRoutesFabricAdapterCollection(App& app) 337 { 338 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/") 339 .privileges(redfish::privileges::getFabricAdapterCollection) 340 .methods(boost::beast::http::verb::get)( 341 std::bind_front(handleFabricAdapterCollectionGet, std::ref(app))); 342 343 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/") 344 .privileges(redfish::privileges::headFabricAdapterCollection) 345 .methods(boost::beast::http::verb::head)( 346 std::bind_front(handleFabricAdapterCollectionHead, std::ref(app))); 347 } 348 349 inline void requestRoutesFabricAdapters(App& app) 350 { 351 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/") 352 .privileges(redfish::privileges::getFabricAdapter) 353 .methods(boost::beast::http::verb::get)( 354 std::bind_front(handleFabricAdapterGet, std::ref(app))); 355 356 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/") 357 .privileges(redfish::privileges::headFabricAdapter) 358 .methods(boost::beast::http::verb::head)( 359 std::bind_front(handleFabricAdapterHead, std::ref(app))); 360 } 361 } // namespace redfish 362