Bug 7302: Enable Ping Responder for router interface IPs , on a BGPVPN
[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.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
48         .VpnInstanceOpDataEntry;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
50         .VpnInstanceOpDataEntryKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
52
53
54
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311
56         .InterVpnLinkStates;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn
59         .link.states.InterVpnLinkState;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn
61         .link.states.InterVpnLinkStateKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn
63         .links.InterVpnLink;
64 import org.opendaylight.yangtools.yang.binding.DataObject;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.RpcResult;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70 import java.math.BigInteger;
71 import java.util.ArrayList;
72 import java.util.Arrays;
73 import java.util.List;
74 import java.util.concurrent.ExecutionException;
75 import java.util.concurrent.Future;
76
77 public class FibUtil {
78     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
79     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
80                                                           InstanceIdentifier<T> path) {
81
82         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
83
84         Optional<T> result = Optional.absent();
85         try {
86             result = tx.read(datastoreType, path).get();
87         } catch (Exception e) {
88             throw new RuntimeException(e);
89         }
90
91         return result;
92     }
93
94     static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
95                                                   InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
96         WriteTransaction tx = broker.newWriteOnlyTransaction();
97         tx.merge(datastoreType, path, data, true);
98         Futures.addCallback(tx.submit(), callback);
99     }
100
101     static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
102                                                  InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
103         WriteTransaction tx = broker.newWriteOnlyTransaction();
104         tx.put(datastoreType, path, data, true);
105         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
106         try {
107             futures.get();
108         } catch (InterruptedException | ExecutionException e) {
109             LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
110             throw new RuntimeException(e.getMessage());
111         }
112     }
113
114     static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
115         WriteTransaction tx = broker.newWriteOnlyTransaction();
116         tx.delete(datastoreType, path);
117         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
118     }
119
120     static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
121         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class)
122                 .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(
123                         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
124                 .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();
125     }
126
127     static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
128         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class)
129                 .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(
130                         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class).build();
131     }
132
133     static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
134         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface.class)
135                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
136                         .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,
137                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
138     }
139
140     static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
141         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces.class)
142                 .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();
143     }
144
145     public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
146         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData.class)
147                 .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))
148                 .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();
149     }
150
151     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
152         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute.class)
153                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn
154                         .class, new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to
155                         .extraroute.VpnKey(vrfId)).child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
156                         .rev130911.vpn.to.extraroute.vpn.Extraroute.class,
157                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey(ipPrefix)).build();
158     }
159
160     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
161         return InstanceIdentifier.builder(VpnInstanceOpData.class)
162                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
163     }
164
165     static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
166         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
167         return read(broker, LogicalDatastoreType.OPERATIONAL, id);
168     }
169
170     static String getNextHopLabelKey(String rd, String prefix){
171         String key = rd + FibConstants.SEPARATOR + prefix;
172         return key;
173     }
174
175     static Prefixes getPrefixToInterface(DataBroker broker, Long vpnId, String ipPrefix) {
176         Optional<Prefixes> localNextHopInfoData = read(broker, LogicalDatastoreType.OPERATIONAL,
177                 getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
178         return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
179     }
180
181     static String getMacAddressFromPrefix(DataBroker broker, String ifName, String ipPrefix) {
182         Optional<Adjacency> adjacencyData = read(broker, LogicalDatastoreType.OPERATIONAL,
183                 getAdjacencyIdentifier(ifName, ipPrefix));
184         return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
185     }
186
187     static void releaseId(IdManagerService idManager, String poolName, String idKey) {
188         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
189         try {
190             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
191             RpcResult<Void> rpcResult = result.get();
192             if(!rpcResult.isSuccessful()) {
193                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
194             }
195         } catch (InterruptedException | ExecutionException e) {
196             LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
197         }
198     }
199
200     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance>
201     getVpnInstanceToVpnIdIdentifier(String vpnName) {
202         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
203                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance.class,
204                         new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey(vpnName)).build();
205     }
206
207     public static long getVpnId(DataBroker broker, String vpnName) {
208
209         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
210                 .VpnInstance> id
211                 = getVpnInstanceToVpnIdIdentifier(vpnName);
212         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
213                 .VpnInstance> vpnInstance
214                 = read(broker, LogicalDatastoreType.CONFIGURATION, id);
215
216         long vpnId = -1;
217         if(vpnInstance.isPresent()) {
218             vpnId = vpnInstance.get().getVpnId();
219         }
220         return vpnId;
221     }
222
223     /**
224      * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher
225      *
226      * @param broker
227      * @param rd
228      * @return
229      */
230     public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
231         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = getVpnInstanceOpData(broker, rd);
232         return Optional.fromNullable(vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get().getVpnInstanceName()
233                 : null);
234     }
235
236     static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
237         InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
238
239         Optional<InterVpnLinks> interVpnLinksOpData = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
240                                                                      interVpnLinksIid);
241
242         return interVpnLinksOpData.isPresent() ? interVpnLinksOpData.get().getInterVpnLink()
243                                                : new ArrayList<>();
244     }
245
246     /**
247      * Returns the instance identifier for a given vpnLinkName
248      *
249      * @param vpnLinkName
250      * @return
251      */
252     public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
253         return InstanceIdentifier.builder(InterVpnLinkStates.class).child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName)).build();
254     }
255
256     /**
257      * Checks if the InterVpnLink is in Active state
258      *
259      * @param broker
260      * @param vpnLinkName
261      * @return
262      */
263     public static boolean isInterVpnLinkActive(DataBroker broker, String vpnLinkName) {
264         Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
265         if ( !interVpnLinkState.isPresent() ) {
266             LOG.warn("Could not find Operative State for InterVpnLink {}", vpnLinkName);
267             return false;
268         }
269
270         return interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active);
271     }
272
273     /**
274      * Checks if the state of the interVpnLink
275      *
276      * @param broker
277      * @param vpnLinkName
278      * @return
279      */
280     public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String vpnLinkName) {
281         InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName);
282         return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid);
283     }
284
285     /**
286      * Retrieves the InterVpnLink in which the VPN, represented by its Uuid,
287      * participates
288      *
289      * @param dataBroker
290      * @param vpnUuid
291      * @return The InterVpnLink or Optional.absent() if the VPN does not
292      *         participate in an InterVpnLink
293      */
294     public static Optional<InterVpnLink> getInterVpnLinkByVpnUuid(DataBroker dataBroker, String vpnUuid) {
295         List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
296         for (InterVpnLink interVpnLink : interVpnLinkList) {
297             if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid)
298                     || interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid)) {
299                 LOG.debug("InterVpnLink found for VPN {}. Details: vpn1=( uuid={} endpoint={})  vpn2=( uuid={} endpoint={} ))",
300                         vpnUuid, interVpnLink.getFirstEndpoint().getVpnUuid(),
301                         interVpnLink.getFirstEndpoint().getIpAddress(), interVpnLink.getSecondEndpoint().getVpnUuid(),
302                         interVpnLink.getSecondEndpoint().getIpAddress());
303                 return Optional.fromNullable(interVpnLink);
304             }
305         }
306         LOG.debug("Could not find a suitable InterVpnLink for VpnUuid={}", vpnUuid);
307         return Optional.absent();
308     }
309
310     /**
311      * Retrieves the InterVpnLink in which the VPN, represented by its
312      * Route-Distinguisher, participates.
313      *
314      * @param dataBroker
315      * @param rd
316      * @return The InterVpnLink or Optional.absent() if the VPN does not
317      *         participate in an InterVpnLink
318      */
319     public static Optional<InterVpnLink> getInterVpnLinkByRd(DataBroker dataBroker, String rd) {
320         Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
321         if ( !vpnId.isPresent() ) {
322             LOG.debug("Could not find vpnId for RouteDistinguisher {}", rd);
323             return Optional.absent();
324         }
325
326         return getInterVpnLinkByVpnUuid(dataBroker, vpnId.get());
327     }
328
329     /**
330      * Checks if the route-distinguisher is involved in any inter-vpn-link, which is returned if its found.
331      *
332      * @param dataBroker
333      * @param rd
334      * @return
335      */
336     public static Optional<InterVpnLink> getActiveInterVpnLinkFromRd(DataBroker dataBroker, String rd) {
337
338         Optional<InterVpnLink> interVpnLink = getInterVpnLinkByRd(dataBroker, rd);
339         if ( interVpnLink.isPresent() ) {
340             if ( isInterVpnLinkActive(dataBroker, interVpnLink.get().getName()) ) {
341                 return interVpnLink;
342             } else {
343                 LOG.warn("InterVpnLink for RouteDistinguisher {} exists, but it's in error state. InterVpnLink={}",
344                         rd, interVpnLink.get().getName());
345                 return Optional.absent();
346             }
347         }
348         return Optional.absent();
349     }
350
351     /**
352      * Checks if the route-distinguisher is involved in any inter-vpn-link. In that case, this method will return
353      * the endpoint of the other vpn involved in the inter-vpn-link.
354      *
355      * @param dataBroker
356      * @param rd
357      * @return
358      */
359     public static Optional<String> getInterVpnLinkOppositeEndPointIpAddress(DataBroker dataBroker, String rd) {
360         Optional<String> vpnId = getVpnNameFromRd(dataBroker, rd);
361         if ( !vpnId.isPresent() ) {
362             LOG.debug("Could not find the VpnName for RouteDistinguisher {}", rd);
363             return Optional.absent();
364         }
365         List<InterVpnLink> interVpnLinkList = getAllInterVpnLinks(dataBroker);
366         if (!interVpnLinkList.isEmpty()) {
367             for (InterVpnLink interVpnLink : interVpnLinkList) {
368                 if (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnId)) {
369                     return Optional.fromNullable(interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
370                 } else if (interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(vpnId)) {
371                     return Optional.fromNullable(interVpnLink.getFirstEndpoint().getIpAddress().getValue());
372                 }
373             }
374         }
375         return Optional.absent();
376     }
377
378     /**
379      * Obtains the route-distinguisher for a given vpn-name
380      *
381      * @param broker
382      * @param vpnName
383      * @return
384      */
385     public static String getVpnRd(DataBroker broker, String vpnName) {
386         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
387                 .VpnInstance> id
388                 = getVpnInstanceToVpnIdIdentifier(vpnName);
389         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
390                 .VpnInstance> vpnInstance
391                 = read(broker, LogicalDatastoreType.CONFIGURATION, id);
392
393         String rd = null;
394         if(vpnInstance.isPresent()) {
395             rd = vpnInstance.get().getVrfId();
396         }
397         return rd;
398     }
399
400     /**
401      * Returns a boolean value which indicates if the endpoint's IP received as parameter belongs to any InterVpnLink.
402      *
403      * @param broker
404      * @param endpointIp IP to serch for.
405      * @return
406      */
407     public static boolean getInterVpnLinkByEndpointIp(DataBroker broker, String endpointIp) {
408         List<InterVpnLink> allInterVpnLinks = getAllInterVpnLinks(broker);
409         for (InterVpnLink interVpnLink : allInterVpnLinks) {
410             if (interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(endpointIp)
411                     || interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(endpointIp)) {
412                 return true;
413             }
414         }
415         return false;
416     }
417
418     public static int getUniqueId(IdManagerService idManager, String poolName, String idKey) {
419         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
420
421         try {
422             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
423             RpcResult<AllocateIdOutput> rpcResult = result.get();
424             if (rpcResult.isSuccessful()) {
425                 return rpcResult.getResult().getIdValue().intValue();
426             } else {
427                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
428             }
429         } catch (InterruptedException | ExecutionException e) {
430             LOG.warn("Exception when getting Unique Id", e);
431         }
432         return 0;
433     }
434
435     static final FutureCallback<Void> DEFAULT_CALLBACK =
436             new FutureCallback<Void>() {
437                 @Override
438                 public void onSuccess(Void result) {
439                     LOG.debug("Success in Datastore operation");
440                 }
441
442                 @Override
443                 public void onFailure(Throwable error) {
444                     LOG.error("Error in Datastore operation", error);
445                 };
446             };
447
448     public static String getVpnNameFromId(DataBroker broker, long vpnId) {
449
450         InstanceIdentifier<VpnIds> id
451                 = getVpnIdToVpnInstanceIdentifier(vpnId);
452         Optional<VpnIds> vpnInstance
453                 = read(broker, LogicalDatastoreType.CONFIGURATION, id);
454
455         String vpnName = null;
456         if (vpnInstance.isPresent()) {
457             vpnName = vpnInstance.get().getVpnInstanceName();
458         }
459         return vpnName;
460     }
461
462     static InstanceIdentifier<VpnIds>
463     getVpnIdToVpnInstanceIdentifier(long vpnId) {
464         return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
465                 .child(VpnIds.class, new VpnIdsKey(Long.valueOf(vpnId))).build();
466     }
467
468     public static <T extends DataObject> void syncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
469                                                          InstanceIdentifier<T> path, T data) {
470         WriteTransaction tx = broker.newWriteOnlyTransaction();
471         tx.put(datastoreType, path, data, true);
472         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
473         try {
474             futures.get();
475         } catch (InterruptedException | ExecutionException e) {
476             LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
477             throw new RuntimeException(e.getMessage());
478         }
479     }
480
481     public static void addOrUpdateFibEntry(DataBroker broker, String rd, String prefix, List<String> nextHopList,
482                                            int label, RouteOrigin origin, WriteTransaction writeConfigTxn) {
483         if (rd == null || rd.isEmpty() ) {
484             LOG.error("Prefix {} not associated with vpn", prefix);
485             return;
486         }
487
488         Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
489
490         try{
491             InstanceIdentifier<VrfEntry> vrfEntryId =
492                     InstanceIdentifier.builder(FibEntries.class)
493                             .child(VrfTables.class, new VrfTablesKey(rd))
494                             .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
495             Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
496
497             if (! entry.isPresent()) {
498                 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(nextHopList)
499                         .setLabel((long)label).setOrigin(origin.getValue()).build();
500
501                 if (writeConfigTxn != null) {
502                     writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
503                 } else {
504                     MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
505                 }
506                 LOG.debug("Created vrfEntry for {} nexthop {} label {}", prefix, nextHopList, label);
507             } else { // Found in MDSAL database
508                 List<String> nh = entry.get().getNextHopAddressList();
509                 for (String nextHop : nextHopList) {
510                     if (!nh.contains(nextHop)) {
511                         nh.add(nextHop);
512                     }
513                 }
514                 VrfEntry vrfEntry = new VrfEntryBuilder().setDestPrefix(prefix).setNextHopAddressList(nh)
515                         .setLabel((long) label).setOrigin(origin.getValue()).build();
516
517                 if (writeConfigTxn != null) {
518                     writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
519                 } else {
520                     MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
521                 }
522                 LOG.debug("Updated vrfEntry for {} nexthop {} label {}", prefix, nh, label);
523             }
524         } catch (Exception e) {
525             LOG.error("addFibEntryToDS: error ", e);
526         }
527     }
528
529     public static void addFibEntryForRouterInterface(DataBroker broker,
530                                                      String rd,
531                                                      String prefix,
532                                                      RouterInterface routerInterface,
533                                                      long label,
534                                                      WriteTransaction writeConfigTxn) {
535         if (rd == null || rd.isEmpty() ) {
536             LOG.error("Prefix {} not associated with vpn", prefix);
537             return;
538         }
539
540         try{
541             InstanceIdentifier<VrfEntry> vrfEntryId =
542                     InstanceIdentifier.builder(FibEntries.class)
543                             .child(VrfTables.class, new VrfTablesKey(rd))
544                             .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
545
546             VrfEntry vrfEntry = new VrfEntryBuilder().setKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
547                     .setNextHopAddressList(Arrays.asList(""))
548                     .setLabel(label)
549                     .setOrigin(RouteOrigin.LOCAL.getValue())
550                     .addAugmentation(RouterInterface.class, routerInterface).build();
551
552             if (writeConfigTxn != null) {
553                 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
554             } else {
555                 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
556             }
557             LOG.debug("Created vrfEntry for router-interface-prefix {} rd {} label {}", prefix, rd, label);
558         } catch (Exception e) {
559             LOG.error("addFibEntryToDS: error ", e);
560         }
561     }
562
563     public static void removeFibEntry(DataBroker broker, String rd, String prefix, WriteTransaction writeConfigTxn) {
564
565         if (rd == null || rd.isEmpty()) {
566             LOG.error("Prefix {} not associated with vpn", prefix);
567             return;
568         }
569         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
570
571         InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
572                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
573         InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
574         if (writeConfigTxn != null) {
575             writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
576         } else {
577             MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
578         }
579     }
580
581     /**
582      * Removes a specific Nexthop from a VrfEntry. If Nexthop to remove is the
583      * last one in the VrfEntry, then the VrfEntry is removed too.
584      *
585      * @param broker dataBroker service reference
586      * @param rd Route-Distinguisher to which the VrfEntry belongs to
587      * @param prefix Destination of the route
588      * @param nextHopToRemove Specific nexthop within the Route to be removed.
589      *           If null or empty, then the whole VrfEntry is removed
590      */
591     public static void removeOrUpdateFibEntry(DataBroker broker, String rd, String prefix, String nextHopToRemove,
592                                               WriteTransaction writeConfigTxn) {
593
594         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
595
596         // Looking for existing prefix in MDSAL database
597         InstanceIdentifier<VrfEntry> vrfEntryId =
598                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
599                         .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
600         Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
601
602         if ( entry.isPresent() ) {
603             List<String> nhListRead = new ArrayList<>();
604             if ( nextHopToRemove != null && !nextHopToRemove.isEmpty()) {
605                 nhListRead = entry.get().getNextHopAddressList();
606                 if (nhListRead.contains(nextHopToRemove)) {
607                     nhListRead.remove(nextHopToRemove);
608                 }
609             }
610
611             if (nhListRead.isEmpty()) {
612                 // Remove the whole entry
613                 if (writeConfigTxn != null) {
614                     writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
615                 } else {
616                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
617                 }
618                 LOG.info("Removed Fib Entry rd {} prefix {}", rd, prefix);
619             } else {
620                 // An update must be done, not including the current next hop
621                 VrfEntry vrfEntry =
622                         new VrfEntryBuilder(entry.get()).setDestPrefix(prefix).setNextHopAddressList(nhListRead)
623                                 .setKey(new VrfEntryKey(prefix)).build();
624                 if (writeConfigTxn != null) {
625                     writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
626                 } else {
627                     MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
628                 }
629                 LOG.info("Removed Nexthop {} from Fib Entry rd {} prefix {}", nextHopToRemove, rd, prefix);
630             }
631         } else {
632             LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
633         }
634     }
635
636     public static void updateFibEntry(DataBroker broker, String rd, String prefix, List<String> nextHopList,
637                                       WriteTransaction writeConfigTxn) {
638
639         LOG.debug("Updating fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
640
641         // Looking for existing prefix in MDSAL database
642         InstanceIdentifier<VrfEntry> vrfEntryId =
643                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
644                         .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
645         Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
646
647         if ( entry.isPresent() ) {
648             // Update the VRF entry with nextHopList
649             VrfEntry vrfEntry =
650                     new VrfEntryBuilder(entry.get()).setDestPrefix(prefix).setNextHopAddressList(nextHopList)
651                             .setKey(new VrfEntryKey(prefix)).build();
652             if(nextHopList.isEmpty()) {
653                 if (writeConfigTxn != null) {
654                     writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
655                 } else {
656                     MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
657                 }
658             } else {
659                 if (writeConfigTxn != null) {
660                     writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
661                 } else {
662                     MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
663                 }
664             }
665             LOG.debug("Updated fib entry for prefix {} with nextHopList {} for rd {}", prefix, nextHopList, rd);
666         } else {
667             LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
668         }
669     }
670
671     public static void addVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
672         LOG.debug("Adding vrf table for rd {}", rd);
673         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
674                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
675         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
676         VrfTablesBuilder vrfTablesBuilder = new VrfTablesBuilder().setKey(new VrfTablesKey(rd)).setRouteDistinguisher(rd).setVrfEntry(new ArrayList<VrfEntry>());
677         if (writeConfigTxn != null) {
678             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build());
679         } else {
680             syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build(), FibUtil.DEFAULT_CALLBACK);
681         }
682
683     }
684
685     public static void removeVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
686         LOG.debug("Removing vrf table for rd {}", rd);
687         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
688                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
689         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
690
691         if (writeConfigTxn != null) {
692             writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfTableId);
693         } else {
694             delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
695         }
696     }
697
698     public static boolean isControllerManagedRoute(RouteOrigin routeOrigin) {
699         if (routeOrigin == RouteOrigin.STATIC ||
700                 routeOrigin == RouteOrigin.CONNECTED ||
701                 routeOrigin == RouteOrigin.LOCAL ||
702                 routeOrigin == RouteOrigin.INTERVPN) {
703             return true;
704         }
705         return false;
706     }
707
708     public static boolean isControllerManagedNonInterVpnLinkRoute(RouteOrigin routeOrigin)
709     {
710         if (routeOrigin == RouteOrigin.STATIC ||
711                 routeOrigin == RouteOrigin.CONNECTED ||
712                 routeOrigin == RouteOrigin.LOCAL) {
713             return true;
714         }
715         return false;
716     }
717 }