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