blob: 1899826e279967a7ddae2028fce8a7411bc8b377 [file] [log] [blame]
Andrew Geisslera80a3af2019-02-04 14:01:49 -06001#include "associations.hpp"
2
Kallas, Pawel5b4357d2022-10-12 15:36:37 +02003#include <boost/asio/steady_timer.hpp>
Lei YUb89c6612021-07-22 15:59:52 +08004#include <sdbusplus/exception.hpp>
Andrew Geissler4511b332019-02-21 15:40:40 -06005
Brad Bishop23520882022-05-26 21:39:53 -04006#include <iostream>
Brad Bishop86d28802022-07-11 15:49:31 -04007#include <string>
Brad Bishop23520882022-05-26 21:39:53 -04008
Kallas, Pawel5b4357d2022-10-12 15:36:37 +02009void updateEndpointsOnDbus(sdbusplus::asio::object_server& objectServer,
10 const std::string& assocPath,
11 AssociationMaps& assocMaps)
12{
13 auto& iface = assocMaps.ifaces[assocPath];
14 auto& i = std::get<ifacePos>(iface);
15 auto& endpoints = std::get<endpointsPos>(iface);
16
17 // If the interface already exists, only need to update
18 // the property value, otherwise create it
19 if (i)
20 {
21 if (endpoints.empty())
22 {
23 objectServer.remove_interface(i);
24 i = nullptr;
25 }
26 else
27 {
28 i->set_property("endpoints", endpoints);
29 }
30 }
31 else
32 {
33 if (!endpoints.empty())
34 {
35 i = objectServer.add_interface(assocPath, xyzAssociationInterface);
36 i->register_property("endpoints", endpoints);
37 i->initialize();
38 }
39 }
40}
41
Patrick Williams9052ebd2024-08-16 15:22:16 -040042void scheduleUpdateEndpointsOnDbus(
43 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
44 const std::string& assocPath, AssociationMaps& assocMaps)
Kallas, Pawel5b4357d2022-10-12 15:36:37 +020045{
46 static std::set<std::string> delayedUpdatePaths;
47
48 if (delayedUpdatePaths.contains(assocPath))
49 {
50 return;
51 }
52
53 auto& iface = assocMaps.ifaces[assocPath];
54 auto& endpoints = std::get<endpointsPos>(iface);
55
56 if (endpoints.size() > endpointsCountTimerThreshold)
57 {
58 delayedUpdatePaths.emplace(assocPath);
59 auto timer = std::make_shared<boost::asio::steady_timer>(
60 io, std::chrono::seconds(endpointUpdateDelaySeconds));
61 timer->async_wait([&objectServer, &assocMaps, timer,
62 assocPath](const boost::system::error_code& ec) {
63 if (!ec)
64 {
65 updateEndpointsOnDbus(objectServer, assocPath, assocMaps);
66 }
67 delayedUpdatePaths.erase(assocPath);
68 });
69 }
70 else
71 {
72 updateEndpointsOnDbus(objectServer, assocPath, assocMaps);
73 }
74}
75
76void removeAssociation(boost::asio::io_context& io,
77 const std::string& sourcePath, const std::string& owner,
Andrew Geisslera80a3af2019-02-04 14:01:49 -060078 sdbusplus::asio::object_server& server,
Matt Spinlere2359fb2019-04-05 14:11:33 -050079 AssociationMaps& assocMaps)
Andrew Geisslera80a3af2019-02-04 14:01:49 -060080{
81 // Use associationOwners to find the association paths and endpoints
82 // that the passed in object path and service own. Remove all of
83 // these endpoints from the actual association D-Bus objects, and if
84 // the endpoints property is then empty, the whole association object
85 // can be removed. Note there can be multiple services that own an
86 // association, and also that sourcePath is the path of the object
87 // that contains the org.openbmc.Associations interface and not the
88 // association path itself.
89
90 // Find the services that have associations for this object path
Matt Spinlere2359fb2019-04-05 14:11:33 -050091 auto owners = assocMaps.owners.find(sourcePath);
92 if (owners == assocMaps.owners.end())
Andrew Geisslera80a3af2019-02-04 14:01:49 -060093 {
94 return;
95 }
96
97 // Find the association paths and endpoints owned by this object
98 // path for this service.
99 auto assocs = owners->second.find(owner);
100 if (assocs == owners->second.end())
101 {
102 return;
103 }
104
105 for (const auto& [assocPath, endpointsToRemove] : assocs->second)
106 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200107 removeAssociationEndpoints(io, server, assocPath, endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500108 assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600109 }
110
111 // Remove the associationOwners entries for this owning path/service.
112 owners->second.erase(assocs);
113 if (owners->second.empty())
114 {
Matt Spinlere2359fb2019-04-05 14:11:33 -0500115 assocMaps.owners.erase(owners);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600116 }
Matt Spinlercb9bcdb2019-04-08 10:58:49 -0500117
118 // If we were still waiting on the other side of this association to
119 // show up, cancel that wait.
120 removeFromPendingAssociations(sourcePath, assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600121}
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600122
123void removeAssociationEndpoints(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200124 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
125 const std::string& assocPath,
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600126 const boost::container::flat_set<std::string>& endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500127 AssociationMaps& assocMaps)
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600128{
Matt Spinlere2359fb2019-04-05 14:11:33 -0500129 auto assoc = assocMaps.ifaces.find(assocPath);
130 if (assoc == assocMaps.ifaces.end())
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600131 {
132 return;
133 }
134
135 auto& endpointsInDBus = std::get<endpointsPos>(assoc->second);
136
137 for (const auto& endpointToRemove : endpointsToRemove)
138 {
139 auto e = std::find(endpointsInDBus.begin(), endpointsInDBus.end(),
140 endpointToRemove);
141
142 if (e != endpointsInDBus.end())
143 {
144 endpointsInDBus.erase(e);
145 }
146 }
147
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200148 scheduleUpdateEndpointsOnDbus(io, objectServer, assocPath, assocMaps);
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600149}
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600150
151void checkAssociationEndpointRemoves(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200152 boost::asio::io_context& io, const std::string& sourcePath,
153 const std::string& owner, const AssociationPaths& newAssociations,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500154 sdbusplus::asio::object_server& objectServer, AssociationMaps& assocMaps)
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600155{
156 // Find the services that have associations on this path.
Matt Spinlere2359fb2019-04-05 14:11:33 -0500157 auto originalOwners = assocMaps.owners.find(sourcePath);
158 if (originalOwners == assocMaps.owners.end())
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600159 {
160 return;
161 }
162
163 // Find the associations for this service
164 auto originalAssociations = originalOwners->second.find(owner);
165 if (originalAssociations == originalOwners->second.end())
166 {
167 return;
168 }
169
170 // Compare the new endpoints versus the original endpoints, and
171 // remove any of the original ones that aren't in the new list.
172 for (const auto& [originalAssocPath, originalEndpoints] :
173 originalAssociations->second)
174 {
175 // Check if this source even still has each association that
176 // was there previously, and if not, remove all of its endpoints
177 // from the D-Bus endpoints property which will cause the whole
178 // association path to be removed if no endpoints remain.
179 auto newEndpoints = newAssociations.find(originalAssocPath);
180 if (newEndpoints == newAssociations.end())
181 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200182 removeAssociationEndpoints(io, objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500183 originalEndpoints, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600184 }
185 else
186 {
187 // The association is still there. Check if the endpoints
188 // changed.
189 boost::container::flat_set<std::string> toRemove;
190
Brad Bishop1f623802022-05-31 18:22:10 -0400191 for (const auto& originalEndpoint : originalEndpoints)
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600192 {
193 if (std::find(newEndpoints->second.begin(),
Patrick Williams9052ebd2024-08-16 15:22:16 -0400194 newEndpoints->second.end(), originalEndpoint) ==
195 newEndpoints->second.end())
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600196 {
197 toRemove.emplace(originalEndpoint);
198 }
199 }
200 if (!toRemove.empty())
201 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200202 removeAssociationEndpoints(io, objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500203 toRemove, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600204 }
205 }
206 }
207}
Andrew Geissler4511b332019-02-21 15:40:40 -0600208
Matt Spinler11401e22019-04-08 13:13:25 -0500209void addEndpointsToAssocIfaces(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200210 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
211 const std::string& assocPath,
Matt Spinler11401e22019-04-08 13:13:25 -0500212 const boost::container::flat_set<std::string>& endpointPaths,
213 AssociationMaps& assocMaps)
214{
215 auto& iface = assocMaps.ifaces[assocPath];
Matt Spinler11401e22019-04-08 13:13:25 -0500216 auto& endpoints = std::get<endpointsPos>(iface);
217
218 // Only add new endpoints
Brad Bishop1f623802022-05-31 18:22:10 -0400219 for (const auto& e : endpointPaths)
Matt Spinler11401e22019-04-08 13:13:25 -0500220 {
221 if (std::find(endpoints.begin(), endpoints.end(), e) == endpoints.end())
222 {
223 endpoints.push_back(e);
224 }
225 }
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200226 scheduleUpdateEndpointsOnDbus(io, objectServer, assocPath, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500227}
228
Patrick Williams9052ebd2024-08-16 15:22:16 -0400229void associationChanged(
230 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
231 const std::vector<Association>& associations, const std::string& path,
232 const std::string& owner, const InterfaceMapType& interfaceMap,
233 AssociationMaps& assocMaps)
Andrew Geissler4511b332019-02-21 15:40:40 -0600234{
235 AssociationPaths objects;
236
237 for (const Association& association : associations)
238 {
239 std::string forward;
240 std::string reverse;
Brad Bishop1f623802022-05-31 18:22:10 -0400241 std::string objectPath;
242 std::tie(forward, reverse, objectPath) = association;
Andrew Geissler4511b332019-02-21 15:40:40 -0600243
Brad Bishop1f623802022-05-31 18:22:10 -0400244 if (objectPath.empty())
Andrew Geissler0a560a52019-03-22 10:59:07 -0500245 {
246 std::cerr << "Found invalid association on path " << path << "\n";
247 continue;
248 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500249
250 // Can't create this association if the endpoint isn't on D-Bus.
Brad Bishop1f623802022-05-31 18:22:10 -0400251 if (interfaceMap.find(objectPath) == interfaceMap.end())
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500252 {
Brad Bishop1f623802022-05-31 18:22:10 -0400253 addPendingAssociation(objectPath, reverse, path, forward, owner,
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500254 assocMaps);
255 continue;
256 }
257
Brad Bishop1f623802022-05-31 18:22:10 -0400258 if (!forward.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600259 {
Brad Bishop1f623802022-05-31 18:22:10 -0400260 objects[path + "/" + forward].emplace(objectPath);
Andrew Geissler4511b332019-02-21 15:40:40 -0600261 }
Brad Bishop1f623802022-05-31 18:22:10 -0400262 if (!reverse.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600263 {
Brad Bishop1f623802022-05-31 18:22:10 -0400264 objects[objectPath + "/" + reverse].emplace(path);
Andrew Geissler4511b332019-02-21 15:40:40 -0600265 }
266 }
267 for (const auto& object : objects)
268 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200269 addEndpointsToAssocIfaces(io, objectServer, object.first, object.second,
Matt Spinler11401e22019-04-08 13:13:25 -0500270 assocMaps);
Andrew Geissler4511b332019-02-21 15:40:40 -0600271 }
272
273 // Check for endpoints being removed instead of added
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200274 checkAssociationEndpointRemoves(io, path, owner, objects, objectServer,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500275 assocMaps);
Andrew Geissler4511b332019-02-21 15:40:40 -0600276
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500277 if (!objects.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600278 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500279 // Update associationOwners with the latest info
280 auto a = assocMaps.owners.find(path);
281 if (a != assocMaps.owners.end())
Andrew Geissler4511b332019-02-21 15:40:40 -0600282 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500283 auto o = a->second.find(owner);
284 if (o != a->second.end())
285 {
286 o->second = std::move(objects);
287 }
288 else
289 {
290 a->second.emplace(owner, std::move(objects));
291 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600292 }
293 else
294 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500295 boost::container::flat_map<std::string, AssociationPaths> owners;
296 owners.emplace(owner, std::move(objects));
297 assocMaps.owners.emplace(path, owners);
Andrew Geissler4511b332019-02-21 15:40:40 -0600298 }
299 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500300}
301
Patrick Williams9052ebd2024-08-16 15:22:16 -0400302void addPendingAssociation(
303 const std::string& objectPath, const std::string& type,
304 const std::string& endpointPath, const std::string& endpointType,
305 const std::string& owner, AssociationMaps& assocMaps)
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500306{
307 Association assoc{type, endpointType, endpointPath};
308
309 auto p = assocMaps.pending.find(objectPath);
310 if (p == assocMaps.pending.end())
311 {
312 ExistingEndpoints ee;
313 ee.emplace_back(owner, std::move(assoc));
314 assocMaps.pending.emplace(objectPath, std::move(ee));
315 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600316 else
317 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500318 // Already waiting on this path for another association,
319 // so just add this endpoint and owner.
320 auto& endpoints = p->second;
Patrick Williams9052ebd2024-08-16 15:22:16 -0400321 auto e =
322 std::find_if(endpoints.begin(), endpoints.end(),
323 [&assoc, &owner](const auto& endpoint) {
324 return (std::get<ownerPos>(endpoint) == owner) &&
325 (std::get<assocPos>(endpoint) == assoc);
326 });
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500327 if (e == endpoints.end())
328 {
329 endpoints.emplace_back(owner, std::move(assoc));
330 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600331 }
332}
Matt Spinlercb9bcdb2019-04-08 10:58:49 -0500333
334void removeFromPendingAssociations(const std::string& endpointPath,
335 AssociationMaps& assocMaps)
336{
337 auto assoc = assocMaps.pending.begin();
338 while (assoc != assocMaps.pending.end())
339 {
340 auto endpoint = assoc->second.begin();
341 while (endpoint != assoc->second.end())
342 {
343 auto& e = std::get<assocPos>(*endpoint);
344 if (std::get<reversePathPos>(e) == endpointPath)
345 {
346 endpoint = assoc->second.erase(endpoint);
347 continue;
348 }
349
350 endpoint++;
351 }
352
353 if (assoc->second.empty())
354 {
355 assoc = assocMaps.pending.erase(assoc);
356 continue;
357 }
358
359 assoc++;
360 }
361}
Matt Spinler11401e22019-04-08 13:13:25 -0500362
Patrick Williams9052ebd2024-08-16 15:22:16 -0400363void addSingleAssociation(
364 boost::asio::io_context& io, sdbusplus::asio::object_server& server,
365 const std::string& assocPath, const std::string& endpoint,
366 const std::string& owner, const std::string& ownerPath,
367 AssociationMaps& assocMaps)
Matt Spinler11401e22019-04-08 13:13:25 -0500368{
369 boost::container::flat_set<std::string> endpoints{endpoint};
370
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200371 addEndpointsToAssocIfaces(io, server, assocPath, endpoints, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500372
373 AssociationPaths objects;
374 boost::container::flat_set e{endpoint};
375 objects.emplace(assocPath, e);
376
377 auto a = assocMaps.owners.find(ownerPath);
378 if (a != assocMaps.owners.end())
379 {
380 auto o = a->second.find(owner);
381 if (o != a->second.end())
382 {
383 auto p = o->second.find(assocPath);
384 if (p != o->second.end())
385 {
386 p->second.emplace(endpoint);
387 }
388 else
389 {
390 o->second.emplace(assocPath, e);
391 }
392 }
393 else
394 {
395 a->second.emplace(owner, std::move(objects));
396 }
397 }
398 else
399 {
400 boost::container::flat_map<std::string, AssociationPaths> owners;
401 owners.emplace(owner, std::move(objects));
402 assocMaps.owners.emplace(endpoint, owners);
403 }
404}
405
Patrick Williams9052ebd2024-08-16 15:22:16 -0400406void checkIfPendingAssociation(
407 boost::asio::io_context& io, const std::string& objectPath,
408 const InterfaceMapType& interfaceMap, AssociationMaps& assocMaps,
409 sdbusplus::asio::object_server& server)
Matt Spinler11401e22019-04-08 13:13:25 -0500410{
411 auto pending = assocMaps.pending.find(objectPath);
412 if (pending == assocMaps.pending.end())
413 {
414 return;
415 }
416
417 if (interfaceMap.find(objectPath) == interfaceMap.end())
418 {
419 return;
420 }
421
422 auto endpoint = pending->second.begin();
423
424 while (endpoint != pending->second.end())
425 {
426 const auto& e = std::get<assocPos>(*endpoint);
427
428 // Ensure the other side of the association still exists
429 if (interfaceMap.find(std::get<reversePathPos>(e)) ==
430 interfaceMap.end())
431 {
432 endpoint++;
433 continue;
434 }
435
436 // Add both sides of the association:
437 // objectPath/forwardType and reversePath/reverseType
438 //
439 // The ownerPath is the reversePath - i.e. the endpoint that
440 // is on D-Bus and owns the org.openbmc.Associations iface.
441 //
442 const auto& ownerPath = std::get<reversePathPos>(e);
443 const auto& owner = std::get<ownerPos>(*endpoint);
444
445 auto assocPath = objectPath + '/' + std::get<forwardTypePos>(e);
446 auto endpointPath = ownerPath;
447
Lei YUb89c6612021-07-22 15:59:52 +0800448 try
449 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200450 addSingleAssociation(io, server, assocPath, endpointPath, owner,
Lei YUb89c6612021-07-22 15:59:52 +0800451 ownerPath, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500452
Lei YUb89c6612021-07-22 15:59:52 +0800453 // Now the reverse direction (still the same owner and ownerPath)
454 assocPath = endpointPath + '/' + std::get<reverseTypePos>(e);
455 endpointPath = objectPath;
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200456 addSingleAssociation(io, server, assocPath, endpointPath, owner,
Lei YUb89c6612021-07-22 15:59:52 +0800457 ownerPath, assocMaps);
458 }
Patrick Williamscc8070b2022-07-22 19:26:55 -0500459 catch (const sdbusplus::exception_t& e)
Lei YUb89c6612021-07-22 15:59:52 +0800460 {
461 // In some case the interface could not be created on DBus and an
462 // exception is thrown. mapper has no control of the interface/path
463 // of the associations, so it has to catch the error and drop the
464 // association request.
Brad Bishop1f623802022-05-31 18:22:10 -0400465 std::cerr << "Error adding association: assocPath " << assocPath
466 << ", endpointPath " << endpointPath
467 << ", what: " << e.what() << "\n";
Lei YUb89c6612021-07-22 15:59:52 +0800468 }
Matt Spinler11401e22019-04-08 13:13:25 -0500469
470 // Not pending anymore
471 endpoint = pending->second.erase(endpoint);
472 }
473
474 if (pending->second.empty())
475 {
476 assocMaps.pending.erase(objectPath);
477 }
478}
Matt Spinler7f8fd1f2019-04-08 15:21:59 -0500479
480void findAssociations(const std::string& endpointPath,
481 AssociationMaps& assocMaps,
482 FindAssocResults& associationData)
483{
484 for (const auto& [sourcePath, owners] : assocMaps.owners)
485 {
486 for (const auto& [owner, assocs] : owners)
487 {
488 for (const auto& [assocPath, endpoints] : assocs)
489 {
490 if (std::find(endpoints.begin(), endpoints.end(),
491 endpointPath) != endpoints.end())
492 {
493 // assocPath is <path>/<type> which tells us what is on the
494 // other side of the association.
495 auto pos = assocPath.rfind('/');
496 auto otherPath = assocPath.substr(0, pos);
497 auto otherType = assocPath.substr(pos + 1);
498
499 // Now we need to find the endpointPath/<type> ->
500 // [otherPath] entry so that we can get the type for
501 // endpointPath's side of the assoc. Do this by finding
502 // otherPath as an endpoint, and also checking for
503 // 'endpointPath/*' as the key.
504 auto a = std::find_if(
505 assocs.begin(), assocs.end(),
506 [&endpointPath, &otherPath](const auto& ap) {
Patrick Williams9052ebd2024-08-16 15:22:16 -0400507 const auto& endpoints = ap.second;
508 auto endpoint = std::find(
509 endpoints.begin(), endpoints.end(), otherPath);
510 if (endpoint != endpoints.end())
511 {
512 return ap.first.starts_with(endpointPath + '/');
513 }
514 return false;
515 });
Matt Spinler7f8fd1f2019-04-08 15:21:59 -0500516
517 if (a != assocs.end())
518 {
519 // Pull out the type from endpointPath/<type>
520 pos = a->first.rfind('/');
521 auto thisType = a->first.substr(pos + 1);
522
523 // Now we know the full association:
524 // endpointPath/thisType -> otherPath/otherType
525 Association association{thisType, otherType, otherPath};
526 associationData.emplace_back(owner, association);
527 }
528 }
529 }
530 }
531 }
532}
Matt Spinler9c3d2852019-04-08 15:57:19 -0500533
534/** @brief Remove an endpoint for a particular association from D-Bus.
535 *
536 * If the last endpoint is gone, remove the whole association interface,
537 * otherwise just update the D-Bus endpoints property.
538 *
539 * @param[in] assocPath - the association path
540 * @param[in] endpointPath - the endpoint path to find and remove
541 * @param[in,out] assocMaps - the association maps
542 * @param[in,out] server - sdbus system object
543 */
Patrick Williams9052ebd2024-08-16 15:22:16 -0400544void removeAssociationIfacesEntry(
545 boost::asio::io_context& io, const std::string& assocPath,
546 const std::string& endpointPath, AssociationMaps& assocMaps,
547 sdbusplus::asio::object_server& server)
Matt Spinler9c3d2852019-04-08 15:57:19 -0500548{
549 auto assoc = assocMaps.ifaces.find(assocPath);
550 if (assoc != assocMaps.ifaces.end())
551 {
552 auto& endpoints = std::get<endpointsPos>(assoc->second);
553 auto e = std::find(endpoints.begin(), endpoints.end(), endpointPath);
554 if (e != endpoints.end())
555 {
556 endpoints.erase(e);
557
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200558 scheduleUpdateEndpointsOnDbus(io, server, assocPath, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500559 }
560 }
561}
562
563/** @brief Remove an endpoint from the association owners map.
564 *
565 * For a specific association path and owner, remove the endpoint.
566 * Remove all remaining artifacts of that endpoint in the owners map
567 * based on what frees up after the erase.
568 *
569 * @param[in] assocPath - the association object path
570 * @param[in] endpointPath - the endpoint object path
571 * @param[in] owner - the owner of the association
572 * @param[in,out] assocMaps - the association maps
Matt Spinler9c3d2852019-04-08 15:57:19 -0500573 */
Patrick Williams9052ebd2024-08-16 15:22:16 -0400574void removeAssociationOwnersEntry(
575 const std::string& assocPath, const std::string& endpointPath,
576 const std::string& owner, AssociationMaps& assocMaps)
Matt Spinler9c3d2852019-04-08 15:57:19 -0500577{
578 auto sources = assocMaps.owners.begin();
579 while (sources != assocMaps.owners.end())
580 {
581 auto owners = sources->second.find(owner);
582 if (owners != sources->second.end())
583 {
584 auto entry = owners->second.find(assocPath);
585 if (entry != owners->second.end())
586 {
587 auto e = std::find(entry->second.begin(), entry->second.end(),
588 endpointPath);
589 if (e != entry->second.end())
590 {
591 entry->second.erase(e);
592 if (entry->second.empty())
593 {
594 owners->second.erase(entry);
595 }
596 }
597 }
598
599 if (owners->second.empty())
600 {
601 sources->second.erase(owners);
602 }
603 }
604
605 if (sources->second.empty())
606 {
607 sources = assocMaps.owners.erase(sources);
608 continue;
609 }
610 sources++;
611 }
612}
613
Patrick Williams9052ebd2024-08-16 15:22:16 -0400614void moveAssociationToPending(
615 boost::asio::io_context& io, const std::string& endpointPath,
616 AssociationMaps& assocMaps, sdbusplus::asio::object_server& server)
Matt Spinler9c3d2852019-04-08 15:57:19 -0500617{
618 FindAssocResults associationData;
619
620 // Check which associations this path is an endpoint of, and
621 // then add them to the pending associations map and remove
622 // the associations objects.
623 findAssociations(endpointPath, assocMaps, associationData);
624
625 for (const auto& [owner, association] : associationData)
626 {
627 const auto& forwardPath = endpointPath;
628 const auto& forwardType = std::get<forwardTypePos>(association);
629 const auto& reversePath = std::get<reversePathPos>(association);
630 const auto& reverseType = std::get<reverseTypePos>(association);
631
632 addPendingAssociation(forwardPath, forwardType, reversePath,
633 reverseType, owner, assocMaps);
634
635 // Remove both sides of the association from assocMaps.ifaces
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200636 removeAssociationIfacesEntry(io, forwardPath + '/' + forwardType,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500637 reversePath, assocMaps, server);
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200638 removeAssociationIfacesEntry(io, reversePath + '/' + reverseType,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500639 forwardPath, assocMaps, server);
640
641 // Remove both sides of the association from assocMaps.owners
642 removeAssociationOwnersEntry(forwardPath + '/' + forwardType,
Brad Bishopa6646902022-06-02 19:05:34 -0400643 reversePath, owner, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500644 removeAssociationOwnersEntry(reversePath + '/' + reverseType,
Brad Bishopa6646902022-06-02 19:05:34 -0400645 forwardPath, owner, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500646 }
647}