blob: b4c0fae12aceab1a6a39176ccf2d3dd42a4b735c [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,
7 AssociationOwnersType& assocOwners,
8 AssociationInterfaces& assocInterfaces)
9{
10 // Use associationOwners to find the association paths and endpoints
11 // that the passed in object path and service own. Remove all of
12 // these endpoints from the actual association D-Bus objects, and if
13 // the endpoints property is then empty, the whole association object
14 // can be removed. Note there can be multiple services that own an
15 // association, and also that sourcePath is the path of the object
16 // that contains the org.openbmc.Associations interface and not the
17 // association path itself.
18
19 // Find the services that have associations for this object path
20 auto owners = assocOwners.find(sourcePath);
21 if (owners == assocOwners.end())
22 {
23 return;
24 }
25
26 // Find the association paths and endpoints owned by this object
27 // path for this service.
28 auto assocs = owners->second.find(owner);
29 if (assocs == owners->second.end())
30 {
31 return;
32 }
33
34 for (const auto& [assocPath, endpointsToRemove] : assocs->second)
35 {
Andrew Geissler5629ae82019-02-21 12:59:09 -060036 removeAssociationEndpoints(server, assocPath, endpointsToRemove,
37 assocInterfaces);
Andrew Geisslera80a3af2019-02-04 14:01:49 -060038 }
39
40 // Remove the associationOwners entries for this owning path/service.
41 owners->second.erase(assocs);
42 if (owners->second.empty())
43 {
44 assocOwners.erase(owners);
45 }
46}
Andrew Geisslerff5ce922019-02-21 12:43:09 -060047
48void removeAssociationEndpoints(
49 sdbusplus::asio::object_server& objectServer, const std::string& assocPath,
50 const boost::container::flat_set<std::string>& endpointsToRemove,
51 AssociationInterfaces& assocInterfaces)
52{
53 auto assoc = assocInterfaces.find(assocPath);
54 if (assoc == assocInterfaces.end())
55 {
56 return;
57 }
58
59 auto& endpointsInDBus = std::get<endpointsPos>(assoc->second);
60
61 for (const auto& endpointToRemove : endpointsToRemove)
62 {
63 auto e = std::find(endpointsInDBus.begin(), endpointsInDBus.end(),
64 endpointToRemove);
65
66 if (e != endpointsInDBus.end())
67 {
68 endpointsInDBus.erase(e);
69 }
70 }
71
72 if (endpointsInDBus.empty())
73 {
74 objectServer.remove_interface(std::get<ifacePos>(assoc->second));
75 std::get<ifacePos>(assoc->second) = nullptr;
76 std::get<endpointsPos>(assoc->second).clear();
77 }
78 else
79 {
80 std::get<ifacePos>(assoc->second)
81 ->set_property("endpoints", endpointsInDBus);
82 }
83}
Andrew Geissler7f1c44d2019-02-21 13:44:16 -060084
85void checkAssociationEndpointRemoves(
86 const std::string& sourcePath, const std::string& owner,
87 const AssociationPaths& newAssociations,
88 sdbusplus::asio::object_server& objectServer,
89 AssociationOwnersType& assocOwners, AssociationInterfaces& assocInterfaces)
90{
91 // Find the services that have associations on this path.
92 auto originalOwners = assocOwners.find(sourcePath);
93 if (originalOwners == assocOwners.end())
94 {
95 return;
96 }
97
98 // Find the associations for this service
99 auto originalAssociations = originalOwners->second.find(owner);
100 if (originalAssociations == originalOwners->second.end())
101 {
102 return;
103 }
104
105 // Compare the new endpoints versus the original endpoints, and
106 // remove any of the original ones that aren't in the new list.
107 for (const auto& [originalAssocPath, originalEndpoints] :
108 originalAssociations->second)
109 {
110 // Check if this source even still has each association that
111 // was there previously, and if not, remove all of its endpoints
112 // from the D-Bus endpoints property which will cause the whole
113 // association path to be removed if no endpoints remain.
114 auto newEndpoints = newAssociations.find(originalAssocPath);
115 if (newEndpoints == newAssociations.end())
116 {
117 removeAssociationEndpoints(objectServer, originalAssocPath,
118 originalEndpoints, assocInterfaces);
119 }
120 else
121 {
122 // The association is still there. Check if the endpoints
123 // changed.
124 boost::container::flat_set<std::string> toRemove;
125
126 for (auto& originalEndpoint : originalEndpoints)
127 {
128 if (std::find(newEndpoints->second.begin(),
129 newEndpoints->second.end(),
130 originalEndpoint) == newEndpoints->second.end())
131 {
132 toRemove.emplace(originalEndpoint);
133 }
134 }
135 if (!toRemove.empty())
136 {
137 removeAssociationEndpoints(objectServer, originalAssocPath,
138 toRemove, assocInterfaces);
139 }
140 }
141 }
142}
Andrew Geissler4511b332019-02-21 15:40:40 -0600143
144void associationChanged(sdbusplus::asio::object_server& objectServer,
145 const std::vector<Association>& associations,
146 const std::string& path, const std::string& owner,
147 AssociationOwnersType& assocOwners,
148 AssociationInterfaces& assocInterfaces)
149{
150 AssociationPaths objects;
151
152 for (const Association& association : associations)
153 {
154 std::string forward;
155 std::string reverse;
156 std::string endpoint;
157 std::tie(forward, reverse, endpoint) = association;
158
Andrew Geissler0a560a52019-03-22 10:59:07 -0500159 if (endpoint.empty())
160 {
161 std::cerr << "Found invalid association on path " << path << "\n";
162 continue;
163 }
Andrew Geissler4511b332019-02-21 15:40:40 -0600164 if (forward.size())
165 {
166 objects[path + "/" + forward].emplace(endpoint);
167 }
168 if (reverse.size())
169 {
Andrew Geissler4511b332019-02-21 15:40:40 -0600170 objects[endpoint + "/" + reverse].emplace(path);
171 }
172 }
173 for (const auto& object : objects)
174 {
175 // the mapper exposes the new association interface but intakes
176 // the old
177
178 auto& iface = assocInterfaces[object.first];
179 auto& i = std::get<ifacePos>(iface);
180 auto& endpoints = std::get<endpointsPos>(iface);
181
182 // Only add new endpoints
183 for (auto& e : object.second)
184 {
185 if (std::find(endpoints.begin(), endpoints.end(), e) ==
186 endpoints.end())
187 {
188 endpoints.push_back(e);
189 }
190 }
191
192 // If the interface already exists, only need to update
193 // the property value, otherwise create it
194 if (i)
195 {
196 i->set_property("endpoints", endpoints);
197 }
198 else
199 {
200 i = objectServer.add_interface(object.first,
201 XYZ_ASSOCIATION_INTERFACE);
202 i->register_property("endpoints", endpoints);
203 i->initialize();
204 }
205 }
206
207 // Check for endpoints being removed instead of added
208 checkAssociationEndpointRemoves(path, owner, objects, objectServer,
209 assocOwners, assocInterfaces);
210
211 // Update associationOwners with the latest info
212 auto a = assocOwners.find(path);
213 if (a != assocOwners.end())
214 {
215 auto o = a->second.find(owner);
216 if (o != a->second.end())
217 {
218 o->second = std::move(objects);
219 }
220 else
221 {
222 a->second.emplace(owner, std::move(objects));
223 }
224 }
225 else
226 {
227 boost::container::flat_map<std::string, AssociationPaths> owners;
228 owners.emplace(owner, std::move(objects));
229 assocOwners.emplace(path, owners);
230 }
231}