blob: 8f13bc07b30f099d806adfce77fcfad7b9f51c42 [file] [edit]
#include "helper/discovery/platform_discovery.hpp"
#include "libpldm/base.h"
#include "libpldm/platform.h"
#include "libpldm/pldm.h"
#include "libpldm/requester/pldm_platform_requester.h"
#include "libpldm/utils.h"
#include "helper/common.hpp"
#include <cstdint>
#include <cstring>
#include <iostream>
#include <iterator>
#include <memory>
#include <unordered_map>
std::unordered_map<uint8_t, int> platformCommandRequestSize = {
{PLDM_GET_PDR, PLDM_GET_PDR_REQ_BYTES}};
/**
* @brief Sends the current GetPDR request to rde device, decodes
* response and stores the response data in containers
*
* @param[in] fd - Socket Id.
* @param[in] eid - Destination EID.
* @param[in] instanceId - Instance ID of rde device.
* @param[in] netId - Net Id of the rde device.
* @param[in] ctx - Pointer to platform requester context
* @param[inout] requestMsg - Vector to store requestMsg bytes
* @param[inout] resourceIdToSubUriMap - Resource Id to Sub URI map
* @param[inout] resourceIdToContainingResourceIdMap - Resource Id to
* Containing resource Id map
* @param[inout] completePdrRecordBytes - Vector to store the complete Pdr
* Record Data bytes
*/
static int processGetPdrRequest(
int fd, uint8_t eid, int instanceId, int netId,
struct pldm_platform_requester_context* ctx,
const std::vector<uint8_t>& requestMsg,
std::unordered_map<uint32_t, std::string>& resourceIdToSubUriMap,
std::unordered_map<uint32_t, uint32_t>& resourceIdToContainingResourceIdMap,
std::vector<uint8_t>& completePdrRecordBytes)
{
ctx->requester_status = PLDM_PLATFORM_REQUESTER_WAITING_FOR_RESPONSE;
int rc = pldm_send_at_network(eid, netId, fd, requestMsg.data(),
requestMsg.size());
if (rc)
{
ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
return PLDM_PLATFORM_REQUESTER_SEND_FAIL;
}
std::vector<uint8_t> response(sizeof(pldm_msg_hdr) + PLDM_MAX_REQUEST_BYTES,
0);
uint8_t* responseMsg = response.data();
size_t responseMsgSize = response.size();
auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
rc = pldm_recv_at_network(eid, fd, instanceId, &responseMsg,
&responseMsgSize, netId);
if (rc)
{
ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
return PLDM_PLATFORM_REQUESTER_RECV_FAIL;
}
bool isRecordDataComplete = false;
size_t recordDataLength = PLDM_MAX_REQUEST_BYTES -
PLDM_GET_PDR_MIN_RESP_BYTES;
std::vector<uint8_t> recordData(recordDataLength);
rc = pldm_platform_push_get_pdr_response(
ctx, responsePtr, responseMsgSize, 1 /*expected_pdr_header_version*/,
recordData.data(), recordDataLength, &isRecordDataComplete);
if (rc)
{
ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
std::cerr << "Saving Get PDR Response failed..." << std::endl;
return PLDM_PLATFORM_REQUESTER_NOT_RESP_MSG;
}
// Insert all the bytes excluding the command header bytes
size_t copyLen = recordDataLength > sizeof(pldm_pdr_hdr)
? recordDataLength - sizeof(pldm_pdr_hdr)
: 0;
completePdrRecordBytes.resize(completePdrRecordBytes.size() + copyLen);
if (copyLen > 0)
{
std::memcpy((void*)(completePdrRecordBytes.data() +
completePdrRecordBytes.size() - copyLen),
(void*)(recordData.data() + sizeof(pldm_pdr_hdr)), copyLen);
}
if (isRecordDataComplete)
{
uint32_t resourceId = 0;
uint8_t resourceFlags = 0;
uint32_t containingResourceId = 0;
uint16_t proposedContainingResourceLength = 0;
char* proposedContainingResourceName = NULL;
uint16_t resourceUriLength = 0;
char* resourceUri = NULL;
uint16_t additionalResourceIdCount = 0;
rc = pldm_platform_decode_first_pdr_resource(
completePdrRecordBytes.data(), &resourceId, &resourceFlags,
&containingResourceId, &proposedContainingResourceLength,
&proposedContainingResourceName, &resourceUriLength, &resourceUri,
&additionalResourceIdCount);
if (rc)
{
ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
std::cerr << "Decoding PDR's first resource failed with rc " << rc
<< std::endl;
return PLDM_PLATFORM_REQUESTER_NOT_RESP_MSG;
}
if (containingResourceId == PLDM_EXTERNAL_RESOURCE_ID)
{
resourceIdToSubUriMap.emplace(resourceId,
proposedContainingResourceName);
}
else
{
resourceIdToSubUriMap.emplace(resourceId, resourceUri);
}
resourceIdToContainingResourceIdMap.emplace(resourceId,
containingResourceId);
for (uint16_t id = 0; id < additionalResourceIdCount; id++)
{
rc = pldm_platform_decode_additional_pdr_resource(
completePdrRecordBytes.data(), id, &resourceId,
&resourceUriLength, &resourceUri);
if (rc)
{
ctx->requester_status = PLDM_PLATFORM_REQUESTER_REQUEST_FAILED;
std::cerr << "Decoding PDR's additional resource failed..."
<< std::endl;
return PLDM_PLATFORM_REQUESTER_NOT_RESP_MSG;
}
resourceIdToSubUriMap.emplace(resourceId, resourceUri);
resourceIdToContainingResourceIdMap.emplace(resourceId,
containingResourceId);
}
// Clear the container so it can be used for next set of PDR data
completePdrRecordBytes.clear();
}
return PLDM_PLATFORM_REQUESTER_SUCCESS;
}
/**
* @brief Initializes platform context for the plaform requests
*
* @param[inout] platformCtx - Pointer to platform requester context
* @param[inout] pdrOpCtx - Pointer to pdr operation context
* @param[in] rdeDeviceId - Rde device Id
* @param[in] netId - Net Id of the rde device.
* @param[in] negotiatedTransferSize - Negotiated PLDM message size
* @return 0 on success, -1 on failure
*/
static int initPlatformContextForRde(
struct pldm_platform_requester_context* platformCtx,
struct pldm_platform_get_pdr_operation* pdrOpCtx,
const std::string& rdeDeviceId, int netId, uint32_t negotiatedTransferSize)
{
if (pldm_platform_init_context(platformCtx, rdeDeviceId.c_str(), netId,
negotiatedTransferSize) != 0)
{
std::cerr << "Unable to initialize platform context" << std::endl;
return -1;
}
if (pldm_platform_init_get_pdr_operation_context(platformCtx, pdrOpCtx) !=
0)
{
std::cerr << "Unable to initialize GetPDR Operation context"
<< std::endl;
return -1;
}
return 0;
}
/**
* @brief API to recursively construct complere Redfish resource URI
* using the sub URI fragments
* @param[in] resourceIdToSubUriMap - Resource ID to Sub Uri map
* @param[in] resourceIdToContainingResourceIdMap - Resource ID to
* Containing resource ID map
* @param[inout] resourcePartialUri - Partially constructed Redfish
* resource URI
* @param[in] containingResourceId - Containing Resource ID
* @return string representing the complete Redfish resource URI
*/
static std::string constructResourceUri(
const std::unordered_map<uint32_t, std::string>& resourceIdToSubUriMap,
const std::unordered_map<uint32_t, uint32_t>&
resourceIdToContainingResourceIdMap,
std::string& resourcePartialUri, uint32_t containingResourceId)
{
// Break the recusion when the resource is root level resource
if (containingResourceId == 0x00000000)
{
return "/redfish/v1/" + resourcePartialUri;
}
auto resourceIdToSubUriMapItr =
resourceIdToSubUriMap.find(containingResourceId);
if (resourceIdToSubUriMapItr == resourceIdToSubUriMap.end())
{
std::cerr << "Cannot find containingResourceId : "
<< containingResourceId << " in resourceIdToSubUriMap"
<< std::endl;
return "";
}
std::string subUri = resourceIdToSubUriMapItr->second;
resourcePartialUri = subUri + "/" + resourcePartialUri;
auto resourceIdToContainingResourceIdMapItr =
resourceIdToContainingResourceIdMap.find(containingResourceId);
if (resourceIdToContainingResourceIdMapItr ==
resourceIdToContainingResourceIdMap.end())
{
std::cerr << "Cannot find containingResourceId : "
<< containingResourceId
<< " in resourceIdToContainingResourceIdMap" << std::endl;
return "";
}
uint32_t nextContainingResourceId =
resourceIdToContainingResourceIdMapItr->second;
return constructResourceUri(resourceIdToSubUriMap,
resourceIdToContainingResourceIdMap,
resourcePartialUri, nextContainingResourceId);
}
/**
* @brief API to recursively construct Redfish resource URI
* to Resource ID Map
* @param[inout] resourceIdMap - Redfish Resource URI to Resource ID map
* @param[in] resourceIdToSubUriMap - Resource ID to Sub Uri map
* @param[in] resourceIdToContainingResourceIdMap - Resource ID to
* Containing resource ID map
* @return string representing the complete Redfish resource URI
*/
static void constructResourceIdMap(
std::unordered_map<std::string, uint32_t>& resourceIdMap,
const std::unordered_map<uint32_t, std::string>& resourceIdToSubUriMap,
const std::unordered_map<uint32_t, uint32_t>&
resourceIdToContainingResourceIdMap)
{
for (auto it = resourceIdToContainingResourceIdMap.begin();
it != resourceIdToContainingResourceIdMap.end(); ++it)
{
uint32_t resourceId = it->first;
uint32_t containingResourceId = it->second;
auto resourceIdToSubUriMapItr = resourceIdToSubUriMap.find(resourceId);
if (resourceIdToSubUriMapItr == resourceIdToSubUriMap.end())
{
std::cerr << "Cannot find resourceId : " << resourceId
<< " in resourceIdToSubUriMap" << std::endl;
return;
}
std::string resourcePartialUri = resourceIdToSubUriMapItr->second;
std::string resourceFullUri = constructResourceUri(
resourceIdToSubUriMap, resourceIdToContainingResourceIdMap,
resourcePartialUri, containingResourceId);
std::cerr << "Adding resourceId " << std::showbase << std::hex
<< resourceId << " with resource URI " << resourceFullUri
<< std::endl;
resourceIdMap.emplace(resourceFullUri, resourceId);
}
}
int performPdrDiscovery(
const std::string& rdeDeviceId, int fd, int netId, uint8_t destEid,
uint8_t instanceId, uint32_t negotiatedTransferSize,
std::unordered_map<std::string, uint32_t>& resourceIdMap)
{
struct pldm_platform_requester_context platformContext = {};
struct pldm_platform_get_pdr_operation pdrOpContext = {};
int rc = initPlatformContextForRde(&platformContext, &pdrOpContext,
rdeDeviceId, netId,
negotiatedTransferSize);
if (rc)
{
return -1;
}
rc = pldm_platform_start_pdr_discovery(&platformContext);
if (rc)
{
std::cerr << "PDR Discovery failed due to context busy with ec: " << rc
<< std::endl;
return -1;
}
std::unordered_map<uint32_t, std::string> resourceIdToSubUriMap;
std::unordered_map<uint32_t, uint32_t> resourceIdToContainingResourceIdMap;
std::vector<uint8_t> completePdrRecordBytes;
std::cerr << "Sending Platform PDR Discovery requests." << std::endl;
while (true)
{
size_t requestBytes;
if (platformContext.requester_status ==
PLDM_PLATFORM_REQUESTER_NO_PENDING_ACTION)
{
break;
}
if (platformCommandRequestSize.find(platformContext.next_command) !=
platformCommandRequestSize.end())
{
requestBytes =
platformCommandRequestSize[platformContext.next_command];
}
else
{
requestBytes = PLDM_MAX_REQUEST_BYTES;
}
std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + requestBytes);
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
rc = pldm_platform_get_next_get_pdr_request(
&platformContext, instanceId, request, requestBytes);
if (rc)
{
std::cerr << "Not a valid request to process" << std::endl;
return rc;
}
rc = processGetPdrRequest(fd, destEid, 1, netId, &platformContext,
requestMsg, resourceIdToSubUriMap,
resourceIdToContainingResourceIdMap,
completePdrRecordBytes);
if (rc)
{
std::cerr << "Unable to process next platform request: "
<< std::to_string(rc) << std::endl;
return rc;
}
}
std::cerr << "PDR Discovery complete." << std::endl;
constructResourceIdMap(resourceIdMap, resourceIdToSubUriMap,
resourceIdToContainingResourceIdMap);
return 0;
}