Containment endpoint can only have relative location
[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                             .build();
119                         wtx.put(LogicalDatastoreType.OPERATIONAL, iid, createRealLocation(ne.getIid(), iface.getIid()),
120                                 true);
121                         wtx.submit();
122                         LOG.debug("New location created for endpoint {}", endpoint);
123                         return;
124                     }
125                 }
126             }
127         }
128     }
129
130     private void removeLocationForEndpoint(AddressEndpoint endpoint) {
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                         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
139                         InstanceIdentifier<AbsoluteLocation> iid = IidFactory
140                             .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
141                                     endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
142                             .child(AbsoluteLocation.class)
143                             .build();
144                         wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
145                         wtx.submit();
146                         LOG.debug("Location deleted for endpoint {}", endpoint);
147                         return;
148                     }
149                 }
150             }
151         }
152     }
153
154     @Override
155     public synchronized void onDataTreeChanged(Collection<DataTreeModification<NetworkElements>> changes) {
156         for (DataTreeModification<NetworkElements> change : changes) {
157             switch (change.getRootNode().getModificationType()) {
158                 case DELETE: {
159                     NetworkElements nes = change.getRootNode().getDataBefore();
160                     for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
161                         for (Interface iface : nullToEmpty(ne.getInterface())) {
162                             for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
163                                 processDeletedEN(en);
164                             }
165                         }
166                     }
167                     networkElements = new NetworkElementsBuilder().build();
168                     LOG.debug("Network elements removed");
169                     break;
170                 }
171                 case WRITE: {
172                     NetworkElements nes = change.getRootNode().getDataBefore();
173                     if (nes != null) {
174                         for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
175                             for (Interface iface : nullToEmpty(ne.getInterface())) {
176                                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
177                                     processDeletedEN(en);
178                                 }
179                             }
180                         }
181                     }
182                     nes = change.getRootNode().getDataAfter();
183                     for (NetworkElement ne : nullToEmpty(nes.getNetworkElement())) {
184                         for (Interface iface : nullToEmpty(ne.getInterface())) {
185                             for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
186                                 processCreatedEN(en, ne.getIid(), iface.getIid());
187                             }
188                         }
189                     }
190                     networkElements = nes;
191                     LOG.debug("New Network elements created {}", change.getRootNode().getDataAfter());
192                     break;
193                 }
194                 case SUBTREE_MODIFIED: {
195                     List<DataObjectModification<NetworkElement>> modifiedNetworkElements =
196                             getModifiedNetworkElements(change.getRootNode());
197                     for (DataObjectModification<NetworkElement> netElement : modifiedNetworkElements) {
198                         processNetworkElementChange(netElement);
199                     }
200                     break;
201                 }
202             }
203         }
204     }
205
206     private List<DataObjectModification<NetworkElement>> getModifiedNetworkElements(
207             DataObjectModification<NetworkElements> modifiedNEs) {
208         Collection<DataObjectModification<? extends DataObject>> potentialModifiedNetworkElements =
209                 modifiedNEs.getModifiedChildren();
210         if (potentialModifiedNetworkElements == null) {
211             return Collections.emptyList();
212         }
213         List<DataObjectModification<NetworkElement>> nes = new ArrayList<>();
214         for (DataObjectModification<? extends DataObject> potentialModifiedNetworkElement : potentialModifiedNetworkElements) {
215             if (potentialModifiedNetworkElement.getDataType().isAssignableFrom(NetworkElement.class)) {
216                 nes.add((DataObjectModification<NetworkElement>) potentialModifiedNetworkElement);
217             }
218         }
219         return nes;
220     }
221
222     private void processNetworkElementChange(DataObjectModification<NetworkElement> netElement) {
223         switch (netElement.getModificationType()) {
224             case DELETE: {
225                 NetworkElement ne = netElement.getDataBefore();
226                 for (Interface iface : nullToEmpty(ne.getInterface())) {
227                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
228                         processDeletedEN(en);
229                     }
230                 }
231                 networkElements.getNetworkElement().remove(ne);
232                 LOG.debug("Netowrk element {} removed", netElement.getDataBefore());
233                 break;
234             }
235             case WRITE: {
236                 NetworkElement ne = netElement.getDataBefore();
237                 if (ne != null) {
238                     for (Interface iface : nullToEmpty(ne.getInterface())) {
239                         for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
240                             processDeletedEN(en);
241                         }
242                     }
243                     networkElements.getNetworkElement().remove(ne);
244                 }
245                 ne = netElement.getDataAfter();
246                 for (Interface iface : nullToEmpty(ne.getInterface())) {
247                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
248                         processCreatedEN(en, ne.getIid(), iface.getIid());
249                     }
250                 }
251                 networkElements.getNetworkElement().add(ne);
252                 LOG.debug("Created new Network element {}", netElement.getDataAfter());
253                 break;
254             }
255             case SUBTREE_MODIFIED: {
256                 List<DataObjectModification<Interface>> modifiedInterfaces = getModifiedInterfaces(netElement);
257                 for (DataObjectModification<Interface> modifiedInterface : modifiedInterfaces) {
258                     processInterfaceChange(modifiedInterface, netElement.getDataBefore());
259                 }
260                 break;
261             }
262         }
263     }
264
265     private List<DataObjectModification<Interface>> getModifiedInterfaces(
266             DataObjectModification<NetworkElement> netElement) {
267         Collection<DataObjectModification<? extends DataObject>> potentialModifiedInterfaces =
268                 netElement.getModifiedChildren();
269         if (potentialModifiedInterfaces == null) {
270             return Collections.emptyList();
271         }
272         List<DataObjectModification<Interface>> interfaces = new ArrayList<>();
273         for (DataObjectModification<? extends DataObject> potentialModifiedInterface : potentialModifiedInterfaces) {
274             if (potentialModifiedInterface.getDataType().isAssignableFrom(Interface.class)) {
275                 interfaces.add((DataObjectModification<Interface>) potentialModifiedInterface);
276             }
277         }
278         return interfaces;
279     }
280
281     private void processInterfaceChange(DataObjectModification<Interface> modifiedInterface,
282             NetworkElement nodeBefore) {
283         switch (modifiedInterface.getModificationType()) {
284             case DELETE: {
285                 Interface iface = modifiedInterface.getDataBefore();
286                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
287                     processDeletedEN(en);
288                 }
289                 int nodeIndex = getIndexOf(nodeBefore);
290                 networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
291                 LOG.debug("Interface {} removed", modifiedInterface.getDataBefore());
292                 break;
293             }
294             case WRITE: {
295                 Interface iface = modifiedInterface.getDataBefore();
296                 int nodeIndex = getIndexOf(nodeBefore);
297                 if (iface != null) {
298                     for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
299                         processDeletedEN(en);
300                     }
301                     networkElements.getNetworkElement().get(nodeIndex).getInterface().remove(iface);
302                 }
303                 iface = modifiedInterface.getDataAfter();
304                 for (EndpointNetwork en : nullToEmpty(iface.getEndpointNetwork())) {
305                     processCreatedEN(en, nodeBefore.getIid(), iface.getIid());
306                 }
307                 networkElements.getNetworkElement().get(nodeIndex).getInterface().add(iface);
308                 LOG.debug("Created new Interface {}", modifiedInterface.getDataAfter());
309                 break;
310             }
311             case SUBTREE_MODIFIED: {
312                 List<DataObjectModification<EndpointNetwork>> modifiedENs =
313                         getModifiedEndpointNetworks(modifiedInterface);
314                 for (DataObjectModification<EndpointNetwork> modifiedEN : modifiedENs) {
315                     processEndpointNetworkChange(modifiedEN, nodeBefore, modifiedInterface.getDataBefore());
316                 }
317                 break;
318             }
319         }
320     }
321
322     private List<DataObjectModification<EndpointNetwork>> getModifiedEndpointNetworks(
323             DataObjectModification<Interface> modifiedInterface) {
324         Collection<DataObjectModification<? extends DataObject>> potentialModifiedEPs =
325                 modifiedInterface.getModifiedChildren();
326         if (potentialModifiedEPs == null) {
327             return Collections.emptyList();
328         }
329         List<DataObjectModification<EndpointNetwork>> eps = new ArrayList<>();
330         for (DataObjectModification<? extends DataObject> potentialModifiedEP : potentialModifiedEPs) {
331             if (potentialModifiedEP.getDataType().isAssignableFrom(EndpointNetwork.class)) {
332                 eps.add((DataObjectModification<EndpointNetwork>) potentialModifiedEP);
333             }
334         }
335         return eps;
336     }
337
338     private void processEndpointNetworkChange(DataObjectModification<EndpointNetwork> modifiedEN,
339             NetworkElement nodeBefore, Interface ifaceBefore) {
340         switch (modifiedEN.getModificationType()) {
341             case DELETE: {
342                 processDeletedEN(modifiedEN.getDataBefore());
343                 int nodeIndex = getIndexOf(nodeBefore);
344                 int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
345                 networkElements.getNetworkElement()
346                     .get(nodeIndex)
347                     .getInterface()
348                     .get(ifaceIndex)
349                     .getEndpointNetwork()
350                     .remove(modifiedEN.getDataBefore());
351                 LOG.debug("Endpoint network {} removed", modifiedEN.getDataBefore());
352                 break;
353             }
354             case WRITE: {
355                 processCreatedEN(modifiedEN.getDataAfter(), nodeBefore.getIid(), ifaceBefore.getIid());
356                 int nodeIndex = getIndexOf(nodeBefore);
357                 int ifaceIndex = getIndexOf(ifaceBefore, nodeIndex);
358                 networkElements.getNetworkElement()
359                     .get(nodeIndex)
360                     .getInterface()
361                     .get(ifaceIndex)
362                     .getEndpointNetwork()
363                     .add(modifiedEN.getDataAfter());
364                 LOG.debug("Created new Endpoint network {}", modifiedEN.getDataAfter());
365                 break;
366             }
367             case SUBTREE_MODIFIED: {
368                 LOG.debug("EndpointNetwork {} changed", modifiedEN.getDataAfter().getKey());
369                 break;
370             }
371         }
372     }
373
374     private void processCreatedEN(EndpointNetwork en, InstanceIdentifier<?> nodeIID,
375             InstanceIdentifier<?> connectorIID) {
376         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
377         for (AddressEndpoint endpoint : endpoints) {
378             if (endpoint.getContextType().isAssignableFrom(L3Context.class)
379                     && endpoint.getContextId().equals(en.getL3ContextId())
380                     && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
381                     && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
382                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory
383                     .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
384                             endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
385                     .child(AbsoluteLocation.class)
386                     .build();
387                 wtx.put(LogicalDatastoreType.OPERATIONAL, iid, createRealLocation(nodeIID, connectorIID), true);
388                 wtx.submit();
389                 LOG.debug("New location created for endpoint {}", endpoint);
390                 return;
391             }
392         }
393     }
394
395     private void processDeletedEN(EndpointNetwork en) {
396         WriteTransaction wtx = dataBroker.newWriteOnlyTransaction();
397         for (AddressEndpoint endpoint : endpoints) {
398             if (endpoint.getContextType().isAssignableFrom(L3Context.class)
399                     && endpoint.getContextId().equals(en.getL3ContextId())
400                     && endpoint.getAddressType().isAssignableFrom(IpPrefixType.class)
401                     && NetUtils.samePrefix(new IpPrefix(endpoint.getAddress().toCharArray()), en.getIpPrefix())) {
402                 InstanceIdentifier<AbsoluteLocation> iid = IidFactory
403                     .providerAddressEndpointLocationIid(NE_LOCATION_PROVIDER_NAME, IpPrefixType.class,
404                             endpoint.getAddress(), endpoint.getContextType(), endpoint.getContextId())
405                     .child(AbsoluteLocation.class)
406                     .build();
407                 wtx.delete(LogicalDatastoreType.OPERATIONAL, iid);
408                 wtx.submit();
409                 LOG.debug("Location deleted for endpoint {}", endpoint);
410                 return;
411             }
412         }
413     }
414
415     private AbsoluteLocation createRealLocation(InstanceIdentifier<?> node, InstanceIdentifier<?> iface) {
416         return new AbsoluteLocationBuilder()
417             .setLocationType(new InternalLocationCaseBuilder().setInternalNode(node).setInternalNodeConnector(iface).build()).build();
418     }
419
420     private <T> List<T> nullToEmpty(@Nullable List<T> list) {
421         return list == null ? Collections.emptyList() : list;
422     }
423
424     private int getIndexOf(NetworkElement ne) {
425         for (NetworkElement listNE : networkElements.getNetworkElement()) {
426             if (ne.getIid().equals(listNE.getIid())) {
427                 return networkElements.getNetworkElement().indexOf(listNE);
428             }
429         }
430         return -1;
431     }
432
433     private int getIndexOf(Interface iface, int nodeIndex) {
434         for (Interface listIface : networkElements.getNetworkElement().get(nodeIndex).getInterface()) {
435             if (iface.getIid().equals(listIface.getIid())) {
436                 return networkElements.getNetworkElement().get(nodeIndex).getInterface().indexOf(listIface);
437             }
438         }
439         return -1;
440     }
441
442     @VisibleForTesting
443     synchronized List<AddressEndpoint> getEndpoints() {
444         return endpoints;
445     }
446
447     @VisibleForTesting
448     synchronized NetworkElements getNetworkElements() {
449         return networkElements;
450     }
451 }