fw-update: Firmware discovery of MCTP endpoints
Tested:
a) Verified MCTP endpoints are discovered by PLDM and fetching the firmware
inventory commands.
b) PLDM firmware update successful after uploading the package, which depends
on the firmware inventory commands.
c) Verified MCTP endpoints are discovered irrespective of the startup order
with the MCTP control application.
Signed-off-by: Tom Joseph <rushtotom@gmail.com>
Change-Id: I7ee9aed40433a8e5a4ebb8e61f917ec82dde9c35
diff --git a/common/types.hpp b/common/types.hpp
index 7f36df9..6f06ecc 100644
--- a/common/types.hpp
+++ b/common/types.hpp
@@ -2,6 +2,8 @@
#include <stdint.h>
+#include <sdbusplus/message/types.hpp>
+
#include <bitset>
#include <map>
#include <set>
@@ -16,6 +18,7 @@
using eid = uint8_t;
using Request = std::vector<uint8_t>;
using Response = std::vector<uint8_t>;
+using Command = uint8_t;
namespace dbus
{
@@ -26,8 +29,13 @@
using Interfaces = std::vector<std::string>;
using Property = std::string;
using PropertyType = std::string;
-using Value = std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
- int64_t, uint64_t, double, std::string>;
+using Value =
+ std::variant<bool, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t,
+ uint64_t, double, std::string, std::vector<uint8_t>>;
+
+using PropertyMap = std::map<Property, Value>;
+using InterfaceMap = std::map<Interface, PropertyMap>;
+using ObjectValueTree = std::map<sdbusplus::message::object_path, InterfaceMap>;
} // namespace dbus
diff --git a/fw-update/manager.hpp b/fw-update/manager.hpp
new file mode 100644
index 0000000..4f86876
--- /dev/null
+++ b/fw-update/manager.hpp
@@ -0,0 +1,95 @@
+#pragma once
+
+#include "libpldm/requester/pldm.h"
+
+#include "activation.hpp"
+#include "common/types.hpp"
+#include "device_updater.hpp"
+#include "inventory_manager.hpp"
+#include "pldmd/dbus_impl_requester.hpp"
+#include "requester/handler.hpp"
+#include "update_manager.hpp"
+
+#include <unordered_map>
+#include <vector>
+
+namespace pldm
+{
+
+namespace fw_update
+{
+
+using namespace pldm::dbus_api;
+
+/** @class Manager
+ *
+ * This class handles all the aspects of the PLDM FW update specification for
+ * the MCTP devices
+ */
+class Manager
+{
+
+ public:
+ Manager() = delete;
+ Manager(const Manager&) = delete;
+ Manager(Manager&&) = delete;
+ Manager& operator=(const Manager&) = delete;
+ Manager& operator=(Manager&&) = delete;
+ ~Manager() = default;
+
+ /** @brief Constructor
+ *
+ * @param[in] handler - PLDM request handler
+ */
+ explicit Manager(Event& event,
+ requester::Handler<requester::Request>& handler,
+ Requester& requester) :
+ inventoryMgr(handler, requester, descriptorMap, componentInfoMap),
+ updateManager(event, handler, requester, descriptorMap,
+ componentInfoMap)
+ {}
+
+ /** @brief Discover MCTP endpoints that support the PLDM firmware update
+ * specification
+ *
+ * @param[in] eids - Array of MCTP endpoints
+ *
+ * @return return PLDM_SUCCESS on success and PLDM_ERROR otherwise
+ */
+ void handleMCTPEndpoints(const std::vector<mctp_eid_t>& eids)
+ {
+ inventoryMgr.discoverFDs(eids);
+ }
+
+ /** @brief Handle PLDM request for the commands in the FW update
+ * specification
+ *
+ * @param[in] eid - Remote MCTP Endpoint ID
+ * @param[in] command - PLDM command code
+ * @param[in] request - PLDM request message
+ * @param[in] requestLen - PLDM request message length
+ * @return PLDM response message
+ */
+ Response handleRequest(mctp_eid_t eid, Command command,
+ const pldm_msg* request, size_t reqMsgLen)
+ {
+ return updateManager.handleRequest(eid, command, request, reqMsgLen);
+ }
+
+ private:
+ /** Descriptor information of all the discovered MCTP endpoints */
+ DescriptorMap descriptorMap;
+
+ /** Component information of all the discovered MCTP endpoints */
+ ComponentInfoMap componentInfoMap;
+
+ /** @brief PLDM firmware inventory manager */
+ InventoryManager inventoryMgr;
+
+ /** @brief PLDM firmware update manager */
+ UpdateManager updateManager;
+};
+
+} // namespace fw_update
+
+} // namespace pldm
diff --git a/meson.build b/meson.build
index 03e2572..9ddfe2f 100644
--- a/meson.build
+++ b/meson.build
@@ -200,6 +200,7 @@
'fw-update/device_updater.cpp',
'fw-update/watch.cpp',
'fw-update/update_manager.cpp',
+ 'requester/mctp_endpoint_discovery.cpp',
implicit_include_directories: false,
dependencies: deps,
install: true,
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index f009e88..d23acf8 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -5,8 +5,10 @@
#include "common/utils.hpp"
#include "dbus_impl_requester.hpp"
+#include "fw-update/manager.hpp"
#include "invoker.hpp"
#include "requester/handler.hpp"
+#include "requester/mctp_endpoint_discovery.hpp"
#include "requester/request.hpp"
#include <err.h>
@@ -63,7 +65,8 @@
static std::optional<Response>
processRxMsg(const std::vector<uint8_t>& requestMsg, Invoker& invoker,
- requester::Handler<requester::Request>& handler)
+ requester::Handler<requester::Request>& handler,
+ fw_update::Manager* fwManager)
{
using type = uint8_t;
uint8_t eid = requestMsg[0];
@@ -84,8 +87,17 @@
sizeof(eid) - sizeof(type);
try
{
- response = invoker.handle(hdrFields.pldm_type, hdrFields.command,
- request, requestLen);
+ if (hdrFields.pldm_type != PLDM_FWUP)
+ {
+ response =
+ invoker.handle(hdrFields.pldm_type, hdrFields.command,
+ request, requestLen);
+ }
+ else
+ {
+ response = fwManager->handleRequest(eid, hdrFields.command,
+ request, requestLen);
+ }
}
catch (const std::out_of_range& e)
{
@@ -168,12 +180,13 @@
auto event = Event::get_default();
auto& bus = pldm::utils::DBusHandler::getBus();
+ sdbusplus::server::manager::manager objManager(
+ bus, "/xyz/openbmc_project/software");
dbus_api::Requester dbusImplReq(bus, "/xyz/openbmc_project/pldm");
Invoker invoker{};
requester::Handler<requester::Request> reqHandler(sockfd, event,
dbusImplReq, verbose);
-
#ifdef LIBPLDMRESPONDER
using namespace pldm::state_sensor;
dbus_api::Host dbusImplHost(bus, "/xyz/openbmc_project/pldm");
@@ -281,8 +294,13 @@
exit(EXIT_FAILURE);
}
- auto callback = [verbose, &invoker, &reqHandler](IO& io, int fd,
- uint32_t revents) {
+ std::unique_ptr<fw_update::Manager> fwManager =
+ std::make_unique<fw_update::Manager>(event, reqHandler, dbusImplReq);
+ std::unique_ptr<MctpDiscovery> mctpDiscoveryHandler =
+ std::make_unique<MctpDiscovery>(bus, fwManager.get());
+
+ auto callback = [verbose, &invoker, &reqHandler,
+ &fwManager](IO& io, int fd, uint32_t revents) {
if (!(revents & EPOLLIN))
{
return;
@@ -327,14 +345,12 @@
if (MCTP_MSG_TYPE_PLDM != requestMsg[1])
{
// Skip this message and continue.
- std::cerr << "Encountered Non-PLDM type message"
- << "\n";
}
else
{
// process message and send response
- auto response =
- processRxMsg(requestMsg, invoker, reqHandler);
+ auto response = processRxMsg(requestMsg, invoker,
+ reqHandler, fwManager.get());
if (response.has_value())
{
if (verbose)
diff --git a/requester/mctp_endpoint_discovery.cpp b/requester/mctp_endpoint_discovery.cpp
new file mode 100644
index 0000000..b95935f
--- /dev/null
+++ b/requester/mctp_endpoint_discovery.cpp
@@ -0,0 +1,106 @@
+#include "mctp_endpoint_discovery.hpp"
+
+#include "libpldm/requester/pldm.h"
+
+#include "common/types.hpp"
+#include "common/utils.hpp"
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace pldm
+{
+
+MctpDiscovery::MctpDiscovery(sdbusplus::bus::bus& bus,
+ fw_update::Manager* fwManager) :
+ bus(bus),
+ fwManager(fwManager),
+ mctpEndpointSignal(bus,
+ sdbusplus::bus::match::rules::interfacesAdded(
+ "/xyz/openbmc_project/mctp"),
+ std::bind_front(&MctpDiscovery::dicoverEndpoints, this))
+{
+ dbus::ObjectValueTree objects;
+
+ try
+ {
+ auto method = bus.new_method_call(
+ "xyz.openbmc_project.MCTP.Control", "/xyz/openbmc_project/mctp",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ auto reply = bus.call(method);
+ reply.read(objects);
+ }
+ catch (const std::exception& e)
+ {
+ return;
+ }
+
+ std::vector<mctp_eid_t> eids;
+
+ for (const auto& [objectPath, interfaces] : objects)
+ {
+ for (const auto& [intfName, properties] : interfaces)
+ {
+ if (intfName == mctpEndpointIntfName)
+ {
+ if (properties.contains("EID") &&
+ properties.contains("SupportedMessageTypes"))
+ {
+ auto eid = std::get<size_t>(properties.at("EID"));
+ auto types = std::get<std::vector<uint8_t>>(
+ properties.at("SupportedMessageTypes"));
+ if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
+ types.end())
+ {
+ eids.emplace_back(eid);
+ }
+ }
+ }
+ }
+ }
+
+ if (eids.size() && fwManager)
+ {
+ fwManager->handleMCTPEndpoints(eids);
+ }
+}
+
+void MctpDiscovery::dicoverEndpoints(sdbusplus::message::message& msg)
+{
+ constexpr std::string_view mctpEndpointIntfName{
+ "xyz.openbmc_project.MCTP.Endpoint"};
+ std::vector<mctp_eid_t> eids;
+
+ sdbusplus::message::object_path objPath;
+ std::map<std::string, std::map<std::string, dbus::Value>> interfaces;
+ msg.read(objPath, interfaces);
+
+ for (const auto& [intfName, properties] : interfaces)
+ {
+ if (intfName == mctpEndpointIntfName)
+ {
+ if (properties.contains("EID") &&
+ properties.contains("SupportedMessageTypes"))
+ {
+ auto eid = std::get<size_t>(properties.at("EID"));
+ auto types = std::get<std::vector<uint8_t>>(
+ properties.at("SupportedMessageTypes"));
+ if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
+ types.end())
+ {
+ eids.emplace_back(eid);
+ }
+ }
+ }
+ }
+
+ if (eids.size() && fwManager)
+ {
+ fwManager->handleMCTPEndpoints(eids);
+ }
+}
+
+} // namespace pldm
\ No newline at end of file
diff --git a/requester/mctp_endpoint_discovery.hpp b/requester/mctp_endpoint_discovery.hpp
new file mode 100644
index 0000000..b09a2e9
--- /dev/null
+++ b/requester/mctp_endpoint_discovery.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "fw-update/manager.hpp"
+
+#include <sdbusplus/bus/match.hpp>
+
+namespace pldm
+{
+
+class MctpDiscovery
+{
+ public:
+ MctpDiscovery() = delete;
+ MctpDiscovery(const MctpDiscovery&) = delete;
+ MctpDiscovery(MctpDiscovery&&) = delete;
+ MctpDiscovery& operator=(const MctpDiscovery&) = delete;
+ MctpDiscovery& operator=(MctpDiscovery&&) = delete;
+ ~MctpDiscovery() = default;
+
+ /** @brief Constructs the MCTP Discovery object to handle discovery of
+ * MCTP enabled devices
+ *
+ * @param[in] bus - reference to systemd bus
+ * @param[in] fwManager - pointer to the firmware manager
+ */
+ explicit MctpDiscovery(sdbusplus::bus::bus& bus,
+ fw_update::Manager* fwManager);
+
+ private:
+ /** @brief reference to the systemd bus */
+ sdbusplus::bus::bus& bus;
+
+ fw_update::Manager* fwManager;
+
+ /** @brief Used to watch for new MCTP endpoints */
+ sdbusplus::bus::match_t mctpEndpointSignal;
+
+ void dicoverEndpoints(sdbusplus::message::message& msg);
+
+ static constexpr uint8_t mctpTypePLDM = 1;
+
+ static constexpr std::string_view mctpEndpointIntfName{
+ "xyz.openbmc_project.MCTP.Endpoint"};
+};
+
+} // namespace pldm
\ No newline at end of file