Bug 8221 - Remove Wait Time To Install L3VPN Groups on OVS
[netvirt.git] / vpnservice / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / netvirt / fibmanager / FibUtil.java
1 /*
2  * Copyright © 2016, 2017 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 static java.util.stream.Collectors.joining;
12 import static java.util.stream.Collectors.toList;
13
14 import com.google.common.base.Optional;
15 import com.google.common.base.Preconditions;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19
20 import java.math.BigInteger;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.Future;
26
27 import org.apache.commons.lang3.tuple.ImmutablePair;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.genius.mdsalutil.BucketInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.NwConstants;
36 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
37 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
38 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
39 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
40 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.extraroute.rds.map.extraroute.rds.DestPrefixesBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.extraroute.rds.map.extraroute.rds.DestPrefixesKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.DpidL3vpnLbNexthops;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.L3vpnLbNexthops;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthops;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpid.l3vpn.lb.nexthops.DpnLbNexthopsKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.Nexthops;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsKey;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkStates;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
109 import org.opendaylight.yangtools.yang.binding.DataObject;
110 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
111 import org.opendaylight.yangtools.yang.common.RpcResult;
112 import org.slf4j.Logger;
113 import org.slf4j.LoggerFactory;
114
115 public class FibUtil {
116     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
117
118     // TODO Clean up the exception handling
119     @SuppressWarnings("checkstyle:IllegalCatch")
120     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
121                                                           InstanceIdentifier<T> path) {
122
123         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
124
125         Optional<T> result = Optional.absent();
126         try {
127             result = tx.read(datastoreType, path).get();
128         } catch (Exception e) {
129             throw new RuntimeException(e);
130         }
131
132         return result;
133     }
134
135     static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
136                                                   InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
137         WriteTransaction tx = broker.newWriteOnlyTransaction();
138         tx.merge(datastoreType, path, data, true);
139         Futures.addCallback(tx.submit(), callback);
140     }
141
142     static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
143                                                  InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
144         WriteTransaction tx = broker.newWriteOnlyTransaction();
145         tx.put(datastoreType, path, data, true);
146         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
147         try {
148             futures.get();
149         } catch (InterruptedException | ExecutionException e) {
150             LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
151             throw new RuntimeException(e.getMessage());
152         }
153     }
154
155     static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
156                                               InstanceIdentifier<T> path) {
157         WriteTransaction tx = broker.newWriteOnlyTransaction();
158         tx.delete(datastoreType, path);
159         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
160     }
161
162     static InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
163         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang
164             .l3vpn.rev140815.VpnInterfaces.class)
165             .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
166                 .VpnInterface.class,
167                 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
168                     .VpnInterfaceKey(vpnInterfaceName))
169             .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
170             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.class,
171                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list
172                     .AdjacencyKey(ipAddress)).build();
173     }
174
175     static InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
176         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
177             .rev140815.VpnInterfaces.class)
178             .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
179                 .VpnInterface.class,
180                 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
181                     .VpnInterfaceKey(vpnInterfaceName))
182             .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies.class)
183             .build();
184     }
185
186     static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
187         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
188             .rev130911.PrefixToInterface.class)
189             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
190                 .VpnIds.class,
191                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
192                     .VpnIdsKey(vpnId))
193             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
194                     .vpn.ids.Prefixes.class,
195                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to
196                     ._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
197     }
198
199     static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
200         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn
201             .rev140815.VpnInterfaces.class)
202             .child(org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
203                 .VpnInterface.class,
204                 new org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces
205                     .VpnInterfaceKey(vpnInterfaceName)).build();
206     }
207
208     public static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
209         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
210             .rev130911.VpnInstanceOpData.class)
211             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
212                 .VpnInstanceOpDataEntry.class,
213                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
214                     .VpnInstanceOpDataEntryKey(rd))
215             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
216                 .vpn.instance.op.data.entry.VpnToDpnList.class,
217                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
218                     .vpn.instance.op.data.entry.VpnToDpnListKey(dpnId)).build();
219     }
220
221     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
222         return InstanceIdentifier.builder(VpnInstanceOpData.class)
223             .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
224     }
225
226     static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(DataBroker broker, String rd) {
227         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
228         return read(broker, LogicalDatastoreType.OPERATIONAL, id);
229     }
230
231     static String getNextHopLabelKey(String rd, String prefix) {
232         String key = rd + FibConstants.SEPARATOR + prefix;
233         return key;
234     }
235
236     static Prefixes getPrefixToInterface(DataBroker broker, Long vpnId, String ipPrefix) {
237         Optional<Prefixes> localNextHopInfoData = read(broker, LogicalDatastoreType.OPERATIONAL,
238             getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
239         return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
240     }
241
242     static String getMacAddressFromPrefix(DataBroker broker, String ifName, String ipPrefix) {
243         Optional<Adjacency> adjacencyData = read(broker, LogicalDatastoreType.OPERATIONAL,
244             getAdjacencyIdentifier(ifName, ipPrefix));
245         return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
246     }
247
248     static void releaseId(IdManagerService idManager, String poolName, String idKey) {
249         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
250         try {
251             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
252             RpcResult<Void> rpcResult = result.get();
253             if (!rpcResult.isSuccessful()) {
254                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
255             }
256         } catch (InterruptedException | ExecutionException e) {
257             LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
258         }
259     }
260
261     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
262         .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
263         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
264             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
265                     .VpnInstance.class,
266                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
267                     .VpnInstanceKey(vpnName)).build();
268     }
269
270     public static long getVpnId(DataBroker broker, String vpnName) {
271
272         InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
273         return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVpnId).or(-1L);
274     }
275
276     /**
277      * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher.
278      *
279      * @param broker The DataBroker
280      * @param rd The route-distinguisher
281      * @return The vpn instance
282      */
283     public static Optional<String> getVpnNameFromRd(DataBroker broker, String rd) {
284         return getVpnInstanceOpData(broker, rd).transform(VpnInstanceOpDataEntry::getVpnInstanceName);
285     }
286
287     static List<InterVpnLink> getAllInterVpnLinks(DataBroker broker) {
288         InstanceIdentifier<InterVpnLinks> interVpnLinksIid = InstanceIdentifier.builder(InterVpnLinks.class).build();
289
290         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinksIid).transform(
291             InterVpnLinks::getInterVpnLink).or(new ArrayList<>());
292     }
293
294     /**
295      * Returns the instance identifier for a given vpnLinkName.
296      *
297      * @param vpnLinkName The vpn link name
298      * @return InstanceIdentifier
299      */
300     public static InstanceIdentifier<InterVpnLinkState> getInterVpnLinkStateIid(String vpnLinkName) {
301         return InstanceIdentifier.builder(InterVpnLinkStates.class)
302             .child(InterVpnLinkState.class, new InterVpnLinkStateKey(vpnLinkName)).build();
303     }
304
305     /**
306      * Checks if the InterVpnLink is in Active state.
307      *
308      * @param broker The DataBroker
309      * @param vpnLinkName The vpn linkname
310      * @return The link state
311      */
312     public static boolean isInterVpnLinkActive(DataBroker broker, String vpnLinkName) {
313         Optional<InterVpnLinkState> interVpnLinkState = getInterVpnLinkState(broker, vpnLinkName);
314         if (!interVpnLinkState.isPresent()) {
315             LOG.warn("Could not find Operative State for InterVpnLink {}", vpnLinkName);
316             return false;
317         }
318
319         return interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active);
320     }
321
322     /**
323      * Checks if the state of the interVpnLink.
324      *
325      * @param broker The DataBroker
326      * @param vpnLinkName The vpn linkname
327      * @return The link state
328      */
329     public static Optional<InterVpnLinkState> getInterVpnLinkState(DataBroker broker, String vpnLinkName) {
330         InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = getInterVpnLinkStateIid(vpnLinkName);
331         return read(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid);
332     }
333
334     /**
335      * Obtains the route-distinguisher for a given vpn-name.
336      *
337      * @param broker The DataBroker
338      * @param vpnName vpn name
339      * @return route-distinguisher
340      */
341     public static String getVpnRd(DataBroker broker, String vpnName) {
342         InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
343         return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnInstance::getVrfId).orNull();
344     }
345
346     public static int getUniqueId(IdManagerService idManager, String poolName, String idKey) {
347         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
348
349         try {
350             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
351             RpcResult<AllocateIdOutput> rpcResult = result.get();
352             if (rpcResult.isSuccessful()) {
353                 return rpcResult.getResult().getIdValue().intValue();
354             } else {
355                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
356             }
357         } catch (InterruptedException | ExecutionException e) {
358             LOG.warn("Exception when getting Unique Id", e);
359         }
360         return 0;
361     }
362
363     static final FutureCallback<Void> DEFAULT_CALLBACK =
364         new FutureCallback<Void>() {
365             @Override
366             public void onSuccess(Void result) {
367                 LOG.debug("Success in Datastore operation");
368             }
369
370             @Override
371             public void onFailure(Throwable error) {
372                 LOG.error("Error in Datastore operation", error);
373             }
374
375             ;
376         };
377
378     public static String getVpnNameFromId(DataBroker broker, long vpnId) {
379         InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
380         return read(broker, LogicalDatastoreType.CONFIGURATION, id).transform(VpnIds::getVpnInstanceName).orNull();
381     }
382
383     static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(long vpnId) {
384         return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
385             .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
386     }
387
388     public static <T extends DataObject> void syncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
389                                                          InstanceIdentifier<T> path, T data) {
390         WriteTransaction tx = broker.newWriteOnlyTransaction();
391         tx.put(datastoreType, path, data, true);
392         CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
393         try {
394             futures.get();
395         } catch (InterruptedException | ExecutionException e) {
396             LOG.error("Error writing to datastore (path, data) : ({}, {})", path, data, e);
397             throw new RuntimeException(e.getMessage());
398         }
399     }
400
401     // TODO Clean up the exception handling
402     @SuppressWarnings("checkstyle:IllegalCatch")
403     public static void addOrUpdateFibEntry(DataBroker broker, String rd, String macAddress, String prefix,
404                                            List<String> nextHopList, VrfEntry.EncapType encapType, long label,
405                                            long l3vni, String gwMacAddress, String parentVpnRd, RouteOrigin origin,
406                                            WriteTransaction writeConfigTxn) {
407         if (rd == null || rd.isEmpty()) {
408             LOG.error("Prefix {} not associated with vpn", prefix);
409             return;
410         }
411
412         Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
413
414         try {
415             InstanceIdentifier<VrfEntry> vrfEntryId =
416                 InstanceIdentifier.builder(FibEntries.class)
417                     .child(VrfTables.class, new VrfTablesKey(rd))
418                     .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
419
420             writeFibEntryToDs(vrfEntryId, prefix, nextHopList, label, l3vni, encapType, origin, macAddress,
421                     gwMacAddress, parentVpnRd, writeConfigTxn, broker);
422             LOG.debug("Created/Updated vrfEntry for {} nexthop {} label {}", prefix, nextHopList, label);
423         } catch (Exception e) {
424             LOG.error("addFibEntryToDS: error ", e);
425         }
426     }
427
428     // TODO Clean up the exception handling
429     @SuppressWarnings("checkstyle:IllegalCatch")
430     public static void writeFibEntryToDs(InstanceIdentifier<VrfEntry> vrfEntryId, String prefix,
431                                          List<String> nextHopList, long label, Long l3vni,
432                                          VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
433                                          String gatewayMacAddress, String parentVpnRd,
434                                          WriteTransaction writeConfigTxn, DataBroker broker) {
435         VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setOrigin(origin.getValue());
436         if (parentVpnRd != null) {
437             vrfEntryBuilder.setParentVpnRd(parentVpnRd);
438         }
439         buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni, macAddress, gatewayMacAddress, nextHopList);
440         if (writeConfigTxn != null) {
441             writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build(), true);
442         } else {
443             MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
444         }
445     }
446
447     @SuppressWarnings("checkstyle:IllegalCatch")
448     public static void addFibEntryForRouterInterface(DataBroker broker,
449                                                      String rd,
450                                                      String prefix,
451                                                      RouterInterface routerInterface,
452                                                      long label,
453                                                      WriteTransaction writeConfigTxn) {
454         if (rd == null || rd.isEmpty()) {
455             LOG.error("Prefix {} not associated with vpn", prefix);
456             return;
457         }
458
459         try {
460             InstanceIdentifier<VrfEntry> vrfEntryId =
461                 InstanceIdentifier.builder(FibEntries.class)
462                     .child(VrfTables.class, new VrfTablesKey(rd))
463                     .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
464
465             // Filling the nextHop with dummy nextHopAddress
466             VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label,
467                     FibConstants.DEFAULT_NEXTHOP_IP, RouteOrigin.LOCAL, null /* parentVpnRd */)
468                 .addAugmentation(RouterInterface.class, routerInterface).build();
469
470             if (writeConfigTxn != null) {
471                 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry, true);
472             } else {
473                 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
474             }
475             LOG.debug("Created vrfEntry for router-interface-prefix {} rd {} label {}", prefix, rd, label);
476         } catch (Exception e) {
477             LOG.error("addFibEntryToDS: error ", e);
478         }
479     }
480
481     private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, long label,
482                                          long l3vni, String macAddress, String gatewayMac, List<String> nextHopList) {
483         if (encapType == null) {
484             builder.setMac(macAddress);
485             return;
486         }
487         //if (!encapType.equals(VrfEntry.EncapType.Mplsgre)) {
488         // TODO - validate this check
489         if (l3vni != 0) {
490             builder.setL3vni(l3vni);
491         }
492         builder.setEncapType(encapType);
493         builder.setGatewayMacAddress(gatewayMac);
494         builder.setMac(macAddress);
495         Long lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
496         List<RoutePaths> routePaths = nextHopList.stream()
497                         .filter(nextHop -> nextHop != null && !nextHop.isEmpty())
498                         .map(nextHop -> {
499                             return FibHelper.buildRoutePath(nextHop, lbl);
500                         }).collect(toList());
501         builder.setRoutePaths(routePaths);
502     }
503
504     public static void removeFibEntry(DataBroker broker, String rd, String prefix, WriteTransaction writeConfigTxn) {
505
506         if (rd == null || rd.isEmpty()) {
507             LOG.error("Prefix {} not associated with vpn", prefix);
508             return;
509         }
510         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
511
512         InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
513             InstanceIdentifier.builder(FibEntries.class)
514                 .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class, new VrfEntryKey(prefix));
515         InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
516         if (writeConfigTxn != null) {
517             writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
518         } else {
519             MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
520         }
521     }
522
523     /**
524      * Removes a specific Nexthop from a VrfEntry. If Nexthop to remove is the
525      * last one in the VrfEntry, then the VrfEntry is removed too.
526      *
527      * @param broker          dataBroker service reference
528      * @param rd              Route-Distinguisher to which the VrfEntry belongs to
529      * @param prefix          Destination of the route
530      * @param nextHopToRemove Specific nexthop within the Route to be removed.
531      *                        If null or empty, then the whole VrfEntry is removed
532      */
533     public static void removeOrUpdateFibEntry(DataBroker broker, String rd, String prefix, String nextHopToRemove,
534                                               WriteTransaction writeConfigTxn) {
535
536         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {}", prefix, rd);
537
538         // Looking for existing prefix in MDSAL database
539         InstanceIdentifier<VrfEntry> vrfEntryId =
540             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
541                 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
542         Optional<VrfEntry> entry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
543         if (entry.isPresent()) {
544             final List<RoutePaths> routePaths = entry.get().getRoutePaths();
545             if (routePaths == null || routePaths.isEmpty()) {
546                 LOG.warn("routePaths is null/empty for given rd {}, prefix {}", rd, prefix);
547                 return;
548             }
549             java.util.Optional<RoutePaths> optRoutePath =
550                     routePaths.stream()
551                               .filter(routePath -> routePath.getNexthopAddress().equals(
552                                     nextHopToRemove)).findFirst();
553             if (!optRoutePath.isPresent()) {
554                 LOG.error("Unable to find a routePath that contains the given nextHop to remove {}", nextHopToRemove);
555                 return;
556             }
557             RoutePaths routePath = optRoutePath.get();
558             if (routePaths.size() == 1) {
559                 // Remove the whole entry
560                 if (writeConfigTxn != null) {
561                     writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfEntryId);
562                 } else {
563                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
564                 }
565                 LOG.info("Removed Fib Entry rd {} prefix {}", rd, prefix);
566             } else {
567                 InstanceIdentifier<RoutePaths> routePathsId =
568                         FibHelper.buildRoutePathId(rd, prefix, routePath.getNexthopAddress());
569                 // Remove route
570                 if (writeConfigTxn != null) {
571                     writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, routePathsId);
572                 } else {
573                     MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathsId);
574                 }
575                 LOG.info("Removed Route Path rd {} prefix {}, nextHop {}, label {}", rd, prefix,
576                         routePath.getNexthopAddress(), routePath.getLabel());
577             }
578         } else {
579             LOG.warn("Could not find VrfEntry for Route-Distinguisher={} and prefix={}", rd, prefix);
580         }
581     }
582
583     /**
584      * Adds or removes nextHop from routePath based on the flag nextHopAdd.
585      */
586     public static void updateRoutePathForFibEntry(DataBroker broker, String rd, String prefix, String nextHop,
587                                       long label, boolean nextHopAdd, WriteTransaction writeConfigTxn) {
588
589         LOG.debug("Updating fib entry for prefix {} with nextHop {} for rd {}.", prefix, nextHop, rd);
590
591         InstanceIdentifier<RoutePaths> routePathId = FibHelper.buildRoutePathId(rd, prefix, nextHop);
592         if (nextHopAdd) {
593             RoutePaths routePaths = FibHelper.buildRoutePath(nextHop, label);
594             if (writeConfigTxn != null) {
595                 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, routePathId, routePaths, true);
596             } else {
597                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, routePathId, routePaths);
598             }
599             LOG.debug("Added routepath with nextHop {} for prefix {} and label {}.", nextHop, prefix, label);
600         } else {
601             Optional<RoutePaths> routePath = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, routePathId);
602             if (!routePath.isPresent()) {
603                 LOG.warn("Couldn't find RoutePath with rd {}, prefix {} and nh {} for deleting", rd, prefix, nextHop);
604                 return;
605             }
606             if (writeConfigTxn != null) {
607                 writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, routePathId);
608             } else {
609                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, routePathId);
610             }
611             LOG.info("Removed routepath with nextHop {} for prefix {} and rd {}.", nextHop, prefix, rd);
612         }
613     }
614
615     public static void addVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
616         LOG.debug("Adding vrf table for rd {}", rd);
617         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
618             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
619         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
620         VrfTablesBuilder vrfTablesBuilder = new VrfTablesBuilder().setKey(new VrfTablesKey(rd))
621             .setRouteDistinguisher(rd).setVrfEntry(new ArrayList<>());
622         if (writeConfigTxn != null) {
623             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build());
624         } else {
625             syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build(),
626                 FibUtil.DEFAULT_CALLBACK);
627         }
628
629     }
630
631     public static void removeVrfTable(DataBroker broker, String rd, WriteTransaction writeConfigTxn) {
632         LOG.debug("Removing vrf table for rd {}", rd);
633         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
634             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
635         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
636
637         if (writeConfigTxn != null) {
638             writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vrfTableId);
639         } else {
640             delete(broker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
641         }
642     }
643
644     public static java.util.Optional<Long> getLabelFromRoutePaths(final VrfEntry vrfEntry) {
645         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
646         if (routePaths == null || routePaths.isEmpty() || vrfEntry.getRoutePaths().get(0).getLabel() == null) {
647             return java.util.Optional.empty();
648         }
649         return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getLabel());
650     }
651
652     public static java.util.Optional<String> getFirstNextHopAddress(final VrfEntry vrfEntry) {
653         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
654         if (routePaths == null || routePaths.isEmpty()) {
655             return java.util.Optional.empty();
656         }
657         return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getNexthopAddress());
658     }
659
660     public static java.util.Optional<Long> getLabelForNextHop(final VrfEntry vrfEntry, String nextHopIp) {
661         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
662         if (routePaths == null || routePaths.isEmpty()) {
663             return java.util.Optional.empty();
664         }
665         return routePaths.stream()
666                 .filter(routePath -> routePath.getNexthopAddress().equals(nextHopIp))
667                 .findFirst()
668                 .map(routePath -> java.util.Optional.of(routePath.getLabel()))
669                 .orElse(java.util.Optional.empty());
670     }
671
672     public static InstanceIdentifier<Interface> buildStateInterfaceId(String interfaceName) {
673         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
674                 InstanceIdentifier.builder(InterfacesState.class)
675                         .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
676                                 .interfaces.state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf
677                                 .params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
678                                 .InterfaceKey(interfaceName));
679         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
680                 .interfaces.state.Interface> id = idBuilder.build();
681         return id;
682     }
683
684     public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
685         .state.Interface getInterfaceStateFromOperDS(DataBroker dataBroker, String interfaceName) {
686         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
687             .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
688         Optional<Interface> ifStateOptional = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
689         if (ifStateOptional.isPresent()) {
690             return ifStateOptional.get();
691         }
692
693         return null;
694     }
695
696     public static String getCreateLocalNextHopJobKey(Long vpnId, BigInteger dpnId, String prefix) {
697         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + prefix;
698     }
699
700     public static void updateUsedRdAndVpnToExtraRoute(WriteTransaction writeOperTxn, DataBroker broker,
701                                                       String nextHopToRemove, String primaryRd, String prefix) {
702         Optional<VpnInstanceOpDataEntry> optVpnInstance = getVpnInstanceOpData(broker, primaryRd);
703         if (!optVpnInstance.isPresent()) {
704             return;
705         }
706         VpnInstanceOpDataEntry vpnInstance = optVpnInstance.get();
707         String vpnName = vpnInstance.getVpnInstanceName();
708         long vpnId = vpnInstance.getVpnId();
709         List<String> usedRds = VpnExtraRouteHelper.getUsedRds(broker, vpnId, prefix);
710         // To identify the rd to be removed, iterate through the allocated rds for the prefix and check
711         // which rd is allocated for the particular OVS.
712         java.util.Optional<String> rdToRemove = usedRds.stream()
713                 .map(usedRd -> {
714                     Optional<Routes> vpnExtraRoutes = VpnExtraRouteHelper
715                             .getVpnExtraroutes(broker, vpnName, usedRd, prefix);
716                     // Since all the nexthops under one OVS will be present under one rd, only 1 nexthop is read
717                     // to identify the OVS
718                     return vpnExtraRoutes.isPresent() ? new ImmutablePair<String, String>(
719                             vpnExtraRoutes.get().getNexthopIpList().get(0),
720                             usedRd) : new ImmutablePair<String, String>("", "");
721                 })
722                 .filter(pair -> {
723                     if (pair.getLeft().isEmpty()) {
724                         return false;
725                     }
726                     Prefixes prefixToInterface = getPrefixToInterface(broker, vpnId, getIpPrefix(pair.getLeft()));
727                     return prefixToInterface != null ? nextHopToRemove
728                             .equals(getEndpointIpAddressForDPN(broker, prefixToInterface.getDpnId())) : false;
729                 })
730                 .map(pair -> pair.getRight()).findFirst();
731         if (!rdToRemove.isPresent()) {
732             return;
733         }
734         Optional<Routes> optRoutes = VpnExtraRouteHelper.getVpnExtraroutes(broker, vpnName, rdToRemove.get(), prefix);
735         if (!optRoutes.isPresent()) {
736             return;
737         }
738         Prefixes prefixToInterface = getPrefixToInterface(broker, vpnId,
739                 getIpPrefix(optRoutes.get().getNexthopIpList().get(0)));
740         if (prefixToInterface != null) {
741             writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
742                     getAdjacencyIdentifier(prefixToInterface.getVpnInterfaceName(), prefix));
743         }
744         writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
745                 VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, rdToRemove.get(), prefix));
746         usedRds.remove(rdToRemove.get());
747         writeOperTxn.put(LogicalDatastoreType.CONFIGURATION,
748                 VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix),
749                 getDestPrefixesBuilder(prefix, usedRds).build());
750     }
751
752     private static String getEndpointIpAddressForDPN(DataBroker broker, BigInteger dpnId) {
753         //TODO: Move it to a common place for vpn and fib
754         String nextHopIp = null;
755         InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
756             InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
757         Optional<DPNTEPsInfo> tunnelInfo = read(broker, LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
758         if (tunnelInfo.isPresent()) {
759             List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
760             if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
761                 nextHopIp = String.valueOf(nexthopIpList.get(0).getIpAddress().getValue());
762             }
763         }
764         return nextHopIp;
765     }
766
767     public static DestPrefixesBuilder getDestPrefixesBuilder(String destPrefix, List<String> rd) {
768         return new DestPrefixesBuilder().setKey(new DestPrefixesKey(destPrefix)).setDestPrefix(destPrefix).setRds(rd);
769     }
770
771     public static String getIpPrefix(String prefix) {
772         String[] prefixValues = prefix.split(FibConstants.PREFIX_SEPARATOR);
773         if (prefixValues.length == 1) {
774             prefix = prefix + NwConstants.IPV4PREFIX;
775         }
776         return prefix;
777     }
778
779     public static boolean isTunnelInterface(AdjacencyResult adjacencyResult) {
780         return Tunnel.class.equals(adjacencyResult.getInterfaceType());
781     }
782
783     public static Optional<Routes> getLastRoutePathExtraRouteIfPresent(DataBroker dataBroker, Long vpnId,
784             String rd, String prefix) {
785         List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, prefix);
786         String vpnName = getVpnNameFromId(dataBroker, vpnId);
787         if (usedRds == null || usedRds.isEmpty()) {
788             LOG.debug("No used rd found for prefix {} on vpn {}", prefix, vpnName);
789             return Optional.absent();
790         } else if (usedRds.size() > 1) {
791             LOG.debug("The extra route prefix is still present in some DPNs");
792             return Optional.absent();
793         } else {
794             rd = usedRds.get(0);
795         }
796         //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
797         return VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
798                 getVpnNameFromId(dataBroker, vpnId), rd, prefix);
799     }
800
801     public static InstanceIdentifier<VrfEntry> getNextHopIdentifier(String rd, String prefix) {
802         return InstanceIdentifier.builder(FibEntries.class)
803                 .child(VrfTables.class,new VrfTablesKey(rd)).child(VrfEntry.class,new VrfEntryKey(prefix)).build();
804     }
805
806     public static List<String> getNextHopAddresses(DataBroker broker, String rd, String prefix) {
807         InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, prefix);
808         Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
809         if (vrfEntry.isPresent()) {
810             return FibHelper.getNextHopListFromRoutePaths(vrfEntry.get());
811         } else {
812             return Collections.emptyList();
813         }
814     }
815
816     public static Optional<String> getGatewayMac(DataBroker dataBroker, String rd, String localNextHopIP) {
817         InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, localNextHopIP);
818         Optional<VrfEntry> vrfEntry = read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
819         if (vrfEntry.isPresent()) {
820             return Optional.fromNullable(vrfEntry.get().getGatewayMacAddress());
821         } else {
822             return Optional.absent();
823         }
824     }
825
826     public static Subnetmap getSubnetMap(DataBroker broker, Uuid subnetId) {
827         InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier.builder(Subnetmaps.class)
828             .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
829         return read(broker, LogicalDatastoreType.CONFIGURATION, subnetmapId).orNull();
830     }
831
832     public static String getGreLbGroupKey(List<String> availableDcGws) {
833         Preconditions.checkNotNull(availableDcGws, "AvailableDcGws is null");
834         return "gre-" + availableDcGws.stream().sorted().collect(joining(":"));
835     }
836
837     public static void updateLbGroupInfo(BigInteger dpnId, String destinationIp, String groupIdKey,
838             String groupId, WriteTransaction tx) {
839         InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
840         DpnLbNexthops dpnToLbNextHop = buildDpnLbNextHops(dpnId, destinationIp, groupIdKey);
841         tx.merge(LogicalDatastoreType.OPERATIONAL, id, dpnToLbNextHop);
842         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(groupIdKey);
843         Nexthops nextHopsToGroupId = buildNextHops(dpnId, groupIdKey, groupId);
844         tx.merge(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
845     }
846
847     public static void removeDpnIdToNextHopInfo(String destinationIp, BigInteger dpnId, WriteTransaction tx) {
848         InstanceIdentifier<DpnLbNexthops> id = getDpnLbNexthopsIdentifier(dpnId, destinationIp);
849         tx.delete(LogicalDatastoreType.OPERATIONAL, id);
850     }
851
852     public static void removeOrUpdateNextHopInfo(BigInteger dpnId, String nextHopKey, String groupId,
853             Nexthops nexthops, WriteTransaction tx) {
854         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(nextHopKey);
855         List<String> targetDeviceIds = nexthops.getTargetDeviceId();
856         targetDeviceIds.remove(dpnId.toString());
857         if (targetDeviceIds.size() == 0) {
858             tx.delete(LogicalDatastoreType.OPERATIONAL, nextHopsId);
859         } else {
860             Nexthops nextHopsToGroupId = new NexthopsBuilder().setKey(new NexthopsKey(nextHopKey))
861                 .setNexthopKey(nextHopKey)
862                 .setGroupId(groupId)
863                 .setTargetDeviceId(targetDeviceIds).build();
864             tx.put(LogicalDatastoreType.OPERATIONAL, nextHopsId, nextHopsToGroupId);
865         }
866     }
867
868     private static InstanceIdentifier<DpnLbNexthops> getDpnLbNexthopsIdentifier(BigInteger dpnId,
869             String destinationIp) {
870         return InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
871                 .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
872                 .build();
873     }
874
875     private static InstanceIdentifier<Nexthops> getNextHopsIdentifier(String groupIdKey) {
876         return InstanceIdentifier.builder(L3vpnLbNexthops.class)
877                 .child(Nexthops.class, new NexthopsKey(groupIdKey)).build();
878     }
879
880     private static Nexthops buildNextHops(BigInteger dpnId, String groupIdKey, String groupId) {
881         return new NexthopsBuilder().setKey(new NexthopsKey(groupIdKey))
882                 .setNexthopKey(groupIdKey)
883                 .setGroupId(groupId)
884                 .setTargetDeviceId(Collections.singletonList(dpnId.toString())).build();
885     }
886
887     private static DpnLbNexthops buildDpnLbNextHops(BigInteger dpnId, String destinationIp,
888             String groupIdKey) {
889         return new DpnLbNexthopsBuilder().setKey(new DpnLbNexthopsKey(destinationIp, dpnId))
890                 .setDstDeviceId(destinationIp).setSrcDpId(dpnId)
891                 .setNexthopKey(Collections.singletonList(groupIdKey)).build();
892     }
893
894     public static Optional<Nexthops> getNexthops(DataBroker dataBroker, String nextHopKey) {
895         InstanceIdentifier<Nexthops> nextHopsId = InstanceIdentifier.builder(L3vpnLbNexthops.class)
896                 .child(Nexthops.class, new NexthopsKey(nextHopKey)).build();
897         return read(dataBroker, LogicalDatastoreType.OPERATIONAL, nextHopsId);
898     }
899
900     public static Optional<DpnLbNexthops> getDpnLbNexthops(DataBroker dataBroker, BigInteger dpnId,
901             String destinationIp) {
902         InstanceIdentifier<DpnLbNexthops> id = InstanceIdentifier.builder(DpidL3vpnLbNexthops.class)
903                 .child(DpnLbNexthops.class, new DpnLbNexthopsKey(destinationIp, dpnId))
904                 .build();
905         return read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
906     }
907
908     static NodeRef buildNodeRef(BigInteger dpId) {
909         return new NodeRef(InstanceIdentifier.builder(Nodes.class)
910                 .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId))).build());
911     }
912
913     static InstanceIdentifier<Group> buildGroupInstanceIdentifier(long groupId, BigInteger dpId) {
914         InstanceIdentifier<Group> groupInstanceId = InstanceIdentifier.builder(Nodes.class)
915                 .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId))).augmentation(FlowCapableNode.class)
916                 .child(Group.class, new GroupKey(new GroupId(groupId))).build();
917         return groupInstanceId;
918     }
919
920     static Buckets buildBuckets(List<BucketInfo> listBucketInfo) {
921         long index = 0;
922         BucketsBuilder bucketsBuilder = new BucketsBuilder();
923         if (listBucketInfo != null) {
924             List<Bucket> bucketList = new ArrayList<>();
925
926             for (BucketInfo bucketInfo : listBucketInfo) {
927                 BucketBuilder bucketBuilder = new BucketBuilder();
928                 bucketBuilder.setAction(bucketInfo.buildActions());
929                 bucketBuilder.setWeight(bucketInfo.getWeight());
930                 bucketBuilder.setBucketId(new BucketId(index++));
931                 bucketBuilder.setWeight(bucketInfo.getWeight()).setWatchPort(bucketInfo.getWatchPort())
932                         .setWatchGroup(bucketInfo.getWatchGroup());
933                 bucketList.add(bucketBuilder.build());
934             }
935
936             bucketsBuilder.setBucket(bucketList);
937         }
938         return bucketsBuilder.build();
939     }
940 }