blob: 30a8e9a1406af536b327c845267c2a29d32f6590 [file] [log] [blame]
Andrew Geisslera80a3af2019-02-04 14:01:49 -06001#include "associations.hpp"
2
Andrew Geissler4511b332019-02-21 15:40:40 -06003#include <iostream>
4
Andrew Geisslera80a3af2019-02-04 14:01:49 -06005void removeAssociation(const std::string& sourcePath, const std::string& owner,
6 sdbusplus::asio::object_server& server,
Matt Spinlere2359fb2019-04-05 14:11:33 -05007 AssociationMaps& assocMaps)
Andrew Geisslera80a3af2019-02-04 14:01:49 -06008{
9 // Use associationOwners to find the association paths and endpoints
10 // that the passed in object path and service own. Remove all of
11 // these endpoints from the actual association D-Bus objects, and if
12 // the endpoints property is then empty, the whole association object
13 // can be removed. Note there can be multiple services that own an
14 // association, and also that sourcePath is the path of the object
15 // that contains the org.openbmc.Associations interface and not the
16 // association path itself.
17
18 // Find the services that have associations for this object path
Matt Spinlere2359fb2019-04-05 14:11:33 -050019 auto owners = assocMaps.owners.find(sourcePath);
20 if (owners == assocMaps.owners.end())
Andrew Geisslera80a3af2019-02-04 14:01:49 -060021 {
22 return;
23 }
24
25 // Find the association paths and endpoints owned by this object
26 // path for this service.
27 auto assocs = owners->second.find(owner);
28 if (assocs == owners->second.end())
29 {
30 return;
31 }
32
33 for (const auto& [assocPath, endpointsToRemove] : assocs->second)
34 {
Andrew Geissler5629ae82019-02-21 12:59:09 -060035 removeAssociationEndpoints(server, assocPath, endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -050036 assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -060037 }
38
39 // Remove the associationOwners entries for this owning path/service.
40 owners->second.erase(assocs);
41 if (owners->second.empty())
42 {
Matt Spinlere2359fb2019-04-05 14:11:33 -050043 assocMaps.owners.erase(owners);
Andrew Geisslera80a3af2019-02-04 14:01:49 -060044 }
Matt Spinlercb9bcdb2019-04-08 10:58:49 -050045
46 // If we were still waiting on the other side of this association to
47 // show up, cancel that wait.
48 removeFromPendingAssociations(sourcePath, assocMaps);
Andrew Geisslera80a3af2019-02-04 14:01:49 -060049}
Andrew Geisslerff5ce922019-02-21 12:43:09 -060050
51void removeAssociationEndpoints(
52 sdbusplus::asio::object_server& objectServer, const std::string& assocPath,
53 const boost::container::flat_set<std::string>& endpointsToRemove,
Matt Spinlere2359fb2019-04-05 14:11:33 -050054 AssociationMaps& assocMaps)
Andrew Geisslerff5ce922019-02-21 12:43:09 -060055{
Matt Spinlere2359fb2019-04-05 14:11:33 -050056 auto assoc = assocMaps.ifaces.find(assocPath);
57 if (assoc == assocMaps.ifaces.end())
Andrew Geisslerff5ce922019-02-21 12:43:09 -060058 {
59 return;
60 }
61
62 auto& endpointsInDBus = std::get<endpointsPos>(assoc->second);
63
64 for (const auto& endpointToRemove : endpointsToRemove)
65 {
66 auto e = std::find(endpointsInDBus.begin(), endpointsInDBus.end(),
67 endpointToRemove);
68
69 if (e != endpointsInDBus.end())
70 {
71 endpointsInDBus.erase(e);
72 }
73 }
74
75 if (endpointsInDBus.empty())
76 {
77 objectServer.remove_interface(std::get<ifacePos>(assoc->second));
78 std::get<ifacePos>(assoc->second) = nullptr;
79 std::get<endpointsPos>(assoc->second).clear();
80 }
81 else
82 {
83 std::get<ifacePos>(assoc->second)
84 ->set_property("endpoints", endpointsInDBus);
85 }
86}
Andrew Geissler7f1c44d2019-02-21 13:44:16 -060087
88void checkAssociationEndpointRemoves(
89 const std::string& sourcePath, const std::string& owner,
90 const AssociationPaths& newAssociations,
Matt Spinlere2359fb2019-04-05 14:11:33 -050091 sdbusplus::asio::object_server& objectServer, AssociationMaps& assocMaps)
Andrew Geissler7f1c44d2019-02-21 13:44:16 -060092{
93 // Find the services that have associations on this path.
Matt Spinlere2359fb2019-04-05 14:11:33 -050094 auto originalOwners = assocMaps.owners.find(sourcePath);
95 if (originalOwners == assocMaps.owners.end())
Andrew Geissler7f1c44d2019-02-21 13:44:16 -060096 {
97 return;
98 }
99
100 // Find the associations for this service
101 auto originalAssociations = originalOwners->second.find(owner);
102 if (originalAssociations == originalOwners->second.end())
103 {
104 return;
105 }
106
107 // Compare the new endpoints versus the original endpoints, and
108 // remove any of the original ones that aren't in the new list.
109 for (const auto& [originalAssocPath, originalEndpoints] :
110 originalAssociations->second)
111 {
112 // Check if this source even still has each association that
113 // was there previously, and if not, remove all of its endpoints
114 // from the D-Bus endpoints property which will cause the whole
115 // association path to be removed if no endpoints remain.
116 auto newEndpoints = newAssociations.find(originalAssocPath);
117 if (newEndpoints == newAssociations.end())
118 {
119 removeAssociationEndpoints(objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500120 originalEndpoints, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600121 }
122 else
123 {
124 // The association is still there. Check if the endpoints
125 // changed.
126 boost::container::flat_set<std::string> toRemove;
127
128 for (auto& originalEndpoint : originalEndpoints)
129 {
130 if (std::find(newEndpoints->second.begin(),
131 newEndpoints->second.end(),
132 originalEndpoint) == newEndpoints->second.end())
133 {
134 toRemove.emplace(originalEndpoint);
135 }
136 }
137 if (!toRemove.empty())
138 {
139 removeAssociationEndpoints(objectServer, originalAssocPath,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500140 toRemove, assocMaps);
Andrew Geissler7f1c44d2019-02-21 13:44:16 -0600141 }
142 }
143 }
144}
Andrew Geissler4511b332019-02-21 15:40:40 -0600145
146void associationChanged(sdbusplus::asio::object_server& objectServer,
147 const std::vector<Association>& associations,
148 const std::string& path, const std::string& owner,
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500149 const interface_map_type& interfaceMap,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500150 AssociationMaps& assocMaps)
Andrew Geissler4511b332019-02-21 15:40:40 -0600151{
152 AssociationPaths objects;
153
154 for (const Association& association : associations)
155 {
156 std::string forward;
157 std::string reverse;
158 std::string endpoint;
159 std::tie(forward, reverse, endpoint) = association;
160
Andrew Geissler0a560a52019-03-22 10:59:07 -0500161 if (endpoint.empty())
162 {
163 std::cerr << "Found invalid association on path " << path << "\n";
164 continue;
165 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500166
167 // Can't create this association if the endpoint isn't on D-Bus.
168 if (interfaceMap.find(endpoint) == interfaceMap.end())
169 {
170 addPendingAssociation(endpoint, reverse, path, forward, owner,
171 assocMaps);
172 continue;
173 }
174
Andrew Geissler4511b332019-02-21 15:40:40 -0600175 if (forward.size())
176 {
177 objects[path + "/" + forward].emplace(endpoint);
178 }
179 if (reverse.size())
180 {
Andrew Geissler4511b332019-02-21 15:40:40 -0600181 objects[endpoint + "/" + reverse].emplace(path);
182 }
183 }
184 for (const auto& object : objects)
185 {
186 // the mapper exposes the new association interface but intakes
187 // the old
188
Matt Spinlere2359fb2019-04-05 14:11:33 -0500189 auto& iface = assocMaps.ifaces[object.first];
Andrew Geissler4511b332019-02-21 15:40:40 -0600190 auto& i = std::get<ifacePos>(iface);
191 auto& endpoints = std::get<endpointsPos>(iface);
192
193 // Only add new endpoints
194 for (auto& e : object.second)
195 {
196 if (std::find(endpoints.begin(), endpoints.end(), e) ==
197 endpoints.end())
198 {
199 endpoints.push_back(e);
200 }
201 }
202
203 // If the interface already exists, only need to update
204 // the property value, otherwise create it
205 if (i)
206 {
207 i->set_property("endpoints", endpoints);
208 }
209 else
210 {
211 i = objectServer.add_interface(object.first,
212 XYZ_ASSOCIATION_INTERFACE);
213 i->register_property("endpoints", endpoints);
214 i->initialize();
215 }
216 }
217
218 // Check for endpoints being removed instead of added
219 checkAssociationEndpointRemoves(path, owner, objects, objectServer,
Matt Spinlere2359fb2019-04-05 14:11:33 -0500220 assocMaps);
Andrew Geissler4511b332019-02-21 15:40:40 -0600221
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500222 if (!objects.empty())
Andrew Geissler4511b332019-02-21 15:40:40 -0600223 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500224 // Update associationOwners with the latest info
225 auto a = assocMaps.owners.find(path);
226 if (a != assocMaps.owners.end())
Andrew Geissler4511b332019-02-21 15:40:40 -0600227 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500228 auto o = a->second.find(owner);
229 if (o != a->second.end())
230 {
231 o->second = std::move(objects);
232 }
233 else
234 {
235 a->second.emplace(owner, std::move(objects));
236 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600237 }
238 else
239 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500240 boost::container::flat_map<std::string, AssociationPaths> owners;
241 owners.emplace(owner, std::move(objects));
242 assocMaps.owners.emplace(path, owners);
Andrew Geissler4511b332019-02-21 15:40:40 -0600243 }
244 }
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500245}
246
247void addPendingAssociation(const std::string& objectPath,
248 const std::string& type,
249 const std::string& endpointPath,
250 const std::string& endpointType,
251 const std::string& owner, AssociationMaps& assocMaps)
252{
253 Association assoc{type, endpointType, endpointPath};
254
255 auto p = assocMaps.pending.find(objectPath);
256 if (p == assocMaps.pending.end())
257 {
258 ExistingEndpoints ee;
259 ee.emplace_back(owner, std::move(assoc));
260 assocMaps.pending.emplace(objectPath, std::move(ee));
261 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600262 else
263 {
Matt Spinlere0b0e3a2019-04-08 10:39:23 -0500264 // Already waiting on this path for another association,
265 // so just add this endpoint and owner.
266 auto& endpoints = p->second;
267 auto e =
268 std::find_if(endpoints.begin(), endpoints.end(),
269 [&assoc, &owner](const auto& endpoint) {
270 return (std::get<ownerPos>(endpoint) == owner) &&
271 (std::get<assocPos>(endpoint) == assoc);
272 });
273 if (e == endpoints.end())
274 {
275 endpoints.emplace_back(owner, std::move(assoc));
276 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600277 }
278}
Matt Spinlercb9bcdb2019-04-08 10:58:49 -0500279
280void removeFromPendingAssociations(const std::string& endpointPath,
281 AssociationMaps& assocMaps)
282{
283 auto assoc = assocMaps.pending.begin();
284 while (assoc != assocMaps.pending.end())
285 {
286 auto endpoint = assoc->second.begin();
287 while (endpoint != assoc->second.end())
288 {
289 auto& e = std::get<assocPos>(*endpoint);
290 if (std::get<reversePathPos>(e) == endpointPath)
291 {
292 endpoint = assoc->second.erase(endpoint);
293 continue;
294 }
295
296 endpoint++;
297 }
298
299 if (assoc->second.empty())
300 {
301 assoc = assocMaps.pending.erase(assoc);
302 continue;
303 }
304
305 assoc++;
306 }
307}