2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.iface;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.List;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.locks.ReentrantLock;
20 import java.util.stream.Collectors;
22 import javax.annotation.Nonnull;
24 import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
25 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
28 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
29 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
30 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
31 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
32 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
33 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
34 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
35 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
36 import org.opendaylight.groupbasedpolicy.renderer.util.AddressEndpointUtils;
37 import org.opendaylight.groupbasedpolicy.renderer.vpp.manager.VppNodeManager;
38 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.CloseOnFailTransactionChain;
39 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.KeyFactory;
40 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
41 import org.opendaylight.groupbasedpolicy.util.EndpointUtils;
42 import org.opendaylight.groupbasedpolicy.util.IidFactory;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.Endpoints;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.AddressEndpoints;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocationBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.RelativeLocations;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.RelativeLocationsBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocation;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.relative.location.relative.locations.ExternalLocationBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.ProviderName;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProvider;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.LocationProviderBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocation;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint_location_provider.rev160419.location.providers.location.provider.ProviderAddressEndpointLocationKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.renderer.policy.configuration.endpoints.AddressEndpointWithLocationKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpoint;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.config.VppEndpointKey;
65 import org.opendaylight.yangtools.concepts.ListenerRegistration;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
70 import com.google.common.annotations.VisibleForTesting;
71 import com.google.common.base.Optional;
72 import com.google.common.util.concurrent.CheckedFuture;
73 import com.google.common.util.concurrent.Futures;
74 import com.google.common.util.concurrent.ListenableFuture;
76 public class VppEndpointLocationProvider
77 implements ClusteredDataTreeChangeListener<AddressEndpoint>, VPPLocationProvider, AutoCloseable {
79 private static final Logger LOG = LoggerFactory.getLogger(VppEndpointLocationProvider.class);
80 public static final ProviderName VPP_ENDPOINT_LOCATION_PROVIDER =
81 new ProviderName("VPP endpoint location provider");
82 public static final long PROVIDER_PRIORITY = 10L;
83 private final SyncedWriter syncedWriter;
84 private final Map<VppEndpointKey, VppEndpoint> vppEndpoints = new HashMap<>();
85 private final Map<VppEndpointKey,AddressEndpoint> pendingAddrEndpoints = new HashMap<>();
86 private ListenerRegistration<VppEndpointLocationProvider> registeredListener;
88 public VppEndpointLocationProvider(DataBroker dataProvider) {
89 LocationProvider locationProvider = new LocationProviderBuilder().setProvider(VPP_ENDPOINT_LOCATION_PROVIDER)
90 .setPriority(PROVIDER_PRIORITY)
92 syncedWriter = new SyncedWriter(checkNotNull(dataProvider)
93 .createTransactionChain(new CloseOnFailTransactionChain(VppEndpointLocationProvider.class.getSimpleName())));
94 WriteTransaction wTx = syncedWriter.newWriteOnlyTransaction();
95 wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER),
96 locationProvider, true);
97 syncedWriter.submitNow(wTx);
98 registeredListener = dataProvider.registerDataTreeChangeListener(
99 checkNotNull(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
100 InstanceIdentifier.builder(Endpoints.class)
101 .child(AddressEndpoints.class)
102 .child(AddressEndpoint.class)
107 public void onDataTreeChanged(Collection<DataTreeModification<AddressEndpoint>> change) {
108 change.forEach(dtm -> {
109 ReadWriteTransaction rwTx = syncedWriter.newReadWriteTransaction();
110 DataObjectModification<AddressEndpoint> rootNode = dtm.getRootNode();
111 if (rootNode.getDataBefore() != null) {
112 locationFromParentWriter.clear(rwTx, rootNode.getDataBefore());
113 regularLocationWriter.clear(rwTx, rootNode.getDataBefore());
115 if (rootNode.getDataAfter() == null || !canCreateLocation(dtm.getRootNode())) {
116 syncedWriter.submitNow(rwTx);
119 if (VppLocationUtils.hasMultihomeParent(rwTx, rootNode.getDataAfter().getParentEndpointChoice())
120 || VppLocationUtils.hasMultipleParents(rootNode.getDataAfter())) {
121 locationFromParentWriter.sync(rwTx, rootNode.getDataAfter());
123 regularLocationWriter.sync(rwTx, rootNode.getDataAfter());
125 syncedWriter.submitNow(rwTx);
130 public ListenableFuture<Void> createLocationForVppEndpoint(VppEndpoint vppEndpoint) {
131 vppEndpoints.put(vppEndpoint.getKey(), vppEndpoint);
132 ReadWriteTransaction rwTx = syncedWriter.newReadWriteTransaction();
133 Optional<AddressEndpoint> cachedAddrEp =
134 Optional.fromNullable(pendingAddrEndpoints.get(vppEndpoint.getKey()));
135 if (cachedAddrEp.isPresent()) {
136 AddressEndpoint after = cachedAddrEp.get();
137 if (after != null && (VppLocationUtils.hasMultihomeParent(rwTx, after.getParentEndpointChoice())
138 || VppLocationUtils.hasMultipleParents(after))) {
139 locationFromParentWriter.sync(rwTx, after);
141 regularLocationWriter.sync(rwTx, after);
144 syncedWriter.submitNow(rwTx);
145 return Futures.immediateFuture(null);
149 public ListenableFuture<Void> deleteLocationForVppEndpoint(VppEndpoint vppEndpoint) {
150 // onDelete location from DS
151 vppEndpoints.remove(vppEndpoint.getKey());
152 return Futures.immediateFuture(null);
156 public ListenableFuture<Void> replaceLocationForEndpoint(@Nonnull ExternalLocationCase location,
157 @Nonnull AddressEndpointWithLocationKey addrEpWithLocKey) {
158 InstanceIdentifier<ProviderAddressEndpointLocation> iid =
159 IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
160 VppLocationUtils.createProviderAddressEndpointLocationKey(addrEpWithLocKey));
161 ReadOnlyTransaction rTx = syncedWriter.newReadOnlyTransaction();
162 Optional<ProviderAddressEndpointLocation> optLoc =
163 DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION, iid, rTx);
164 syncedWriter.close(rTx);
165 ProviderAddressEndpointLocationKey provAddrEpLocKey =
166 KeyFactory.providerAddressEndpointLocationKey(addrEpWithLocKey);
167 ProviderAddressEndpointLocationBuilder builder =
168 new ProviderAddressEndpointLocationBuilder().setKey(provAddrEpLocKey);
169 if (optLoc.isPresent() && optLoc.get().getAbsoluteLocation() != null) {
170 AbsoluteLocation absoluteLocation = optLoc.get().getAbsoluteLocation();
172 .setAbsoluteLocation(new AbsoluteLocationBuilder(absoluteLocation).setLocationType(location).build());
173 } else if (optLoc.isPresent() && optLoc.get().getRelativeLocations() != null) {
174 ExternalLocation extLoc = new ExternalLocationBuilder().setExternalNode(location.getExternalNode())
175 .setExternalNodeConnector(location.getExternalNodeConnector())
176 .setExternalNodeMountPoint(location.getExternalNodeMountPoint())
178 List<ExternalLocation> externalLocation = optLoc.get().getRelativeLocations().getExternalLocation();
179 externalLocation.add(extLoc);
180 RelativeLocations relativeLocation = new RelativeLocationsBuilder(optLoc.get().getRelativeLocations())
181 .setExternalLocation(externalLocation).build();
182 builder.setRelativeLocations(relativeLocation);
184 LOG.warn("Cannot replace location for endpoint {}", addrEpWithLocKey);
185 return Futures.immediateFuture(null);
187 ProviderAddressEndpointLocation providerLocation = builder.build();
188 WriteTransaction wTx = syncedWriter.newWriteOnlyTransaction();
189 wTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.providerAddressEndpointLocationIid(
190 VPP_ENDPOINT_LOCATION_PROVIDER, providerLocation.getKey()), providerLocation);
191 LOG.debug("Updating location for {}", builder.build().getKey());
192 syncedWriter.submitNow(wTx);
193 return Futures.immediateFuture(null);
197 synchronized boolean canCreateLocation(@Nonnull DataObjectModification<AddressEndpoint> rootNode) {
198 VppEndpoint vpp = vppEndpoints.get(VppLocationUtils.vppEndpointKeyFrom(rootNode.getDataAfter().getKey()));
200 VppEndpointKey key = VppLocationUtils.vppEndpointKeyFrom(rootNode.getDataAfter().getKey());
201 LOG.debug("Caching VPP endpoint {}" + key);
202 pendingAddrEndpoints.put(key, rootNode.getDataAfter());
209 public void close() {
210 registeredListener.close();
211 WriteTransaction wTx = syncedWriter.newWriteOnlyTransaction();
212 wTx.delete(LogicalDatastoreType.CONFIGURATION, IidFactory.locationProviderIid(VPP_ENDPOINT_LOCATION_PROVIDER));
213 syncedWriter.submitNow(wTx);
216 private class SyncedWriter {
218 private final BindingTransactionChain txChain;
219 private final ReentrantLock SYNC_LOCK = new ReentrantLock();
221 SyncedWriter(BindingTransactionChain txChain) {
222 this.txChain = txChain;
225 ReadOnlyTransaction newReadOnlyTransaction() {
227 return txChain.newReadOnlyTransaction();
230 WriteTransaction newWriteOnlyTransaction() {
232 return txChain.newWriteOnlyTransaction();
235 ReadWriteTransaction newReadWriteTransaction() {
237 return txChain.newReadWriteTransaction();
240 void close(ReadOnlyTransaction rTx) {
245 void submitNow(WriteTransaction wTx) {
246 CheckedFuture<Void, TransactionCommitFailedException> submit = wTx.submit();
250 } catch (InterruptedException | ExecutionException e) {
251 LOG.error("Failed to submit transaction {}", e);
253 LOG.info("Submit done.");
257 private abstract class LocationWriter {
259 abstract void clear(ReadWriteTransaction rwTx, AddressEndpoint before);
261 abstract void sync(ReadWriteTransaction rwTx, AddressEndpoint after);
264 LocationWriter regularLocationWriter = new LocationWriter() {
267 void sync(ReadWriteTransaction rwTx, AddressEndpoint after) {
271 if (EndpointUtils.isExternalEndpoint(rwTx, after)) {
272 ProviderAddressEndpointLocation location = VppLocationUtils.createRelativeAddressEndpointLocation(
273 after.getKey(), VppNodeManager.resolvePublicInterfaces(rwTx));
274 InstanceIdentifier<ProviderAddressEndpointLocation> iid = IidFactory.providerAddressEndpointLocationIid(
275 VppEndpointLocationProvider.VPP_ENDPOINT_LOCATION_PROVIDER, location.getKey());
276 rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, location, true);
278 VppEndpoint vpp = vppEndpoints.get(VppLocationUtils.vppEndpointKeyFrom(after.getKey()));
279 ProviderAddressEndpointLocation location = VppLocationUtils.createAbsoluteLocationFromVppEndpoint(vpp);
280 InstanceIdentifier<ProviderAddressEndpointLocation> iid = IidFactory.providerAddressEndpointLocationIid(
281 VppEndpointLocationProvider.VPP_ENDPOINT_LOCATION_PROVIDER, location.getKey());
282 rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, location, true);
287 void clear(ReadWriteTransaction rwTx, AddressEndpoint before) {
288 if (before != null) {
289 InstanceIdentifier<ProviderAddressEndpointLocation> iid =
290 IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
291 VppLocationUtils.createProviderAddressEndpointLocationKey(before.getKey()));
292 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, iid, rwTx);
297 LocationWriter locationFromParentWriter = new LocationWriter() {
300 void clear(ReadWriteTransaction rwTx, AddressEndpoint before) {
301 if (before != null) {
302 InstanceIdentifier<ProviderAddressEndpointLocation> iid =
303 IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
304 VppLocationUtils.createProviderAddressEndpointLocationKey(before.getKey()));
305 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, iid, rwTx);
306 for (ParentEndpoint l3Endpoint : EndpointUtils.getParentEndpoints(before.getParentEndpointChoice())) {
307 iid = IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
308 VppLocationUtils.createProviderAddressEndpointLocationKey(l3Endpoint.getKey()));
309 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION, iid, rwTx);
315 void sync(ReadWriteTransaction rwTx, AddressEndpoint after) {
319 for (ParentEndpoint l3Endpoint : EndpointUtils.getParentEndpoints(after.getParentEndpointChoice())) {
320 InstanceIdentifier<ProviderAddressEndpointLocation> iid =
321 IidFactory.providerAddressEndpointLocationIid(VPP_ENDPOINT_LOCATION_PROVIDER,
322 VppLocationUtils.createProviderAddressEndpointLocationKey(l3Endpoint.getKey()));
323 List<VppEndpoint> l2childs = getL2Childs(rwTx, l3Endpoint);
324 if (!l2childs.isEmpty() && l2childs.size() > 1) {
325 // multihome interface
326 ProviderAddressEndpointLocation location = VppLocationUtils.createRelativeAddressEndpointLocation(
327 VppLocationUtils.createProviderAddressEndpointLocationKey(l3Endpoint.getKey()), l2childs);
328 rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, location, true);
330 VppEndpoint vppEndpoint = vppEndpoints.get(VppLocationUtils.vppEndpointKeyFrom(after.getKey()));
331 ProviderAddressEndpointLocation location =
332 VppLocationUtils.createAbsoluteLocationFromVppEndpoint(new VppEndpointBuilder(vppEndpoint)
333 .setKey(VppLocationUtils.vppEndpointKeyFrom(l3Endpoint.getKey())).build());
334 rwTx.put(LogicalDatastoreType.CONFIGURATION, iid, location, true);
339 private List<VppEndpoint> getL2Childs(ReadTransaction rTx, ParentEndpoint parentEndpoint) {
340 AddressEndpointKey addrEpKey =
341 new AddressEndpointKey(AddressEndpointUtils.fromParentEndpointKey(parentEndpoint.getKey()));
342 Optional<AddressEndpoint> optParent = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
343 IidFactory.addressEndpointIid(addrEpKey), rTx);
344 if (!optParent.isPresent() || optParent.get().getChildEndpoint() == null) {
345 return Collections.emptyList();
347 return optParent.get()
350 .filter(l2Ep -> vppEndpoints.get(VppLocationUtils.vppEndpointKeyFrom(l2Ep.getKey())) != null)
351 .map(l2Ep -> vppEndpoints.get(VppLocationUtils.vppEndpointKeyFrom(l2Ep.getKey())))
352 .collect(Collectors.toList());