1 #include "config.h"
2 
3 #include "mctp_endpoint_discovery.hpp"
4 
5 #include "common/types.hpp"
6 #include "common/utils.hpp"
7 
8 #include <phosphor-logging/lg2.hpp>
9 
10 #include <algorithm>
11 #include <fstream>
12 #include <iostream>
13 #include <map>
14 #include <string>
15 #include <string_view>
16 #include <vector>
17 
18 using namespace sdbusplus::bus::match::rules;
19 
20 PHOSPHOR_LOG2_USING;
21 
22 namespace pldm
23 {
24 MctpDiscovery::MctpDiscovery(
25     sdbusplus::bus_t& bus,
26     std::initializer_list<MctpDiscoveryHandlerIntf*> list) :
27     bus(bus),
28     mctpEndpointAddedSignal(
29         bus, interfacesAdded(MCTPPath),
30         std::bind_front(&MctpDiscovery::discoverEndpoints, this)),
31     mctpEndpointRemovedSignal(
32         bus, interfacesRemoved(MCTPPath),
33         std::bind_front(&MctpDiscovery::removeEndpoints, this)),
34     handlers(list)
35 {
36     getMctpInfos(existingMctpInfos);
37     handleMctpEndpoints(existingMctpInfos);
38 }
39 
40 void MctpDiscovery::getMctpInfos(MctpInfos& mctpInfos)
41 {
42     // Find all implementations of the MCTP Endpoint interface
43     pldm::utils::GetSubTreeResponse mapperResponse;
44     try
45     {
46         mapperResponse = pldm::utils::DBusHandler().getSubtree(
47             MCTPPath, 0, std::vector<std::string>({MCTPInterface}));
48     }
49     catch (const sdbusplus::exception_t& e)
50     {
51         error(
52             "Failed to getSubtree call at path '{PATH}' and interface '{INTERFACE}', error - {ERROR} ",
53             "ERROR", e, "PATH", MCTPPath, "INTERFACE", MCTPInterface);
54         return;
55     }
56 
57     for (const auto& [path, services] : mapperResponse)
58     {
59         for (const auto& serviceIter : services)
60         {
61             const std::string& service = serviceIter.first;
62             try
63             {
64                 auto properties =
65                     pldm::utils::DBusHandler().getDbusPropertiesVariant(
66                         service.c_str(), path.c_str(), MCTPInterface);
67 
68                 if (properties.contains("NetworkId") &&
69                     properties.contains("EID") &&
70                     properties.contains("SupportedMessageTypes"))
71                 {
72                     auto networkId =
73                         std::get<NetworkId>(properties.at("NetworkId"));
74                     auto eid = std::get<mctp_eid_t>(properties.at("EID"));
75                     auto types = std::get<std::vector<uint8_t>>(
76                         properties.at("SupportedMessageTypes"));
77                     if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
78                         types.end())
79                     {
80                         info(
81                             "Adding Endpoint networkId '{NETWORK}' and EID '{EID}'",
82                             "NETWORK", networkId, "EID", eid);
83                         mctpInfos.emplace_back(
84                             MctpInfo(eid, emptyUUID, "", networkId));
85                     }
86                 }
87             }
88             catch (const sdbusplus::exception_t& e)
89             {
90                 error(
91                     "Error reading MCTP Endpoint property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
92                     "ERROR", e, "SERVICE", service, "PATH", path);
93                 return;
94             }
95         }
96     }
97 }
98 
99 void MctpDiscovery::getAddedMctpInfos(sdbusplus::message_t& msg,
100                                       MctpInfos& mctpInfos)
101 {
102     using ObjectPath = sdbusplus::message::object_path;
103     ObjectPath objPath;
104     using Property = std::string;
105     using PropertyMap = std::map<Property, dbus::Value>;
106     std::map<std::string, PropertyMap> interfaces;
107 
108     try
109     {
110         msg.read(objPath, interfaces);
111     }
112     catch (const sdbusplus::exception_t& e)
113     {
114         error(
115             "Error reading MCTP Endpoint added interface message, error - {ERROR}",
116             "ERROR", e);
117         return;
118     }
119 
120     for (const auto& [intfName, properties] : interfaces)
121     {
122         if (intfName == MCTPInterface)
123         {
124             if (properties.contains("NetworkId") &&
125                 properties.contains("EID") &&
126                 properties.contains("SupportedMessageTypes"))
127             {
128                 auto networkId =
129                     std::get<NetworkId>(properties.at("NetworkId"));
130                 auto eid = std::get<mctp_eid_t>(properties.at("EID"));
131                 auto types = std::get<std::vector<uint8_t>>(
132                     properties.at("SupportedMessageTypes"));
133                 if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
134                     types.end())
135                 {
136                     info(
137                         "Adding Endpoint networkId '{NETWORK}' and EID '{EID}'",
138                         "NETWORK", networkId, "EID", eid);
139                     mctpInfos.emplace_back(
140                         MctpInfo(eid, emptyUUID, "", networkId));
141                 }
142             }
143         }
144     }
145 }
146 
147 void MctpDiscovery::addToExistingMctpInfos(const MctpInfos& addedInfos)
148 {
149     for (const auto& mctpInfo : addedInfos)
150     {
151         if (std::find(existingMctpInfos.begin(), existingMctpInfos.end(),
152                       mctpInfo) == existingMctpInfos.end())
153         {
154             existingMctpInfos.emplace_back(mctpInfo);
155         }
156     }
157 }
158 
159 void MctpDiscovery::removeFromExistingMctpInfos(MctpInfos& mctpInfos,
160                                                 MctpInfos& removedInfos)
161 {
162     for (const auto& mctpInfo : existingMctpInfos)
163     {
164         if (std::find(mctpInfos.begin(), mctpInfos.end(), mctpInfo) ==
165             mctpInfos.end())
166         {
167             removedInfos.emplace_back(mctpInfo);
168         }
169     }
170     for (const auto& mctpInfo : removedInfos)
171     {
172         info("Removing Endpoint networkId '{NETWORK}' and  EID '{EID}'",
173              "NETWORK", std::get<3>(mctpInfo), "EID", std::get<0>(mctpInfo));
174         existingMctpInfos.erase(std::remove(existingMctpInfos.begin(),
175                                             existingMctpInfos.end(), mctpInfo),
176                                 existingMctpInfos.end());
177     }
178 }
179 
180 void MctpDiscovery::discoverEndpoints(sdbusplus::message_t& msg)
181 {
182     MctpInfos addedInfos;
183     getAddedMctpInfos(msg, addedInfos);
184     addToExistingMctpInfos(addedInfos);
185     handleMctpEndpoints(addedInfos);
186 }
187 
188 void MctpDiscovery::removeEndpoints(sdbusplus::message_t&)
189 {
190     MctpInfos mctpInfos;
191     MctpInfos removedInfos;
192     getMctpInfos(mctpInfos);
193     removeFromExistingMctpInfos(mctpInfos, removedInfos);
194     handleRemovedMctpEndpoints(removedInfos);
195 }
196 
197 void MctpDiscovery::handleMctpEndpoints(const MctpInfos& mctpInfos)
198 {
199     for (const auto& handler : handlers)
200     {
201         if (handler)
202         {
203             handler->handleMctpEndpoints(mctpInfos);
204         }
205     }
206 }
207 
208 void MctpDiscovery::handleRemovedMctpEndpoints(const MctpInfos& mctpInfos)
209 {
210     for (const auto& handler : handlers)
211     {
212         if (handler)
213         {
214             handler->handleRemovedMctpEndpoints(mctpInfos);
215         }
216     }
217 }
218 
219 } // namespace pldm
220