blob: 6d333497ad88b8623e58ce38098cf54e9d4eb590 [file] [log] [blame]
Andrew Jeffery275f7c32024-01-31 12:41:14 +10301#include "MCTPEndpoint.hpp"
2#include "MCTPReactor.hpp"
3#include "Utils.hpp"
4
5#include <boost/asio/io_context.hpp>
6#include <boost/asio/post.hpp>
7#include <boost/asio/steady_timer.hpp>
8#include <phosphor-logging/lg2.hpp>
9#include <sdbusplus/asio/connection.hpp>
10#include <sdbusplus/asio/object_server.hpp>
11#include <sdbusplus/bus.hpp>
12#include <sdbusplus/bus/match.hpp>
13#include <sdbusplus/message.hpp>
14#include <sdbusplus/message/native_types.hpp>
15
16#include <chrono>
17#include <cstdlib>
18#include <format>
19#include <functional>
20#include <map>
21#include <memory>
22#include <optional>
23#include <set>
24#include <stdexcept>
25#include <system_error>
26#include <vector>
27
28PHOSPHOR_LOG2_USING;
29
30class DBusAssociationServer : public AssociationServer
31{
32 public:
33 DBusAssociationServer() = delete;
34 DBusAssociationServer(const DBusAssociationServer&) = delete;
35 DBusAssociationServer(DBusAssociationServer&&) = delete;
36 explicit DBusAssociationServer(
37 const std::shared_ptr<sdbusplus::asio::connection>& connection) :
38 server(connection)
39 {
Thu Nguyen19d1fda2024-12-05 08:43:06 +000040 server.add_manager("/au/com/codeconstruct/mctp1");
Andrew Jeffery275f7c32024-01-31 12:41:14 +103041 }
42 ~DBusAssociationServer() override = default;
43 DBusAssociationServer& operator=(const DBusAssociationServer&) = delete;
44 DBusAssociationServer& operator=(DBusAssociationServer&&) = delete;
45
46 void associate(const std::string& path,
47 const std::vector<Association>& associations) override
48 {
49 auto [entry, _] = objects.emplace(
50 path, server.add_interface(path, association::interface));
51 std::shared_ptr<sdbusplus::asio::dbus_interface> iface = entry->second;
52 iface->register_property("Associations", associations);
53 iface->initialize();
54 }
55
56 void disassociate(const std::string& path) override
57 {
58 const auto entry = objects.find(path);
59 if (entry == objects.end())
60 {
61 throw std::logic_error(std::format(
62 "Attempted to untrack path that was not tracked: {}", path));
63 }
64 std::shared_ptr<sdbusplus::asio::dbus_interface> iface = entry->second;
65 server.remove_interface(entry->second);
66 objects.erase(entry);
67 }
68
69 private:
70 std::shared_ptr<sdbusplus::asio::connection> connection;
71 sdbusplus::asio::object_server server;
72 std::map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>>
73 objects;
74};
75
76static std::shared_ptr<MCTPDevice> deviceFromConfig(
77 const std::shared_ptr<sdbusplus::asio::connection>& connection,
78 const SensorData& config)
79{
80 try
81 {
82 std::optional<SensorBaseConfigMap> iface;
Unive Tienbd815c72025-05-28 09:28:54 +080083 iface = I2CMCTPDDevice::match(config);
84 if (iface)
Andrew Jeffery275f7c32024-01-31 12:41:14 +103085 {
Unive Tienbd815c72025-05-28 09:28:54 +080086 info("Creating I2CMCTPDDevice");
Andrew Jeffery275f7c32024-01-31 12:41:14 +103087 return I2CMCTPDDevice::from(connection, *iface);
88 }
Unive Tienbd815c72025-05-28 09:28:54 +080089
90 iface = I3CMCTPDDevice::match(config);
91 if (iface)
92 {
93 info("Creating I3CMCTPDDevice");
94 return I3CMCTPDDevice::from(connection, *iface);
95 }
Andrew Jeffery275f7c32024-01-31 12:41:14 +103096 }
97 catch (const std::invalid_argument& ex)
98 {
99 error("Unable to create device: {EXCEPTION}", "EXCEPTION", ex);
100 }
101
102 return {};
103}
104
105static void addInventory(
106 const std::shared_ptr<sdbusplus::asio::connection>& connection,
107 const std::shared_ptr<MCTPReactor>& reactor, sdbusplus::message_t& msg)
108{
109 auto [path,
110 exposed] = msg.unpack<sdbusplus::message::object_path, SensorData>();
111 try
112 {
113 reactor->manageMCTPDevice(path, deviceFromConfig(connection, exposed));
114 }
115 catch (const std::logic_error& e)
116 {
117 error(
118 "Addition of inventory at '{INVENTORY_PATH}' caused an invalid program state: {EXCEPTION}",
119 "INVENTORY_PATH", path, "EXCEPTION", e);
120 }
121 catch (const std::system_error& e)
122 {
123 error(
124 "Failed to manage device described by inventory at '{INVENTORY_PATH}: {EXCEPTION}'",
125 "INVENTORY_PATH", path, "EXCEPTION", e);
126 }
127}
128
129static void removeInventory(const std::shared_ptr<MCTPReactor>& reactor,
130 sdbusplus::message_t& msg)
131{
132 auto [path, removed] =
133 msg.unpack<sdbusplus::message::object_path, std::set<std::string>>();
134 try
135 {
Unive Tienbd815c72025-05-28 09:28:54 +0800136 if (I2CMCTPDDevice::match(removed) || I3CMCTPDDevice::match(removed))
Andrew Jeffery275f7c32024-01-31 12:41:14 +1030137 {
138 reactor->unmanageMCTPDevice(path.str);
139 }
140 }
141 catch (const std::logic_error& e)
142 {
143 error(
144 "Removal of inventory at '{INVENTORY_PATH}' caused an invalid program state: {EXCEPTION}",
145 "INVENTORY_PATH", path, "EXCEPTION", e);
146 }
147 catch (const std::system_error& e)
148 {
149 error(
150 "Failed to unmanage device described by inventory at '{INVENTORY_PATH}: {EXCEPTION}'",
151 "INVENTORY_PATH", path, "EXCEPTION", e);
152 }
153}
154
155static void manageMCTPEntity(
156 const std::shared_ptr<sdbusplus::asio::connection>& connection,
157 const std::shared_ptr<MCTPReactor>& reactor, ManagedObjectType& entities)
158{
159 for (const auto& [path, config] : entities)
160 {
161 try
162 {
163 reactor->manageMCTPDevice(path,
164 deviceFromConfig(connection, config));
165 }
166 catch (const std::logic_error& e)
167 {
168 error(
169 "Addition of inventory at '{INVENTORY_PATH}' caused an invalid program state: {EXCEPTION}",
170 "INVENTORY_PATH", path, "EXCEPTION", e);
171 }
172 catch (const std::system_error& e)
173 {
174 error(
175 "Failed to manage device described by inventory at '{INVENTORY_PATH}: {EXCEPTION}'",
176 "INVENTORY_PATH", path, "EXCEPTION", e);
177 }
178 }
179}
180
181static void exitReactor(boost::asio::io_context* io, sdbusplus::message_t& msg)
182{
183 auto name = msg.unpack<std::string>();
184 info("Shutting down mctpreactor, lost dependency '{SERVICE_NAME}'",
185 "SERVICE_NAME", name);
186 io->stop();
187}
188
189int main()
190{
191 constexpr std::chrono::seconds period(5);
192
193 boost::asio::io_context io;
194 auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
195 DBusAssociationServer associationServer(systemBus);
196 auto reactor = std::make_shared<MCTPReactor>(associationServer);
197 boost::asio::steady_timer clock(io);
198
199 std::function<void(const boost::system::error_code&)> alarm =
200 [&](const boost::system::error_code& ec) {
201 if (ec)
202 {
203 return;
204 }
205 clock.expires_after(period);
206 clock.async_wait(alarm);
207 reactor->tick();
208 };
209 clock.expires_after(period);
210 clock.async_wait(alarm);
211
212 using namespace sdbusplus::bus::match;
213
214 const std::string entityManagerNameLostSpec =
215 rules::nameOwnerChanged("xyz.openbmc_project.EntityManager");
216
217 auto entityManagerNameLostMatch = sdbusplus::bus::match_t(
218 static_cast<sdbusplus::bus_t&>(*systemBus), entityManagerNameLostSpec,
219 std::bind_front(exitReactor, &io));
220
221 const std::string mctpdNameLostSpec =
Thu Nguyen19d1fda2024-12-05 08:43:06 +0000222 rules::nameOwnerChanged("au.com.codeconstruct.MCTP1");
Andrew Jeffery275f7c32024-01-31 12:41:14 +1030223
224 auto mctpdNameLostMatch = sdbusplus::bus::match_t(
225 static_cast<sdbusplus::bus_t&>(*systemBus), mctpdNameLostSpec,
226 std::bind_front(exitReactor, &io));
227
228 const std::string interfacesRemovedMatchSpec =
229 rules::sender("xyz.openbmc_project.EntityManager") +
230 // Trailing slash on path: Listen for signals on the inventory subtree
231 rules::interfacesRemovedAtPath("/xyz/openbmc_project/inventory/");
232
233 auto interfacesRemovedMatch = sdbusplus::bus::match_t(
234 static_cast<sdbusplus::bus_t&>(*systemBus), interfacesRemovedMatchSpec,
235 std::bind_front(removeInventory, reactor));
236
237 const std::string interfacesAddedMatchSpec =
238 rules::sender("xyz.openbmc_project.EntityManager") +
239 // Trailing slash on path: Listen for signals on the inventory subtree
240 rules::interfacesAddedAtPath("/xyz/openbmc_project/inventory/");
241
242 auto interfacesAddedMatch = sdbusplus::bus::match_t(
243 static_cast<sdbusplus::bus_t&>(*systemBus), interfacesAddedMatchSpec,
244 std::bind_front(addInventory, systemBus, reactor));
245
246 systemBus->request_name("xyz.openbmc_project.MCTPReactor");
247
248 boost::asio::post(io, [reactor, systemBus]() {
249 auto gsc = std::make_shared<GetSensorConfiguration>(
250 systemBus, std::bind_front(manageMCTPEntity, systemBus, reactor));
Unive Tienbd815c72025-05-28 09:28:54 +0800251 gsc->getConfiguration({"MCTPI2CTarget", "MCTPI3CTarget"});
Andrew Jeffery275f7c32024-01-31 12:41:14 +1030252 });
253
254 io.run();
255
256 return EXIT_SUCCESS;
257}