Merge "FibManager module sync up"
[netvirt.git] / vpnservice / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / netvirt / fibmanager / FibUtil.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.netvirt.fibmanager;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
17 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.mdsalutil.MDSALUtil;
20 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.*;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
28         .VpnInstanceOpDataEntry;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
30         .VpnInstanceOpDataEntryKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
32
33
34
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311
36         .InterVpnLinkStates;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn
39         .link.states.InterVpnLinkState;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn
41         .link.states.InterVpnLinkStateKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn
43         .links.InterVpnLink;
44 import org.opendaylight.yangtools.yang.binding.DataObject;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.opendaylight.yangtools.yang.common.RpcResult;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import java.math.BigInteger;
51 import java.util.ArrayList;
52 import java.util.List;
53 import java.util.concurrent.ExecutionException;
54 import java.util.concurrent.Future;
55
56 public class FibUtil {
57     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
58     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
59                                                           InstanceIdentifier<T> path) {
60
61         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
62
63         Optional<T> result = Optional.absent();
64         try {
65             result = tx.read(datastoreType, path).get();
66         } catch (Exception e) {
67             throw new RuntimeException(e);
68         }
69
70         return result;
71     }
72
73     static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
74                                                   InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
75         WriteTransaction tx = broker.newWriteOnlyTransaction();
76         tx.merge(datastoreType, path, data, true);
77         Futures.addCallback(tx.submit(), callback);
78     }
79
80     static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
81                                                  InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
82         WriteTransaction tx = broker.newWriteOnlyTransaction();
83         tx.merge(datastoreType, path, data, true);
84         tx.submit();
85     }
86
87     static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
88         WriteTransaction tx = broker.newWriteOnlyTransaction();
89         tx.delete(datastoreType, path);
90         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
91     }
92
93     static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
94         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class)
95                 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface.class, new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey(vpnInterfaceName)).augmentation(
96                         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
97                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey(ipAddress)).build();
98     }
99
100     static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
101         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class)
102                 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface.class, new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey(vpnInterfaceName)).augmentation(
103                         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class).build();
104     }
105
106     static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
107         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface.class)
108                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
109                         .VpnIds.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey(vpnId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes.class,
110                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
111     }
112
113     static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
114         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class)
115                 .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface.class, new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey(vpnInterfaceName)).build();
116     }
117
118     public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
119         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData.class)
120                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey(rd))
121                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey(dpnId)).build();
122     }
123
124     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
125         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute.class)
126                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn
127                         .class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to
128                         .extraroute.VpnKey(vrfId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
129                         .rev130911.vpn.to.extraroute.vpn.Extraroute.class,
130                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey(ipPrefix)).build();
131     }
132
133     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
134         return InstanceIdentifier.builder(VpnInstanceOpData.class)
135                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
136     }
137
138     static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
139         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
140         return read(broker, LogicalDatastoreType.OPERATIONAL, id);
141     }
142
143     static String getNextHopLabelKey(String rd, String prefix){
144         String key = rd + FibConstants.SEPARATOR + prefix;
145         return key;
146     }
147
148     static void releaseId(IdManagerService idManager, String poolName, String idKey) {
149         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
150         try {
151             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
152             RpcResult<Void> rpcResult = result.get();
153             if(!rpcResult.isSuccessful()) {
154                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
155             }
156         } catch (InterruptedException | ExecutionException e) {
157             LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
158         }
159     }
160
161     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
162     getVpnInstanceToVpnIdIdentifier(String vpnName) {
163         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
164                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
165                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
166     }
167
168     public static long getVpnId(DataBroker broker, String vpnName) {
169
170         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
171                 .VpnInstance> id
172                 = getVpnInstanceToVpnIdIdentifier(vpnName);
173         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
174                 .VpnInstance> vpnInstance
175                 = read(broker, LogicalDatastoreType.CONFIGURATION, id);
176
177         long vpnId = -1;
178         if(vpnInstance.isPresent()) {
179             vpnId = vpnInstance.get().getVpnId();
180         }
181         return vpnId;
182     }
183
184     /**
185      * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher
186      *
187      * @param broker
188      * @param rd
189      * @return
190      */
191     public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
192         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = getVpnInstanceOpData(broker, rd);
193         return Optional.fromNullable(vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get().getVpnInstanceName()
194                 : null);
195     }
196
197     static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
198         InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
199
200         Optional<InterVpnLinks> interVpnLinksOpData = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
201                 interVpnLinksIid);
202
203         return ( interVpnLinksOpData.isPresent() ) ? interVpnLinksOpData.get().getInterVpnLink()
204                 : new ArrayList<InterVpnLink>();
205     }
206
207     /**
208      * Returns the instance identifier for a given vpnLinkName
209      *
210      * @param vpnLinkName
211      * @return
212      */
213     public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
214         return InstanceIdentifier.builder(InterVpnLinkStates.class).child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName)).build();
215     }
216
217     /**
218      * Checks if the InterVpnLink is in Active state
219      *
220      * @param broker
221      * @param vpnLinkName
222      * @return
223      */
224     public static boolean isInterVpnLinkActive(DataBroker broker, String vpnLinkName) {
225         Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
226         if ( !interVpnLinkState.isPresent() ) {
227             LOG.warn("Could not find Operative State for InterVpnLink {}", vpnLinkName);
228             return false;
229         }
230
231         return interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active);
232     }
233
234     /**
235      * Checks if the state of the interVpnLink
236      *
237      * @param broker
238      * @param vpnLinkName
239      * @return
240      */
241     public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String vpnLinkName) {
242         InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName);
243         return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid);
244     }
245
246     /**
247      * Retrieves the InterVpnLink in which the VPN, represented by its Uuid,
248      * participates
249      *
250      * @param dataBroker
251      * @param vpnUuid
252      * @return The InterVpnLink or Optional.absent() if the VPN does not
253      *         participate in an InterVpnLink
254      */
255     public static Optional<InterVpnLink> getInterVpnLinkByVpnUuid(DataBroker dataBroker, String vpnUuid) {
256         List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
257         for (InterVpnLink interVpnLink : interVpnLinkList) {
258             if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid)
259                     || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid)) {
260                 LOG.debug("InterVpnLink found for VPN {}. Details: vpn1=( uuid={} endpoint={})  vpn2=( uuid={} endpoint={} ))",
261                         vpnUuid, interVpnLink.getFirstEndpoint().getVpnUuid(),
262                         interVpnLink.getFirstEndpoint().getIpAddress(), interVpnLink.getSecondEndpoint().getVpnUuid(),
263                         interVpnLink.getSecondEndpoint().getIpAddress());
264                 return Optional.fromNullable(interVpnLink);
265             }
266         }
267         LOG.debug("Could not find a suitable InterVpnLink for VpnUuid={}", vpnUuid);
268         return Optional.absent();
269     }
270
271     /**
272      * Retrieves the InterVpnLink in which the VPN, represented by its
273      * Route-Distinguisher, participates.
274      *
275      * @param dataBroker
276      * @param rd
277      * @return The InterVpnLink or Optional.absent() if the VPN does not
278      *         participate in an InterVpnLink
279      */
280     public static Optional<InterVpnLink> getInterVpnLinkByRd(DataBroker dataBroker, String rd) {
281         Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
282         if ( !vpnId.isPresent() ) {
283             LOG.debug("Could not find vpnId for RouteDistinguisher {}", rd);
284             return Optional.absent();
285         }
286
287         return getInterVpnLinkByVpnUuid(dataBroker, vpnId.get());
288     }
289
290     /**
291      * Checks if the route-distinguisher is involved in any inter-vpn-link, which is returned if its found.
292      *
293      * @param dataBroker
294      * @param rd
295      * @return
296      */
297     public static Optional<InterVpnLink> getActiveInterVpnLinkFromRd(DataBroker dataBroker, String rd) {
298
299         Optional<InterVpnLink> interVpnLink = getInterVpnLinkByRd(dataBroker, rd);
300         if ( interVpnLink.isPresent() ) {
301             if ( isInterVpnLinkActive(dataBroker, interVpnLink.get().getName()) ) {
302                 return interVpnLink;
303             } else {
304                 LOG.warn("InterVpnLink for RouteDistinguisher {} exists, but it's in error state. InterVpnLink={}",
305                         rd, interVpnLink.get().getName());
306                 return Optional.absent();
307             }
308         }
309         return Optional.absent();
310     }
311
312     /**
313      * Checks if the route-distinguisher is involved in any inter-vpn-link. In that case, this method will return
314      * the endpoint of the other vpn involved in the inter-vpn-link.
315      *
316      * @param dataBroker
317      * @param rd
318      * @return
319      */
320     public static Optional<String> getInterVpnLinkOppositeEndPointIpAddress(DataBroker dataBroker, String rd) {
321         Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
322         if ( !vpnId.isPresent() ) {
323             LOG.debug("Could not find the VpnName for RouteDistinguisher {}", rd);
324             return Optional.absent();
325         }
326         List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
327         if (!interVpnLinkList.isEmpty()) {
328             for (InterVpnLink interVpnLink : interVpnLinkList) {
329                 if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnId)) {
330                     return Optional.fromNullable(interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
331                 } else if (interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(vpnId)) {
332                     return Optional.fromNullable(interVpnLink.getFirstEndpoint().getIpAddress().getValue());
333                 }
334             }
335         }
336         return Optional.absent();
337     }
338
339     /**
340      * Obtains the route-distinguisher for a given vpn-name
341      *
342      * @param broker
343      * @param vpnName
344      * @return
345      */
346     public static String getVpnRd(DataBroker broker, String vpnName) {
347         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
348                 .VpnInstance> id
349                 = getVpnInstanceToVpnIdIdentifier(vpnName);
350         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
351                 .VpnInstance> vpnInstance
352                 = read(broker, LogicalDatastoreType.CONFIGURATION, id);
353
354         String rd = null;
355         if(vpnInstance.isPresent()) {
356             rd = vpnInstance.get().getVrfId();
357         }
358         return rd;
359     }
360
361     /**
362      * Returns a boolean value which indicates if the endpoint's IP received as parameter belongs to any InterVpnLink.
363      *
364      * @param broker
365      * @param endpointIp IP to serch for.
366      * @return
367      */
368     public static boolean getInterVpnLinkByEndpointIp(DataBroker broker, String endpointIp) {
369         List<InterVpnLink> allInterVpnLinks = getAllInterVpnLinks(broker);
370         for (InterVpnLink interVpnLink : allInterVpnLinks) {
371             if (interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp)
372                     || interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(endpointIp)) {
373                 return true;
374             }
375         }
376         return false;
377     }
378
379     public static int getUniqueId(IdManagerService idManager, String poolName, String idKey) {
380         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
381
382         try {
383             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
384             RpcResult<AllocateIdOutput> rpcResult = result.get();
385             if (rpcResult.isSuccessful()) {
386                 return rpcResult.getResult().getIdValue().intValue();
387             } else {
388                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
389             }
390         } catch (InterruptedException | ExecutionException e) {
391             LOG.warn("Exception when getting Unique Id", e);
392         }
393         return 0;
394     }
395
396     static final FutureCallback<Void> DEFAULT_CALLBACK =
397             new FutureCallback<Void>() {
398                 @Override
399                 public void onSuccess(Void result) {
400                     LOG.debug("Success in Datastore operation");
401                 }
402
403                 @Override
404                 public void onFailure(Throwable error) {
405                     LOG.error("Error in Datastore operation", error);
406                 };
407             };
408
409 }