| #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; |
| } |