Add mctpreactor for dynamic configuration of MCTP networks
While mctpd[1] may see heavy use in projects such as OpenBMC, it
implements generic functionality necessary to operate MCTP as a
protocol. It therefore should be easy to use in other contexts, and so
it feels unwise to embed OpenBMC-specific details in its implementation.
Conversely, entity-manager's scope is to expose inventory and board
configuration. It externalises all other responsibilities for the sake
of stability and maintenance. While entity-manager is central to
OpenBMC's implementation and has little use in other contexts, embedding
details of how to configure mctpd in entity-manager exceeds its scope.
Thus we reach the design point of mctpreactor, an intermediary process
that encapsulates OpenBMC-specific and mctpd-specific behaviors to
constrain their dispersion in either direction. The design-point was
reached via discussion at [2].
mctpreactor tracks instances of transport-specific MCTP device
configurations[3] appearing as a result of inventory changes, and uses
them to assign endpoint IDs via mctpd.
The lifecycle of an MCTP device can be quite dynamic - mctpd provides
behaviors to recover[4] or remove endpoints from the network. Their
presence cannot be assumed. mctpreactor handles these events: If
a device is removed at the MCTP layer (as it may be unresponsive),
mctpreactor will periodically attempt to re-establish it as an endpoint
so long as the associated configuration on the entity-manager inventory
object remains exposed.
[1]: https://github.com/CodeConstruct/mctp/
[2]: https://github.com/CodeConstruct/mctp/pull/17
[3]: https://gerrit.openbmc.org/c/openbmc/entity-manager/+/70628
[4]: https://github.com/CodeConstruct/mctp/blob/7ec2f8daa3a8948066390aee621d6afa03f6ecd9/docs/endpoint-recovery.md
Change-Id: I5e362cf6e5ce80ce282bab48d912a1038003e236
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/mctp/MCTPReactor.hpp b/src/mctp/MCTPReactor.hpp
new file mode 100644
index 0000000..ca20b45
--- /dev/null
+++ b/src/mctp/MCTPReactor.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include "MCTPDeviceRepository.hpp"
+#include "MCTPEndpoint.hpp"
+#include "Utils.hpp"
+
+#include <string>
+#include <vector>
+
+struct AssociationServer
+{
+ virtual ~AssociationServer() = default;
+
+ virtual void associate(const std::string& path,
+ const std::vector<Association>& associations) = 0;
+ virtual void disassociate(const std::string& path) = 0;
+};
+
+class MCTPReactor : public std::enable_shared_from_this<MCTPReactor>
+{
+ using MCTPDeviceFactory = std::function<std::shared_ptr<MCTPDevice>(
+ const std::string& interface, const std::vector<std::uint8_t>& physaddr,
+ std::optional<std::uint8_t> eid)>;
+
+ public:
+ MCTPReactor() = delete;
+ MCTPReactor(const MCTPReactor&) = delete;
+ MCTPReactor(MCTPReactor&&) = delete;
+ explicit MCTPReactor(AssociationServer& server) : server(server) {}
+ ~MCTPReactor() = default;
+ MCTPReactor& operator=(const MCTPReactor&) = delete;
+ MCTPReactor& operator=(MCTPReactor&&) = delete;
+
+ void tick();
+
+ void manageMCTPDevice(const std::string& path,
+ const std::shared_ptr<MCTPDevice>& device);
+ void unmanageMCTPDevice(const std::string& path);
+
+ private:
+ static std::optional<std::string> findSMBusInterface(int bus);
+
+ AssociationServer& server;
+ MCTPDeviceRepository devices;
+
+ // Tracks MCTP devices that have failed their setup
+ std::set<std::shared_ptr<MCTPDevice>> deferred;
+
+ void deferSetup(const std::shared_ptr<MCTPDevice>& dev);
+ void setupEndpoint(const std::shared_ptr<MCTPDevice>& dev);
+ void trackEndpoint(const std::shared_ptr<MCTPEndpoint>& ep);
+ void untrackEndpoint(const std::shared_ptr<MCTPEndpoint>& ep);
+};