Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ endif
if get_option('oem-amd').allowed()
add_project_arguments('-DOEM_AMD', language: 'cpp')
endif

conf_data.set(
'NUMBER_OF_REQUEST_RETRIES',
get_option('number-of-request-retries'),
Expand Down Expand Up @@ -239,6 +240,12 @@ deps = [
]

oem_files = []

if get_option('oem-amd').allowed()
subdir('oem/amd')
deps += oem_amd_dep
endif

if get_option('oem-ampere').allowed()
subdir('oem/ampere')
endif
Expand Down
118 changes: 118 additions & 0 deletions oem/amd/cache_manager_dbus.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#include "cache_manager_dbus.hpp"
#include "rde/device_common.hpp"
#include "rde/utils.hpp"
#include <nlohmann/json.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/message.hpp>
#include <sdbusplus/server/object.hpp>
#include <xyz/openbmc_project/Common/error.hpp>

PHOSPHOR_LOG2_USING;

using namespace sdbusplus::xyz::openbmc_project::Common::Error;

namespace pldm::rde
{

std::vector<std::string> CacheManagerObject::getCurrentCache(std::string uuid)
{
std::vector<std::string> results;

// Get internal cache data from singleton
auto internalCache = RDECacheManager::getInstance().getCache(uuid);

for (const auto& entry : internalCache)
{
nlohmann::json j;
j["Operation"] = sdbusplus::message::convert_to_string(entry.operationType);
j["URI"] = entry.targetURI;
j["Payload"] = entry.payload;
j["PayloadFormat"] = sdbusplus::message::convert_to_string(entry.payloadFormat);
j["EncodingFormat"] = sdbusplus::message::convert_to_string(entry.encodingType);
j["SessionId"] = entry.sessionId;
j["Timestamp"] = entry.timestamp;
j["Status"] = (entry.status == CacheStatus::Pending) ? "Pending" : "Processing";

results.push_back(j.dump());
}

return results;
}

bool CacheManagerObject::createCache(
sdbusplus::common::xyz::openbmc_project::rde::Common::OperationType
operationType,
std::string targetURI, std::string deviceUUID,
std::string payload,
sdbusplus::xyz::openbmc_project::RDE::server::Manager::PayloadFormatType
payloadFormat,
sdbusplus::xyz::openbmc_project::RDE::server::Manager::EncodingFormatType
encodingFormat,
std::string sessionId)
{
info("RDE Cache: createCache called for UUID={UUID}", "UUID", deviceUUID);

// Validate deviceUUID exists in metadata
std::string processorURI = loadProcessorURI(deviceUUID);
if (processorURI.empty())
{
error(
"RDE Cache: Device UUID={UUID} not found in rde_device_metadata.json, cannot create cache",
"UUID", deviceUUID);
throw InvalidArgument();
}

// Validate payload format if JSON encoding
if (encodingFormat ==
sdbusplus::xyz::openbmc_project::RDE::server::Manager::EncodingFormatType::
JSON)
{
if (!payload.empty())
{
try
{
[[maybe_unused]] auto _ = nlohmann::json::parse(payload);
}
catch (const nlohmann::json::parse_error& e)
{
error(
"RDE Cache: Invalid JSON payload for UUID={UUID}: {MSG}",
"UUID", deviceUUID, "MSG", e.what());
throw InvalidArgument();
}
}
}

// Build OperationInfo (eid will be set during replay from Device)
OperationInfo opInfo{
0, // operationID will be generated during replay
static_cast<OperationType>(operationType),
targetURI,
deviceUUID,
0, // eid will be retrieved from Device during replay
payload,
static_cast<PayloadFormatType>(payloadFormat),
static_cast<EncodingFormatType>(encodingFormat),
sessionId,
"" // opTaskPath will be generated during replay
};

// Call RDECacheManager::cacheOperation()
auto& cacheManager = RDECacheManager::getInstance();
if (!cacheManager.cacheOperation(opInfo))
{
error("RDE Cache: Failed to cache operation for device UUID={UUID}",
"UUID", deviceUUID);
throw InternalFailure();
}

info(
"RDE Cache: Successfully created cache entry via D-Bus for UUID={UUID}, type={TYPE}, URI={URI}",
"UUID", deviceUUID, "TYPE", static_cast<int>(operationType), "URI",
targetURI);

return true;
}

} // namespace pldm::rde

60 changes: 60 additions & 0 deletions oem/amd/cache_manager_dbus.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

#include "rde_cache_manager.hpp"
#include <sdbusplus/bus.hpp>
#include <sdbusplus/server/object.hpp>
#include <xyz/openbmc_project/RDE/CacheManager/server.hpp>

#include <vector>
#include <string>

namespace pldm::rde
{

using CacheManagerIface = sdbusplus::server::object_t<
sdbusplus::xyz::openbmc_project::RDE::server::CacheManager>;

class CacheManagerObject : public CacheManagerIface
{
public:
CacheManagerObject(sdbusplus::bus_t& bus, const char* path) :
CacheManagerIface(bus, path)
{}

/**
* @brief Implementation for GetCurrentCache
* Retrieve all cached operations for a specific RDE device.
*
* @param[in] uuid - The UUID of the device to query.
* @return Operations - List of cached operations as JSON strings.
*/
std::vector<std::string> getCurrentCache(std::string uuid) override;

/**
* @brief Implementation for CreateCache
* Manually create a cache entry for a specific RDE device.
* Parameter order matches StartRedfishOperation (excluding OperationID and EID).
*
* @param[in] operationType - Operation type
* @param[in] targetURI - Target URI
* @param[in] deviceUUID - Device UUID
* @param[in] payload - Operation payload (JSON string)
* @param[in] payloadFormat - Payload format (default: Inline)
* @param[in] encodingFormat - Encoding format (default: JSON)
* @param[in] sessionId - Session ID (optional)
* @return bool - true if successfully cached, false otherwise
*/
bool createCache(
sdbusplus::common::xyz::openbmc_project::rde::Common::OperationType
operationType,
std::string targetURI, std::string deviceUUID,
std::string payload,
sdbusplus::xyz::openbmc_project::RDE::server::Manager::PayloadFormatType
payloadFormat,
sdbusplus::xyz::openbmc_project::RDE::server::Manager::EncodingFormatType
encodingFormat,
std::string sessionId) override;
};

} // namespace pldm::rde

8 changes: 8 additions & 0 deletions oem/amd/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
oem_amd_dep = declare_dependency(
sources: files(
'cache_manager_dbus.cpp',
'rde_cache_manager.cpp',
),
include_directories: include_directories('.')
)

187 changes: 187 additions & 0 deletions oem/amd/rde_cache_manager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#include "rde_cache_manager.hpp"

#include <nlohmann/json.hpp>
#include <phosphor-logging/lg2.hpp>

#include <algorithm>
#include <chrono>

PHOSPHOR_LOG2_USING;

namespace pldm::rde
{

RDECacheManager& RDECacheManager::getInstance()
{
static RDECacheManager instance;
return instance;
}

bool RDECacheManager::cacheOperation(const OperationInfo& opInfo)
{
auto& deviceCache = cache_[opInfo.deviceUUID];

for (auto& entry : deviceCache)
{
if (entry.status == CacheStatus::Pending &&
entry.operationType == opInfo.operationType &&
entry.targetURI == opInfo.targetURI)
{
try
{
auto jExisting = nlohmann::json::parse(entry.payload);
auto jNew = nlohmann::json::parse(opInfo.payload);

jExisting.update(jNew);

entry.payload = jExisting.dump();
entry.timestamp = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();

info("RDE Cache: Merged payload for UUID={UUID}, URI={URI}",
"UUID", opInfo.deviceUUID, "URI", entry.targetURI);
return true;
}
catch (...)
{
break;
}
}
}

try
{
CacheEntry entry(opInfo.deviceUUID, opInfo.operationType,
opInfo.targetURI, opInfo.payload,
opInfo.payloadFormat, opInfo.encodingType,
opInfo.sessionId);
deviceCache.push_back(std::move(entry));

info(
"RDE Cache: Added new cache entry for UUID={UUID}, type={TYPE}, URI={URI}, payload_size={SIZE}, total_entries={COUNT}",
"UUID", opInfo.deviceUUID, "TYPE",
static_cast<int>(opInfo.operationType), "URI", opInfo.targetURI,
"SIZE", opInfo.payload.size(), "COUNT", deviceCache.size());

return true;
}
catch (const std::exception& e)
{
error("RDE Cache: Failed to cache operation for UUID={UUID}: {MSG}",
"UUID", opInfo.deviceUUID, "MSG", e.what());
return false;
}
}

std::optional<CacheEntry>
RDECacheManager::markNextPendingForProcessing(const std::string& deviceUUID)
{
auto it = cache_.find(deviceUUID);
if (it == cache_.end())
{
return std::nullopt;
}

for (auto& entry : it->second)
{
entry.status = CacheStatus::Processing;
return entry; // Return a copy
}

return std::nullopt;
}

void RDECacheManager::completeOperation(const std::string& deviceUUID,
uint64_t timestamp)
{
auto it = cache_.find(deviceUUID);
if (it == cache_.end())
{
return;
}

auto& deviceCache = it->second;
auto entryIt = std::find_if(deviceCache.begin(), deviceCache.end(),
[timestamp](const CacheEntry& e) {
return e.timestamp == timestamp;
});

if (entryIt != deviceCache.end())
{
info("RDE Cache: Operation completed and removed from cache for UUID={UUID}, URI={URI}",
"UUID", deviceUUID, "URI", entryIt->targetURI);
deviceCache.erase(entryIt);
}
}

void RDECacheManager::markOperationAsFailed(const std::string& deviceUUID,
uint64_t timestamp)
{
auto it = cache_.find(deviceUUID);
if (it == cache_.end())
{
return;
}

auto& deviceCache = it->second;
auto entryIt = std::find_if(deviceCache.begin(), deviceCache.end(),
[timestamp](const CacheEntry& e) {
return e.timestamp == timestamp;
});

if (entryIt != deviceCache.end())
{
entryIt->status = CacheStatus::Failed;
info("RDE Cache: Operation marked as failed for UUID={UUID}, URI={URI}",
"UUID", deviceUUID, "URI", entryIt->targetURI);
}
}

void RDECacheManager::resetProcessingToPending(const std::string& deviceUUID)
{
auto it = cache_.find(deviceUUID);
if (it == cache_.end())
{
return;
}

for (auto& entry : it->second)
{
if (entry.status == CacheStatus::Processing)
{
entry.status = CacheStatus::Pending;
}
}
info("RDE Cache: Reset all 'Processing' entries to 'Pending' for UUID={UUID}",
"UUID", deviceUUID);
}

std::vector<CacheEntry>
RDECacheManager::getCache(const std::string& deviceUUID) const
{
auto it = cache_.find(deviceUUID);
if (it != cache_.end())
{
return it->second;
}
return {};
}

OperationInfo RDECacheManager::toOperationInfo(const CacheEntry& entry,
uint32_t operationID,
pldm::eid eid)
{
std::string taskPathStr =
"/xyz/openbmc_project/RDE/OperationTask/" + std::to_string(operationID);

OperationInfo opInfo{
operationID, entry.operationType, entry.targetURI,
entry.deviceUUID, eid, entry.payload,
entry.payloadFormat, entry.encodingType, entry.sessionId,
taskPathStr};

return opInfo;
}

} // namespace pldm::rde
Loading