blob: 6042d4d69a6f914a9a062998e49375d110ec0139 [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
42void scheduleUpdateEndpointsOnDbus(boost::asio::io_context& io,
43 sdbusplus::asio::object_server& objectServer,
44 const std::string& assocPath,
45 AssociationMaps& assocMaps)
46{
47 static std::set<std::string> delayedUpdatePaths;
48
49 if (delayedUpdatePaths.contains(assocPath))
50 {
51 return;
52 }
53
54 auto& iface = assocMaps.ifaces[assocPath];
55 auto& endpoints = std::get<endpointsPos>(iface);
56
57 if (endpoints.size() > endpointsCountTimerThreshold)
58 {
59 delayedUpdatePaths.emplace(assocPath);
60 auto timer = std::make_shared<boost::asio::steady_timer>(
61 io, std::chrono::seconds(endpointUpdateDelaySeconds));
62 timer->async_wait([&objectServer, &assocMaps, timer,
63 assocPath](const boost::system::error_code& ec) {
64 if (!ec)
65 {
66 updateEndpointsOnDbus(objectServer, assocPath, assocMaps);
67 }
68 delayedUpdatePaths.erase(assocPath);
69 });
70 }
71 else
72 {
73 updateEndpointsOnDbus(objectServer, assocPath, assocMaps);
74 }
75}
76
77void removeAssociation(boost::asio::io_context& io,
78 const std::string& sourcePath, const std::string& owner,
Andrew Geisslera80a3af2019-02-04 14:01:49 -060079 sdbusplus::asio::object_server& server,
Matt Spinlere2359fb2019-04-05 14:11:33 -050080 AssociationMaps& assocMaps)
Andrew Geisslera80a3af2019-02-04 14:01:49 -060081{
82 // Use associationOwners to find the association paths and endpoints
83 // that the passed in object path and service own. Remove all of
84 // these endpoints from the actual association D-Bus objects, and if
85 // the endpoints property is then empty, the whole association object
86 // can be removed. Note there can be multiple services that own an
87 // association, and also that sourcePath is the path of the object
88 // that contains the org.openbmc.Associations interface and not the
89 // association path itself.
90
91 // Find the services that have associations for this object path
Matt Spinlere2359fb2019-04-05 14:11:33 -050092 auto owners = assocMaps.owners.find(sourcePath);
93 if (owners == assocMaps.owners.end())
Andrew Geisslera80a3af2019-02-04 14:01:49 -060094 {
95 return;
96 }
97
98 // Find the association paths and endpoints owned by this object
99 // path for this service.
100 auto assocs = owners->second.find(owner);
101 if (assocs == owners->second.end())
102 {
103 return;
104 }
105
106 for (const auto& [assocPath, endpointsToRemove] : assocs->second)
107 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200108 removeAssociationEndpoints(io, server, assocPath, endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500109 assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600110 }
111
112 // Remove the associationOwners entries for this owning path/service.
113 owners->second.erase(assocs);
114 if (owners->second.empty())
115 {
Matt Spinlere2359fb2019-04-05 14:11:33 -0500116 assocMaps.owners.erase(owners);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600117 }
Matt Spinlercb9bcdb2019-04-08 10:58:49 -0500118
119 // If we were still waiting on the other side of this association to
120 // show up, cancel that wait.
121 removeFromPendingAssociations(sourcePath, assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -0600122}
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600123
124void removeAssociationEndpoints(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200125 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
126 const std::string& assocPath,
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600127 const boost::container::flat_set<std::string>& endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500128 AssociationMaps& assocMaps)
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600129{
Matt Spinlere2359fb2019-04-05 14:11:33 -0500130 auto assoc = assocMaps.ifaces.find(assocPath);
131 if (assoc == assocMaps.ifaces.end())
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600132 {
133 return;
134 }
135
136 auto& endpointsInDBus = std::get<endpointsPos>(assoc->second);
137
138 for (const auto& endpointToRemove : endpointsToRemove)
139 {
140 auto e = std::find(endpointsInDBus.begin(), endpointsInDBus.end(),
141 endpointToRemove);
142
143 if (e != endpointsInDBus.end())
144 {
145 endpointsInDBus.erase(e);
146 }
147 }
148
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200149 scheduleUpdateEndpointsOnDbus(io, objectServer, assocPath, assocMaps);
Andrew Geisslerff5ce922019-02-21 12:43:09 -0600150}
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600151
152void checkAssociationEndpointRemoves(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200153 boost::asio::io_context& io, const std::string& sourcePath,
154 const std::string& owner, const AssociationPaths& newAssociations,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500155 sdbusplus::asio::object_server& objectServer, AssociationMaps& assocMaps)
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600156{
157 // Find the services that have associations on this path.
Matt Spinlere2359fb2019-04-05 14:11:33 -0500158 auto originalOwners = assocMaps.owners.find(sourcePath);
159 if (originalOwners == assocMaps.owners.end())
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600160 {
161 return;
162 }
163
164 // Find the associations for this service
165 auto originalAssociations = originalOwners->second.find(owner);
166 if (originalAssociations == originalOwners->second.end())
167 {
168 return;
169 }
170
171 // Compare the new endpoints versus the original endpoints, and
172 // remove any of the original ones that aren't in the new list.
173 for (const auto& [originalAssocPath, originalEndpoints] :
174 originalAssociations->second)
175 {
176 // Check if this source even still has each association that
177 // was there previously, and if not, remove all of its endpoints
178 // from the D-Bus endpoints property which will cause the whole
179 // association path to be removed if no endpoints remain.
180 auto newEndpoints = newAssociations.find(originalAssocPath);
181 if (newEndpoints == newAssociations.end())
182 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200183 removeAssociationEndpoints(io, objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500184 originalEndpoints, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600185 }
186 else
187 {
188 // The association is still there. Check if the endpoints
189 // changed.
190 boost::container::flat_set<std::string> toRemove;
191
Brad Bishop1f623802022-05-31 18:22:10 -0400192 for (const auto& originalEndpoint : originalEndpoints)
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600193 {
194 if (std::find(newEndpoints->second.begin(),
195 newEndpoints->second.end(),
196 originalEndpoint) == newEndpoints->second.end())
197 {
198 toRemove.emplace(originalEndpoint);
199 }
200 }
201 if (!toRemove.empty())
202 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200203 removeAssociationEndpoints(io, objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500204 toRemove, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600205 }
206 }
207 }
208}
Andrew Geissler4511b332019-02-21 15:40:40 -0600209
Matt Spinler11401e22019-04-08 13:13:25 -0500210void addEndpointsToAssocIfaces(
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200211 boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
212 const std::string& assocPath,
Matt Spinler11401e22019-04-08 13:13:25 -0500213 const boost::container::flat_set<std::string>& endpointPaths,
214 AssociationMaps& assocMaps)
215{
216 auto& iface = assocMaps.ifaces[assocPath];
Matt Spinler11401e22019-04-08 13:13:25 -0500217 auto& endpoints = std::get<endpointsPos>(iface);
218
219 // Only add new endpoints
Brad Bishop1f623802022-05-31 18:22:10 -0400220 for (const auto& e : endpointPaths)
Matt Spinler11401e22019-04-08 13:13:25 -0500221 {
222 if (std::find(endpoints.begin(), endpoints.end(), e) == endpoints.end())
223 {
224 endpoints.push_back(e);
225 }
226 }
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200227 scheduleUpdateEndpointsOnDbus(io, objectServer, assocPath, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500228}
229
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200230void associationChanged(boost::asio::io_context& io,
231 sdbusplus::asio::object_server& objectServer,
Andrew Geissler4511b332019-02-21 15:40:40 -0600232 const std::vector<Association>& associations,
233 const std::string& path, const std::string& owner,
Brad Bishopa098a372022-05-05 15:19:04 -0400234 const InterfaceMapType& interfaceMap,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500235 AssociationMaps& assocMaps)
Andrew Geissler4511b332019-02-21 15:40:40 -0600236{
237 AssociationPaths objects;
238
239 for (const Association& association : associations)
240 {
241 std::string forward;
242 std::string reverse;
Brad Bishop1f623802022-05-31 18:22:10 -0400243 std::string objectPath;
244 std::tie(forward, reverse, objectPath) = association;
Andrew Geissler4511b332019-02-21 15:40:40 -0600245
Brad Bishop1f623802022-05-31 18:22:10 -0400246 if (objectPath.empty())
Andrew Geissler0a560a52019-03-22 10:59:07 -0500247 {
248 std::cerr << "Found invalid association on path " << path << "\n";
249 continue;
250 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500251
252 // Can't create this association if the endpoint isn't on D-Bus.
Brad Bishop1f623802022-05-31 18:22:10 -0400253 if (interfaceMap.find(objectPath) == interfaceMap.end())
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500254 {
Brad Bishop1f623802022-05-31 18:22:10 -0400255 addPendingAssociation(objectPath, reverse, path, forward, owner,
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500256 assocMaps);
257 continue;
258 }
259
Brad Bishop1f623802022-05-31 18:22:10 -0400260 if (!forward.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600261 {
Brad Bishop1f623802022-05-31 18:22:10 -0400262 objects[path + "/" + forward].emplace(objectPath);
Andrew Geissler4511b332019-02-21 15:40:40 -0600263 }
Brad Bishop1f623802022-05-31 18:22:10 -0400264 if (!reverse.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600265 {
Brad Bishop1f623802022-05-31 18:22:10 -0400266 objects[objectPath + "/" + reverse].emplace(path);
Andrew Geissler4511b332019-02-21 15:40:40 -0600267 }
268 }
269 for (const auto& object : objects)
270 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200271 addEndpointsToAssocIfaces(io, objectServer, object.first, object.second,
Matt Spinler11401e22019-04-08 13:13:25 -0500272 assocMaps);
Andrew Geissler4511b332019-02-21 15:40:40 -0600273 }
274
275 // Check for endpoints being removed instead of added
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200276 checkAssociationEndpointRemoves(io, path, owner, objects, objectServer,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500277 assocMaps);
Andrew Geissler4511b332019-02-21 15:40:40 -0600278
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500279 if (!objects.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600280 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500281 // Update associationOwners with the latest info
282 auto a = assocMaps.owners.find(path);
283 if (a != assocMaps.owners.end())
Andrew Geissler4511b332019-02-21 15:40:40 -0600284 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500285 auto o = a->second.find(owner);
286 if (o != a->second.end())
287 {
288 o->second = std::move(objects);
289 }
290 else
291 {
292 a->second.emplace(owner, std::move(objects));
293 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600294 }
295 else
296 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500297 boost::container::flat_map<std::string, AssociationPaths> owners;
298 owners.emplace(owner, std::move(objects));
299 assocMaps.owners.emplace(path, owners);
Andrew Geissler4511b332019-02-21 15:40:40 -0600300 }
301 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500302}
303
304void addPendingAssociation(const std::string& objectPath,
305 const std::string& type,
306 const std::string& endpointPath,
307 const std::string& endpointType,
308 const std::string& owner, AssociationMaps& assocMaps)
309{
310 Association assoc{type, endpointType, endpointPath};
311
312 auto p = assocMaps.pending.find(objectPath);
313 if (p == assocMaps.pending.end())
314 {
315 ExistingEndpoints ee;
316 ee.emplace_back(owner, std::move(assoc));
317 assocMaps.pending.emplace(objectPath, std::move(ee));
318 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600319 else
320 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500321 // Already waiting on this path for another association,
322 // so just add this endpoint and owner.
323 auto& endpoints = p->second;
Patrick Williams670edd12023-02-15 15:06:52 -0600324 auto e = std::find_if(endpoints.begin(), endpoints.end(),
325 [&assoc, &owner](const auto& endpoint) {
326 return (std::get<ownerPos>(endpoint) == owner) &&
327 (std::get<assocPos>(endpoint) == assoc);
328 });
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500329 if (e == endpoints.end())
330 {
331 endpoints.emplace_back(owner, std::move(assoc));
332 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600333 }
334}
Matt Spinlercb9bcdb2019-04-08 10:58:49 -0500335
336void removeFromPendingAssociations(const std::string& endpointPath,
337 AssociationMaps& assocMaps)
338{
339 auto assoc = assocMaps.pending.begin();
340 while (assoc != assocMaps.pending.end())
341 {
342 auto endpoint = assoc->second.begin();
343 while (endpoint != assoc->second.end())
344 {
345 auto& e = std::get<assocPos>(*endpoint);
346 if (std::get<reversePathPos>(e) == endpointPath)
347 {
348 endpoint = assoc->second.erase(endpoint);
349 continue;
350 }
351
352 endpoint++;
353 }
354
355 if (assoc->second.empty())
356 {
357 assoc = assocMaps.pending.erase(assoc);
358 continue;
359 }
360
361 assoc++;
362 }
363}
Matt Spinler11401e22019-04-08 13:13:25 -0500364
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200365void addSingleAssociation(boost::asio::io_context& io,
366 sdbusplus::asio::object_server& server,
Matt Spinler11401e22019-04-08 13:13:25 -0500367 const std::string& assocPath,
368 const std::string& endpoint, const std::string& owner,
369 const std::string& ownerPath,
370 AssociationMaps& assocMaps)
371{
372 boost::container::flat_set<std::string> endpoints{endpoint};
373
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200374 addEndpointsToAssocIfaces(io, server, assocPath, endpoints, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500375
376 AssociationPaths objects;
377 boost::container::flat_set e{endpoint};
378 objects.emplace(assocPath, e);
379
380 auto a = assocMaps.owners.find(ownerPath);
381 if (a != assocMaps.owners.end())
382 {
383 auto o = a->second.find(owner);
384 if (o != a->second.end())
385 {
386 auto p = o->second.find(assocPath);
387 if (p != o->second.end())
388 {
389 p->second.emplace(endpoint);
390 }
391 else
392 {
393 o->second.emplace(assocPath, e);
394 }
395 }
396 else
397 {
398 a->second.emplace(owner, std::move(objects));
399 }
400 }
401 else
402 {
403 boost::container::flat_map<std::string, AssociationPaths> owners;
404 owners.emplace(owner, std::move(objects));
405 assocMaps.owners.emplace(endpoint, owners);
406 }
407}
408
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200409void checkIfPendingAssociation(boost::asio::io_context& io,
410 const std::string& objectPath,
Brad Bishopa098a372022-05-05 15:19:04 -0400411 const InterfaceMapType& interfaceMap,
Matt Spinler11401e22019-04-08 13:13:25 -0500412 AssociationMaps& assocMaps,
413 sdbusplus::asio::object_server& server)
414{
415 auto pending = assocMaps.pending.find(objectPath);
416 if (pending == assocMaps.pending.end())
417 {
418 return;
419 }
420
421 if (interfaceMap.find(objectPath) == interfaceMap.end())
422 {
423 return;
424 }
425
426 auto endpoint = pending->second.begin();
427
428 while (endpoint != pending->second.end())
429 {
430 const auto& e = std::get<assocPos>(*endpoint);
431
432 // Ensure the other side of the association still exists
433 if (interfaceMap.find(std::get<reversePathPos>(e)) ==
434 interfaceMap.end())
435 {
436 endpoint++;
437 continue;
438 }
439
440 // Add both sides of the association:
441 // objectPath/forwardType and reversePath/reverseType
442 //
443 // The ownerPath is the reversePath - i.e. the endpoint that
444 // is on D-Bus and owns the org.openbmc.Associations iface.
445 //
446 const auto& ownerPath = std::get<reversePathPos>(e);
447 const auto& owner = std::get<ownerPos>(*endpoint);
448
449 auto assocPath = objectPath + '/' + std::get<forwardTypePos>(e);
450 auto endpointPath = ownerPath;
451
Lei YUb89c6612021-07-22 15:59:52 +0800452 try
453 {
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200454 addSingleAssociation(io, server, assocPath, endpointPath, owner,
Lei YUb89c6612021-07-22 15:59:52 +0800455 ownerPath, assocMaps);
Matt Spinler11401e22019-04-08 13:13:25 -0500456
Lei YUb89c6612021-07-22 15:59:52 +0800457 // Now the reverse direction (still the same owner and ownerPath)
458 assocPath = endpointPath + '/' + std::get<reverseTypePos>(e);
459 endpointPath = objectPath;
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200460 addSingleAssociation(io, server, assocPath, endpointPath, owner,
Lei YUb89c6612021-07-22 15:59:52 +0800461 ownerPath, assocMaps);
462 }
Patrick Williamscc8070b2022-07-22 19:26:55 -0500463 catch (const sdbusplus::exception_t& e)
Lei YUb89c6612021-07-22 15:59:52 +0800464 {
465 // In some case the interface could not be created on DBus and an
466 // exception is thrown. mapper has no control of the interface/path
467 // of the associations, so it has to catch the error and drop the
468 // association request.
Brad Bishop1f623802022-05-31 18:22:10 -0400469 std::cerr << "Error adding association: assocPath " << assocPath
470 << ", endpointPath " << endpointPath
471 << ", what: " << e.what() << "\n";
Lei YUb89c6612021-07-22 15:59:52 +0800472 }
Matt Spinler11401e22019-04-08 13:13:25 -0500473
474 // Not pending anymore
475 endpoint = pending->second.erase(endpoint);
476 }
477
478 if (pending->second.empty())
479 {
480 assocMaps.pending.erase(objectPath);
481 }
482}
Matt Spinler7f8fd1f2019-04-08 15:21:59 -0500483
484void findAssociations(const std::string& endpointPath,
485 AssociationMaps& assocMaps,
486 FindAssocResults& associationData)
487{
488 for (const auto& [sourcePath, owners] : assocMaps.owners)
489 {
490 for (const auto& [owner, assocs] : owners)
491 {
492 for (const auto& [assocPath, endpoints] : assocs)
493 {
494 if (std::find(endpoints.begin(), endpoints.end(),
495 endpointPath) != endpoints.end())
496 {
497 // assocPath is <path>/<type> which tells us what is on the
498 // other side of the association.
499 auto pos = assocPath.rfind('/');
500 auto otherPath = assocPath.substr(0, pos);
501 auto otherType = assocPath.substr(pos + 1);
502
503 // Now we need to find the endpointPath/<type> ->
504 // [otherPath] entry so that we can get the type for
505 // endpointPath's side of the assoc. Do this by finding
506 // otherPath as an endpoint, and also checking for
507 // 'endpointPath/*' as the key.
508 auto a = std::find_if(
509 assocs.begin(), assocs.end(),
510 [&endpointPath, &otherPath](const auto& ap) {
Patrick Williams670edd12023-02-15 15:06:52 -0600511 const auto& endpoints = ap.second;
512 auto endpoint = std::find(endpoints.begin(),
513 endpoints.end(), otherPath);
514 if (endpoint != endpoints.end())
515 {
516 return ap.first.starts_with(endpointPath + '/');
517 }
518 return false;
Matt Spinler7f8fd1f2019-04-08 15:21:59 -0500519 });
520
521 if (a != assocs.end())
522 {
523 // Pull out the type from endpointPath/<type>
524 pos = a->first.rfind('/');
525 auto thisType = a->first.substr(pos + 1);
526
527 // Now we know the full association:
528 // endpointPath/thisType -> otherPath/otherType
529 Association association{thisType, otherType, otherPath};
530 associationData.emplace_back(owner, association);
531 }
532 }
533 }
534 }
535 }
536}
Matt Spinler9c3d2852019-04-08 15:57:19 -0500537
538/** @brief Remove an endpoint for a particular association from D-Bus.
539 *
540 * If the last endpoint is gone, remove the whole association interface,
541 * otherwise just update the D-Bus endpoints property.
542 *
543 * @param[in] assocPath - the association path
544 * @param[in] endpointPath - the endpoint path to find and remove
545 * @param[in,out] assocMaps - the association maps
546 * @param[in,out] server - sdbus system object
547 */
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200548void removeAssociationIfacesEntry(boost::asio::io_context& io,
549 const std::string& assocPath,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500550 const std::string& endpointPath,
551 AssociationMaps& assocMaps,
552 sdbusplus::asio::object_server& server)
553{
554 auto assoc = assocMaps.ifaces.find(assocPath);
555 if (assoc != assocMaps.ifaces.end())
556 {
557 auto& endpoints = std::get<endpointsPos>(assoc->second);
558 auto e = std::find(endpoints.begin(), endpoints.end(), endpointPath);
559 if (e != endpoints.end())
560 {
561 endpoints.erase(e);
562
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200563 scheduleUpdateEndpointsOnDbus(io, server, assocPath, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500564 }
565 }
566}
567
568/** @brief Remove an endpoint from the association owners map.
569 *
570 * For a specific association path and owner, remove the endpoint.
571 * Remove all remaining artifacts of that endpoint in the owners map
572 * based on what frees up after the erase.
573 *
574 * @param[in] assocPath - the association object path
575 * @param[in] endpointPath - the endpoint object path
576 * @param[in] owner - the owner of the association
577 * @param[in,out] assocMaps - the association maps
Matt Spinler9c3d2852019-04-08 15:57:19 -0500578 */
579void removeAssociationOwnersEntry(const std::string& assocPath,
580 const std::string& endpointPath,
581 const std::string& owner,
Brad Bishopa6646902022-06-02 19:05:34 -0400582 AssociationMaps& assocMaps)
Matt Spinler9c3d2852019-04-08 15:57:19 -0500583{
584 auto sources = assocMaps.owners.begin();
585 while (sources != assocMaps.owners.end())
586 {
587 auto owners = sources->second.find(owner);
588 if (owners != sources->second.end())
589 {
590 auto entry = owners->second.find(assocPath);
591 if (entry != owners->second.end())
592 {
593 auto e = std::find(entry->second.begin(), entry->second.end(),
594 endpointPath);
595 if (e != entry->second.end())
596 {
597 entry->second.erase(e);
598 if (entry->second.empty())
599 {
600 owners->second.erase(entry);
601 }
602 }
603 }
604
605 if (owners->second.empty())
606 {
607 sources->second.erase(owners);
608 }
609 }
610
611 if (sources->second.empty())
612 {
613 sources = assocMaps.owners.erase(sources);
614 continue;
615 }
616 sources++;
617 }
618}
619
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200620void moveAssociationToPending(boost::asio::io_context& io,
621 const std::string& endpointPath,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500622 AssociationMaps& assocMaps,
623 sdbusplus::asio::object_server& server)
624{
625 FindAssocResults associationData;
626
627 // Check which associations this path is an endpoint of, and
628 // then add them to the pending associations map and remove
629 // the associations objects.
630 findAssociations(endpointPath, assocMaps, associationData);
631
632 for (const auto& [owner, association] : associationData)
633 {
634 const auto& forwardPath = endpointPath;
635 const auto& forwardType = std::get<forwardTypePos>(association);
636 const auto& reversePath = std::get<reversePathPos>(association);
637 const auto& reverseType = std::get<reverseTypePos>(association);
638
639 addPendingAssociation(forwardPath, forwardType, reversePath,
640 reverseType, owner, assocMaps);
641
642 // Remove both sides of the association from assocMaps.ifaces
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200643 removeAssociationIfacesEntry(io, forwardPath + '/' + forwardType,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500644 reversePath, assocMaps, server);
Kallas, Pawel5b4357d2022-10-12 15:36:37 +0200645 removeAssociationIfacesEntry(io, reversePath + '/' + reverseType,
Matt Spinler9c3d2852019-04-08 15:57:19 -0500646 forwardPath, assocMaps, server);
647
648 // Remove both sides of the association from assocMaps.owners
649 removeAssociationOwnersEntry(forwardPath + '/' + forwardType,
Brad Bishopa6646902022-06-02 19:05:34 -0400650 reversePath, owner, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500651 removeAssociationOwnersEntry(reversePath + '/' + reverseType,
Brad Bishopa6646902022-06-02 19:05:34 -0400652 forwardPath, owner, assocMaps);
Matt Spinler9c3d2852019-04-08 15:57:19 -0500653 }
654}