/* Copyright (c) 2018 Intel Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #pragma once #include "bmcweb_config.h" #include "app.hpp" #include "dbus_utility.hpp" #include "generated/enums/memory.hpp" #include "generated/enums/resource.hpp" #include "query.hpp" #include "registries/privilege_registry.hpp" #include "utils/collection.hpp" #include "utils/dbus_utils.hpp" #include "utils/hex_utils.hpp" #include "utils/json_utils.hpp" #include #include #include #include #include #include #include namespace redfish { inline std::string translateMemoryTypeToRedfish(const std::string& memoryType) { if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR") { return "DDR"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2") { return "DDR2"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR3") { return "DDR3"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4") { return "DDR4"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR4E_SDRAM") { return "DDR4E_SDRAM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR5") { return "DDR5"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR4_SDRAM") { return "LPDDR4_SDRAM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.LPDDR3_SDRAM") { return "LPDDR3_SDRAM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM") { return "DDR2_SDRAM_FB_DIMM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR2_SDRAM_FB_DIMM_PROB") { return "DDR2_SDRAM_FB_DIMM_PROBE"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.DDR_SGRAM") { return "DDR_SGRAM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.ROM") { return "ROM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.SDRAM") { return "SDRAM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.EDO") { return "EDO"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.FastPageMode") { return "FastPageMode"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.PipelinedNibble") { return "PipelinedNibble"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.Logical") { return "Logical"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM") { return "HBM"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM2") { return "HBM2"; } if (memoryType == "xyz.openbmc_project.Inventory.Item.Dimm.DeviceType.HBM3") { return "HBM3"; } // This is values like Other or Unknown // Also D-Bus values: // DRAM // EDRAM // VRAM // SRAM // RAM // FLASH // EEPROM // FEPROM // EPROM // CDRAM // ThreeDRAM // RDRAM // FBD2 // LPDDR_SDRAM // LPDDR2_SDRAM // LPDDR5_SDRAM return ""; } inline void dimmPropToHex(const std::shared_ptr& asyncResp, const char* key, const uint16_t* value, const nlohmann::json::json_pointer& jsonPtr) { if (value == nullptr) { return; } asyncResp->res.jsonValue[jsonPtr][key] = "0x" + intToHexString(*value, 4); } inline void getPersistentMemoryProperties( const std::shared_ptr& asyncResp, const dbus::utility::DBusPropertiesMap& properties, const nlohmann::json::json_pointer& jsonPtr) { const uint16_t* moduleManufacturerID = nullptr; const uint16_t* moduleProductID = nullptr; const uint16_t* subsystemVendorID = nullptr; const uint16_t* subsystemDeviceID = nullptr; const uint64_t* volatileRegionSizeLimitInKiB = nullptr; const uint64_t* pmRegionSizeLimitInKiB = nullptr; const uint64_t* volatileSizeInKiB = nullptr; const uint64_t* pmSizeInKiB = nullptr; const uint64_t* cacheSizeInKB = nullptr; const uint64_t* voltaileRegionMaxSizeInKib = nullptr; const uint64_t* pmRegionMaxSizeInKiB = nullptr; const uint64_t* allocationIncrementInKiB = nullptr; const uint64_t* allocationAlignmentInKiB = nullptr; const uint64_t* volatileRegionNumberLimit = nullptr; const uint64_t* pmRegionNumberLimit = nullptr; const uint64_t* spareDeviceCount = nullptr; const bool* isSpareDeviceInUse = nullptr; const bool* isRankSpareEnabled = nullptr; const std::vector* maxAveragePowerLimitmW = nullptr; const bool* configurationLocked = nullptr; const std::string* allowedMemoryModes = nullptr; const std::string* memoryMedia = nullptr; const bool* configurationLockCapable = nullptr; const bool* dataLockCapable = nullptr; const bool* passphraseCapable = nullptr; const uint64_t* maxPassphraseCount = nullptr; const uint64_t* passphraseLockLimit = nullptr; const bool success = sdbusplus::unpackPropertiesNoThrow( dbus_utils::UnpackErrorPrinter(), properties, "ModuleManufacturerID", moduleManufacturerID, "ModuleProductID", moduleProductID, "SubsystemVendorID", subsystemVendorID, "SubsystemDeviceID", subsystemDeviceID, "VolatileRegionSizeLimitInKiB", volatileRegionSizeLimitInKiB, "PmRegionSizeLimitInKiB", pmRegionSizeLimitInKiB, "VolatileSizeInKiB", volatileSizeInKiB, "PmSizeInKiB", pmSizeInKiB, "CacheSizeInKB", cacheSizeInKB, "VoltaileRegionMaxSizeInKib", voltaileRegionMaxSizeInKib, "PmRegionMaxSizeInKiB", pmRegionMaxSizeInKiB, "AllocationIncrementInKiB", allocationIncrementInKiB, "AllocationAlignmentInKiB", allocationAlignmentInKiB, "VolatileRegionNumberLimit", volatileRegionNumberLimit, "PmRegionNumberLimit", pmRegionNumberLimit, "SpareDeviceCount", spareDeviceCount, "IsSpareDeviceInUse", isSpareDeviceInUse, "IsRankSpareEnabled", isRankSpareEnabled, "MaxAveragePowerLimitmW", maxAveragePowerLimitmW, "ConfigurationLocked", configurationLocked, "AllowedMemoryModes", allowedMemoryModes, "MemoryMedia", memoryMedia, "ConfigurationLockCapable", configurationLockCapable, "DataLockCapable", dataLockCapable, "PassphraseCapable", passphraseCapable, "MaxPassphraseCount", maxPassphraseCount, "PassphraseLockLimit", passphraseLockLimit); if (!success) { messages::internalError(asyncResp->res); return; } dimmPropToHex(asyncResp, "ModuleManufacturerID", moduleManufacturerID, jsonPtr); dimmPropToHex(asyncResp, "ModuleProductID", moduleProductID, jsonPtr); dimmPropToHex(asyncResp, "MemorySubsystemControllerManufacturerID", subsystemVendorID, jsonPtr); dimmPropToHex(asyncResp, "MemorySubsystemControllerProductID", subsystemDeviceID, jsonPtr); if (volatileRegionSizeLimitInKiB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["VolatileRegionSizeLimitMiB"] = (*volatileRegionSizeLimitInKiB) >> 10; } if (pmRegionSizeLimitInKiB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["PersistentRegionSizeLimitMiB"] = (*pmRegionSizeLimitInKiB) >> 10; } if (volatileSizeInKiB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["VolatileSizeMiB"] = (*volatileSizeInKiB) >> 10; } if (pmSizeInKiB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["NonVolatileSizeMiB"] = (*pmSizeInKiB) >> 10; } if (cacheSizeInKB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["CacheSizeMiB"] = (*cacheSizeInKB >> 10); } if (voltaileRegionMaxSizeInKib != nullptr) { asyncResp->res.jsonValue[jsonPtr]["VolatileRegionSizeMaxMiB"] = (*voltaileRegionMaxSizeInKib) >> 10; } if (pmRegionMaxSizeInKiB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["PersistentRegionSizeMaxMiB"] = (*pmRegionMaxSizeInKiB) >> 10; } if (allocationIncrementInKiB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["AllocationIncrementMiB"] = (*allocationIncrementInKiB) >> 10; } if (allocationAlignmentInKiB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["AllocationAlignmentMiB"] = (*allocationAlignmentInKiB) >> 10; } if (volatileRegionNumberLimit != nullptr) { asyncResp->res.jsonValue[jsonPtr]["VolatileRegionNumberLimit"] = *volatileRegionNumberLimit; } if (pmRegionNumberLimit != nullptr) { asyncResp->res.jsonValue[jsonPtr]["PersistentRegionNumberLimit"] = *pmRegionNumberLimit; } if (spareDeviceCount != nullptr) { asyncResp->res.jsonValue[jsonPtr]["SpareDeviceCount"] = *spareDeviceCount; } if (isSpareDeviceInUse != nullptr) { asyncResp->res.jsonValue[jsonPtr]["IsSpareDeviceEnabled"] = *isSpareDeviceInUse; } if (isRankSpareEnabled != nullptr) { asyncResp->res.jsonValue[jsonPtr]["IsRankSpareEnabled"] = *isRankSpareEnabled; } if (maxAveragePowerLimitmW != nullptr) { asyncResp->res.jsonValue[jsonPtr]["MaxTDPMilliWatts"] = *maxAveragePowerLimitmW; } if (configurationLocked != nullptr) { asyncResp->res.jsonValue[jsonPtr]["ConfigurationLocked"] = *configurationLocked; } if (allowedMemoryModes != nullptr) { constexpr const std::array values{"Volatile", "PMEM", "Block"}; for (const char* v : values) { if (allowedMemoryModes->ends_with(v)) { asyncResp->res.jsonValue[jsonPtr]["OperatingMemoryModes"] .push_back(v); break; } } } if (memoryMedia != nullptr) { constexpr const std::array values{"DRAM", "NAND", "Intel3DXPoint"}; for (const char* v : values) { if (memoryMedia->ends_with(v)) { asyncResp->res.jsonValue[jsonPtr]["MemoryMedia"].push_back(v); break; } } } if (configurationLockCapable != nullptr) { asyncResp->res.jsonValue[jsonPtr]["SecurityCapabilities"] ["ConfigurationLockCapable"] = *configurationLockCapable; } if (dataLockCapable != nullptr) { asyncResp->res .jsonValue[jsonPtr]["SecurityCapabilities"]["DataLockCapable"] = *dataLockCapable; } if (passphraseCapable != nullptr) { asyncResp->res .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseCapable"] = *passphraseCapable; } if (maxPassphraseCount != nullptr) { asyncResp->res .jsonValue[jsonPtr]["SecurityCapabilities"]["MaxPassphraseCount"] = *maxPassphraseCount; } if (passphraseLockLimit != nullptr) { asyncResp->res .jsonValue[jsonPtr]["SecurityCapabilities"]["PassphraseLockLimit"] = *passphraseLockLimit; } } inline void assembleDimmProperties( std::string_view dimmId, const std::shared_ptr& asyncResp, const dbus::utility::DBusPropertiesMap& properties, const nlohmann::json::json_pointer& jsonPtr) { asyncResp->res.jsonValue[jsonPtr]["Id"] = dimmId; asyncResp->res.jsonValue[jsonPtr]["Name"] = "DIMM Slot"; asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] = resource::State::Enabled; asyncResp->res.jsonValue[jsonPtr]["Status"]["Health"] = resource::Health::OK; const uint16_t* memoryDataWidth = nullptr; const size_t* memorySizeInKB = nullptr; const std::string* partNumber = nullptr; const std::string* serialNumber = nullptr; const std::string* manufacturer = nullptr; const uint16_t* revisionCode = nullptr; const bool* present = nullptr; const uint16_t* memoryTotalWidth = nullptr; const std::string* ecc = nullptr; const std::string* formFactor = nullptr; const std::vector* allowedSpeedsMT = nullptr; const size_t* memoryAttributes = nullptr; const uint16_t* memoryConfiguredSpeedInMhz = nullptr; const std::string* memoryType = nullptr; const std::uint8_t* channel = nullptr; const std::uint8_t* memoryController = nullptr; const std::uint8_t* slot = nullptr; const std::uint8_t* socket = nullptr; const std::string* sparePartNumber = nullptr; const std::string* model = nullptr; const std::string* locationCode = nullptr; const bool success = sdbusplus::unpackPropertiesNoThrow( dbus_utils::UnpackErrorPrinter(), properties, "MemoryDataWidth", memoryDataWidth, "MemorySizeInKB", memorySizeInKB, "PartNumber", partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer, "RevisionCode", revisionCode, "Present", present, "MemoryTotalWidth", memoryTotalWidth, "ECC", ecc, "FormFactor", formFactor, "AllowedSpeedsMT", allowedSpeedsMT, "MemoryAttributes", memoryAttributes, "MemoryConfiguredSpeedInMhz", memoryConfiguredSpeedInMhz, "MemoryType", memoryType, "Channel", channel, "MemoryController", memoryController, "Slot", slot, "Socket", socket, "SparePartNumber", sparePartNumber, "Model", model, "LocationCode", locationCode); if (!success) { messages::internalError(asyncResp->res); return; } if (memoryDataWidth != nullptr) { asyncResp->res.jsonValue[jsonPtr]["DataWidthBits"] = *memoryDataWidth; } if (memorySizeInKB != nullptr) { asyncResp->res.jsonValue[jsonPtr]["CapacityMiB"] = (*memorySizeInKB >> 10); } if (partNumber != nullptr) { asyncResp->res.jsonValue[jsonPtr]["PartNumber"] = *partNumber; } if (serialNumber != nullptr) { asyncResp->res.jsonValue[jsonPtr]["SerialNumber"] = *serialNumber; } if (manufacturer != nullptr) { asyncResp->res.jsonValue[jsonPtr]["Manufacturer"] = *manufacturer; } if (revisionCode != nullptr) { asyncResp->res.jsonValue[jsonPtr]["FirmwareRevision"] = std::to_string(*revisionCode); } if (present != nullptr && !*present) { asyncResp->res.jsonValue[jsonPtr]["Status"]["State"] = resource::State::Absent; } if (memoryTotalWidth != nullptr) { asyncResp->res.jsonValue[jsonPtr]["BusWidthBits"] = *memoryTotalWidth; } if (ecc != nullptr) { constexpr const std::array values{ "NoECC", "SingleBitECC", "MultiBitECC", "AddressParity"}; for (const char* v : values) { if (ecc->ends_with(v)) { asyncResp->res.jsonValue[jsonPtr]["ErrorCorrection"] = v; break; } } } if (formFactor != nullptr) { constexpr const std::array values{ "RDIMM", "UDIMM", "SO_DIMM", "LRDIMM", "Mini_RDIMM", "Mini_UDIMM", "SO_RDIMM_72b", "SO_UDIMM_72b", "SO_DIMM_16b", "SO_DIMM_32b", "Die"}; for (const char* v : values) { if (formFactor->ends_with(v)) { asyncResp->res.jsonValue[jsonPtr]["BaseModuleType"] = v; break; } } } if (allowedSpeedsMT != nullptr) { nlohmann::json& jValue = asyncResp->res.jsonValue[jsonPtr]["AllowedSpeedsMHz"]; jValue = nlohmann::json::array(); for (uint16_t subVal : *allowedSpeedsMT) { jValue.push_back(subVal); } } if (memoryAttributes != nullptr) { asyncResp->res.jsonValue[jsonPtr]["RankCount"] = *memoryAttributes; } if (memoryConfiguredSpeedInMhz != nullptr) { asyncResp->res.jsonValue[jsonPtr]["OperatingSpeedMhz"] = *memoryConfiguredSpeedInMhz; } if (memoryType != nullptr) { std::string memoryDeviceType = translateMemoryTypeToRedfish(*memoryType); // Values like "Unknown" or "Other" will return empty // so just leave off if (!memoryDeviceType.empty()) { asyncResp->res.jsonValue[jsonPtr]["MemoryDeviceType"] = memoryDeviceType; } if (memoryType->find("DDR") != std::string::npos) { asyncResp->res.jsonValue[jsonPtr]["MemoryType"] = memory::MemoryType::DRAM; } else if (memoryType->ends_with("Logical")) { asyncResp->res.jsonValue[jsonPtr]["MemoryType"] = memory::MemoryType::IntelOptane; } } if (channel != nullptr) { asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Channel"] = *channel; } if (memoryController != nullptr) { asyncResp->res .jsonValue[jsonPtr]["MemoryLocation"]["MemoryController"] = *memoryController; } if (slot != nullptr) { asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Slot"] = *slot; } if (socket != nullptr) { asyncResp->res.jsonValue[jsonPtr]["MemoryLocation"]["Socket"] = *socket; } if (sparePartNumber != nullptr) { asyncResp->res.jsonValue[jsonPtr]["SparePartNumber"] = *sparePartNumber; } if (model != nullptr) { asyncResp->res.jsonValue[jsonPtr]["Model"] = *model; } if (locationCode != nullptr) { asyncResp->res .jsonValue[jsonPtr]["Location"]["PartLocation"]["ServiceLabel"] = *locationCode; } getPersistentMemoryProperties(asyncResp, properties, jsonPtr); } inline void getDimmDataByService( std::shared_ptr asyncResp, const std::string& dimmId, const std::string& service, const std::string& objPath) { BMCWEB_LOG_DEBUG("Get available system components."); dbus::utility::getAllProperties( service, objPath, "", [dimmId, asyncResp{std::move(asyncResp)}]( const boost::system::error_code& ec, const dbus::utility::DBusPropertiesMap& properties) { if (ec) { BMCWEB_LOG_DEBUG("DBUS response error"); messages::internalError(asyncResp->res); return; } assembleDimmProperties(dimmId, asyncResp, properties, ""_json_pointer); }); } inline void assembleDimmPartitionData( const std::shared_ptr& asyncResp, const dbus::utility::DBusPropertiesMap& properties, const nlohmann::json::json_pointer& regionPtr) { const std::string* memoryClassification = nullptr; const uint64_t* offsetInKiB = nullptr; const std::string* partitionId = nullptr; const bool* passphraseState = nullptr; const uint64_t* sizeInKiB = nullptr; const bool success = sdbusplus::unpackPropertiesNoThrow( dbus_utils::UnpackErrorPrinter(), properties, "MemoryClassification", memoryClassification, "OffsetInKiB", offsetInKiB, "PartitionId", partitionId, "PassphraseState", passphraseState, "SizeInKiB", sizeInKiB); if (!success) { messages::internalError(asyncResp->res); return; } nlohmann::json::object_t partition; if (memoryClassification != nullptr) { partition["MemoryClassification"] = *memoryClassification; } if (offsetInKiB != nullptr) { partition["OffsetMiB"] = (*offsetInKiB >> 10); } if (partitionId != nullptr) { partition["RegionId"] = *partitionId; } if (passphraseState != nullptr) { partition["PassphraseEnabled"] = *passphraseState; } if (sizeInKiB != nullptr) { partition["SizeMiB"] = (*sizeInKiB >> 10); } asyncResp->res.jsonValue[regionPtr].emplace_back(std::move(partition)); } inline void getDimmPartitionData(std::shared_ptr asyncResp, const std::string& service, const std::string& path) { dbus::utility::getAllProperties( service, path, "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition", [asyncResp{std::move(asyncResp)}]( const boost::system::error_code& ec, const dbus::utility::DBusPropertiesMap& properties) { if (ec) { BMCWEB_LOG_DEBUG("DBUS response error"); messages::internalError(asyncResp->res); return; } nlohmann::json::json_pointer regionPtr = "/Regions"_json_pointer; assembleDimmPartitionData(asyncResp, properties, regionPtr); } ); } inline void getDimmData(std::shared_ptr asyncResp, const std::string& dimmId) { BMCWEB_LOG_DEBUG("Get available system dimm resources."); constexpr std::array dimmInterfaces = { "xyz.openbmc_project.Inventory.Item.Dimm", "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition"}; dbus::utility::getSubTree( "/xyz/openbmc_project/inventory", 0, dimmInterfaces, [dimmId, asyncResp{std::move(asyncResp)}]( const boost::system::error_code& ec, const dbus::utility::MapperGetSubTreeResponse& subtree) { if (ec) { BMCWEB_LOG_DEBUG("DBUS response error"); messages::internalError(asyncResp->res); return; } bool found = false; for (const auto& [rawPath, object] : subtree) { sdbusplus::message::object_path path(rawPath); for (const auto& [service, interfaces] : object) { for (const auto& interface : interfaces) { if (interface == "xyz.openbmc_project.Inventory.Item.Dimm" && path.filename() == dimmId) { getDimmDataByService(asyncResp, dimmId, service, rawPath); found = true; } // partitions are separate as there can be multiple // per // device, i.e. // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition1 // /xyz/openbmc_project/Inventory/Item/Dimm1/Partition2 if (interface == "xyz.openbmc_project.Inventory.Item.PersistentMemory.Partition" && path.parent_path().filename() == dimmId) { getDimmPartitionData(asyncResp, service, rawPath); } } } } // Object not found if (!found) { messages::resourceNotFound(asyncResp->res, "Memory", dimmId); return; } // Set @odata only if object is found asyncResp->res.jsonValue["@odata.type"] = "#Memory.v1_11_0.Memory"; asyncResp->res.jsonValue["@odata.id"] = boost::urls::format("/redfish/v1/Systems/{}/Memory/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME, dimmId); return; }); } inline void requestRoutesMemoryCollection(App& app) { /** * Functions triggers appropriate requests on DBus */ BMCWEB_ROUTE(app, "/redfish/v1/Systems//Memory/") .privileges(redfish::privileges::getMemoryCollection) .methods(boost::beast::http::verb::get)( [&app](const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& systemName) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) { // Option currently returns no systems. TBD messages::resourceNotFound(asyncResp->res, "ComputerSystem", systemName); return; } if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) { messages::resourceNotFound(asyncResp->res, "ComputerSystem", systemName); return; } asyncResp->res.jsonValue["@odata.type"] = "#MemoryCollection.MemoryCollection"; asyncResp->res.jsonValue["Name"] = "Memory Module Collection"; asyncResp->res.jsonValue["@odata.id"] = boost::urls::format("/redfish/v1/Systems/{}/Memory", BMCWEB_REDFISH_SYSTEM_URI_NAME); constexpr std::array interfaces{ "xyz.openbmc_project.Inventory.Item.Dimm"}; collection_util::getCollectionMembers( asyncResp, boost::urls::format("/redfish/v1/Systems/{}/Memory", BMCWEB_REDFISH_SYSTEM_URI_NAME), interfaces, "/xyz/openbmc_project/inventory"); }); } inline void requestRoutesMemory(App& app) { /** * Functions triggers appropriate requests on DBus */ BMCWEB_ROUTE(app, "/redfish/v1/Systems//Memory//") .privileges(redfish::privileges::getMemory) .methods(boost::beast::http::verb::get)( [&app](const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& systemName, const std::string& dimmId) { if (!redfish::setUpRedfishRoute(app, req, asyncResp)) { return; } if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) { // Option currently returns no systems. TBD messages::resourceNotFound(asyncResp->res, "ComputerSystem", systemName); return; } if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) { messages::resourceNotFound(asyncResp->res, "ComputerSystem", systemName); return; } getDimmData(asyncResp, dimmId); }); } } // namespace redfish