Add HostPDRHandler class
HostPDRHandler has an API to fetch PDRs from the host.
The class HostPDRHandler has a function fetchPDR which basically calls
GetPDR on the host using libpldm's pldm_send_recv API.
The retrieved PDRs are stored in the BMCs primary PDR repo.
Change-Id: Ifd727316caf37d49f17e117b32ee105f6d941e0e
Signed-off-by: Pavithra Barithaya <pbaritha@in.ibm.com>
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/host_pdr_handler.cpp b/host_pdr_handler.cpp
new file mode 100644
index 0000000..1e78846
--- /dev/null
+++ b/host_pdr_handler.cpp
@@ -0,0 +1,81 @@
+#include "host_pdr_handler.hpp"
+
+#include "libpldm/requester/pldm.h"
+
+namespace pldm
+{
+
+void HostPDRHandler::fetchPDR(const std::vector<uint32_t>& recordHandles)
+{
+ std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+ PLDM_GET_PDR_REQ_BYTES);
+ auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+ for (auto recordHandle : recordHandles)
+ {
+ auto instanceId = requester.getInstanceId(mctp_eid);
+
+ auto rc =
+ encode_get_pdr_req(instanceId, recordHandle, 0, PLDM_GET_FIRSTPART,
+ UINT16_MAX, 0, request, PLDM_GET_PDR_REQ_BYTES);
+ if (rc != PLDM_SUCCESS)
+ {
+ requester.markFree(mctp_eid, instanceId);
+ std::cerr << "Failed to encode_get_pdr_req, rc = " << rc << "\n";
+ return;
+ }
+
+ uint8_t* responseMsg = nullptr;
+ size_t responseMsgSize{};
+ auto requesterRc =
+ pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(),
+ requestMsg.size(), &responseMsg, &responseMsgSize);
+ std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
+ responseMsg, std::free};
+ requester.markFree(mctp_eid, instanceId);
+ if (requesterRc != PLDM_REQUESTER_SUCCESS)
+ {
+ std::cerr << "Failed to send msg to fetch pdrs, rc = "
+ << requesterRc << "\n";
+ return;
+ }
+
+ auto responsePtr =
+ reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
+ uint8_t completionCode{};
+ uint32_t nextRecordHandle{};
+ uint32_t nextDataTransferHandle{};
+ uint8_t transferFlag{};
+ uint16_t respCount{};
+ uint8_t transferCRC{};
+ rc = decode_get_pdr_resp(
+ responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
+ &completionCode, &nextRecordHandle, &nextDataTransferHandle,
+ &transferFlag, &respCount, nullptr, 0, &transferCRC);
+ if (rc != PLDM_SUCCESS)
+ {
+ std::cerr << "Failed to decode_get_pdr_resp, rc = " << rc << "\n";
+ }
+ else
+ {
+ std::vector<uint8_t> pdr(respCount, 0);
+ rc = decode_get_pdr_resp(
+ responsePtr, responseMsgSize - sizeof(pldm_msg_hdr),
+ &completionCode, &nextRecordHandle, &nextDataTransferHandle,
+ &transferFlag, &respCount, pdr.data(), respCount, &transferCRC);
+ if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+ {
+ std::cerr << "Failed to decode_get_pdr_resp: "
+ << "rc=" << rc
+ << ", cc=" << static_cast<int>(completionCode)
+ << "\n";
+ }
+ else
+ {
+ pldm_pdr_add(repo, pdr.data(), respCount, 0);
+ }
+ }
+ }
+}
+
+} // namespace pldm
diff --git a/host_pdr_handler.hpp b/host_pdr_handler.hpp
new file mode 100644
index 0000000..b590e7c
--- /dev/null
+++ b/host_pdr_handler.hpp
@@ -0,0 +1,74 @@
+#pragma once
+
+#include "dbus_impl_requester.hpp"
+#include "utils.hpp"
+
+#include <sdeventplus/event.hpp>
+#include <vector>
+
+#include "libpldm/base.h"
+#include "libpldm/platform.h"
+
+using namespace pldm::dbus_api;
+
+namespace pldm
+{
+
+/** @class HostPDRHandler
+ * @brief This class can fetch and process PDRs from host firmware
+ * @details Provides an API to fetch PDRs from the host firmware. Upon
+ * receiving the PDRs, they are stored into the BMC's primary PDR repo.
+ * Adjustments are made to entity association PDRs received from the host,
+ * because they need to be assimilated into the BMC's entity association
+ * tree. A PLDM event containing the record handles of the updated entity
+ * association PDRs is sent to the host.
+ */
+class HostPDRHandler
+{
+ public:
+ HostPDRHandler() = delete;
+ HostPDRHandler(const HostPDRHandler&) = delete;
+ HostPDRHandler(HostPDRHandler&&) = delete;
+ HostPDRHandler& operator=(const HostPDRHandler&) = delete;
+ HostPDRHandler& operator=(HostPDRHandler&&) = delete;
+ ~HostPDRHandler() = default;
+
+ /** @brief Constructor
+ * @param[in] mctp_fd - fd of MCTP communications socket
+ * @param[in] mctp_eid - MCTP EID of host firmware
+ * @param[in] event - reference of main event loop of pldmd
+ * @param[in] repo - pointer to BMC's primary PDR repo
+ * @param[in] requester - reference to Requester object
+ */
+ explicit HostPDRHandler(int mctp_fd, uint8_t mctp_eid,
+ sdeventplus::Event& event, pldm_pdr* repo,
+ Requester& requester) :
+ mctp_fd(mctp_fd),
+ mctp_eid(mctp_eid), event(event), repo(repo), requester(requester)
+ {
+ }
+
+ /** @brief fetch PDRs from host firmware. See @class.
+ * @param[in] recordHandles - list of record handles pointing to host's
+ * PDRs that need to be fetched.
+ */
+ void fetchPDR(const std::vector<uint32_t>& recordHandles);
+
+ private:
+ /** @brief fd of MCTP communications socket */
+ int mctp_fd;
+ /** @brief MCTP EID of host firmware */
+ uint8_t mctp_eid;
+ /** @brief reference of main event loop of pldmd, primarily used to schedule
+ * work.
+ */
+ sdeventplus::Event& event;
+ /** @brief pointer to BMC's primary PDR repo, host PDRs are added here */
+ pldm_pdr* repo;
+ /** @brief reference to Requester object, primarily used to access API to
+ * obtain PLDM instance id.
+ */
+ Requester& requester;
+};
+
+} // namespace pldm
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index 696434b..893a709 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -3,6 +3,7 @@
#include "config.h"
#include "handler.hpp"
+#include "host_pdr_handler.hpp"
#include "libpldmresponder/pdr.hpp"
#include "libpldmresponder/pdr_utils.hpp"
#include "utils.hpp"
@@ -53,8 +54,10 @@
{
public:
Handler(const std::string& dir, pldm_pdr* repo,
+ HostPDRHandler* hostPDRHandler,
const std::optional<EventMap>& addOnHandlersMap = std::nullopt) :
- pdrRepo(repo)
+ pdrRepo(repo),
+ hostPDRHandler(hostPDRHandler)
{
generate(dir, pdrRepo);
@@ -340,6 +343,7 @@
pdr_utils::Repo pdrRepo;
uint16_t nextEffecterId{};
DbusObjMaps dbusObjMaps{};
+ HostPDRHandler* hostPDRHandler;
};
} // namespace platform
diff --git a/meson.build b/meson.build
index 923197a..d6fd8c9 100644
--- a/meson.build
+++ b/meson.build
@@ -56,6 +56,7 @@
deps = [
libpldm,
libpldmresponder,
+ libpldmutils,
dependency('sdbusplus'),
dependency('sdeventplus'),
dependency('phosphor-dbus-interfaces')
@@ -66,6 +67,7 @@
'pldmd.cpp',
'dbus_impl_requester.cpp',
'instance_id.cpp',
+ 'host_pdr_handler.cpp',
implicit_include_directories: false,
dependencies: deps,
install: true,
diff --git a/pldmd.cpp b/pldmd.cpp
index 501de5a..030fcb1 100644
--- a/pldmd.cpp
+++ b/pldmd.cpp
@@ -1,4 +1,5 @@
#include "dbus_impl_requester.hpp"
+#include "host_pdr_handler.hpp"
#include "invoker.hpp"
#include "libpldmresponder/base.hpp"
#include "libpldmresponder/bios.hpp"
@@ -17,6 +18,7 @@
#include <cstdio>
#include <cstring>
+#include <fstream>
#include <iomanip>
#include <iostream>
#include <iterator>
@@ -146,26 +148,6 @@
break;
}
- std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> pdrRepo(
- pldm_pdr_init(), pldm_pdr_destroy);
- std::unique_ptr<pldm_entity_association_tree,
- decltype(&pldm_entity_association_tree_destroy)>
- entityTree(pldm_entity_association_tree_init(),
- pldm_entity_association_tree_destroy);
-
- Invoker invoker{};
- invoker.registerHandler(PLDM_BASE, std::make_unique<base::Handler>());
- invoker.registerHandler(PLDM_BIOS, std::make_unique<bios::Handler>());
- invoker.registerHandler(PLDM_PLATFORM, std::make_unique<platform::Handler>(
- PDR_JSONS_DIR, pdrRepo.get()));
- invoker.registerHandler(
- PLDM_FRU, std::make_unique<fru::Handler>(FRU_JSONS_DIR, pdrRepo.get(),
- entityTree.get()));
-
-#ifdef OEM_IBM
- invoker.registerHandler(PLDM_OEM, std::make_unique<oem_ibm::Handler>());
-#endif
-
/* Create local socket. */
int returnCode = 0;
int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
@@ -176,6 +158,37 @@
exit(EXIT_FAILURE);
}
+ auto event = Event::get_default();
+ std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> pdrRepo(
+ pldm_pdr_init(), pldm_pdr_destroy);
+ std::unique_ptr<pldm_entity_association_tree,
+ decltype(&pldm_entity_association_tree_destroy)>
+ entityTree(pldm_entity_association_tree_init(),
+ pldm_entity_association_tree_destroy);
+ auto& bus = pldm::utils::DBusHandler::getBus();
+ dbus_api::Requester dbusImplReq(bus, "/xyz/openbmc_project/pldm");
+ std::unique_ptr<HostPDRHandler> hostPDRHandler;
+ auto hostEID = pldm::utils::readHostEID();
+ if (hostEID)
+ {
+ hostPDRHandler = std::make_unique<HostPDRHandler>(
+ sockfd, hostEID, event, pdrRepo.get(), dbusImplReq);
+ }
+
+ Invoker invoker{};
+ invoker.registerHandler(PLDM_BASE, std::make_unique<base::Handler>());
+ invoker.registerHandler(PLDM_BIOS, std::make_unique<bios::Handler>());
+ invoker.registerHandler(
+ PLDM_PLATFORM, std::make_unique<platform::Handler>(
+ PDR_JSONS_DIR, pdrRepo.get(), hostPDRHandler.get()));
+ invoker.registerHandler(
+ PLDM_FRU, std::make_unique<fru::Handler>(FRU_JSONS_DIR, pdrRepo.get(),
+ entityTree.get()));
+
+#ifdef OEM_IBM
+ invoker.registerHandler(PLDM_OEM, std::make_unique<oem_ibm::Handler>());
+#endif
+
pldm::utils::CustomFD socketFd(sockfd);
struct sockaddr_un addr
@@ -203,8 +216,6 @@
exit(EXIT_FAILURE);
}
- auto& bus = pldm::utils::DBusHandler::getBus();
- dbus_api::Requester dbusImplReq(bus, "/xyz/openbmc_project/pldm");
auto callback = [verbose, &invoker, &dbusImplReq](IO& /*io*/, int fd,
uint32_t revents) {
if (!(revents & EPOLLIN))
@@ -292,7 +303,6 @@
}
};
- auto event = Event::get_default();
bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
bus.request_name("xyz.openbmc_project.PLDM");
IO io(event, socketFd(), EPOLLIN, std::move(callback));
diff --git a/test/libpldmresponder_pdr_state_effecter_test.cpp b/test/libpldmresponder_pdr_state_effecter_test.cpp
index 73bcfbb..e17fe89 100644
--- a/test/libpldmresponder_pdr_state_effecter_test.cpp
+++ b/test/libpldmresponder_pdr_state_effecter_test.cpp
@@ -15,7 +15,7 @@
auto inPDRRepo = pldm_pdr_init();
auto outPDRRepo = pldm_pdr_init();
Repo outRepo(outPDRRepo);
- Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
Repo inRepo(inPDRRepo);
getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
@@ -107,7 +107,8 @@
{
auto pdrRepo = pldm_pdr_init();
- ASSERT_THROW(Handler("./pdr_jsons/not_there", pdrRepo), std::exception);
+ ASSERT_THROW(Handler("./pdr_jsons/not_there", pdrRepo, nullptr),
+ std::exception);
pldm_pdr_destroy(pdrRepo);
}
@@ -117,7 +118,7 @@
auto inPDRRepo = pldm_pdr_init();
auto outPDRRepo = pldm_pdr_init();
Repo outRepo(outPDRRepo);
- Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
Repo inRepo(inPDRRepo);
getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
diff --git a/test/libpldmresponder_platform_test.cpp b/test/libpldmresponder_platform_test.cpp
index 8dfe6f1..818d5b2 100644
--- a/test/libpldmresponder_platform_test.cpp
+++ b/test/libpldmresponder_platform_test.cpp
@@ -24,7 +24,7 @@
request->request_count = 100;
auto pdrRepo = pldm_pdr_init();
- Handler handler("./pdr_jsons/state_effecter/good", pdrRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
Repo repo(pdrRepo);
ASSERT_EQ(repo.empty(), false);
auto response = handler.getPDR(req, requestPayloadLength);
@@ -55,7 +55,7 @@
request->request_count = 1;
auto pdrRepo = pldm_pdr_init();
- Handler handler("./pdr_jsons/state_effecter/good", pdrRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
Repo repo(pdrRepo);
ASSERT_EQ(repo.empty(), false);
auto response = handler.getPDR(req, requestPayloadLength);
@@ -80,7 +80,7 @@
request->request_count = 1;
auto pdrRepo = pldm_pdr_init();
- Handler handler("./pdr_jsons/state_effecter/good", pdrRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
Repo repo(pdrRepo);
ASSERT_EQ(repo.empty(), false);
auto response = handler.getPDR(req, requestPayloadLength);
@@ -103,7 +103,7 @@
request->record_handle = 1;
auto pdrRepo = pldm_pdr_init();
- Handler handler("./pdr_jsons/state_effecter/good", pdrRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
Repo repo(pdrRepo);
ASSERT_EQ(repo.empty(), false);
auto response = handler.getPDR(req, requestPayloadLength);
@@ -128,7 +128,7 @@
request->request_count = 100;
auto pdrRepo = pldm_pdr_init();
- Handler handler("./pdr_jsons/state_effecter/good", pdrRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
Repo repo(pdrRepo);
ASSERT_EQ(repo.empty(), false);
auto response = handler.getPDR(req, requestPayloadLength);
@@ -179,7 +179,7 @@
auto inPDRRepo = pldm_pdr_init();
auto outPDRRepo = pldm_pdr_init();
Repo outRepo(outPDRRepo);
- Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
Repo inRepo(inPDRRepo);
getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
pdr_utils::PdrEntry e;
@@ -214,7 +214,7 @@
auto inPDRRepo = pldm_pdr_init();
auto outPDRRepo = pldm_pdr_init();
Repo outRepo(outPDRRepo);
- Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo);
+ Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
Repo inRepo(inPDRRepo);
getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
pdr_utils::PdrEntry e;
diff --git a/test/meson.build b/test/meson.build
index 159cfc2..3adab01 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -14,7 +14,11 @@
gtest = dependency('gtest', main: true, disabler: true, required: true)
gmock = dependency('gmock', disabler: true, required: true)
-pldmd = declare_dependency(sources: '../instance_id.cpp')
+pldmd = declare_dependency(
+ sources: [
+ '../instance_id.cpp',
+ '../dbus_impl_requester.cpp',
+ '../host_pdr_handler.cpp'])
tests = [
'libpldmresponder_base_test',
diff --git a/utils.cpp b/utils.cpp
index 20d2b06..98e8d21 100644
--- a/utils.cpp
+++ b/utils.cpp
@@ -2,6 +2,7 @@
#include <array>
#include <ctime>
+#include <fstream>
#include <iostream>
#include <map>
#include <stdexcept>
@@ -17,6 +18,34 @@
constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
constexpr auto mapperPath = "/xyz/openbmc_project/object_mapper";
constexpr auto mapperInterface = "xyz.openbmc_project.ObjectMapper";
+constexpr auto eidPath = "/usr/share/pldm/host_eid";
+
+uint8_t readHostEID()
+{
+ uint8_t eid{};
+ std::ifstream eidFile{eidPath};
+ if (!eidFile.good())
+ {
+ std::cerr << "Could not open host EID file"
+ << "\n";
+ }
+ else
+ {
+ std::string eidStr;
+ eidFile >> eidStr;
+ if (!eidStr.empty())
+ {
+ eid = atoi(eidStr.c_str());
+ }
+ else
+ {
+ std::cerr << "Host EID file was empty"
+ << "\n";
+ }
+ }
+
+ return eid;
+}
uint8_t getNumPadBytes(uint32_t data)
{
diff --git a/utils.hpp b/utils.hpp
index 567138a..830a97f 100644
--- a/utils.hpp
+++ b/utils.hpp
@@ -241,5 +241,11 @@
return p.parent_path().string();
}
+/** @brief Read (static) MCTP EID of host firmware from a file
+ *
+ * @return uint8_t - MCTP EID
+ */
+uint8_t readHostEID();
+
} // namespace utils
} // namespace pldm