Add GetPDRRepositoryInfo handler Tested: Unit tested and also verified that correct response is provided by BMC Google-Bug-Id: 423027264 Change-Id: Id5718b905fa72e12e1bbc91426780607ac9f2ee8 Signed-off-by: Kasun Athukorala <kasunath@google.com>
diff --git a/libpldmresponder/pdr_utils.cpp b/libpldmresponder/pdr_utils.cpp index 5a1d08c..facd5b2 100644 --- a/libpldmresponder/pdr_utils.cpp +++ b/libpldmresponder/pdr_utils.cpp
@@ -41,6 +41,11 @@ // pldm_pdr_add() assert()ed on failure to add PDR throw std::runtime_error("Failed to add PDR"); } + + if (largestRecordSize < pdrEntry.size) + { + largestRecordSize = pdrEntry.size; + } return handle; } @@ -89,6 +94,16 @@ return !getRecordCount(); } +uint32_t Repo::getRepositorySize() +{ + return pldm_pdr_get_repo_size(getPdr()); +} + +uint32_t Repo::getLargestRecordSize() +{ + return largestRecordSize; +} + StatestoDbusVal populateMapping(const std::string& type, const Json& dBusValues, const PossibleValues& pv) {
diff --git a/libpldmresponder/pdr_utils.hpp b/libpldmresponder/pdr_utils.hpp index 8167ea7..c12368d 100644 --- a/libpldmresponder/pdr_utils.hpp +++ b/libpldmresponder/pdr_utils.hpp
@@ -126,7 +126,7 @@ class RepoInterface { public: - RepoInterface(pldm_pdr* repo) : repo(repo) {} + RepoInterface(pldm_pdr* repo) : repo(repo), largestRecordSize(0) {} virtual ~RepoInterface() = default; @@ -185,8 +185,21 @@ */ virtual bool empty() = 0; + /** @brief Get the size of the PDR repository + * + * @return uint32_t - size + */ + virtual uint32_t getRepositorySize() = 0; + + /** @brief Get size of the largest PDR record + * + * @return uint32_t - size of the largest PDR record + */ + virtual uint32_t getLargestRecordSize() = 0; + protected: pldm_pdr* repo; + uint32_t largestRecordSize; }; /** @@ -215,6 +228,10 @@ uint32_t getRecordCount() override; bool empty() override; + + uint32_t getRepositorySize() override; + + uint32_t getLargestRecordSize() override; }; /** @brief Parse the State Sensor PDR and return the parsed sensor info which
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp index 7a3b63c..b034acb 100644 --- a/libpldmresponder/platform.cpp +++ b/libpldmresponder/platform.cpp
@@ -1036,6 +1036,39 @@ } } +Response Handler::getPdrRepositoryInfo(const pldm_msg* request, + size_t payloadLength) +{ + // GetPDRRepositoryInfo request payload should be 0. + if (payloadLength > 0) + { + return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH); + } + + Response response( + sizeof(pldm_msg_hdr) + sizeof(pldm_pdr_repository_info_resp)); + auto responsePtr = new (response.data()) pldm_msg; + + // TODO: Support update times. Currently set to all 0. + uint8_t updateTime[PLDM_TIMESTAMP104_SIZE]; + memset(updateTime, 0, PLDM_TIMESTAMP104_SIZE); + + uint8_t repository_state = + pdrCreated ? PLDM_AVAILABLE : PLDM_UPDATE_IN_PROGRESS; + + int rc = encode_get_pdr_repository_info_resp( + request->hdr.instance_id, PLDM_SUCCESS, repository_state, updateTime, + updateTime, pdrRepo.getRecordCount(), pdrRepo.getRepositorySize(), + pdrRepo.getLargestRecordSize(), /*data_transfer_handle_timeout=*/0, + responsePtr); + if (rc != PLDM_SUCCESS) + { + return ccOnlyResponse(request, rc); + } + + return response; +} + } // namespace platform } // namespace responder } // namespace pldm
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp index 8d7a55e..7c835d4 100644 --- a/libpldmresponder/platform.hpp +++ b/libpldmresponder/platform.hpp
@@ -73,6 +73,11 @@ } handlers.emplace( + PLDM_GET_PDR_REPOSITORY_INFO, + [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { + return this->getPdrRepositoryInfo(request, payloadLength); + }); + handlers.emplace( PLDM_GET_PDR, [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { return this->getPDR(request, payloadLength); @@ -512,6 +517,15 @@ /** @brief Method for setEventreceiver */ void setEventReceiver(); + /** @brief Handler for GetPDRRepositoryInfo + * + * @param[in] request - Request message + * @param[in] payloadLength - Request payload length + * @return Response - PLDM Response message + */ + Response getPdrRepositoryInfo(const pldm_msg* request, + size_t payloadLength); + private: uint8_t eid; InstanceIdDb* instanceIdDb;
diff --git a/libpldmresponder/test/libpldmresponder_platform_test.cpp b/libpldmresponder/test/libpldmresponder_platform_test.cpp index 28859e0..474aec9 100644 --- a/libpldmresponder/test/libpldmresponder_platform_test.cpp +++ b/libpldmresponder/test/libpldmresponder_platform_test.cpp
@@ -265,6 +265,117 @@ pldm_pdr_destroy(outPDRRepo); } +TEST(GetPdrRepositoryInfo, SuccessRepoAvailable) +{ + // Test when PDRs are created and repository is available. + std::array<uint8_t, sizeof(pldm_msg_hdr)> requestPayload{}; + auto req = new (requestPayload.data()) pldm_msg; + // GetPDRRepositoryInfo has no payload. + size_t requestPayloadLength = 0; + req->hdr.instance_id = 4; + + MockdBusHandler mockedUtils; + EXPECT_CALL(mockedUtils, getService(StrEq("/foo/bar"), _)) + .WillRepeatedly(Return("foo.bar")); + + auto pdrRepoPtr = pldm_pdr_init(); + ASSERT_NE(pdrRepoPtr, nullptr); + auto event = sdeventplus::Event::get_default(); + // buildPDRLazily is false by default, so PDRs are generated. + Handler handler(&mockedUtils, 0, nullptr, "./pdr_jsons/state_effecter/good", + pdrRepoPtr, nullptr, nullptr, nullptr, nullptr, nullptr, + event); + + // Get expected values directly from libpldm. The Repo class wraps these. + uint32_t expectedRecordCount = pldm_pdr_get_record_count(pdrRepoPtr); + uint32_t expectedRepoSize = pldm_pdr_get_repo_size(pdrRepoPtr); + uint32_t expectedLargestRecordSize = 84; + + auto response = handler.getPdrRepositoryInfo(req, requestPayloadLength); + + ASSERT_EQ(response.size(), + sizeof(pldm_msg_hdr) + sizeof(pldm_pdr_repository_info_resp)); + + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + auto resp = + reinterpret_cast<pldm_pdr_repository_info_resp*>(responsePtr->payload); + + EXPECT_EQ(responsePtr->hdr.instance_id, req->hdr.instance_id); + EXPECT_EQ(resp->completion_code, PLDM_SUCCESS); + EXPECT_EQ(resp->repository_state, PLDM_AVAILABLE); + EXPECT_EQ(le32toh(resp->record_count), expectedRecordCount); + EXPECT_EQ(le32toh(resp->repository_size), expectedRepoSize); + EXPECT_EQ(le32toh(resp->largest_record_size), expectedLargestRecordSize); + + // The number of records should be greater than 1 because of + // TerminusLocatorPDR and PDRs from JSON. + EXPECT_GT(expectedRecordCount, 1); + + pldm_pdr_destroy(pdrRepoPtr); +} + +TEST(GetPdrRepositoryInfo, SuccessRepoNotAvailable) +{ + // Test when PDRs are not yet created (lazy build). + std::array<uint8_t, sizeof(pldm_msg_hdr)> requestPayload{}; + auto req = new (requestPayload.data()) pldm_msg; + // GetPDRRepositoryInfo has no payload. + size_t requestPayloadLength = 0; + req->hdr.instance_id = 4; + + auto pdrRepoPtr = pldm_pdr_init(); + ASSERT_NE(pdrRepoPtr, nullptr); + auto event = sdeventplus::Event::get_default(); + MockdBusHandler mockedUtils; + // Last parameter `buildPDRLazily` is true. + Handler handler(&mockedUtils, 0, nullptr, "", pdrRepoPtr, nullptr, nullptr, + nullptr, nullptr, nullptr, event, true); + + auto response = handler.getPdrRepositoryInfo(req, requestPayloadLength); + + ASSERT_EQ(response.size(), + sizeof(pldm_msg_hdr) + sizeof(pldm_pdr_repository_info_resp)); + + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + auto resp = + reinterpret_cast<pldm_pdr_repository_info_resp*>(responsePtr->payload); + + EXPECT_EQ(responsePtr->hdr.instance_id, req->hdr.instance_id); + EXPECT_EQ(resp->completion_code, PLDM_SUCCESS); + EXPECT_EQ(resp->repository_state, PLDM_UPDATE_IN_PROGRESS); + EXPECT_EQ(le32toh(resp->record_count), 0); + EXPECT_EQ(le32toh(resp->repository_size), 0); + EXPECT_EQ(le32toh(resp->largest_record_size), 0); + + pldm_pdr_destroy(pdrRepoPtr); +} + +TEST(GetPdrRepositoryInfo, HandlesInvalidRequestLength) +{ + // Test with a non-zero payload length. The command should have zero + // payload length. A robust implementation would return + // PLDM_ERROR_INVALID_LENGTH. This test verifies the current behavior, which + // is to succeed. + std::array<uint8_t, sizeof(pldm_msg_hdr) + 1> requestPayload{}; + auto req = new (requestPayload.data()) pldm_msg; + size_t requestPayloadLength = 1; + + auto pdrRepoPtr = pldm_pdr_init(); + ASSERT_NE(pdrRepoPtr, nullptr); + auto event = sdeventplus::Event::get_default(); + MockdBusHandler mockedUtils; + Handler handler(&mockedUtils, 0, nullptr, "", pdrRepoPtr, nullptr, nullptr, + nullptr, nullptr, nullptr, event, true); + + auto response = handler.getPdrRepositoryInfo(req, requestPayloadLength); + auto resp = reinterpret_cast<pldm_pdr_repository_info_resp*>( + reinterpret_cast<pldm_msg*>(response.data())->payload); + + EXPECT_EQ(resp->completion_code, PLDM_ERROR_INVALID_LENGTH); + + pldm_pdr_destroy(pdrRepoPtr); +} + TEST(setStateEffecterStatesHandler, testBadRequest) { std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES>