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