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("getSubtree call failed with, {ERROR} {PATH} {INTERFACE}",
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("Adding Endpoint networkId={NETWORK} EID={EID}",
80                              "NETWORK", networkId, "EID", unsigned(eid));
81                         mctpInfos.emplace_back(
82                             MctpInfo(eid, emptyUUID, "", networkId));
83                     }
84                 }
85             }
86             catch (const sdbusplus::exception_t& e)
87             {
88                 error(
89                     "Error reading MCTP Endpoint property, {ERROR} {SERVICE} {PATH}",
90                     "ERROR", e, "SERVICE", service, "PATH", path);
91                 return;
92             }
93         }
94     }
95 }
96 
97 void MctpDiscovery::getAddedMctpInfos(sdbusplus::message_t& msg,
98                                       MctpInfos& mctpInfos)
99 {
100     using ObjectPath = sdbusplus::message::object_path;
101     ObjectPath objPath;
102     using Property = std::string;
103     using PropertyMap = std::map<Property, dbus::Value>;
104     std::map<std::string, PropertyMap> interfaces;
105 
106     try
107     {
108         msg.read(objPath, interfaces);
109     }
110     catch (const sdbusplus::exception_t& e)
111     {
112         error("Error reading MCTP Endpoint addedInterace message, {ERROR}",
113               "ERROR", e);
114         return;
115     }
116 
117     for (const auto& [intfName, properties] : interfaces)
118     {
119         if (intfName == MCTPInterface)
120         {
121             if (properties.contains("NetworkId") &&
122                 properties.contains("EID") &&
123                 properties.contains("SupportedMessageTypes"))
124             {
125                 auto networkId =
126                     std::get<NetworkId>(properties.at("NetworkId"));
127                 auto eid = std::get<mctp_eid_t>(properties.at("EID"));
128                 auto types = std::get<std::vector<uint8_t>>(
129                     properties.at("SupportedMessageTypes"));
130                 if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
131                     types.end())
132                 {
133                     info("Adding Endpoint networkId={NETWORK} EID={EID}",
134                          "NETWORK", networkId, "EID", unsigned(eid));
135                     mctpInfos.emplace_back(
136                         MctpInfo(eid, emptyUUID, "", networkId));
137                 }
138             }
139         }
140     }
141 }
142 
143 void MctpDiscovery::addToExistingMctpInfos(const MctpInfos& addedInfos)
144 {
145     for (const auto& mctpInfo : addedInfos)
146     {
147         if (std::find(existingMctpInfos.begin(), existingMctpInfos.end(),
148                       mctpInfo) == existingMctpInfos.end())
149         {
150             existingMctpInfos.emplace_back(mctpInfo);
151         }
152     }
153 }
154 
155 void MctpDiscovery::removeFromExistingMctpInfos(MctpInfos& mctpInfos,
156                                                 MctpInfos& removedInfos)
157 {
158     for (const auto& mctpInfo : existingMctpInfos)
159     {
160         if (std::find(mctpInfos.begin(), mctpInfos.end(), mctpInfo) ==
161             mctpInfos.end())
162         {
163             removedInfos.emplace_back(mctpInfo);
164         }
165     }
166     for (const auto& mctpInfo : removedInfos)
167     {
168         info("Removing Endpoint networkId={NETWORK} EID={EID}", "NETWORK",
169              std::get<3>(mctpInfo), "EID", unsigned(std::get<0>(mctpInfo)));
170         existingMctpInfos.erase(std::remove(existingMctpInfos.begin(),
171                                             existingMctpInfos.end(), mctpInfo),
172                                 existingMctpInfos.end());
173     }
174 }
175 
176 void MctpDiscovery::discoverEndpoints(sdbusplus::message_t& msg)
177 {
178     MctpInfos addedInfos;
179     getAddedMctpInfos(msg, addedInfos);
180     addToExistingMctpInfos(addedInfos);
181     handleMctpEndpoints(addedInfos);
182 }
183 
184 void MctpDiscovery::removeEndpoints(sdbusplus::message_t&)
185 {
186     MctpInfos mctpInfos;
187     MctpInfos removedInfos;
188     getMctpInfos(mctpInfos);
189     removeFromExistingMctpInfos(mctpInfos, removedInfos);
190     handleRemovedMctpEndpoints(removedInfos);
191 }
192 
193 void MctpDiscovery::handleMctpEndpoints(const MctpInfos& mctpInfos)
194 {
195     for (const auto& handler : handlers)
196     {
197         if (handler)
198         {
199             handler->handleMctpEndpoints(mctpInfos);
200         }
201     }
202 }
203 
204 void MctpDiscovery::handleRemovedMctpEndpoints(const MctpInfos& mctpInfos)
205 {
206     for (const auto& handler : handlers)
207     {
208         if (handler)
209         {
210             handler->handleRemovedMctpEndpoints(mctpInfos);
211         }
212     }
213 }
214 
215 } // namespace pldm
216