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