xref: /openbmc/dbus-sensors/src/mctp/MCTPReactorMain.cpp (revision 19d1fda609a4c39caca73858c90ebee823028362)
1275f7c39SAndrew Jeffery #include "MCTPEndpoint.hpp"
2275f7c39SAndrew Jeffery #include "MCTPReactor.hpp"
3275f7c39SAndrew Jeffery #include "Utils.hpp"
4275f7c39SAndrew Jeffery 
5275f7c39SAndrew Jeffery #include <boost/asio/io_context.hpp>
6275f7c39SAndrew Jeffery #include <boost/asio/post.hpp>
7275f7c39SAndrew Jeffery #include <boost/asio/steady_timer.hpp>
8275f7c39SAndrew Jeffery #include <phosphor-logging/lg2.hpp>
9275f7c39SAndrew Jeffery #include <sdbusplus/asio/connection.hpp>
10275f7c39SAndrew Jeffery #include <sdbusplus/asio/object_server.hpp>
11275f7c39SAndrew Jeffery #include <sdbusplus/bus.hpp>
12275f7c39SAndrew Jeffery #include <sdbusplus/bus/match.hpp>
13275f7c39SAndrew Jeffery #include <sdbusplus/message.hpp>
14275f7c39SAndrew Jeffery #include <sdbusplus/message/native_types.hpp>
15275f7c39SAndrew Jeffery 
16275f7c39SAndrew Jeffery #include <chrono>
17275f7c39SAndrew Jeffery #include <cstdlib>
18275f7c39SAndrew Jeffery #include <format>
19275f7c39SAndrew Jeffery #include <functional>
20275f7c39SAndrew Jeffery #include <map>
21275f7c39SAndrew Jeffery #include <memory>
22275f7c39SAndrew Jeffery #include <optional>
23275f7c39SAndrew Jeffery #include <set>
24275f7c39SAndrew Jeffery #include <stdexcept>
25275f7c39SAndrew Jeffery #include <system_error>
26275f7c39SAndrew Jeffery #include <vector>
27275f7c39SAndrew Jeffery 
28275f7c39SAndrew Jeffery PHOSPHOR_LOG2_USING;
29275f7c39SAndrew Jeffery 
30275f7c39SAndrew Jeffery class DBusAssociationServer : public AssociationServer
31275f7c39SAndrew Jeffery {
32275f7c39SAndrew Jeffery   public:
33275f7c39SAndrew Jeffery     DBusAssociationServer() = delete;
34275f7c39SAndrew Jeffery     DBusAssociationServer(const DBusAssociationServer&) = delete;
35275f7c39SAndrew Jeffery     DBusAssociationServer(DBusAssociationServer&&) = delete;
DBusAssociationServer(const std::shared_ptr<sdbusplus::asio::connection> & connection)36275f7c39SAndrew Jeffery     explicit DBusAssociationServer(
37275f7c39SAndrew Jeffery         const std::shared_ptr<sdbusplus::asio::connection>& connection) :
38275f7c39SAndrew Jeffery         server(connection)
39275f7c39SAndrew Jeffery     {
40*19d1fda6SThu Nguyen         server.add_manager("/au/com/codeconstruct/mctp1");
41275f7c39SAndrew Jeffery     }
42275f7c39SAndrew Jeffery     ~DBusAssociationServer() override = default;
43275f7c39SAndrew Jeffery     DBusAssociationServer& operator=(const DBusAssociationServer&) = delete;
44275f7c39SAndrew Jeffery     DBusAssociationServer& operator=(DBusAssociationServer&&) = delete;
45275f7c39SAndrew Jeffery 
associate(const std::string & path,const std::vector<Association> & associations)46275f7c39SAndrew Jeffery     void associate(const std::string& path,
47275f7c39SAndrew Jeffery                    const std::vector<Association>& associations) override
48275f7c39SAndrew Jeffery     {
49275f7c39SAndrew Jeffery         auto [entry, _] = objects.emplace(
50275f7c39SAndrew Jeffery             path, server.add_interface(path, association::interface));
51275f7c39SAndrew Jeffery         std::shared_ptr<sdbusplus::asio::dbus_interface> iface = entry->second;
52275f7c39SAndrew Jeffery         iface->register_property("Associations", associations);
53275f7c39SAndrew Jeffery         iface->initialize();
54275f7c39SAndrew Jeffery     }
55275f7c39SAndrew Jeffery 
disassociate(const std::string & path)56275f7c39SAndrew Jeffery     void disassociate(const std::string& path) override
57275f7c39SAndrew Jeffery     {
58275f7c39SAndrew Jeffery         const auto entry = objects.find(path);
59275f7c39SAndrew Jeffery         if (entry == objects.end())
60275f7c39SAndrew Jeffery         {
61275f7c39SAndrew Jeffery             throw std::logic_error(std::format(
62275f7c39SAndrew Jeffery                 "Attempted to untrack path that was not tracked: {}", path));
63275f7c39SAndrew Jeffery         }
64275f7c39SAndrew Jeffery         std::shared_ptr<sdbusplus::asio::dbus_interface> iface = entry->second;
65275f7c39SAndrew Jeffery         server.remove_interface(entry->second);
66275f7c39SAndrew Jeffery         objects.erase(entry);
67275f7c39SAndrew Jeffery     }
68275f7c39SAndrew Jeffery 
69275f7c39SAndrew Jeffery   private:
70275f7c39SAndrew Jeffery     std::shared_ptr<sdbusplus::asio::connection> connection;
71275f7c39SAndrew Jeffery     sdbusplus::asio::object_server server;
72275f7c39SAndrew Jeffery     std::map<std::string, std::shared_ptr<sdbusplus::asio::dbus_interface>>
73275f7c39SAndrew Jeffery         objects;
74275f7c39SAndrew Jeffery };
75275f7c39SAndrew Jeffery 
deviceFromConfig(const std::shared_ptr<sdbusplus::asio::connection> & connection,const SensorData & config)76275f7c39SAndrew Jeffery static std::shared_ptr<MCTPDevice> deviceFromConfig(
77275f7c39SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::connection>& connection,
78275f7c39SAndrew Jeffery     const SensorData& config)
79275f7c39SAndrew Jeffery {
80275f7c39SAndrew Jeffery     try
81275f7c39SAndrew Jeffery     {
82275f7c39SAndrew Jeffery         std::optional<SensorBaseConfigMap> iface;
83275f7c39SAndrew Jeffery         // NOLINTNEXTLINE(bugprone-assignment-in-if-condition)
84275f7c39SAndrew Jeffery         if ((iface = I2CMCTPDDevice::match(config)))
85275f7c39SAndrew Jeffery         {
86275f7c39SAndrew Jeffery             return I2CMCTPDDevice::from(connection, *iface);
87275f7c39SAndrew Jeffery         }
88275f7c39SAndrew Jeffery     }
89275f7c39SAndrew Jeffery     catch (const std::invalid_argument& ex)
90275f7c39SAndrew Jeffery     {
91275f7c39SAndrew Jeffery         error("Unable to create device: {EXCEPTION}", "EXCEPTION", ex);
92275f7c39SAndrew Jeffery     }
93275f7c39SAndrew Jeffery 
94275f7c39SAndrew Jeffery     return {};
95275f7c39SAndrew Jeffery }
96275f7c39SAndrew Jeffery 
addInventory(const std::shared_ptr<sdbusplus::asio::connection> & connection,const std::shared_ptr<MCTPReactor> & reactor,sdbusplus::message_t & msg)97275f7c39SAndrew Jeffery static void addInventory(
98275f7c39SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::connection>& connection,
99275f7c39SAndrew Jeffery     const std::shared_ptr<MCTPReactor>& reactor, sdbusplus::message_t& msg)
100275f7c39SAndrew Jeffery {
101275f7c39SAndrew Jeffery     auto [path,
102275f7c39SAndrew Jeffery           exposed] = msg.unpack<sdbusplus::message::object_path, SensorData>();
103275f7c39SAndrew Jeffery     try
104275f7c39SAndrew Jeffery     {
105275f7c39SAndrew Jeffery         reactor->manageMCTPDevice(path, deviceFromConfig(connection, exposed));
106275f7c39SAndrew Jeffery     }
107275f7c39SAndrew Jeffery     catch (const std::logic_error& e)
108275f7c39SAndrew Jeffery     {
109275f7c39SAndrew Jeffery         error(
110275f7c39SAndrew Jeffery             "Addition of inventory at '{INVENTORY_PATH}' caused an invalid program state: {EXCEPTION}",
111275f7c39SAndrew Jeffery             "INVENTORY_PATH", path, "EXCEPTION", e);
112275f7c39SAndrew Jeffery     }
113275f7c39SAndrew Jeffery     catch (const std::system_error& e)
114275f7c39SAndrew Jeffery     {
115275f7c39SAndrew Jeffery         error(
116275f7c39SAndrew Jeffery             "Failed to manage device described by inventory at '{INVENTORY_PATH}: {EXCEPTION}'",
117275f7c39SAndrew Jeffery             "INVENTORY_PATH", path, "EXCEPTION", e);
118275f7c39SAndrew Jeffery     }
119275f7c39SAndrew Jeffery }
120275f7c39SAndrew Jeffery 
removeInventory(const std::shared_ptr<MCTPReactor> & reactor,sdbusplus::message_t & msg)121275f7c39SAndrew Jeffery static void removeInventory(const std::shared_ptr<MCTPReactor>& reactor,
122275f7c39SAndrew Jeffery                             sdbusplus::message_t& msg)
123275f7c39SAndrew Jeffery {
124275f7c39SAndrew Jeffery     auto [path, removed] =
125275f7c39SAndrew Jeffery         msg.unpack<sdbusplus::message::object_path, std::set<std::string>>();
126275f7c39SAndrew Jeffery     try
127275f7c39SAndrew Jeffery     {
128275f7c39SAndrew Jeffery         if (I2CMCTPDDevice::match(removed))
129275f7c39SAndrew Jeffery         {
130275f7c39SAndrew Jeffery             reactor->unmanageMCTPDevice(path.str);
131275f7c39SAndrew Jeffery         }
132275f7c39SAndrew Jeffery     }
133275f7c39SAndrew Jeffery     catch (const std::logic_error& e)
134275f7c39SAndrew Jeffery     {
135275f7c39SAndrew Jeffery         error(
136275f7c39SAndrew Jeffery             "Removal of inventory at '{INVENTORY_PATH}' caused an invalid program state: {EXCEPTION}",
137275f7c39SAndrew Jeffery             "INVENTORY_PATH", path, "EXCEPTION", e);
138275f7c39SAndrew Jeffery     }
139275f7c39SAndrew Jeffery     catch (const std::system_error& e)
140275f7c39SAndrew Jeffery     {
141275f7c39SAndrew Jeffery         error(
142275f7c39SAndrew Jeffery             "Failed to unmanage device described by inventory at '{INVENTORY_PATH}: {EXCEPTION}'",
143275f7c39SAndrew Jeffery             "INVENTORY_PATH", path, "EXCEPTION", e);
144275f7c39SAndrew Jeffery     }
145275f7c39SAndrew Jeffery }
146275f7c39SAndrew Jeffery 
manageMCTPEntity(const std::shared_ptr<sdbusplus::asio::connection> & connection,const std::shared_ptr<MCTPReactor> & reactor,ManagedObjectType & entities)147275f7c39SAndrew Jeffery static void manageMCTPEntity(
148275f7c39SAndrew Jeffery     const std::shared_ptr<sdbusplus::asio::connection>& connection,
149275f7c39SAndrew Jeffery     const std::shared_ptr<MCTPReactor>& reactor, ManagedObjectType& entities)
150275f7c39SAndrew Jeffery {
151275f7c39SAndrew Jeffery     for (const auto& [path, config] : entities)
152275f7c39SAndrew Jeffery     {
153275f7c39SAndrew Jeffery         try
154275f7c39SAndrew Jeffery         {
155275f7c39SAndrew Jeffery             reactor->manageMCTPDevice(path,
156275f7c39SAndrew Jeffery                                       deviceFromConfig(connection, config));
157275f7c39SAndrew Jeffery         }
158275f7c39SAndrew Jeffery         catch (const std::logic_error& e)
159275f7c39SAndrew Jeffery         {
160275f7c39SAndrew Jeffery             error(
161275f7c39SAndrew Jeffery                 "Addition of inventory at '{INVENTORY_PATH}' caused an invalid program state: {EXCEPTION}",
162275f7c39SAndrew Jeffery                 "INVENTORY_PATH", path, "EXCEPTION", e);
163275f7c39SAndrew Jeffery         }
164275f7c39SAndrew Jeffery         catch (const std::system_error& e)
165275f7c39SAndrew Jeffery         {
166275f7c39SAndrew Jeffery             error(
167275f7c39SAndrew Jeffery                 "Failed to manage device described by inventory at '{INVENTORY_PATH}: {EXCEPTION}'",
168275f7c39SAndrew Jeffery                 "INVENTORY_PATH", path, "EXCEPTION", e);
169275f7c39SAndrew Jeffery         }
170275f7c39SAndrew Jeffery     }
171275f7c39SAndrew Jeffery }
172275f7c39SAndrew Jeffery 
exitReactor(boost::asio::io_context * io,sdbusplus::message_t & msg)173275f7c39SAndrew Jeffery static void exitReactor(boost::asio::io_context* io, sdbusplus::message_t& msg)
174275f7c39SAndrew Jeffery {
175275f7c39SAndrew Jeffery     auto name = msg.unpack<std::string>();
176275f7c39SAndrew Jeffery     info("Shutting down mctpreactor, lost dependency '{SERVICE_NAME}'",
177275f7c39SAndrew Jeffery          "SERVICE_NAME", name);
178275f7c39SAndrew Jeffery     io->stop();
179275f7c39SAndrew Jeffery }
180275f7c39SAndrew Jeffery 
main()181275f7c39SAndrew Jeffery int main()
182275f7c39SAndrew Jeffery {
183275f7c39SAndrew Jeffery     constexpr std::chrono::seconds period(5);
184275f7c39SAndrew Jeffery 
185275f7c39SAndrew Jeffery     boost::asio::io_context io;
186275f7c39SAndrew Jeffery     auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
187275f7c39SAndrew Jeffery     DBusAssociationServer associationServer(systemBus);
188275f7c39SAndrew Jeffery     auto reactor = std::make_shared<MCTPReactor>(associationServer);
189275f7c39SAndrew Jeffery     boost::asio::steady_timer clock(io);
190275f7c39SAndrew Jeffery 
191275f7c39SAndrew Jeffery     std::function<void(const boost::system::error_code&)> alarm =
192275f7c39SAndrew Jeffery         [&](const boost::system::error_code& ec) {
193275f7c39SAndrew Jeffery             if (ec)
194275f7c39SAndrew Jeffery             {
195275f7c39SAndrew Jeffery                 return;
196275f7c39SAndrew Jeffery             }
197275f7c39SAndrew Jeffery             clock.expires_after(period);
198275f7c39SAndrew Jeffery             clock.async_wait(alarm);
199275f7c39SAndrew Jeffery             reactor->tick();
200275f7c39SAndrew Jeffery         };
201275f7c39SAndrew Jeffery     clock.expires_after(period);
202275f7c39SAndrew Jeffery     clock.async_wait(alarm);
203275f7c39SAndrew Jeffery 
204275f7c39SAndrew Jeffery     using namespace sdbusplus::bus::match;
205275f7c39SAndrew Jeffery 
206275f7c39SAndrew Jeffery     const std::string entityManagerNameLostSpec =
207275f7c39SAndrew Jeffery         rules::nameOwnerChanged("xyz.openbmc_project.EntityManager");
208275f7c39SAndrew Jeffery 
209275f7c39SAndrew Jeffery     auto entityManagerNameLostMatch = sdbusplus::bus::match_t(
210275f7c39SAndrew Jeffery         static_cast<sdbusplus::bus_t&>(*systemBus), entityManagerNameLostSpec,
211275f7c39SAndrew Jeffery         std::bind_front(exitReactor, &io));
212275f7c39SAndrew Jeffery 
213275f7c39SAndrew Jeffery     const std::string mctpdNameLostSpec =
214*19d1fda6SThu Nguyen         rules::nameOwnerChanged("au.com.codeconstruct.MCTP1");
215275f7c39SAndrew Jeffery 
216275f7c39SAndrew Jeffery     auto mctpdNameLostMatch = sdbusplus::bus::match_t(
217275f7c39SAndrew Jeffery         static_cast<sdbusplus::bus_t&>(*systemBus), mctpdNameLostSpec,
218275f7c39SAndrew Jeffery         std::bind_front(exitReactor, &io));
219275f7c39SAndrew Jeffery 
220275f7c39SAndrew Jeffery     const std::string interfacesRemovedMatchSpec =
221275f7c39SAndrew Jeffery         rules::sender("xyz.openbmc_project.EntityManager") +
222275f7c39SAndrew Jeffery         // Trailing slash on path: Listen for signals on the inventory subtree
223275f7c39SAndrew Jeffery         rules::interfacesRemovedAtPath("/xyz/openbmc_project/inventory/");
224275f7c39SAndrew Jeffery 
225275f7c39SAndrew Jeffery     auto interfacesRemovedMatch = sdbusplus::bus::match_t(
226275f7c39SAndrew Jeffery         static_cast<sdbusplus::bus_t&>(*systemBus), interfacesRemovedMatchSpec,
227275f7c39SAndrew Jeffery         std::bind_front(removeInventory, reactor));
228275f7c39SAndrew Jeffery 
229275f7c39SAndrew Jeffery     const std::string interfacesAddedMatchSpec =
230275f7c39SAndrew Jeffery         rules::sender("xyz.openbmc_project.EntityManager") +
231275f7c39SAndrew Jeffery         // Trailing slash on path: Listen for signals on the inventory subtree
232275f7c39SAndrew Jeffery         rules::interfacesAddedAtPath("/xyz/openbmc_project/inventory/");
233275f7c39SAndrew Jeffery 
234275f7c39SAndrew Jeffery     auto interfacesAddedMatch = sdbusplus::bus::match_t(
235275f7c39SAndrew Jeffery         static_cast<sdbusplus::bus_t&>(*systemBus), interfacesAddedMatchSpec,
236275f7c39SAndrew Jeffery         std::bind_front(addInventory, systemBus, reactor));
237275f7c39SAndrew Jeffery 
238275f7c39SAndrew Jeffery     systemBus->request_name("xyz.openbmc_project.MCTPReactor");
239275f7c39SAndrew Jeffery 
240275f7c39SAndrew Jeffery     boost::asio::post(io, [reactor, systemBus]() {
241275f7c39SAndrew Jeffery         auto gsc = std::make_shared<GetSensorConfiguration>(
242275f7c39SAndrew Jeffery             systemBus, std::bind_front(manageMCTPEntity, systemBus, reactor));
243275f7c39SAndrew Jeffery         gsc->getConfiguration({"MCTPI2CTarget"});
244275f7c39SAndrew Jeffery     });
245275f7c39SAndrew Jeffery 
246275f7c39SAndrew Jeffery     io.run();
247275f7c39SAndrew Jeffery 
248275f7c39SAndrew Jeffery     return EXIT_SUCCESS;
249275f7c39SAndrew Jeffery }
250