blob: db764bfe75c78ac3bf135a2dbe93116a1b41935f [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) :
Eric Yang70eca962025-05-11 01:48:15 +080029 bus(bus),
30 mctpEndpointAddedSignal(
31 bus, interfacesAdded(MCTPPath),
32 [this](sdbusplus::message_t& msg) { this->discoverEndpoints(msg); }),
Gilbert Chen44524a52022-02-14 12:12:25 +000033 mctpEndpointRemovedSignal(
34 bus, interfacesRemoved(MCTPPath),
Eric Yang70eca962025-05-11 01:48:15 +080035 [this](sdbusplus::message_t& msg) { this->removeEndpoints(msg); }),
Chau Ly75e00422024-03-19 12:33:08 +000036 mctpEndpointPropChangedSignal(
37 bus, propertiesChangedNamespace(MCTPPath, MCTPInterfaceCC),
Eric Yang70eca962025-05-11 01:48:15 +080038 [this](sdbusplus::message_t& msg) { this->propertiesChangedCb(msg); }),
Gilbert Chen44524a52022-02-14 12:12:25 +000039 handlers(list)
Tom Josephfb3bc062021-08-17 07:48:11 -070040{
Chau Ly75e00422024-03-19 12:33:08 +000041 std::map<MctpInfo, Availability> currentMctpInfoMap;
42 getMctpInfos(currentMctpInfoMap);
43 for (const auto& mapIt : currentMctpInfoMap)
44 {
45 if (mapIt.second)
46 {
47 // Only add the available endpoints to the terminus
48 // Let the propertiesChanged signal tells us when it comes back
49 // to Available again
50 addToExistingMctpInfos(MctpInfos(1, mapIt.first));
51 }
52 }
Gilbert Chen44524a52022-02-14 12:12:25 +000053 handleMctpEndpoints(existingMctpInfos);
54}
Tom Josephfb3bc062021-08-17 07:48:11 -070055
Chau Ly75e00422024-03-19 12:33:08 +000056void MctpDiscovery::getMctpInfos(std::map<MctpInfo, Availability>& mctpInfoMap)
Gilbert Chen44524a52022-02-14 12:12:25 +000057{
58 // Find all implementations of the MCTP Endpoint interface
59 pldm::utils::GetSubTreeResponse mapperResponse;
Tom Josephfb3bc062021-08-17 07:48:11 -070060 try
61 {
Gilbert Chen44524a52022-02-14 12:12:25 +000062 mapperResponse = pldm::utils::DBusHandler().getSubtree(
63 MCTPPath, 0, std::vector<std::string>({MCTPInterface}));
Tom Josephfb3bc062021-08-17 07:48:11 -070064 }
Gilbert Chen44524a52022-02-14 12:12:25 +000065 catch (const sdbusplus::exception_t& e)
Tom Josephfb3bc062021-08-17 07:48:11 -070066 {
Riya Dixit087a7512024-04-06 14:28:08 -050067 error(
68 "Failed to getSubtree call at path '{PATH}' and interface '{INTERFACE}', error - {ERROR} ",
69 "ERROR", e, "PATH", MCTPPath, "INTERFACE", MCTPInterface);
Tom Josephfb3bc062021-08-17 07:48:11 -070070 return;
71 }
72
Gilbert Chen44524a52022-02-14 12:12:25 +000073 for (const auto& [path, services] : mapperResponse)
Tom Josephfb3bc062021-08-17 07:48:11 -070074 {
Gilbert Chen44524a52022-02-14 12:12:25 +000075 for (const auto& serviceIter : services)
Tom Josephfb3bc062021-08-17 07:48:11 -070076 {
Gilbert Chen44524a52022-02-14 12:12:25 +000077 const std::string& service = serviceIter.first;
Thu Nguyen90274972024-07-17 07:02:16 +000078 const MctpEndpointProps& epProps =
79 getMctpEndpointProps(service, path);
80 const UUID& uuid = getEndpointUUIDProp(service, path);
Chau Ly75e00422024-03-19 12:33:08 +000081 const Availability& availability =
82 getEndpointConnectivityProp(path);
Thu Nguyen90274972024-07-17 07:02:16 +000083 auto types = std::get<MCTPMsgTypes>(epProps);
84 if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
85 types.end())
Tom Josephfb3bc062021-08-17 07:48:11 -070086 {
Unive Tienc40d4a62025-03-12 11:36:07 +080087 auto mctpInfo =
88 MctpInfo(std::get<eid>(epProps), uuid, "",
89 std::get<NetworkId>(epProps), std::nullopt);
90 searchConfigurationFor(pldm::utils::DBusHandler(), mctpInfo);
91 mctpInfoMap[std::move(mctpInfo)] = availability;
Gilbert Chen44524a52022-02-14 12:12:25 +000092 }
Tom Josephfb3bc062021-08-17 07:48:11 -070093 }
94 }
Tom Josephfb3bc062021-08-17 07:48:11 -070095}
96
Thu Nguyen90274972024-07-17 07:02:16 +000097MctpEndpointProps MctpDiscovery::getMctpEndpointProps(
98 const std::string& service, const std::string& path)
99{
100 try
101 {
102 auto properties = pldm::utils::DBusHandler().getDbusPropertiesVariant(
103 service.c_str(), path.c_str(), MCTPInterface);
104
105 if (properties.contains("NetworkId") && properties.contains("EID") &&
106 properties.contains("SupportedMessageTypes"))
107 {
108 auto networkId = std::get<NetworkId>(properties.at("NetworkId"));
109 auto eid = std::get<mctp_eid_t>(properties.at("EID"));
110 auto types = std::get<std::vector<uint8_t>>(
111 properties.at("SupportedMessageTypes"));
112 return MctpEndpointProps(networkId, eid, types);
113 }
114 }
115 catch (const sdbusplus::exception_t& e)
116 {
117 error(
118 "Error reading MCTP Endpoint property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
119 "SERVICE", service, "PATH", path, "ERROR", e);
120 return MctpEndpointProps(0, MCTP_ADDR_ANY, {});
121 }
122
123 return MctpEndpointProps(0, MCTP_ADDR_ANY, {});
124}
125
126UUID MctpDiscovery::getEndpointUUIDProp(const std::string& service,
127 const std::string& path)
128{
129 try
130 {
131 auto properties = pldm::utils::DBusHandler().getDbusPropertiesVariant(
132 service.c_str(), path.c_str(), EndpointUUID);
133
134 if (properties.contains("UUID"))
135 {
136 return std::get<UUID>(properties.at("UUID"));
137 }
138 }
139 catch (const sdbusplus::exception_t& e)
140 {
141 error(
142 "Error reading Endpoint UUID property at path '{PATH}' and service '{SERVICE}', error - {ERROR}",
143 "SERVICE", service, "PATH", path, "ERROR", e);
144 return static_cast<UUID>(emptyUUID);
145 }
146
147 return static_cast<UUID>(emptyUUID);
148}
149
Chau Ly75e00422024-03-19 12:33:08 +0000150Availability MctpDiscovery::getEndpointConnectivityProp(const std::string& path)
151{
152 Availability available = false;
153 try
154 {
155 pldm::utils::PropertyValue propertyValue =
156 pldm::utils::DBusHandler().getDbusPropertyVariant(
157 path.c_str(), MCTPConnectivityProp, MCTPInterfaceCC);
158 if (std::get<std::string>(propertyValue) == "Available")
159 {
160 available = true;
161 }
162 }
163 catch (const sdbusplus::exception_t& e)
164 {
165 error(
166 "Error reading Endpoint Connectivity property at path '{PATH}', error - {ERROR}",
167 "PATH", path, "ERROR", e);
168 }
169
170 return available;
171}
172
Gilbert Chen44524a52022-02-14 12:12:25 +0000173void MctpDiscovery::getAddedMctpInfos(sdbusplus::message_t& msg,
174 MctpInfos& mctpInfos)
Tom Josephfb3bc062021-08-17 07:48:11 -0700175{
Gilbert Chen44524a52022-02-14 12:12:25 +0000176 using ObjectPath = sdbusplus::message::object_path;
177 ObjectPath objPath;
178 using Property = std::string;
179 using PropertyMap = std::map<Property, dbus::Value>;
180 std::map<std::string, PropertyMap> interfaces;
Thu Nguyen90274972024-07-17 07:02:16 +0000181 std::string uuid = emptyUUID;
Tom Josephfb3bc062021-08-17 07:48:11 -0700182
Gilbert Chen44524a52022-02-14 12:12:25 +0000183 try
184 {
185 msg.read(objPath, interfaces);
186 }
187 catch (const sdbusplus::exception_t& e)
188 {
Riya Dixit087a7512024-04-06 14:28:08 -0500189 error(
190 "Error reading MCTP Endpoint added interface message, error - {ERROR}",
191 "ERROR", e);
Gilbert Chen44524a52022-02-14 12:12:25 +0000192 return;
193 }
Chau Ly75e00422024-03-19 12:33:08 +0000194 const Availability& availability = getEndpointConnectivityProp(objPath.str);
Tom Josephfb3bc062021-08-17 07:48:11 -0700195
Thu Nguyen90274972024-07-17 07:02:16 +0000196 /* Get UUID */
197 try
198 {
199 auto service = pldm::utils::DBusHandler().getService(
200 objPath.str.c_str(), EndpointUUID);
201 uuid = getEndpointUUIDProp(service, objPath.str);
202 }
203 catch (const sdbusplus::exception_t& e)
204 {
205 error("Error getting Endpoint UUID D-Bus interface, error - {ERROR}",
206 "ERROR", e);
207 }
208
Tom Josephfb3bc062021-08-17 07:48:11 -0700209 for (const auto& [intfName, properties] : interfaces)
210 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000211 if (intfName == MCTPInterface)
Tom Josephfb3bc062021-08-17 07:48:11 -0700212 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000213 if (properties.contains("NetworkId") &&
214 properties.contains("EID") &&
Tom Josephfb3bc062021-08-17 07:48:11 -0700215 properties.contains("SupportedMessageTypes"))
216 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000217 auto networkId =
218 std::get<NetworkId>(properties.at("NetworkId"));
Dung Cao66794d02023-10-25 04:06:23 +0000219 auto eid = std::get<mctp_eid_t>(properties.at("EID"));
Tom Josephfb3bc062021-08-17 07:48:11 -0700220 auto types = std::get<std::vector<uint8_t>>(
221 properties.at("SupportedMessageTypes"));
Chau Ly75e00422024-03-19 12:33:08 +0000222
223 if (!availability)
224 {
225 // Log an error message here, but still add it to the
226 // terminus
227 error(
228 "mctpd added a DEGRADED endpoint {EID} networkId {NET} to D-Bus",
229 "NET", networkId, "EID", static_cast<unsigned>(eid));
230 }
Tom Josephfb3bc062021-08-17 07:48:11 -0700231 if (std::find(types.begin(), types.end(), mctpTypePLDM) !=
232 types.end())
233 {
Riya Dixit087a7512024-04-06 14:28:08 -0500234 info(
Thu Nguyen90274972024-07-17 07:02:16 +0000235 "Adding Endpoint networkId '{NETWORK}' and EID '{EID}' UUID '{UUID}'",
236 "NETWORK", networkId, "EID", eid, "UUID", uuid);
Unive Tienc40d4a62025-03-12 11:36:07 +0800237 auto mctpInfo =
238 MctpInfo(eid, uuid, "", networkId, std::nullopt);
239 searchConfigurationFor(pldm::utils::DBusHandler(),
240 mctpInfo);
241 mctpInfos.emplace_back(std::move(mctpInfo));
Tom Josephfb3bc062021-08-17 07:48:11 -0700242 }
243 }
244 }
245 }
Gilbert Chen44524a52022-02-14 12:12:25 +0000246}
Tom Josephfb3bc062021-08-17 07:48:11 -0700247
Gilbert Chen44524a52022-02-14 12:12:25 +0000248void MctpDiscovery::addToExistingMctpInfos(const MctpInfos& addedInfos)
249{
250 for (const auto& mctpInfo : addedInfos)
Tom Josephfb3bc062021-08-17 07:48:11 -0700251 {
Gilbert Chen44524a52022-02-14 12:12:25 +0000252 if (std::find(existingMctpInfos.begin(), existingMctpInfos.end(),
253 mctpInfo) == existingMctpInfos.end())
254 {
255 existingMctpInfos.emplace_back(mctpInfo);
256 }
257 }
258}
259
260void MctpDiscovery::removeFromExistingMctpInfos(MctpInfos& mctpInfos,
261 MctpInfos& removedInfos)
262{
263 for (const auto& mctpInfo : existingMctpInfos)
264 {
265 if (std::find(mctpInfos.begin(), mctpInfos.end(), mctpInfo) ==
266 mctpInfos.end())
267 {
268 removedInfos.emplace_back(mctpInfo);
269 }
270 }
271 for (const auto& mctpInfo : removedInfos)
272 {
Riya Dixit087a7512024-04-06 14:28:08 -0500273 info("Removing Endpoint networkId '{NETWORK}' and EID '{EID}'",
Riya Dixit1e5c81e2024-05-03 07:54:00 -0500274 "NETWORK", std::get<3>(mctpInfo), "EID", std::get<0>(mctpInfo));
Gilbert Chen44524a52022-02-14 12:12:25 +0000275 existingMctpInfos.erase(std::remove(existingMctpInfos.begin(),
276 existingMctpInfos.end(), mctpInfo),
277 existingMctpInfos.end());
278 }
279}
280
Chau Ly75e00422024-03-19 12:33:08 +0000281void MctpDiscovery::propertiesChangedCb(sdbusplus::message_t& msg)
282{
283 using Interface = std::string;
284 using Property = std::string;
285 using Value = std::string;
286 using Properties = std::map<Property, std::variant<Value>>;
287
288 Interface interface;
289 Properties properties;
290 std::string objPath{};
291 std::string service{};
292
293 try
294 {
295 msg.read(interface, properties);
296 objPath = msg.get_path();
297 }
298 catch (const sdbusplus::exception_t& e)
299 {
300 error(
301 "Error handling Connectivity property changed message, error - {ERROR}",
302 "ERROR", e);
303 return;
304 }
305
306 for (const auto& [key, valueVariant] : properties)
307 {
308 Value propVal = std::get<std::string>(valueVariant);
309 auto availability = (propVal == "Available") ? true : false;
310
311 if (key == MCTPConnectivityProp)
312 {
313 service = pldm::utils::DBusHandler().getService(objPath.c_str(),
314 MCTPInterface);
315 const MctpEndpointProps& epProps =
316 getMctpEndpointProps(service, objPath);
317
318 auto types = std::get<MCTPMsgTypes>(epProps);
319 if (!std::ranges::contains(types, mctpTypePLDM))
320 {
321 return;
322 }
323 const UUID& uuid = getEndpointUUIDProp(service, objPath);
324
325 MctpInfo mctpInfo(std::get<eid>(epProps), uuid, "",
Unive Tienc40d4a62025-03-12 11:36:07 +0800326 std::get<NetworkId>(epProps), std::nullopt);
327 searchConfigurationFor(pldm::utils::DBusHandler(), mctpInfo);
Chau Ly75e00422024-03-19 12:33:08 +0000328 if (!std::ranges::contains(existingMctpInfos, mctpInfo))
329 {
330 if (availability)
331 {
332 // The endpoint not in existingMctpInfos and is
333 // available Add it to existingMctpInfos
334 info(
335 "Adding Endpoint networkId {NETWORK} ID {EID} by propertiesChanged signal",
336 "NETWORK", std::get<3>(mctpInfo), "EID",
337 unsigned(std::get<0>(mctpInfo)));
338 addToExistingMctpInfos(MctpInfos(1, mctpInfo));
339 handleMctpEndpoints(MctpInfos(1, mctpInfo));
340 }
341 }
342 else
343 {
344 // The endpoint already in existingMctpInfos
345 updateMctpEndpointAvailability(mctpInfo, availability);
346 }
347 }
348 }
349}
350
Gilbert Chen44524a52022-02-14 12:12:25 +0000351void MctpDiscovery::discoverEndpoints(sdbusplus::message_t& msg)
352{
353 MctpInfos addedInfos;
354 getAddedMctpInfos(msg, addedInfos);
355 addToExistingMctpInfos(addedInfos);
356 handleMctpEndpoints(addedInfos);
357}
358
359void MctpDiscovery::removeEndpoints(sdbusplus::message_t&)
360{
361 MctpInfos mctpInfos;
362 MctpInfos removedInfos;
Chau Ly75e00422024-03-19 12:33:08 +0000363 std::map<MctpInfo, Availability> currentMctpInfoMap;
364 getMctpInfos(currentMctpInfoMap);
365 for (const auto& mapIt : currentMctpInfoMap)
366 {
367 mctpInfos.push_back(mapIt.first);
368 }
Gilbert Chen44524a52022-02-14 12:12:25 +0000369 removeFromExistingMctpInfos(mctpInfos, removedInfos);
370 handleRemovedMctpEndpoints(removedInfos);
Unive Tienc40d4a62025-03-12 11:36:07 +0800371 removeConfigs(removedInfos);
Gilbert Chen44524a52022-02-14 12:12:25 +0000372}
373
374void MctpDiscovery::handleMctpEndpoints(const MctpInfos& mctpInfos)
375{
376 for (const auto& handler : handlers)
377 {
378 if (handler)
379 {
Unive Tienc40d4a62025-03-12 11:36:07 +0800380 handler->handleConfigurations(configurations);
Gilbert Chen44524a52022-02-14 12:12:25 +0000381 handler->handleMctpEndpoints(mctpInfos);
382 }
383 }
384}
385
386void MctpDiscovery::handleRemovedMctpEndpoints(const MctpInfos& mctpInfos)
387{
388 for (const auto& handler : handlers)
389 {
390 if (handler)
391 {
392 handler->handleRemovedMctpEndpoints(mctpInfos);
393 }
Tom Josephfb3bc062021-08-17 07:48:11 -0700394 }
395}
396
Chau Ly75e00422024-03-19 12:33:08 +0000397void MctpDiscovery::updateMctpEndpointAvailability(const MctpInfo& mctpInfo,
398 Availability availability)
399{
400 for (const auto& handler : handlers)
401 {
402 if (handler)
403 {
404 handler->updateMctpEndpointAvailability(mctpInfo, availability);
405 }
406 }
407}
408
Unive Tienc40d4a62025-03-12 11:36:07 +0800409std::string MctpDiscovery::getNameFromProperties(
410 const utils::PropertyMap& properties)
411{
412 if (!properties.contains("Name"))
413 {
414 error("Missing name property");
415 return "";
416 }
417 return std::get<std::string>(properties.at("Name"));
418}
419
420std::string MctpDiscovery::constructMctpReactorObjectPath(
421 const MctpInfo& mctpInfo)
422{
423 const auto networkId = std::get<NetworkId>(mctpInfo);
424 const auto eid = std::get<pldm::eid>(mctpInfo);
425 return std::string{MCTPPath} + "/networks/" + std::to_string(networkId) +
426 "/endpoints/" + std::to_string(eid) + "/configured_by";
427}
428
429void MctpDiscovery::searchConfigurationFor(
430 const pldm::utils::DBusHandler& handler, MctpInfo& mctpInfo)
431{
432 const auto mctpReactorObjectPath = constructMctpReactorObjectPath(mctpInfo);
433 try
434 {
435 std::string associatedObjPath;
436 std::string associatedService;
437 std::string associatedInterface;
438 sdbusplus::message::object_path inventorySubtreePath(
439 inventorySubtreePathStr);
440
441 //"/{board or chassis type}/{board or chassis}/{device}"
442 auto constexpr subTreeDepth = 3;
443 auto response = handler.getAssociatedSubTree(
444 mctpReactorObjectPath, inventorySubtreePath, subTreeDepth,
445 interfaceFilter);
446 if (response.empty())
447 {
448 warning("No associated subtree found for path {PATH}", "PATH",
449 mctpReactorObjectPath);
450 return;
451 }
452 // Assume the first entry is the one we want
453 auto subTree = response.begin();
454 associatedObjPath = subTree->first;
455 auto associatedServiceProp = subTree->second;
456 if (associatedServiceProp.empty())
457 {
458 warning("No associated service found for path {PATH}", "PATH",
459 mctpReactorObjectPath);
460 return;
461 }
462 // Assume the first entry is the one we want
463 auto entry = associatedServiceProp.begin();
464 associatedService = entry->first;
465 auto dBusIntfList = entry->second;
466 auto associatedInterfaceItr = std::find_if(
467 dBusIntfList.begin(), dBusIntfList.end(), [](const auto& intf) {
468 return std::find(interfaceFilter.begin(), interfaceFilter.end(),
469 intf) != interfaceFilter.end();
470 });
471 if (associatedInterfaceItr == dBusIntfList.end())
472 {
473 error("No associated interface found for path {PATH}", "PATH",
474 mctpReactorObjectPath);
475 return;
476 }
477 associatedInterface = *associatedInterfaceItr;
478 auto mctpTargetProperties = handler.getDbusPropertiesVariant(
479 associatedService.c_str(), associatedObjPath.c_str(),
480 associatedInterface.c_str());
481 auto name = getNameFromProperties(mctpTargetProperties);
482 if (!name.empty())
483 {
484 std::get<std::optional<std::string>>(mctpInfo) = name;
485 }
486 configurations.emplace(associatedObjPath, mctpInfo);
487 }
488 catch (const std::exception& e)
489 {
490 error(
491 "Error getting associated subtree for path {PATH}, error - {ERROR}",
492 "PATH", mctpReactorObjectPath, "ERROR", e);
493 return;
494 }
495}
496
497void MctpDiscovery::removeConfigs(const MctpInfos& removedInfos)
498{
499 for (const auto& mctpInfo : removedInfos)
500 {
501 auto eidToRemove = std::get<eid>(mctpInfo);
502 std::erase_if(configurations, [eidToRemove](const auto& config) {
503 auto& [__, mctpInfo] = config;
504 auto eidValue = std::get<eid>(mctpInfo);
505 return eidValue == eidToRemove;
506 });
507 }
508}
509
Andrew Jeffery27a022c2022-08-10 23:12:49 +0930510} // namespace pldm