97153e2766bc02535179f55e8cd39835c129c30c
[groupbasedpolicy.git] / location-providers / ne-location-provider / src / main / java / org / opendaylight / groupbasedpolicy / ne / location / provider / NeLocationProvider.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.ne.location.provider;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.List;
15
16 import javax.annotation.Nullable;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
20 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
26 import org.opendaylight.groupbasedpolicy.util.IidFactory;
27 import org.opendaylight.groupbasedpolicy.util.NetUtils;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpoint;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocation;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.AbsoluteLocationBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.absolute.location.absolute.location.location.type.ExternalLocationCaseBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElements;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.NetworkElementsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.NetworkElement;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element.Interface;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.network.elements.rev160407.network.elements.network.element._interface.EndpointNetwork;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context;
40 import org.opendaylight.yangtools.concepts.ListenerRegistration;
41 import org.opendaylight.yangtools.yang.binding.DataObject;
42 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import com.google.common.annotations.VisibleForTesting;
47
48 public class NeLocationProvider implements DataTreeChangeListener<NetworkElements>, AutoCloseable {
49
50     private static final Logger LOG = LoggerFactory.getLogger(NeLocationProvider.class);
51     public static final String NE_LOCATION_PROVIDER_NAME = "ne-location-provider";
52
53     private List<AddressEndpoint> endpoints;
54     private NetworkElements networkElements;
55     private DataBroker dataBroker;
56     private ListenerRegistration<NeLocationProvider> listenerRegistration;
57     private EndpointsListener endpointsListener;
58
59     public NeLocationProvider(DataBroker dataBroker) {
60         this.listenerRegistration =
61                 dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
62                         InstanceIdentifier.builder(NetworkElements.class).build()), this);
63         this.endpoints = new ArrayList<>();
64         this.networkElements = new NetworkElementsBuilder().build();
65         this.dataBroker = dataBroker;
66         this.endpointsListener = new EndpointsListener(dataBroker, this);
67         LOG.info("NE location provider created");
68     }
69
70     @Override
71     public void close() {
72         this.listenerRegistration.close();
73         this.endpointsListener.close();
74     }
75
76     public synchronized void onEndpointsChange(Collection<DataTreeModification<AddressEndpoint>> changes) {
77         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
78         for (DataTreeModification<AddressEndpoint> change : changes) {
79             switch (change.getRootNode().getModificationType()) {
80                 case DELETE: {
81                     AddressEndpoint endpoint = change.getRootNode().getDataBefore();
82                     removeLocationForEndpoint(endpoint, wtx);
83                     this.endpoints.remove(endpoint);
84                     break;
85                 }
86                 case WRITE: {
87                     AddressEndpoint endpoint = change.getRootNode().getDataBefore();
88                     if (endpoint != null) {
89                         this.endpoints.remove(endpoint);
90                         this.endpoints.add(change.getRootNode().getDataAfter());
91                         break;
92                     }
93                     endpoint = change.getRootNode().getDataAfter();
94                     createLocationForEndpoint(endpoint, wtx);
95                     this.endpoints.add(endpoint);
96                     break;
97                 }
98                 case SUBTREE_MODIFIED: {
99                     this.endpoints.remove(change.getRootNode().getDataBefore());
100                     this.endpoints.add(change.getRootNode().getDataAfter());
101                     break;
102                 }
103             }
104         }
105         DataStoreHelper.submitToDs(wtx);
106     }
107
108     private void createLocationForEndpoint(AddressEndpoint endpoint, WriteTransaction wtx) {
109         for (NetworkElement ne : nullToEmpty(networkElements.getNetworkElement())) {
110             for (Interface iface : nullToEmpty(ne.getInterface())) {
111                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
112                     if (endpoint.getContextType().isAssignableFrom(L3Context.class)
113                             && endpoint.getContextId().equals(en.getL3ContextId())
114                             && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class) && NetUtils
115                                 .samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
116                         InstanceIdentifier<AbsoluteLocation> iid = IidFactory
117                             .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
118                                     endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
119                             .child(AbsoluteLocation.class);
120                         wtx.put(LogicalDatastoreType.OPERATIONAL, iid, createRealLocation(ne.getIid(), iface.getIid()),
121                                 true);
122                         LOG.debug("New location created for endpoint {}", endpoint);
123                         return;
124                     }
125                 }
126             }
127         }
128     }
129
130     private void removeLocationForEndpoint(AddressEndpoint endpoint, WriteTransaction wtx) {
131         for (NetworkElement ne : nullToEmpty(networkElements.getNetworkElement())) {
132             for (Interface iface : nullToEmpty(ne.getInterface())) {
133                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
134                     if (endpoint.getContextType().isAssignableFrom(L3Context.class)
135                             && endpoint.getContextId().equals(en.getL3ContextId())
136                             && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class) && NetUtils
137                                 .samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
138                         InstanceIdentifier<AbsoluteLocation> iid = IidFactory
139                             .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
140                                     endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
141                             .child(AbsoluteLocation.class);
142                         wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
143                         LOG.debug("Location deleted for endpoint {}", endpoint);
144                         return;
145                     }
146                 }
147             }
148         }
149     }
150
151     @Override
152     public synchronized void onDataTreeChanged(Collection<DataTreeModification<NetworkElements>> changes) {
153         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
154         for (DataTreeModification<NetworkElements> change : changes) {
155             switch (change.getRootNode().getModificationType()) {
156                 case DELETE: {
157                     NetworkElements nes = change.getRootNode().getDataBefore();
158                     for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
159                         for (Interface iface : nullToEmpty(ne.getInterface())) {
160                             for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
161                                 processDeletedEN(en, wtx);
162                             }
163                         }
164                     }
165                     networkElements = new NetworkElementsBuilder().build();
166                     LOG.debug("Network elements removed");
167                     break;
168                 }
169                 case WRITE: {
170                     NetworkElements nes = change.getRootNode().getDataBefore();
171                     if (nes != null) {
172                         for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
173                             for (Interface iface : nullToEmpty(ne.getInterface())) {
174                                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
175                                     processDeletedEN(en, wtx);
176                                 }
177                             }
178                         }
179                     }
180                     nes = change.getRootNode().getDataAfter();
181                     for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
182                         for (Interface iface : nullToEmpty(ne.getInterface())) {
183                             for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
184                                 processCreatedEN(en, ne.getIid(), iface.getIid(), wtx);
185                             }
186                         }
187                     }
188                     networkElements = nes;
189                     LOG.debug("New Network elements created {}", change.getRootNode().getDataAfter());
190                     break;
191                 }
192                 case SUBTREE_MODIFIED: {
193                     List<DataObjectModification<NetworkElement>> modifiedNetworkElements =
194                             getModifiedNetworkElements(change.getRootNode());
195                     for (DataObjectModification<NetworkElement> netElement : modifiedNetworkElements) {
196                         processNetworkElementChange(netElement, wtx);
197                     }
198                     break;
199                 }
200             }
201         }
202         DataStoreHelper.submitToDs(wtx);
203     }
204
205     private List<DataObjectModification<NetworkElement>> getModifiedNetworkElements(
206             DataObjectModification<NetworkElements> modifiedNEs) {
207         Collection<DataObjectModification<? extends DataObject>> potentialModifiedNetworkElements =
208                 modifiedNEs.getModifiedChildren();
209         if (potentialModifiedNetworkElements == null) {
210             return Collections.emptyList();
211         }
212         List<DataObjectModification<NetworkElement>> nes = new ArrayList<>();
213         for (DataObjectModification<? extends DataObject> potentialModifiedNetworkElement : potentialModifiedNetworkElements) {
214             if (potentialModifiedNetworkElement.getDataType().isAssignableFrom(NetworkElement.class)) {
215                 nes.add((DataObjectModification<NetworkElement>) potentialModifiedNetworkElement);
216             }
217         }
218         return nes;
219     }
220
221     private void processNetworkElementChange(DataObjectModification<NetworkElement> netElement, WriteTransaction wtx) {
222         switch (netElement.getModificationType()) {
223             case DELETE: {
224                 NetworkElement ne = netElement.getDataBefore();
225                 for (Interface iface : nullToEmpty(ne.getInterface())) {
226                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
227                         processDeletedEN(en, wtx);
228                     }
229                 }
230                 networkElements.getNetworkElement().remove(ne);
231                 LOG.debug("Netowrk element {} removed", netElement.getDataBefore());
232                 break;
233             }
234             case WRITE: {
235                 NetworkElement ne = netElement.getDataBefore();
236                 if (ne != null) {
237                     for (Interface iface : nullToEmpty(ne.getInterface())) {
238                         for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
239                             processDeletedEN(en, wtx);
240                         }
241                     }
242                     networkElements.getNetworkElement().remove(ne);
243                 }
244                 ne = netElement.getDataAfter();
245                 for (Interface iface : nullToEmpty(ne.getInterface())) {
246                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
247                         processCreatedEN(en, ne.getIid(), iface.getIid(), wtx);
248                     }
249                 }
250                 networkElements.getNetworkElement().add(ne);
251                 LOG.debug("Created new Network element {}", netElement.getDataAfter());
252                 break;
253             }
254             case SUBTREE_MODIFIED: {
255                 List<DataObjectModification<Interface>> modifiedInterfaces = getModifiedInterfaces(netElement);
256                 for (DataObjectModification<Interface> modifiedInterface : modifiedInterfaces) {
257                     processInterfaceChange(modifiedInterface, netElement.getDataBefore(), wtx);
258                 }
259                 break;
260             }
261         }
262     }
263
264     private List<DataObjectModification<Interface>> getModifiedInterfaces(
265             DataObjectModification<NetworkElement> netElement) {
266         Collection<DataObjectModification<? extends DataObject>> potentialModifiedInterfaces =
267                 netElement.getModifiedChildren();
268         if (potentialModifiedInterfaces == null) {
269             return Collections.emptyList();
270         }
271         List<DataObjectModification<Interface>> interfaces = new ArrayList<>();
272         for (DataObjectModification<? extends DataObject> potentialModifiedInterface : potentialModifiedInterfaces) {
273             if (potentialModifiedInterface.getDataType().isAssignableFrom(Interface.class)) {
274                 interfaces.add((DataObjectModification<Interface>) potentialModifiedInterface);
275             }
276         }
277         return interfaces;
278     }
279
280     private void processInterfaceChange(DataObjectModification<Interface> modifiedInterface,
281             NetworkElement nodeBefore, WriteTransaction wtx) {
282         switch (modifiedInterface.getModificationType()) {
283             case DELETE: {
284                 Interface iface = modifiedInterface.getDataBefore();
285                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
286                     processDeletedEN(en, wtx);
287                 }
288                 int nodeIndex = getIndexOf(nodeBefore);
289                 networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
290                 LOG.debug("Interface {} removed", modifiedInterface.getDataBefore());
291                 break;
292             }
293             case WRITE: {
294                 Interface iface = modifiedInterface.getDataBefore();
295                 int nodeIndex = getIndexOf(nodeBefore);
296                 if (iface != null) {
297                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
298                         processDeletedEN(en, wtx);
299                     }
300                     networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
301                 }
302                 iface = modifiedInterface.getDataAfter();
303                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
304                     processCreatedEN(en, nodeBefore.getIid(), iface.getIid(), wtx);
305                 }
306                 networkElements.getNetworkElement().get(nodeIndex).getInterface().add(iface);
307                 LOG.debug("Created new Interface {}", modifiedInterface.getDataAfter());
308                 break;
309             }
310             case SUBTREE_MODIFIED: {
311                 List<DataObjectModification<EndpointNetwork>> modifiedENs =
312                         getModifiedEndpointNetworks(modifiedInterface);
313                 for (DataObjectModification<EndpointNetwork> modifiedEN : modifiedENs) {
314                     processEndpointNetworkChange(modifiedEN, nodeBefore, modifiedInterface.getDataBefore(), wtx);
315                 }
316                 break;
317             }
318         }
319     }
320
321     private List<DataObjectModification<EndpointNetwork>> getModifiedEndpointNetworks(
322             DataObjectModification<Interface> modifiedInterface) {
323         Collection<DataObjectModification<? extends DataObject>> potentialModifiedEPs =
324                 modifiedInterface.getModifiedChildren();
325         if (potentialModifiedEPs == null) {
326             return Collections.emptyList();
327         }
328         List<DataObjectModification<EndpointNetwork>> eps = new ArrayList<>();
329         for (DataObjectModification<? extends DataObject> potentialModifiedEP : potentialModifiedEPs) {
330             if (potentialModifiedEP.getDataType().isAssignableFrom(EndpointNetwork.class)) {
331                 eps.add((DataObjectModification<EndpointNetwork>) potentialModifiedEP);
332             }
333         }
334         return eps;
335     }
336
337     private void processEndpointNetworkChange(DataObjectModification<EndpointNetwork> modifiedEN,
338             NetworkElement nodeBefore, Interface ifaceBefore, WriteTransaction wtx) {
339         switch (modifiedEN.getModificationType()) {
340             case DELETE: {
341                 processDeletedEN(modifiedEN.getDataBefore(), wtx);
342                 int nodeIndex = getIndexOf(nodeBefore);
343                 int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
344                 networkElements.getNetworkElement()
345                     .get(nodeIndex)
346                     .getInterface()
347                     .get(ifaceIndex)
348                     .getEndpointNetwork()
349                     .remove(modifiedEN.getDataBefore());
350                 LOG.debug("Endpoint network {} removed", modifiedEN.getDataBefore());
351                 break;
352             }
353             case WRITE: {
354                 processCreatedEN(modifiedEN.getDataAfter(), nodeBefore.getIid(), ifaceBefore.getIid(), wtx);
355                 int nodeIndex = getIndexOf(nodeBefore);
356                 int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
357                 networkElements.getNetworkElement()
358                     .get(nodeIndex)
359                     .getInterface()
360                     .get(ifaceIndex)
361                     .getEndpointNetwork()
362                     .add(modifiedEN.getDataAfter());
363                 LOG.debug("Created new Endpoint network {}", modifiedEN.getDataAfter());
364                 break;
365             }
366             case SUBTREE_MODIFIED: {
367                 LOG.debug("EndpointNetwork {} changed", modifiedEN.getDataAfter().getKey());
368                 break;
369             }
370         }
371     }
372
373     private void processCreatedEN(EndpointNetwork en, InstanceIdentifier<?> nodeIID,
374             InstanceIdentifier<?> connectorIID, WriteTransaction wtx) {
375         for (AddressEndpoint endpoint : endpoints) {
376             if (endpoint.getContextType().isAssignableFrom(L3Context.class)
377                     && endpoint.getContextId().equals(en.getL3ContextId())
378                     && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
379                     && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
380                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory
381                     .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
382                             endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
383                     .child(AbsoluteLocation.class);
384                 wtx.put(LogicalDatastoreType.OPERATIONAL, iid, createRealLocation(nodeIID, connectorIID), true);
385                 LOG.debug("New location created for endpoint {}", endpoint);
386                 return;
387             }
388         }
389     }
390
391     private void processDeletedEN(EndpointNetwork en, WriteTransaction wtx) {
392         for (AddressEndpoint endpoint : endpoints) {
393             if (endpoint.getContextType().isAssignableFrom(L3Context.class)
394                     && endpoint.getContextId().equals(en.getL3ContextId())
395                     && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
396                     && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
397                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory
398                     .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
399                             endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
400                     .child(AbsoluteLocation.class);
401                 wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
402                 LOG.debug("Location deleted for endpoint {}", endpoint);
403                 return;
404             }
405         }
406     }
407
408     private AbsoluteLocation createRealLocation(InstanceIdentifier<?> node, InstanceIdentifier<?> iface) {
409         return new AbsoluteLocationBuilder()
410             .setLocationType(new ExternalLocationCaseBuilder().setExternalNodeMountPoint(node)
411                     .setExternalNodeConnector(iface.toString()).build()).build();
412     }
413
414     private <T> List<T> nullToEmpty(@Nullable List<T> list) {
415         return list == null ? Collections.emptyList() : list;
416     }
417
418     private int getIndexOf(NetworkElement ne) {
419         for (NetworkElement listNE : networkElements.getNetworkElement()) {
420             if (ne.getIid().equals(listNE.getIid())) {
421                 return networkElements.getNetworkElement().indexOf(listNE);
422             }
423         }
424         return -1;
425     }
426
427     private int getIndexOf(Interface iface, int nodeIndex) {
428         for (Interface listIface : networkElements.getNetworkElement().get(nodeIndex).getInterface()) {
429             if (iface.getIid().equals(listIface.getIid())) {
430                 return networkElements.getNetworkElement().get(nodeIndex).getInterface().indexOf(listIface);
431             }
432         }
433         return -1;
434     }
435
436     @VisibleForTesting
437     synchronized List<AddressEndpoint> getEndpoints() {
438         return endpoints;
439     }
440
441     @VisibleForTesting
442     synchronized NetworkElements getNetworkElements() {
443         return networkElements;
444     }
445 }