fw_update: Introduce AggregateUpdateManager
Description:
This commit introduces the `AggregateUpdateManager` class for handling
multiple firmware update sessions simultaneously. The
`AggregateUpdateManager` acts as a reverse proxy for PLDM messages,
routing them to the appropriate `UpdateManager` instance based on the
`instanceId`. This allows for concurrent firmware updates, improving
the efficiency and flexibility of the firmware update process.
Motivation:
We have introduced the `FirmwareInventory`/`FirmwareInventoryManager`
classes to manage D-Bus interfaces for firmware update, After that, we
would like to implement the `StartUpdate` method for `FirmwareInventory`
properly for the update process implementation[1], which
`AggregateUpdateManager` will help route the command to the specific
update sessions.
Details of the PLDM message reverse proxy:
By the implementation, different update session would be handled with
different `instanceId`s, which can help `UpdateManager`s to identify
whether the message is for them or not.
Whenever a PLDM response message is received, the flow that
the `AggregateUpdateManager` do:
1. Handle the message for existing update flow if the instance_id
(the pldm instance numbers) matches the update task which using the
existing update flow.
2. Traverse forward the message to each `ItemUpdateManager`
(implementation in the next patch) instances if there's no match in
step 1.
3. Return error message PLDM_FWUP_COMMAND_NOT_EXPECTED if no matches in
step 2.
[1]: https://gerrit.openbmc.org/c/openbmc/pldm/+/74774
Change-Id: Icfdb8d238121f9f44a624396e00b378e491ce652
Signed-off-by: Unive Tien <unive.tien.wiwynn@gmail.com>
diff --git a/fw-update/aggregate_update_manager.cpp b/fw-update/aggregate_update_manager.cpp
new file mode 100644
index 0000000..c27db95
--- /dev/null
+++ b/fw-update/aggregate_update_manager.cpp
@@ -0,0 +1,54 @@
+#include "aggregate_update_manager.hpp"
+
+namespace pldm::fw_update
+{
+
+Response AggregateUpdateManager::handleRequest(
+ mctp_eid_t eid, uint8_t command, const pldm_msg* request, size_t reqMsgLen)
+{
+ Response response;
+ response = UpdateManager::handleRequest(eid, command, request, reqMsgLen);
+ auto responseMsg = new (response.data()) pldm_msg;
+ if (responseMsg->payload[0] != PLDM_FWUP_COMMAND_NOT_EXPECTED)
+ {
+ return response;
+ }
+ for (auto& [_, updateManager] : updateManagers)
+ {
+ response =
+ updateManager->handleRequest(eid, command, request, reqMsgLen);
+ if (responseMsg->payload[0] != PLDM_FWUP_COMMAND_NOT_EXPECTED)
+ {
+ return response;
+ }
+ }
+ return response;
+}
+
+void AggregateUpdateManager::eraseUpdateManager(
+ const SoftwareIdentifier& softwareIdentifier)
+{
+ updateManagers.erase(softwareIdentifier);
+ descriptorMap.erase(softwareIdentifier);
+ componentInfoMap.erase(softwareIdentifier);
+}
+
+void AggregateUpdateManager::eraseUpdateManagerIf(
+ std::function<bool(const SoftwareIdentifier&)>&& predicate)
+{
+ for (auto it = updateManagers.begin(); it != updateManagers.end();)
+ {
+ if (predicate(it->first))
+ {
+ descriptorMap.erase(it->first);
+ componentInfoMap.erase(it->first);
+ it = updateManagers.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+}
+
+} // namespace pldm::fw_update
diff --git a/fw-update/aggregate_update_manager.hpp b/fw-update/aggregate_update_manager.hpp
new file mode 100644
index 0000000..eb15dc9
--- /dev/null
+++ b/fw-update/aggregate_update_manager.hpp
@@ -0,0 +1,116 @@
+#pragma once
+
+#include "update_manager.hpp"
+
+namespace pldm::fw_update
+{
+
+class AggregateUpdateManager : public UpdateManager
+{
+ public:
+ AggregateUpdateManager() = delete;
+ AggregateUpdateManager(const AggregateUpdateManager&) = delete;
+ AggregateUpdateManager(AggregateUpdateManager&&) = delete;
+ AggregateUpdateManager& operator=(const AggregateUpdateManager&) = delete;
+ AggregateUpdateManager& operator=(AggregateUpdateManager&&) = delete;
+
+ /**
+ * @brief Constructor for AggregateUpdateManager
+ *
+ * @param[in] event - Reference to the PLDM daemon's main event loop
+ * @param[in] handler - PLDM request handler
+ * @param[in] instanceIdDb - Reference to the instance ID database
+ * @param[in] descriptorMap - Descriptor map for the update manager
+ * @param[in] componentInfoMap - Component information map for the update
+ * manager
+ */
+ explicit AggregateUpdateManager(
+ Event& event,
+ pldm::requester::Handler<pldm::requester::Request>& handler,
+ InstanceIdDb& instanceIdDb, const DescriptorMap& descriptorMap,
+ const ComponentInfoMap& componentInfoMap) :
+ UpdateManager(event, handler, instanceIdDb, descriptorMap,
+ componentInfoMap)
+ {}
+
+ /**
+ * @brief Handle PLDM requests for the aggregate update manager
+ *
+ * This function processes incoming PLDM requests and dispatches them to the
+ * appropriate update manager based on the software identifier.
+ *
+ * @param[in] eid - Remote MCTP Endpoint ID
+ * @param[in] command - PLDM command code
+ * @param[in] request - PLDM request message
+ * @param[in] reqMsgLen - PLDM request message length
+ * @return PLDM response message
+ */
+ Response handleRequest(mctp_eid_t eid, uint8_t command,
+ const pldm_msg* request, size_t reqMsgLen) override;
+
+ /**
+ * @brief Create a new UpdateManager instance for a specific software
+ * identifier
+ *
+ * This function creates and stores a new UpdateManager instance associated
+ * with the given software identifier, along with its corresponding
+ * descriptor and component information maps.
+ *
+ * @param[in] softwareIdentifier - The software identifier (pair of eid and
+ * component identifier)
+ * @param[in] descriptors - The descriptors associated with the software
+ * identifier
+ * @param[in] componentInfo - The component information associated with the
+ * software identifier
+ * @param[in] updateObjPath - The D-Bus object path for the update manager
+ */
+ void createUpdateManager(const SoftwareIdentifier& softwareIdentifier,
+ const Descriptors& descriptors,
+ const ComponentInfo& componentInfo,
+ const std::string& updateObjPath);
+
+ /**
+ * @brief Erase an existing UpdateManager instance associated with a
+ * specific software identifier
+ *
+ * This function removes the UpdateManager instance and its associated
+ * descriptor and component information maps from the internal storage based
+ * on the provided software identifier.
+ *
+ * @param[in] softwareIdentifier - The software identifier (pair of eid and
+ * component identifier)
+ */
+ void eraseUpdateManager(const SoftwareIdentifier& softwareIdentifier);
+
+ /**
+ * @brief Erase UpdateManager instances that satisfy a given predicate
+ *
+ * This function iterates through the stored UpdateManager instances and
+ * removes those that satisfy the provided predicate function. It also
+ * removes the associated descriptor and component information maps.
+ *
+ * @param[in] predicate - A function that takes a SoftwareIdentifier and
+ * returns true if the corresponding UpdateManager should be erased
+ */
+ void eraseUpdateManagerIf(
+ std::function<bool(const SoftwareIdentifier&)>&& predicate);
+
+ private:
+ /**
+ * @brief Map of UpdateManager instances keyed by software identifier
+ */
+ std::map<SoftwareIdentifier, std::unique_ptr<UpdateManager>> updateManagers;
+
+ /**
+ * @brief Map of descriptor maps keyed by software identifier
+ */
+ std::map<SoftwareIdentifier, std::unique_ptr<Descriptors>> descriptorMap;
+
+ /**
+ * @brief Map of component information maps keyed by software identifier
+ */
+ std::map<SoftwareIdentifier, std::unique_ptr<ComponentInfo>>
+ componentInfoMap;
+};
+
+} // namespace pldm::fw_update
diff --git a/fw-update/firmware_inventory.cpp b/fw-update/firmware_inventory.cpp
index e59b5ba..ffbb4e8 100644
--- a/fw-update/firmware_inventory.cpp
+++ b/fw-update/firmware_inventory.cpp
@@ -6,7 +6,6 @@
FirmwareInventory::FirmwareInventory(
SoftwareIdentifier /*softwareIdentifier*/, const std::string& softwarePath,
const std::string& softwareVersion, const std::string& associatedEndpoint,
- const Descriptors& /*descriptors*/, const ComponentInfo& /*componentInfo*/,
SoftwareVersionPurpose purpose) :
softwarePath(softwarePath),
association(this->bus, this->softwarePath.c_str()),
diff --git a/fw-update/firmware_inventory.hpp b/fw-update/firmware_inventory.hpp
index 729989e..9d6dda8 100644
--- a/fw-update/firmware_inventory.hpp
+++ b/fw-update/firmware_inventory.hpp
@@ -52,8 +52,6 @@
SoftwareIdentifier /*softwareIdentifier*/,
const std::string& softwarePath, const std::string& softwareVersion,
const std::string& associatedEndpoint,
- const Descriptors& /*descriptors*/,
- const ComponentInfo& /*componentInfo*/,
SoftwareVersionPurpose purpose = SoftwareVersionPurpose::Unknown);
private:
diff --git a/fw-update/firmware_inventory_manager.cpp b/fw-update/firmware_inventory_manager.cpp
index bb9a6aa..a3e0ac9 100644
--- a/fw-update/firmware_inventory_manager.cpp
+++ b/fw-update/firmware_inventory_manager.cpp
@@ -13,7 +13,7 @@
void FirmwareInventoryManager::createFirmwareEntry(
const SoftwareIdentifier& softwareIdentifier,
const SoftwareName& softwareName, const std::string& activeVersion,
- const Descriptors& descriptors, const ComponentInfo& componentInfo)
+ const Descriptors& /*descriptors*/, const ComponentInfo& /*componentInfo*/)
{
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
@@ -42,15 +42,19 @@
softwareName, utils::generateSwId());
softwareMap.insert_or_assign(
- softwareIdentifier, std::make_unique<FirmwareInventory>(
- softwareIdentifier, softwarePath, activeVersion,
- *boardPath, descriptors, componentInfo));
+ softwareIdentifier,
+ std::make_unique<FirmwareInventory>(softwareIdentifier, softwarePath,
+ activeVersion, *boardPath));
}
void FirmwareInventoryManager::deleteFirmwareEntry(const pldm::eid& eid)
{
std::erase_if(softwareMap,
[&](const auto& pair) { return pair.first.first == eid; });
+ updateManager.eraseUpdateManagerIf(
+ [&](const SoftwareIdentifier& softwareIdentifier) {
+ return softwareIdentifier.first == eid;
+ });
}
std::optional<std::filesystem::path> getBoardPath(
diff --git a/fw-update/firmware_inventory_manager.hpp b/fw-update/firmware_inventory_manager.hpp
index e6616ce..45ffd8e 100644
--- a/fw-update/firmware_inventory_manager.hpp
+++ b/fw-update/firmware_inventory_manager.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "aggregate_update_manager.hpp"
#include "common/types.hpp"
#include "firmware_inventory.hpp"
@@ -40,8 +41,9 @@
*/
explicit FirmwareInventoryManager(
const pldm::utils::DBusHandler* dbusHandler,
- const Configurations& config) :
- dbusHandler(dbusHandler), configurations(config)
+ const Configurations& config, AggregateUpdateManager& updateManager) :
+ dbusHandler(dbusHandler), configurations(config),
+ updateManager(updateManager)
{}
/**
@@ -96,6 +98,11 @@
* the initialization of the FirmwareInventoryManager.
*/
const Configurations& configurations;
+
+ /**
+ * @brief Reference to the aggregate update manager
+ */
+ AggregateUpdateManager& updateManager;
};
} // namespace pldm::fw_update
diff --git a/fw-update/inventory_manager.hpp b/fw-update/inventory_manager.hpp
index 673b513..e100a52 100644
--- a/fw-update/inventory_manager.hpp
+++ b/fw-update/inventory_manager.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include "aggregate_update_manager.hpp"
#include "common/instance_id.hpp"
#include "common/types.hpp"
#include "firmware_inventory_manager.hpp"
@@ -47,12 +48,13 @@
InstanceIdDb& instanceIdDb, DescriptorMap& descriptorMap,
DownstreamDescriptorMap& downstreamDescriptorMap,
ComponentInfoMap& componentInfoMap,
- const Configurations& configurations) :
+ const Configurations& configurations,
+ AggregateUpdateManager& updateManager) :
handler(handler), instanceIdDb(instanceIdDb),
descriptorMap(descriptorMap),
downstreamDescriptorMap(downstreamDescriptorMap),
componentInfoMap(componentInfoMap), configurations(configurations),
- firmwareInventoryManager(dbusHandler, configurations)
+ firmwareInventoryManager(dbusHandler, configurations, updateManager)
{}
/** @brief Discover the firmware identifiers and component details of FDs
diff --git a/fw-update/manager.hpp b/fw-update/manager.hpp
index 2e75f6c..39e8376 100644
--- a/fw-update/manager.hpp
+++ b/fw-update/manager.hpp
@@ -1,13 +1,13 @@
#pragma once
#include "activation.hpp"
+#include "aggregate_update_manager.hpp"
#include "common/instance_id.hpp"
#include "common/types.hpp"
#include "device_updater.hpp"
#include "inventory_manager.hpp"
#include "requester/handler.hpp"
#include "requester/mctp_endpoint_discovery.hpp"
-#include "update_manager.hpp"
#include <unordered_map>
#include <vector>
@@ -48,10 +48,11 @@
explicit Manager(const pldm::utils::DBusHandler* dbusHandler, Event& event,
requester::Handler<requester::Request>& handler,
pldm::InstanceIdDb& instanceIdDb) :
- inventoryMgr(dbusHandler, handler, instanceIdDb, descriptorMap,
- downstreamDescriptorMap, componentInfoMap, configurations),
updateManager(event, handler, instanceIdDb, descriptorMap,
- componentInfoMap)
+ componentInfoMap),
+ inventoryMgr(dbusHandler, handler, instanceIdDb, descriptorMap,
+ downstreamDescriptorMap, componentInfoMap, configurations,
+ updateManager)
{}
/** @brief Helper function to invoke registered handlers for
@@ -134,11 +135,11 @@
/** Configuration bindings from the Entity Manager */
Configurations configurations;
+ /** @brief PLDM firmware update manager */
+ AggregateUpdateManager updateManager;
+
/** @brief PLDM firmware inventory manager */
InventoryManager inventoryMgr;
-
- /** @brief PLDM firmware update manager */
- UpdateManager updateManager;
};
} // namespace fw_update
diff --git a/fw-update/test/firmware_inventory_manager_test.cpp b/fw-update/test/firmware_inventory_manager_test.cpp
index 4814838..c7effaa 100644
--- a/fw-update/test/firmware_inventory_manager_test.cpp
+++ b/fw-update/test/firmware_inventory_manager_test.cpp
@@ -1,6 +1,7 @@
#include "common/test/mocked_utils.hpp"
#include "fw-update/firmware_inventory.hpp"
#include "fw-update/firmware_inventory_manager.hpp"
+#include "test/test_instance_id.hpp"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -33,8 +34,9 @@
{
public:
FirmwareInventoryManagerTest(const pldm::utils::DBusHandler* handler,
- const Configurations& config) :
- FirmwareInventoryManager(handler, config)
+ const Configurations& config,
+ AggregateUpdateManager& updateManager) :
+ FirmwareInventoryManager(handler, config, updateManager)
{}
SoftwareMap& getSoftwareMap()
@@ -64,7 +66,19 @@
endpointId, endpointUuid, endpointMedium, endpointNetId, endpointName);
configurations[boardInventoryPath] = endpointInfo;
- FirmwareInventoryManagerTest inventoryManager(&mockHandler, configurations);
+ Event event(sdeventplus::Event::get_default());
+ TestInstanceIdDb instanceIdDb;
+ requester::Handler<requester::Request> handler(
+ nullptr, event, instanceIdDb, false, seconds(1), 2, milliseconds(100));
+
+ DescriptorMap descriptorMap{};
+ ComponentInfoMap componentInfoMap{};
+
+ AggregateUpdateManager updateManager(event, handler, instanceIdDb,
+ descriptorMap, componentInfoMap);
+
+ FirmwareInventoryManagerTest inventoryManager(&mockHandler, configurations,
+ updateManager);
SoftwareIdentifier softwareIdentifier{endpointId, 100};
SoftwareName softwareName{"TestDevice"};
diff --git a/fw-update/test/firmware_inventory_test.cpp b/fw-update/test/firmware_inventory_test.cpp
index 46611bd..47d8396 100644
--- a/fw-update/test/firmware_inventory_test.cpp
+++ b/fw-update/test/firmware_inventory_test.cpp
@@ -36,10 +36,9 @@
ComponentInfo firmwareComponentInfo;
SoftwareVersionPurpose expectedPurpose = SoftwareVersionPurpose::Unknown;
- FirmwareInventoryTest inventory(
- softwareIdentifier, expectedSoftwarePath, expectedSoftwareVersion,
- expectedEndpointPath, firmwareDescriptors, firmwareComponentInfo,
- expectedPurpose);
+ FirmwareInventoryTest inventory(softwareIdentifier, expectedSoftwarePath,
+ expectedSoftwareVersion,
+ expectedEndpointPath, expectedPurpose);
EXPECT_EQ(inventory.getSoftwarePath(), expectedSoftwarePath);
auto associationTuples = inventory.getAssociation().associations();
diff --git a/fw-update/test/inventory_manager_test.cpp b/fw-update/test/inventory_manager_test.cpp
index f2fd789..5e76b46 100644
--- a/fw-update/test/inventory_manager_test.cpp
+++ b/fw-update/test/inventory_manager_test.cpp
@@ -1,4 +1,5 @@
#include "common/utils.hpp"
+#include "fw-update/aggregate_update_manager.hpp"
#include "fw-update/inventory_manager.hpp"
#include "requester/test/mock_request.hpp"
#include "test/test_instance_id.hpp"
@@ -18,9 +19,11 @@
event(sdeventplus::Event::get_default()), instanceIdDb(),
reqHandler(nullptr, event, instanceIdDb, false, seconds(1), 2,
milliseconds(100)),
+ updateManager(event, reqHandler, instanceIdDb, outDescriptorMap,
+ outComponentInfoMap),
inventoryManager(&dBusHandler, reqHandler, instanceIdDb,
outDescriptorMap, outDownstreamDescriptorMap,
- outComponentInfoMap, configurations)
+ outComponentInfoMap, configurations, updateManager)
{}
int fd = -1;
@@ -28,6 +31,7 @@
sdeventplus::Event event;
TestInstanceIdDb instanceIdDb;
requester::Handler<requester::Request> reqHandler;
+ AggregateUpdateManager updateManager;
InventoryManager inventoryManager;
DescriptorMap outDescriptorMap{};
DownstreamDescriptorMap outDownstreamDescriptorMap{};
diff --git a/fw-update/test/meson.build b/fw-update/test/meson.build
index ba78fcd..7ea17cd 100644
--- a/fw-update/test/meson.build
+++ b/fw-update/test/meson.build
@@ -1,12 +1,14 @@
fw_update_test_src = declare_dependency(
sources: [
'../activation.cpp',
+ '../aggregate_update_manager.cpp',
'../inventory_manager.cpp',
'../package_parser.cpp',
'../device_updater.cpp',
'../update_manager.cpp',
'../firmware_inventory_manager.cpp',
'../firmware_inventory.cpp',
+ '../update.cpp',
'../../common/utils.cpp',
],
)
diff --git a/fw-update/update_manager.hpp b/fw-update/update_manager.hpp
index 5aa80ec..4320de1 100644
--- a/fw-update/update_manager.hpp
+++ b/fw-update/update_manager.hpp
@@ -47,7 +47,7 @@
UpdateManager(UpdateManager&&) = delete;
UpdateManager& operator=(const UpdateManager&) = delete;
UpdateManager& operator=(UpdateManager&&) = delete;
- ~UpdateManager() = default;
+ virtual ~UpdateManager() = default;
explicit UpdateManager(
Event& event,
@@ -80,8 +80,8 @@
*
* @return PLDM response message
*/
- Response handleRequest(mctp_eid_t eid, uint8_t command,
- const pldm_msg* request, size_t reqMsgLen);
+ virtual Response handleRequest(mctp_eid_t eid, uint8_t command,
+ const pldm_msg* request, size_t reqMsgLen);
int processPackage(const std::filesystem::path& packageFilePath);
diff --git a/meson.build b/meson.build
index d0ec1c1..5ef9512 100644
--- a/meson.build
+++ b/meson.build
@@ -257,6 +257,7 @@
fw_update_sources = [
'fw-update/activation.cpp',
+ 'fw-update/aggregate_update_manager.cpp',
'fw-update/inventory_manager.cpp',
'fw-update/firmware_inventory_manager.cpp',
'fw-update/firmware_inventory.cpp',