blob: ac1277f95c24991367631a7ad14926d922065e0d [file] [log] [blame]
Gilbert Chen44524a52022-02-14 12:12:25 +00001#include "config.h"
2
Tom Josephfb3bc062021-08-17 07:48:11 -07003#include "mctp_endpoint_discovery.hpp"
4
Tom Josephfb3bc062021-08-17 07:48:11 -07005#include "common/types.hpp"
6#include "common/utils.hpp"
7
Thu Nguyen90274972024-07-17 07:02:16 +00008#include <linux/mctp.h>
9
Gilbert Chen44524a52022-02-14 12:12:25 +000010#include <phosphor-logging/lg2.hpp>
11
Tom Josephfb3bc062021-08-17 07:48:11 -070012#include <algorithm>
Gilbert Chen44524a52022-02-14 12:12:25 +000013#include <fstream>
14#include <iostream>
Tom Josephfb3bc062021-08-17 07:48:11 -070015#include <map>
16#include <string>
17#include <string_view>
18#include <vector>
19
Gilbert Chen44524a52022-02-14 12:12:25 +000020using namespace sdbusplus::bus::match::rules;
21
22PHOSPHOR_LOG2_USING;
23
Tom Josephfb3bc062021-08-17 07:48:11 -070024namespace pldm
25{
Gilbert Chen44524a52022-02-14 12:12:25 +000026MctpDiscovery::MctpDiscovery(
Patrick Williamsba741d52024-05-08 02:32:10 -050027 sdbusplus::bus_t& bus,
Gilbert Chen44524a52022-02-14 12:12:25 +000028 std::initializer_list<MctpDiscoveryHandlerIntf*> list) :
Patrick Williams16c2a0a2024-08-16 15:20:59 -040029 bus(bus), mctpEndpointAddedSignal(
30 bus, interfacesAdded(MCTPPath),
31 std::bind_front(&MctpDiscovery::discoverEndpoints, this)),
Gilbert Chen44524a52022-02-14 12:12:25 +000032 mctpEndpointRemovedSignal(
33 bus, interfacesRemoved(MCTPPath),
34 std::bind_front(&MctpDiscovery::removeEndpoints, this)),
Chau Ly75e00422024-03-19 12:33:08 +000035 mctpEndpointPropChangedSignal(
36 bus, propertiesChangedNamespace(MCTPPath, MCTPInterfaceCC),
37 std::bind_front(&MctpDiscovery::propertiesChangedCb, this)),
Gilbert Chen44524a52022-02-14 12:12:25 +000038 handlers(list)
Tom Josephfb3bc062021-08-17 07:48:11 -070039{
Chau Ly75e00422024-03-19 12:33:08 +000040 std::map<MctpInfo, Availability> currentMctpInfoMap;
41 getMctpInfos(currentMctpInfoMap);
42 for (const auto& mapIt : currentMctpInfoMap)
43 {
44 if (mapIt.second)
45 {
46 // Only add the available endpoints to the terminus
47 // Let the propertiesChanged signal tells us when it comes back
48 // to Available again
49 addToExistingMctpInfos(MctpInfos(1, mapIt.first));
50 }
51 }
Gilbert Chen44524a52022-02-14 12:12:25 +000052 handleMctpEndpoints(existingMctpInfos);
53}
Tom Josephfb3bc062021-08-17 07:48:11 -070054
Chau Ly75e00422024-03-19 12:33:08 +000055void MctpDiscovery::getMctpInfos(std::map<MctpInfo, Availability>& mctpInfoMap)
Gilbert Chen44524a52022-02-14 12:12:25 +000056{
57 // Find all implementations of the MCTP Endpoint interface
58 pldm::utils::GetSubTreeResponse mapperResponse;
Tom Josephfb3bc062021-08-17 07:48:11 -070059 try
60 {
Gilbert Chen44524a52022-02-14 12:12:25 +000061 mapperResponse = pldm::utils::DBusHandler().getSubtree(
62 MCTPPath, 0, std::vector<std::string>({MCTPInterface}));
Tom Josephfb3bc062021-08-17 07:48:11 -070063 }
Gilbert Chen44524a52022-02-14 12:12:25 +000064 catch (const sdbusplus::exception_t& e)
Tom Josephfb3bc062021-08-17 07:48:11 -070065 {
Riya Dixit087a7512024-04-06 14:28:08 -050066 error(
67 "Failed to getSubtree call at path '{PATH}' and interface '{INTERFACE}', error - {ERROR} ",
68 "ERROR", e, "PATH", MCTPPath, "INTERFACE", MCTPInterface);
Tom Josephfb3bc062021-08-17 07:48:11 -070069 return;
70 }
71
Gilbert Chen44524a52022-02-14 12:12:25 +000072 for (const auto& [path, services] : mapperResponse)
Tom Josephfb3bc062021-08-17 07:48:11 -070073 {
Gilbert Chen44524a52022-02-14 12:12:25 +000074 for (const auto& serviceIter : services)
Tom Josephfb3bc062021-08-17 07:48:11 -070075 {
Gilbert Chen44524a52022-02-14 12:12:25 +000076 const std::string& service = serviceIter.first;
Thu Nguyen90274972024-07-17 07:02:16 +000077 const MctpEndpointProps& epProps =
78 getMctpEndpointProps(service, path);
79 const UUID& uuid = getEndpointUUIDProp(service, path);
Chau Ly75e00422024-03-19 12:33:08 +000080 const Availability& availability =
81 getEndpointConnectivityProp(path);
Thu Nguyen90274972024-07-17 07:02:16 +000082 auto types = std::get<MCTPMsgTypes>(epProps);
83 if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
84 types.end())
Tom Josephfb3bc062021-08-17 07:48:11 -070085 {
Unive Tienc40d4a62025-03-12 11:36:07 +080086 auto mctpInfo =
87 MctpInfo(std::get<eid>(epProps), uuid, "",
88 std::get<NetworkId>(epProps), std::nullopt);
89 searchConfigurationFor(pldm::utils::DBusHandler(), mctpInfo);
90 mctpInfoMap[std::move(mctpInfo)] = availability;
Gilbert Chen44524a52022-02-14 12:12:25 +000091 }
Tom Josephfb3bc062021-08-17 07:48:11 -070092 }
93 }
Tom Josephfb3bc062021-08-17 07:48:11 -070094}
95
Thu Nguyen90274972024-07-17 07:02:16 +000096MctpEndpointProps MctpDiscovery::getMctpEndpointProps(
97 const std::string& service, const std::string& path)
98{
99 try
100 {
101 auto properties = pldm::utils::DBusHandler().getDbusPropertiesVariant(
102 service.c_str(), path.c_str(), MCTPInterface);
103
104 if (properties.contains("NetworkId") && properties.contains("EID") &&
105 properties.contains("SupportedMessageTypes"))
106 {
107 auto networkId = std::get<NetworkId>(properties.at("NetworkId"));
108 auto eid = std::get<mctp_eid_t>(properties.at("EID"));
109 auto types = std::get<std::vector<uint8_t>>(
110 properties.at("SupportedMessageTypes"));
111 return MctpEndpointProps(networkId, eid, types);
112 }
113 }
114 catch (const sdbusplus::exception_t& e)
115 {
116 error(
117 "Error reading MCTP Endpoint property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
118 "SERVICE", service, "PATH", path, "ERROR", e);
119 return MctpEndpointProps(0, MCTP_ADDR_ANY, {});
120 }
121
122 return MctpEndpointProps(0, MCTP_ADDR_ANY, {});
123}
124
125UUID MctpDiscovery::getEndpointUUIDProp(const std::string& service,
126 const std::string& path)
127{
128 try
129 {
130 auto properties = pldm::utils::DBusHandler().getDbusPropertiesVariant(
131 service.c_str(), path.c_str(), EndpointUUID);
132
133 if (properties.contains("UUID"))
134 {
135 return std::get<UUID>(properties.at("UUID"));
136 }
137 }
138 catch (const sdbusplus::exception_t& e)
139 {
140 error(
141 "Error reading Endpoint UUID property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
142 "SERVICE", service, "PATH", path, "ERROR", e);
143 return static_cast<UUID>(emptyUUID);
144 }
145
146 return static_cast<UUID>(emptyUUID);
147}
148
Chau Ly75e00422024-03-19 12:33:08 +0000149Availability MctpDiscovery::getEndpointConnectivityProp(const std::string& path)
150{
151 Availability available = false;
152 try
153 {
154 pldm::utils::PropertyValue propertyValue =
155 pldm::utils::DBusHandler().getDbusPropertyVariant(
156 path.c_str(), MCTPConnectivityProp, MCTPInterfaceCC);
157 if (std::get<std::string>(propertyValue) == "Available")
158 {
159 available = true;
160 }
161 }
162 catch (const sdbusplus::exception_t& e)
163 {
164 error(
165 "Error reading Endpoint Connectivity property at path '{PATH}', error - {ERROR}",
166 "PATH", path, "ERROR", e);
167 }
168
169 return available;
170}
171
Gilbert Chen44524a52022-02-14 12:12:25 +0000172void MctpDiscovery::getAddedMctpInfos(sdbusplus::message_t& msg,
173 MctpInfos& mctpInfos)
Tom Josephfb3bc062021-08-17 07:48:11 -0700174{
Gilbert Chen44524a52022-02-14 12:12:25 +0000175 using ObjectPath = sdbusplus::message::object_path;
176 ObjectPath objPath;
177 using Property = std::string;
178 using PropertyMap = std::map<Property, dbus::Value>;
179 std::map<std::string, PropertyMap> interfaces;
Thu Nguyen90274972024-07-17 07:02:16 +0000180 std::string uuid = emptyUUID;
Tom Josephfb3bc062021-08-17 07:48:11 -0700181
Gilbert Chen44524a52022-02-14 12:12:25 +0000182 try
183 {
184 msg.read(objPath, interfaces);
185 }
186 catch (const sdbusplus::exception_t& e)
187 {
Riya Dixit087a7512024-04-06 14:28:08 -0500188 error(
189 "Error reading MCTP Endpoint added interface message, error - {ERROR}",
190 "ERROR", e);
Gilbert Chen44524a52022-02-14 12:12:25 +0000191 return;
192 }
Chau Ly75e00422024-03-19 12:33:08 +0000193 const Availability& availability = getEndpointConnectivityProp(objPath.str);
Tom Josephfb3bc062021-08-17 07:48:11 -0700194
Thu Nguyen90274972024-07-17 07:02:16 +0000195 /* Get UUID */
196 try
197 {
198 auto service = pldm::utils::DBusHandler().getService(
199 objPath.str.c_str(), EndpointUUID);
200 uuid = getEndpointUUIDProp(service, objPath.str);
201 }
202 catch (const sdbusplus::exception_t& e)
203 {
204 error("Error getting Endpoint UUID D-Bus interface, error - {ERROR}",
205 "ERROR", e);
206 }
207
Tom Josephfb3bc062021-08-17 07:48:11 -0700208 for (const auto& [intfName, properties] : interfaces)
209 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000210 if (intfName == MCTPInterface)
Tom Josephfb3bc062021-08-17 07:48:11 -0700211 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000212 if (properties.contains("NetworkId") &&
213 properties.contains("EID") &&
Tom Josephfb3bc062021-08-17 07:48:11 -0700214 properties.contains("SupportedMessageTypes"))
215 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000216 auto networkId =
217 std::get<NetworkId>(properties.at("NetworkId"));
Dung Cao66794d02023-10-25 04:06:23 +0000218 auto eid = std::get<mctp_eid_t>(properties.at("EID"));
Tom Josephfb3bc062021-08-17 07:48:11 -0700219 auto types = std::get<std::vector<uint8_t>>(
220 properties.at("SupportedMessageTypes"));
Chau Ly75e00422024-03-19 12:33:08 +0000221
222 if (!availability)
223 {
224 // Log an error message here, but still add it to the
225 // terminus
226 error(
227 "mctpd added a DEGRADED endpoint {EID} networkId {NET} to D-Bus",
228 "NET", networkId, "EID", static_cast<unsigned>(eid));
229 }
Tom Josephfb3bc062021-08-17 07:48:11 -0700230 if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
231 types.end())
232 {
Riya Dixit087a7512024-04-06 14:28:08 -0500233 info(
Thu Nguyen90274972024-07-17 07:02:16 +0000234 "Adding Endpoint networkId '{NETWORK}' and EID '{EID}' UUID '{UUID}'",
235 "NETWORK", networkId, "EID", eid, "UUID", uuid);
Unive Tienc40d4a62025-03-12 11:36:07 +0800236 auto mctpInfo =
237 MctpInfo(eid, uuid, "", networkId, std::nullopt);
238 searchConfigurationFor(pldm::utils::DBusHandler(),
239 mctpInfo);
240 mctpInfos.emplace_back(std::move(mctpInfo));
Tom Josephfb3bc062021-08-17 07:48:11 -0700241 }
242 }
243 }
244 }
Gilbert Chen44524a52022-02-14 12:12:25 +0000245}
Tom Josephfb3bc062021-08-17 07:48:11 -0700246
Gilbert Chen44524a52022-02-14 12:12:25 +0000247void MctpDiscovery::addToExistingMctpInfos(const MctpInfos& addedInfos)
248{
249 for (const auto& mctpInfo : addedInfos)
Tom Josephfb3bc062021-08-17 07:48:11 -0700250 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000251 if (std::find(existingMctpInfos.begin(), existingMctpInfos.end(),
252 mctpInfo) == existingMctpInfos.end())
253 {
254 existingMctpInfos.emplace_back(mctpInfo);
255 }
256 }
257}
258
259void MctpDiscovery::removeFromExistingMctpInfos(MctpInfos& mctpInfos,
260 MctpInfos& removedInfos)
261{
262 for (const auto& mctpInfo : existingMctpInfos)
263 {
264 if (std::find(mctpInfos.begin(), mctpInfos.end(), mctpInfo) ==
265 mctpInfos.end())
266 {
267 removedInfos.emplace_back(mctpInfo);
268 }
269 }
270 for (const auto& mctpInfo : removedInfos)
271 {
Riya Dixit087a7512024-04-06 14:28:08 -0500272 info("Removing Endpoint networkId '{NETWORK}' and EID '{EID}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500273 "NETWORK", std::get<3>(mctpInfo), "EID", std::get<0>(mctpInfo));
Gilbert Chen44524a52022-02-14 12:12:25 +0000274 existingMctpInfos.erase(std::remove(existingMctpInfos.begin(),
275 existingMctpInfos.end(), mctpInfo),
276 existingMctpInfos.end());
277 }
278}
279
Chau Ly75e00422024-03-19 12:33:08 +0000280void MctpDiscovery::propertiesChangedCb(sdbusplus::message_t& msg)
281{
282 using Interface = std::string;
283 using Property = std::string;
284 using Value = std::string;
285 using Properties = std::map<Property, std::variant<Value>>;
286
287 Interface interface;
288 Properties properties;
289 std::string objPath{};
290 std::string service{};
291
292 try
293 {
294 msg.read(interface, properties);
295 objPath = msg.get_path();
296 }
297 catch (const sdbusplus::exception_t& e)
298 {
299 error(
300 "Error handling Connectivity property changed message, error - {ERROR}",
301 "ERROR", e);
302 return;
303 }
304
305 for (const auto& [key, valueVariant] : properties)
306 {
307 Value propVal = std::get<std::string>(valueVariant);
308 auto availability = (propVal == "Available") ? true : false;
309
310 if (key == MCTPConnectivityProp)
311 {
312 service = pldm::utils::DBusHandler().getService(objPath.c_str(),
313 MCTPInterface);
314 const MctpEndpointProps& epProps =
315 getMctpEndpointProps(service, objPath);
316
317 auto types = std::get<MCTPMsgTypes>(epProps);
318 if (!std::ranges::contains(types, mctpTypePLDM))
319 {
320 return;
321 }
322 const UUID& uuid = getEndpointUUIDProp(service, objPath);
323
324 MctpInfo mctpInfo(std::get<eid>(epProps), uuid, "",
Unive Tienc40d4a62025-03-12 11:36:07 +0800325 std::get<NetworkId>(epProps), std::nullopt);
326 searchConfigurationFor(pldm::utils::DBusHandler(), mctpInfo);
Chau Ly75e00422024-03-19 12:33:08 +0000327 if (!std::ranges::contains(existingMctpInfos, mctpInfo))
328 {
329 if (availability)
330 {
331 // The endpoint not in existingMctpInfos and is
332 // available Add it to existingMctpInfos
333 info(
334 "Adding Endpoint networkId {NETWORK} ID {EID} by propertiesChanged signal",
335 "NETWORK", std::get<3>(mctpInfo), "EID",
336 unsigned(std::get<0>(mctpInfo)));
337 addToExistingMctpInfos(MctpInfos(1, mctpInfo));
338 handleMctpEndpoints(MctpInfos(1, mctpInfo));
339 }
340 }
341 else
342 {
343 // The endpoint already in existingMctpInfos
344 updateMctpEndpointAvailability(mctpInfo, availability);
345 }
346 }
347 }
348}
349
Gilbert Chen44524a52022-02-14 12:12:25 +0000350void MctpDiscovery::discoverEndpoints(sdbusplus::message_t& msg)
351{
352 MctpInfos addedInfos;
353 getAddedMctpInfos(msg, addedInfos);
354 addToExistingMctpInfos(addedInfos);
355 handleMctpEndpoints(addedInfos);
356}
357
358void MctpDiscovery::removeEndpoints(sdbusplus::message_t&)
359{
360 MctpInfos mctpInfos;
361 MctpInfos removedInfos;
Chau Ly75e00422024-03-19 12:33:08 +0000362 std::map<MctpInfo, Availability> currentMctpInfoMap;
363 getMctpInfos(currentMctpInfoMap);
364 for (const auto& mapIt : currentMctpInfoMap)
365 {
366 mctpInfos.push_back(mapIt.first);
367 }
Gilbert Chen44524a52022-02-14 12:12:25 +0000368 removeFromExistingMctpInfos(mctpInfos, removedInfos);
369 handleRemovedMctpEndpoints(removedInfos);
Unive Tienc40d4a62025-03-12 11:36:07 +0800370 removeConfigs(removedInfos);
Gilbert Chen44524a52022-02-14 12:12:25 +0000371}
372
373void MctpDiscovery::handleMctpEndpoints(const MctpInfos& mctpInfos)
374{
375 for (const auto& handler : handlers)
376 {
377 if (handler)
378 {
Unive Tienc40d4a62025-03-12 11:36:07 +0800379 handler->handleConfigurations(configurations);
Gilbert Chen44524a52022-02-14 12:12:25 +0000380 handler->handleMctpEndpoints(mctpInfos);
381 }
382 }
383}
384
385void MctpDiscovery::handleRemovedMctpEndpoints(const MctpInfos& mctpInfos)
386{
387 for (const auto& handler : handlers)
388 {
389 if (handler)
390 {
391 handler->handleRemovedMctpEndpoints(mctpInfos);
392 }
Tom Josephfb3bc062021-08-17 07:48:11 -0700393 }
394}
395
Chau Ly75e00422024-03-19 12:33:08 +0000396void MctpDiscovery::updateMctpEndpointAvailability(const MctpInfo& mctpInfo,
397 Availability availability)
398{
399 for (const auto& handler : handlers)
400 {
401 if (handler)
402 {
403 handler->updateMctpEndpointAvailability(mctpInfo, availability);
404 }
405 }
406}
407
Unive Tienc40d4a62025-03-12 11:36:07 +0800408std::string MctpDiscovery::getNameFromProperties(
409 const utils::PropertyMap& properties)
410{
411 if (!properties.contains("Name"))
412 {
413 error("Missing name property");
414 return "";
415 }
416 return std::get<std::string>(properties.at("Name"));
417}
418
419std::string MctpDiscovery::constructMctpReactorObjectPath(
420 const MctpInfo& mctpInfo)
421{
422 const auto networkId = std::get<NetworkId>(mctpInfo);
423 const auto eid = std::get<pldm::eid>(mctpInfo);
424 return std::string{MCTPPath} + "/networks/" + std::to_string(networkId) +
425 "/endpoints/" + std::to_string(eid) + "/configured_by";
426}
427
428void MctpDiscovery::searchConfigurationFor(
429 const pldm::utils::DBusHandler& handler, MctpInfo& mctpInfo)
430{
431 const auto mctpReactorObjectPath = constructMctpReactorObjectPath(mctpInfo);
432 try
433 {
434 std::string associatedObjPath;
435 std::string associatedService;
436 std::string associatedInterface;
437 sdbusplus::message::object_path inventorySubtreePath(
438 inventorySubtreePathStr);
439
440 //"/{board or chassis type}/{board or chassis}/{device}"
441 auto constexpr subTreeDepth = 3;
442 auto response = handler.getAssociatedSubTree(
443 mctpReactorObjectPath, inventorySubtreePath, subTreeDepth,
444 interfaceFilter);
445 if (response.empty())
446 {
447 warning("No associated subtree found for path {PATH}", "PATH",
448 mctpReactorObjectPath);
449 return;
450 }
451 // Assume the first entry is the one we want
452 auto subTree = response.begin();
453 associatedObjPath = subTree->first;
454 auto associatedServiceProp = subTree->second;
455 if (associatedServiceProp.empty())
456 {
457 warning("No associated service found for path {PATH}", "PATH",
458 mctpReactorObjectPath);
459 return;
460 }
461 // Assume the first entry is the one we want
462 auto entry = associatedServiceProp.begin();
463 associatedService = entry->first;
464 auto dBusIntfList = entry->second;
465 auto associatedInterfaceItr = std::find_if(
466 dBusIntfList.begin(), dBusIntfList.end(), [](const auto& intf) {
467 return std::find(interfaceFilter.begin(), interfaceFilter.end(),
468 intf) != interfaceFilter.end();
469 });
470 if (associatedInterfaceItr == dBusIntfList.end())
471 {
472 error("No associated interface found for path {PATH}", "PATH",
473 mctpReactorObjectPath);
474 return;
475 }
476 associatedInterface = *associatedInterfaceItr;
477 auto mctpTargetProperties = handler.getDbusPropertiesVariant(
478 associatedService.c_str(), associatedObjPath.c_str(),
479 associatedInterface.c_str());
480 auto name = getNameFromProperties(mctpTargetProperties);
481 if (!name.empty())
482 {
483 std::get<std::optional<std::string>>(mctpInfo) = name;
484 }
485 configurations.emplace(associatedObjPath, mctpInfo);
486 }
487 catch (const std::exception& e)
488 {
489 error(
490 "Error getting associated subtree for path {PATH}, error - {ERROR}",
491 "PATH", mctpReactorObjectPath, "ERROR", e);
492 return;
493 }
494}
495
496void MctpDiscovery::removeConfigs(const MctpInfos& removedInfos)
497{
498 for (const auto& mctpInfo : removedInfos)
499 {
500 auto eidToRemove = std::get<eid>(mctpInfo);
501 std::erase_if(configurations, [eidToRemove](const auto& config) {
502 auto& [__, mctpInfo] = config;
503 auto eidValue = std::get<eid>(mctpInfo);
504 return eidValue == eidToRemove;
505 });
506 }
507}
508
Andrew Jeffery27a022c2022-08-10 23:12:49 +0930509} // namespace pldm