8531ed324716330bf65ce784a1d71147e5f608b7
[netvirt.git] / 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 import static org.opendaylight.mdsal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
14
15 import com.google.common.base.Preconditions;
16 import com.google.common.net.InetAddresses;
17 import java.net.InetAddress;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Objects;
22 import java.util.Optional;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Future;
25 import java.util.concurrent.locks.ReentrantLock;
26 import javax.inject.Inject;
27 import javax.inject.Singleton;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.opendaylight.genius.datastoreutils.ExpectedDataObjectNotFoundException;
30 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
31 import org.opendaylight.genius.infra.Datastore.Configuration;
32 import org.opendaylight.genius.infra.Datastore.Operational;
33 import org.opendaylight.genius.infra.TypedReadTransaction;
34 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
35 import org.opendaylight.genius.infra.TypedWriteTransaction;
36 import org.opendaylight.genius.itm.api.IITMProvider;
37 import org.opendaylight.genius.mdsalutil.BucketInfo;
38 import org.opendaylight.genius.mdsalutil.MDSALUtil;
39 import org.opendaylight.genius.mdsalutil.NWUtil;
40 import org.opendaylight.genius.mdsalutil.NwConstants;
41 import org.opendaylight.genius.utils.JvmGlobalLocks;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.binding.api.WriteTransaction;
44 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
45 import org.opendaylight.mdsal.common.api.ReadFailedException;
46 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
47 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
48 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
49 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.Tunnel;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfoKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TimeUnits;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInputBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockOutput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.L3vpnDcGws;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.L3vpnLbNexthops;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.dc.gws.DcGateway;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.dc.gws.DcGatewayBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.dc.gws.DcGatewayKey;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.Nexthops;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.l3vpn.lb.nexthops.NexthopsKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
120 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
121 import org.opendaylight.yangtools.yang.common.RpcResult;
122 import org.opendaylight.yangtools.yang.common.Uint32;
123 import org.opendaylight.yangtools.yang.common.Uint64;
124 import org.slf4j.Logger;
125 import org.slf4j.LoggerFactory;
126
127 @Singleton
128 public class FibUtil {
129     private static final Logger LOG = LoggerFactory.getLogger(FibUtil.class);
130     private static final String FLOWID_PREFIX = "L3.";
131
132     private final DataBroker dataBroker;
133     private final IdManagerService idManager;
134     private final IITMProvider iitmProvider;
135
136     @Inject
137     public FibUtil(DataBroker dataBroker, IdManagerService idManager, IITMProvider iitmProvider) {
138         this.dataBroker = dataBroker;
139         this.idManager = idManager;
140         this.iitmProvider = iitmProvider;
141     }
142
143     static InstanceIdentifier<Adjacency> getAdjacencyIdentifierOp(String vpnInterfaceName,
144                                       String vpnName, String ipAddress) {
145         LOG.debug("getAdjacencyIdentifierOp vpninterface {} vpn {} ip {}", vpnInterfaceName, vpnName, ipAddress);
146         return getAdjListPathOp(vpnInterfaceName, vpnName).builder()
147                           .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204
148                                           .adjacency.list.Adjacency.class,
149                           new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204
150                                   .adjacency.list.AdjacencyKey(ipAddress)).build();
151     }
152
153     static InstanceIdentifier<AdjacenciesOp> getAdjListPathOp(String vpnInterfaceName, String vpnName) {
154         return getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, vpnName).builder()
155             .augmentation(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911
156             .AdjacenciesOp.class).build();
157     }
158
159     static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Uint32 vpnId, String ipPrefix) {
160         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn
161             .rev130911.PrefixToInterface.class)
162             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
163                 .VpnIds.class,
164                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
165                     .VpnIdsKey(vpnId))
166             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface
167                     .vpn.ids.Prefixes.class,
168                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to
169                     ._interface.vpn.ids.PrefixesKey(ipPrefix)).build();
170     }
171
172     static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
173                        String vpnInterfaceName, String vpnName) {
174         return InstanceIdentifier.builder(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911
175             .VpnInterfaceOpData.class)
176             .child(VpnInterfaceOpDataEntry.class,
177                 new VpnInterfaceOpDataEntryKey(vpnInterfaceName, vpnName)).build();
178     }
179
180     static InstanceIdentifier<VpnInstanceOpDataEntry> getVpnInstanceOpDataIdentifier(String rd) {
181         return InstanceIdentifier.builder(VpnInstanceOpData.class)
182             .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)).build();
183     }
184
185     Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(String rd) {
186         InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnInstanceOpDataIdentifier(rd);
187         try {
188             return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
189         } catch (ExecutionException | InterruptedException e) {
190             LOG.error("getVpnInstance: Exception while reading the VpnInstanceOpData DS for the rd {} ", rd, e);
191         }
192         return Optional.empty();
193     }
194
195     static Optional<VpnInstanceOpDataEntry> getVpnInstanceOpData(TypedReadTransaction<Operational> operTx, String rd)
196         throws ExecutionException, InterruptedException {
197         return operTx.read(getVpnInstanceOpDataIdentifier(rd)).get();
198     }
199
200     @Nullable
201     VpnInstanceOpDataEntry getVpnInstance(String rd) {
202         InstanceIdentifier<VpnInstanceOpDataEntry> id =
203                 InstanceIdentifier.create(VpnInstanceOpData.class)
204                         .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
205         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = Optional.empty();
206         try {
207             vpnInstanceOpData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
208                     LogicalDatastoreType.OPERATIONAL, id);
209         } catch (ExecutionException | InterruptedException e) {
210             LOG.error("getVpnInstance: Exception while reading the VpnInstanceOpData DS for the rd {} ", rd, e);
211         }
212         return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
213     }
214
215     static String getNextHopLabelKey(String rd, String prefix) {
216         return rd + FibConstants.SEPARATOR + prefix;
217     }
218
219     @Nullable
220     Prefixes getPrefixToInterface(Uint32 vpnId, String ipPrefix) {
221         Optional<Prefixes> localNextHopInfoData = Optional.empty();
222         try {
223             localNextHopInfoData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
224                     LogicalDatastoreType.OPERATIONAL,
225                 getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
226         } catch (ExecutionException | InterruptedException e) {
227             LOG.error("getPrefixToInterface: Exception while reading the prefixToInterface DS for the "
228                     + "prefix {} vpnId {}", ipPrefix, vpnId, e);
229         }
230         return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
231     }
232
233     @Nullable
234     static Prefixes getPrefixToInterface(TypedReadTransaction<Operational> operTx, Uint32 vpnId, String ipPrefix)
235             throws ExecutionException, InterruptedException {
236         return operTx.read(getPrefixToInterfaceIdentifier(vpnId, ipPrefix)).get().orElse(null);
237     }
238
239     @Nullable
240     String getMacAddressFromPrefix(String ifName, String vpnName, String ipPrefix) {
241         Optional<Adjacency> adjacencyData;
242         try {
243             adjacencyData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
244                     LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifierOp(ifName, vpnName, ipPrefix));
245         } catch (ExecutionException | InterruptedException e) {
246             LOG.error("getMacAddressFromPrefix: Exception while reading adj-op DS for the interface {} prefix {} "
247                     + "vpn {}", ifName, ipPrefix, vpnName, e);
248             return null;
249         }
250         return adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
251     }
252
253     void releaseId(String poolName, String idKey) {
254         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
255         try {
256             RpcResult<ReleaseIdOutput> rpcResult = idManager.releaseId(idInput).get();
257             if (!rpcResult.isSuccessful()) {
258                 LOG.error("RPC Call to Get Unique Id for key {} returned with Errors {}", idKey, rpcResult.getErrors());
259             }
260         } catch (InterruptedException | ExecutionException e) {
261             LOG.warn("Exception when getting Unique Id for key {}", idKey, e);
262         }
263     }
264
265     static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
266         .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
267         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
268             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
269                     .VpnInstance.class,
270                 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
271                     .VpnInstanceKey(vpnName)).build();
272     }
273
274     public Uint32 getVpnId(String vpnName) {
275         InstanceIdentifier<VpnInstance> id = getVpnInstanceToVpnIdIdentifier(vpnName);
276         try {
277             return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id)
278                     .map(VpnInstance::getVpnId).orElse(Uint32.ZERO);
279         } catch (ExecutionException | InterruptedException e) {
280             LOG.error("getVpnNameFromId: Exception while reading vpnInstanceToVpnId DS for the vpn {}", vpnName, e);
281         }
282         return Uint32.ZERO;
283     }
284
285     /**
286      * Retrieves the VpnInstance name (typically the VPN Uuid) out from the route-distinguisher.
287      * @param rd The route-distinguisher
288      *
289      * @return The vpn instance
290      */
291     public Optional<String> getVpnNameFromRd(String rd) {
292         return Optional.ofNullable(getVpnInstanceOpData(rd).map(VpnInstanceOpDataEntry::getVpnInstanceName)
293                 .orElse(null));
294     }
295
296     @Nullable
297     public String getVpnNameFromId(Uint32 vpnId) {
298         InstanceIdentifier<VpnIds> id = getVpnIdToVpnInstanceIdentifier(vpnId);
299         try {
300             return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id)
301                     .map(VpnIds::getVpnInstanceName).orElse(null);
302         } catch (ExecutionException | InterruptedException e) {
303             LOG.error("getVpnNameFromId: Exception while reading vpnIdToVpnInstance DS for the vpnId {}", vpnId, e);
304         }
305         return null;
306     }
307
308     static InstanceIdentifier<VpnIds> getVpnIdToVpnInstanceIdentifier(Uint32 vpnId) {
309         return InstanceIdentifier.builder(VpnIdToVpnInstance.class)
310             .child(VpnIds.class, new VpnIdsKey(vpnId)).build();
311     }
312
313     // TODO Clean up the exception handling
314     @SuppressWarnings("checkstyle:IllegalCatch")
315     public void addOrUpdateFibEntry(String rd, String macAddress, String prefix, List<String> nextHopList,
316             VrfEntry.EncapType encapType, Uint32 label, Uint32 l3vni, String gwMacAddress, String parentVpnRd,
317             RouteOrigin origin, TypedWriteTransaction<Configuration> writeConfigTxn) {
318         if (rd == null || rd.isEmpty()) {
319             LOG.error("Prefix {} not associated with vpn", prefix);
320             return;
321         }
322
323         Preconditions.checkNotNull(nextHopList, "NextHopList can't be null");
324
325         try {
326             InstanceIdentifier<VrfEntry> vrfEntryId =
327                 InstanceIdentifier.builder(FibEntries.class)
328                     .child(VrfTables.class, new VrfTablesKey(rd))
329                     .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
330
331             writeFibEntryToDs(vrfEntryId, prefix, nextHopList, label, l3vni, encapType, origin, macAddress,
332                     gwMacAddress, parentVpnRd, writeConfigTxn);
333             LOG.info("addOrUpdateFibEntry: Created/Updated vrfEntry for rd {} prefix {} nexthop {} label {} l3vni {}"
334                     + " origin {} encapType {}", rd, prefix, nextHopList, label, l3vni, origin, encapType);
335         } catch (Exception e) {
336             LOG.error("addOrUpdateFibEntry: rd {} prefix {} nexthop {} label {} l3vni {} origin {} encapType {}"
337                     + " error ", rd, prefix, nextHopList, label, l3vni, origin, encapType, e);
338         }
339     }
340
341     // TODO Clean up the exception handling
342     @SuppressWarnings("checkstyle:IllegalCatch")
343     public void writeFibEntryToDs(InstanceIdentifier<VrfEntry> vrfEntryId, String prefix, List<String> nextHopList,
344             Uint32 label, Uint32 l3vni, VrfEntry.EncapType encapType, RouteOrigin origin, String macAddress,
345             String gatewayMacAddress, String parentVpnRd, TypedWriteTransaction<Configuration> writeConfigTxn) {
346         VrfEntryBuilder vrfEntryBuilder = new VrfEntryBuilder().setDestPrefix(prefix).setOrigin(origin.getValue());
347         if (parentVpnRd != null) {
348             vrfEntryBuilder.setParentVpnRd(parentVpnRd);
349         }
350         buildVpnEncapSpecificInfo(vrfEntryBuilder, encapType, label, l3vni, macAddress, gatewayMacAddress, nextHopList);
351         if (writeConfigTxn != null) {
352             writeConfigTxn.merge(vrfEntryId, vrfEntryBuilder.build(), CREATE_MISSING_PARENTS);
353         } else {
354             MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntryBuilder.build());
355         }
356     }
357
358     @SuppressWarnings("checkstyle:IllegalCatch")
359     public void addFibEntryForRouterInterface(String rd, String prefix, RouterInterface routerInterface, Uint32 label,
360             TypedWriteTransaction<Configuration> writeConfigTxn) {
361         if (rd == null || rd.isEmpty()) {
362             LOG.error("Prefix {} not associated with vpn", prefix);
363             return;
364         }
365
366         try {
367             InstanceIdentifier<VrfEntry> vrfEntryId =
368                 InstanceIdentifier.builder(FibEntries.class)
369                     .child(VrfTables.class, new VrfTablesKey(rd))
370                     .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
371
372             // Filling the nextHop with dummy nextHopAddress
373             VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label,
374                     FibConstants.DEFAULT_NEXTHOP_IP, RouteOrigin.LOCAL, null /* parentVpnRd */)
375                 .addAugmentation(RouterInterface.class, routerInterface).build();
376
377             if (writeConfigTxn != null) {
378                 writeConfigTxn.merge(vrfEntryId, vrfEntry, CREATE_MISSING_PARENTS);
379             } else {
380                 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId, vrfEntry);
381             }
382             LOG.debug("Created vrfEntry for router-interface-prefix {} rd {} label {}", prefix, rd, label);
383         } catch (Exception e) {
384             LOG.error("addFibEntryForRouterInterface: prefix {} rd {} label {} error ", prefix, rd, label, e);
385         }
386     }
387
388     private static void buildVpnEncapSpecificInfo(VrfEntryBuilder builder, VrfEntry.EncapType encapType, Uint32 label,
389                                          Uint32 l3vni, String macAddress, String gatewayMac, List<String> nextHopList) {
390         if (encapType == null) {
391             builder.setMac(macAddress);
392             return;
393         }
394
395         // TODO - validate this check
396         if (l3vni.longValue() != 0) {
397             builder.setL3vni(l3vni);
398         }
399         builder.setEncapType(encapType);
400         builder.setGatewayMacAddress(gatewayMac);
401         builder.setMac(macAddress);
402         Uint32 lbl = encapType.equals(VrfEntry.EncapType.Mplsgre) ? label : null;
403         List<RoutePaths> routePaths = nextHopList.stream()
404                         .filter(nextHop -> nextHop != null && !nextHop.isEmpty())
405                         .map(nextHop -> FibHelper.buildRoutePath(nextHop, lbl)).collect(toList());
406         builder.setRoutePaths(routePaths);
407     }
408
409     @SuppressWarnings("checkstyle:IllegalCatch")
410     public void removeFibEntry(String rd, String prefix, String eventSource,
411                                TypedWriteTransaction<Configuration> writeConfigTxn) {
412
413         if (rd == null || rd.isEmpty()) {
414             LOG.error("Prefix {} not associated with vpn", prefix);
415             return;
416         }
417         try {
418             LOG.debug("removeFibEntry: Removing fib entry with destination prefix {} from vrf table for rd {}",
419                     prefix, rd);
420
421             InstanceIdentifier.InstanceIdentifierBuilder<VrfEntry> idBuilder =
422                     InstanceIdentifier.builder(FibEntries.class)
423                             .child(VrfTables.class, new VrfTablesKey(rd)).child(VrfEntry.class,
424                             new VrfEntryKey(prefix));
425             InstanceIdentifier<VrfEntry> vrfEntryId = idBuilder.build();
426             if (writeConfigTxn != null) {
427                 writeConfigTxn.delete(vrfEntryId);
428             } else {
429                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
430             }
431             LOG.error("removeFibEntry: Removed Fib Entry rd {} prefix {} source {} ",
432                     rd, prefix, eventSource);
433         } catch (RuntimeException e) {
434             LOG.error("removeFibEntry: Unable to remove Fib Entry for rd {} prefix {} source {} ",
435                     rd, prefix, eventSource);
436         }
437     }
438
439     /**
440      * Removes a specific Nexthop from a VrfEntry. If Nexthop to remove is the
441      * last one in the VrfEntry, then the VrfEntry is removed too.
442      * @param rd              Route-Distinguisher to which the VrfEntry belongs to
443      * @param prefix          Destination of the route
444      * @param nextHopToRemove Specific nexthop within the Route to be removed.
445      *                        If null or empty, then the whole VrfEntry is removed
446      */
447     public void removeOrUpdateFibEntry(String rd, String prefix, String nextHopToRemove,
448             TypedWriteTransaction<Configuration> writeConfigTxn) {
449         LOG.debug("Removing fib entry with destination prefix {} from vrf table for rd {} nextHop {}", prefix, rd,
450                 nextHopToRemove);
451
452         // Looking for existing prefix in MDSAL database
453         InstanceIdentifier<VrfEntry> vrfEntryId =
454             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
455                 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
456         Optional<VrfEntry> entry = Optional.empty();
457         try {
458             entry = SingleTransactionDataBroker.syncReadOptional(dataBroker,
459                     LogicalDatastoreType.CONFIGURATION, vrfEntryId);
460         } catch (ExecutionException | InterruptedException e) {
461             LOG.error("removeOrUpdateFibEntry: Exception while reading vrfEntry for the prefix {} rd {} nexthop {}",
462                     prefix, rd, nextHopToRemove, e);
463         }
464         if (entry.isPresent()) {
465             final List<RoutePaths> routePaths = entry.get().getRoutePaths();
466             if (routePaths == null || routePaths.isEmpty()) {
467                 LOG.warn("routePaths is null/empty for given rd {}, prefix {}", rd, prefix);
468                 return;
469             }
470             java.util.Optional<RoutePaths> optRoutePath =
471                     routePaths.stream()
472                         .filter(
473                             routePath -> Objects.equals(routePath.getNexthopAddress(), nextHopToRemove)).findFirst();
474             if (!optRoutePath.isPresent()) {
475                 LOG.error("Unable to find a routePath that contains the given nextHop to remove {}", nextHopToRemove);
476                 return;
477             }
478             RoutePaths routePath = optRoutePath.get();
479             if (routePaths.size() == 1) {
480                 // Remove the whole entry
481                 if (writeConfigTxn != null) {
482                     writeConfigTxn.delete(vrfEntryId);
483                 } else {
484                     MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
485                 }
486                 LOG.info("Removed Fib Entry rd {} prefix {} nextHop {}", rd, prefix, nextHopToRemove);
487             } else {
488                 InstanceIdentifier<RoutePaths> routePathsId =
489                         FibHelper.buildRoutePathId(rd, prefix, routePath.getNexthopAddress());
490                 // Remove route
491                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, routePathsId);
492                 LOG.info("Removed Route Path rd {} prefix {}, nextHop {}, label {}", rd, prefix,
493                         routePath.getNexthopAddress(), routePath.getLabel());
494             }
495         } else {
496             LOG.warn("Could not find VrfEntry for Route-Distinguisher {} prefix {} nexthop {}", rd, prefix,
497                     nextHopToRemove);
498         }
499     }
500
501     /**
502      * Adds or removes nextHop from routePath based on the flag nextHopAdd.
503      */
504     public void updateRoutePathForFibEntry(String rd, String prefix, String nextHop, Uint32 label,
505             boolean nextHopAdd, TypedWriteTransaction<Configuration> writeConfigTxn) {
506
507         LOG.debug("Updating fib entry for prefix {} with nextHop {} for rd {}.", prefix, nextHop, rd);
508
509         InstanceIdentifier<RoutePaths> routePathId = FibHelper.buildRoutePathId(rd, prefix, nextHop);
510
511         // FIXME: use routePathId instead?
512         final ReentrantLock lock = JvmGlobalLocks.getLockForString(rd + prefix + nextHop);
513         lock.lock();
514         try {
515             if (nextHopAdd) {
516                 RoutePaths routePaths = FibHelper.buildRoutePath(nextHop, label);
517                 if (writeConfigTxn != null) {
518                     writeConfigTxn.put(routePathId, routePaths, CREATE_MISSING_PARENTS);
519                 } else {
520                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routePathId, routePaths);
521                 }
522                 LOG.debug("Added routepath with nextHop {} for prefix {} and label {}.", nextHop, prefix, label);
523             } else {
524                 Optional<RoutePaths> routePath;
525                 try {
526                     routePath = SingleTransactionDataBroker.syncReadOptional(dataBroker,
527                             LogicalDatastoreType.CONFIGURATION, routePathId);
528                 } catch (ExecutionException | InterruptedException e) {
529                     LOG.error("updateRoutePathForFibEntry: Exception while reading the RoutePath with rd {}, "
530                                     + "prefix {} and nh {}", rd, prefix, nextHop, e);
531                     return;
532                 }
533                 if (!routePath.isPresent()) {
534                     LOG.warn("Couldn't find RoutePath with rd {}, prefix {} and nh {} for deleting",
535                             rd, prefix, nextHop);
536                     return;
537                 }
538                 if (writeConfigTxn != null) {
539                     writeConfigTxn.delete(routePathId);
540                 } else {
541                     MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, routePathId);
542                 }
543                 LOG.info("Removed routepath with nextHop {} for prefix {} and rd {}.", nextHop, prefix, rd);
544             }
545         } finally {
546             lock.unlock();
547         }
548     }
549
550     public void addVrfTable(String rd, WriteTransaction writeConfigTxn) {
551         LOG.debug("Adding vrf table for rd {}", rd);
552         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
553             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
554         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
555         VrfTablesBuilder vrfTablesBuilder = new VrfTablesBuilder().withKey(new VrfTablesKey(rd))
556             .setRouteDistinguisher(rd).setVrfEntry(new ArrayList<VrfEntry>());
557         if (writeConfigTxn != null) {
558             writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTablesBuilder.build());
559         } else {
560             MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
561                                  vrfTableId, vrfTablesBuilder.build());
562         }
563     }
564
565     public void removeVrfTable(String rd, TypedWriteTransaction<Configuration> writeConfigTxn) {
566         LOG.debug("Removing vrf table for rd {}", rd);
567         InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
568             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
569         InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
570
571         if (writeConfigTxn != null) {
572             writeConfigTxn.delete(vrfTableId);
573         } else {
574             Optional<VrfTables> ifStateOptional;
575             try {
576                 ifStateOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
577                         LogicalDatastoreType.CONFIGURATION, vrfTableId);
578             } catch (ExecutionException | InterruptedException e) {
579                 LOG.error("removeVrfTable: Exception while reading vrfTable for the rd {}", rd, e);
580                 return;
581             }
582             if (ifStateOptional.isPresent()) {
583                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfTableId);
584             }
585         }
586     }
587
588     public static java.util.Optional<Uint32> getLabelFromRoutePaths(final VrfEntry vrfEntry) {
589         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
590         if (routePaths == null || routePaths.isEmpty() || vrfEntry.getRoutePaths().get(0).getLabel() == null) {
591             return java.util.Optional.empty();
592         }
593         return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getLabel());
594     }
595
596     public static java.util.Optional<String> getFirstNextHopAddress(final VrfEntry vrfEntry) {
597         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
598         if (routePaths == null || routePaths.isEmpty()) {
599             return java.util.Optional.empty();
600         }
601         return java.util.Optional.of(vrfEntry.getRoutePaths().get(0).getNexthopAddress());
602     }
603
604     public static java.util.Optional<Uint32> getLabelForNextHop(final VrfEntry vrfEntry, String nextHopIp) {
605         List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
606         if (routePaths == null || routePaths.isEmpty()) {
607             return java.util.Optional.empty();
608         }
609         return routePaths.stream()
610                 .filter(routePath -> Objects.equals(routePath.getNexthopAddress(), nextHopIp))
611                 .findFirst()
612                 .map(RoutePaths::getLabel);
613     }
614
615     @Nullable
616     public StateTunnelList getTunnelState(String interfaceName) throws ReadFailedException {
617         Optional<StateTunnelList> tunnelStateOptional = iitmProvider.getTunnelState(interfaceName);
618         if (tunnelStateOptional.isPresent()) {
619             return tunnelStateOptional.get();
620         }
621         return null;
622     }
623
624     public static InstanceIdentifier<Interface> buildStateInterfaceId(String interfaceName) {
625         InstanceIdentifier.InstanceIdentifierBuilder<Interface> idBuilder =
626                 InstanceIdentifier.builder(InterfacesState.class)
627                         .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
628                                 .interfaces.state.Interface.class, new org.opendaylight.yang.gen.v1.urn.ietf
629                                 .params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
630                                 .InterfaceKey(interfaceName));
631         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
632                 .interfaces.state.Interface> id = idBuilder.build();
633         return id;
634     }
635
636     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
637         .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName) {
638         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
639             .interfaces.state.Interface> ifStateId = buildStateInterfaceId(interfaceName);
640         Optional<Interface> ifStateOptional;
641         try {
642             ifStateOptional = SingleTransactionDataBroker.syncReadOptional(dataBroker,
643                     LogicalDatastoreType.OPERATIONAL, ifStateId);
644         } catch (ExecutionException | InterruptedException e) {
645             LOG.error("getInterfaceStateFromOperDS: Exception while reading interface-state for the interface {}",
646                     interfaceName, e);
647             return null;
648         }
649         if (ifStateOptional.isPresent()) {
650             return ifStateOptional.get();
651         }
652         return null;
653     }
654
655     public static String getCreateLocalNextHopJobKey(Uint32 vpnId, Uint64 dpnId, String prefix) {
656         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + prefix;
657     }
658
659     public static String getCreateRemoteNextHopJobKey(Uint32 vpnId, Uint64 dpnId, String prefix) {
660         return getCreateLocalNextHopJobKey(vpnId, dpnId, prefix);
661     }
662
663     public static String getJobKeyForRdPrefix(String rd, String prefix) {
664         return "FIB-" + rd + "-" + prefix;
665     }
666
667     public static String getJobKeyForVpnIdDpnId(Uint32 vpnId, Uint64 dpnId) {
668         return "FIB-" + vpnId.toString() + "-" + dpnId.toString() ;
669     }
670
671     public void updateUsedRdAndVpnToExtraRoute(TypedReadWriteTransaction<Configuration> confTx,
672             TypedReadWriteTransaction<Operational> operTx, String tunnelIpRemoved, String primaryRd, String prefix)
673             throws ExecutionException, InterruptedException {
674         Optional<VpnInstanceOpDataEntry> optVpnInstance = getVpnInstanceOpData(operTx, primaryRd);
675         if (!optVpnInstance.isPresent()) {
676             return;
677         }
678         VpnInstanceOpDataEntry vpnInstance = optVpnInstance.get();
679         String vpnName = vpnInstance.getVpnInstanceName();
680         Uint32 vpnId = vpnInstance.getVpnId();
681         List<String> usedRds = VpnExtraRouteHelper.getUsedRds(confTx, vpnId, prefix);
682         // To identify the rd to be removed, iterate through the allocated rds for the prefix and check
683         // which rd is allocated for the particular OVS.
684         for (String usedRd : usedRds) {
685             Optional<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getVpnExtraroutes(operTx, vpnName, usedRd, prefix);
686             if (vpnExtraRoutes.isPresent()) {
687                 // Since all the nexthops under one OVS will be present under one rd, only 1 nexthop is read
688                 // to identify the OVS
689                 String nextHopRemoved = vpnExtraRoutes.get().getNexthopIpList().get(0);
690                 Prefixes prefixToInterface = getPrefixToInterface(operTx, vpnId, getIpPrefix(nextHopRemoved));
691                 if (prefixToInterface != null && tunnelIpRemoved
692                         .equals(getEndpointIpAddressForDPN(prefixToInterface.getDpnId()))) {
693                     LOG.info("updating data-stores for prefix {} with primaryRd {} for interface {} on vpn {} ",
694                             prefix, primaryRd, prefixToInterface.getVpnInterfaceName(), vpnName);
695                     operTx.delete(FibUtil.getAdjacencyIdentifierOp(prefixToInterface.getVpnInterfaceName(),
696                                     vpnName, prefix));
697                     operTx.delete(VpnExtraRouteHelper.getVpnToExtrarouteVrfIdIdentifier(vpnName, usedRd, prefix));
698                     MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
699                             VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, prefix, nextHopRemoved));
700                     break;
701                 }
702             }
703         }
704     }
705
706     private String getEndpointIpAddressForDPN(Uint64 dpnId) {
707         //TODO: Move it to a common place for vpn and fib
708         String nextHopIp = null;
709         InstanceIdentifier<DPNTEPsInfo> tunnelInfoId =
710             InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, new DPNTEPsInfoKey(dpnId)).build();
711         Optional<DPNTEPsInfo> tunnelInfo;
712         try {
713             tunnelInfo = SingleTransactionDataBroker.syncReadOptional(dataBroker,
714                     LogicalDatastoreType.CONFIGURATION, tunnelInfoId);
715         } catch (ExecutionException | InterruptedException e) {
716             LOG.error("getEndpointIpAddressForDPN: Exception while reading DPN {} TEP info", dpnId, e);
717             return null;
718         }
719         if (tunnelInfo.isPresent()) {
720             List<TunnelEndPoints> nexthopIpList = tunnelInfo.get().getTunnelEndPoints();
721             if (nexthopIpList != null && !nexthopIpList.isEmpty()) {
722                 nextHopIp = nexthopIpList.get(0).getIpAddress().stringValue();
723             }
724         }
725         return nextHopIp;
726     }
727
728     public static String getIpPrefix(String prefix) {
729         String[] prefixValues = prefix.split(FibConstants.PREFIX_SEPARATOR);
730         if (prefixValues.length == 1) {
731             return NWUtil.toIpPrefix(prefix);
732         }
733         return prefix;
734     }
735
736     public static boolean isTunnelInterface(AdjacencyResult adjacencyResult) {
737         return Tunnel.class.equals(adjacencyResult.getInterfaceType());
738     }
739
740     public static InstanceIdentifier<VrfEntry> getNextHopIdentifier(String rd, String prefix) {
741         return InstanceIdentifier.builder(FibEntries.class)
742                 .child(VrfTables.class,new VrfTablesKey(rd)).child(VrfEntry.class,new VrfEntryKey(prefix)).build();
743     }
744
745     public List<String> getNextHopAddresses(String rd, String prefix) {
746         InstanceIdentifier<VrfEntry> vrfEntryId = getNextHopIdentifier(rd, prefix);
747         Optional<VrfEntry> vrfEntry;
748         try {
749             vrfEntry = SingleTransactionDataBroker.syncReadOptional(dataBroker,
750                     LogicalDatastoreType.CONFIGURATION, vrfEntryId);
751         } catch (ExecutionException | InterruptedException e) {
752             LOG.error("getNextHopAddresses: Exception while reading vrfEntry DS for the prefix {} rd {}",
753                     prefix, rd, e);
754             return Collections.emptyList();
755         }
756         if (vrfEntry.isPresent()) {
757             return FibHelper.getNextHopListFromRoutePaths(vrfEntry.get());
758         } else {
759             return Collections.emptyList();
760         }
761     }
762
763     public static String getGreLbGroupKey(List<String> availableDcGws) {
764         Preconditions.checkNotNull(availableDcGws, "AvailableDcGws is null");
765         return "gre-" + availableDcGws.stream().sorted().collect(joining(":"));
766     }
767
768     public static void updateLbGroupInfo(Uint64 dpnId, String groupIdKey,
769             String groupId, TypedWriteTransaction<Operational> tx) {
770         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(groupIdKey);
771         Nexthops nextHopsToGroupId = buildNextHops(dpnId, groupIdKey, groupId);
772         tx.merge(nextHopsId, nextHopsToGroupId);
773     }
774
775     public static void removeL3vpnDcGateWay(String destinationIp, TypedReadWriteTransaction<Operational> tx)
776             throws InterruptedException, ExecutionException {
777         InstanceIdentifier<DcGateway> dcGateWayId = getDcGwInstance(destinationIp);
778         Optional<DcGateway> dcGateWayOpt = tx.read(dcGateWayId).get();
779         if (!dcGateWayOpt.isPresent()) {
780             return;
781         }
782         tx.delete(dcGateWayId);
783     }
784
785     public static void addL3vpnDcGateWay(String destinationIp, TypedReadWriteTransaction<Operational> tx)
786             throws InterruptedException, ExecutionException {
787         InstanceIdentifier<DcGateway> dcGateWayId = getDcGwInstance(destinationIp);
788         Optional<DcGateway> dcGateWayOpt = tx.read(dcGateWayId).get();
789         if (!dcGateWayOpt.isPresent()) {
790             tx.put(dcGateWayId,
791                     new DcGatewayBuilder()
792                     .withKey(new DcGatewayKey(destinationIp))
793                     .setIpAddress(destinationIp).build()
794             );
795         }
796     }
797
798     private static InstanceIdentifier<DcGateway> getDcGwInstance(String destinationIp) {
799         return InstanceIdentifier.builder(L3vpnDcGws.class)
800                 .child(DcGateway.class, new DcGatewayKey(destinationIp))
801                 .build();
802     }
803
804     public static void removeOrUpdateNextHopInfo(Uint64 dpnId, String nextHopKey, String groupId,
805             Nexthops nexthops, TypedWriteTransaction<Operational> tx) {
806         InstanceIdentifier<Nexthops> nextHopsId = getNextHopsIdentifier(nextHopKey);
807         List<String> targetDeviceIds =
808             nexthops.getTargetDeviceId() != null ? new ArrayList<>(nexthops.getTargetDeviceId()) : new ArrayList<>();
809         targetDeviceIds.remove(dpnId.toString());
810         if (targetDeviceIds.isEmpty()) {
811             tx.delete(nextHopsId);
812         } else {
813             Nexthops nextHopsToGroupId = new NexthopsBuilder().withKey(new NexthopsKey(nextHopKey))
814                 .setNexthopKey(nextHopKey)
815                 .setGroupId(groupId)
816                 .setTargetDeviceId(targetDeviceIds).build();
817             tx.put(nextHopsId, nextHopsToGroupId);
818         }
819     }
820
821     private static InstanceIdentifier<Nexthops> getNextHopsIdentifier(String groupIdKey) {
822         return InstanceIdentifier.builder(L3vpnLbNexthops.class)
823                 .child(Nexthops.class, new NexthopsKey(groupIdKey)).build();
824     }
825
826     private static Nexthops buildNextHops(Uint64 dpnId, String groupIdKey, String groupId) {
827         return new NexthopsBuilder().withKey(new NexthopsKey(groupIdKey))
828                 .setNexthopKey(groupIdKey)
829                 .setGroupId(groupId)
830                 .setTargetDeviceId(Collections.singletonList(dpnId.toString())).build();
831     }
832
833     public Optional<Nexthops> getNexthops(String nextHopKey) {
834         InstanceIdentifier<Nexthops> nextHopsId = InstanceIdentifier.builder(L3vpnLbNexthops.class)
835                 .child(Nexthops.class, new NexthopsKey(nextHopKey)).build();
836         try {
837             return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
838                     nextHopsId);
839         } catch (ExecutionException | InterruptedException e) {
840             LOG.error("getNexthops: Exception while reading L3-vpn-nexthop DS for the nexthop {}", nextHopKey, e);
841         }
842         return Optional.empty();
843     }
844
845     public List<String> getL3VpnDcGateWays() {
846         InstanceIdentifier<L3vpnDcGws> id = InstanceIdentifier.builder(L3vpnDcGws.class)
847                 .build();
848         Optional<L3vpnDcGws> dcGwsOpt;
849         try {
850             dcGwsOpt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
851                     LogicalDatastoreType.OPERATIONAL, id);
852         } catch (ExecutionException | InterruptedException e) {
853             LOG.error("getNexthops: Exception while reading L3vpnDcGws DS", e);
854             return Collections.emptyList();
855         }
856         if (!dcGwsOpt.isPresent()) {
857             return Collections.emptyList();
858         }
859         return dcGwsOpt.get().getDcGateway().stream().map(DcGateway::getIpAddress).collect(toList());
860     }
861
862     static boolean isVxlanNetwork(NetworkType networkType) {
863         if (networkType != null) {
864             return networkType == NetworkAttributes.NetworkType.VXLAN;
865         }
866         return false;
867     }
868
869     static boolean isBgpVpn(String vpnName, String rd) {
870         return vpnName != null && !vpnName.equals(rd);
871     }
872
873     static NodeRef buildNodeRef(Uint64 dpId) {
874         return new NodeRef(InstanceIdentifier.builder(Nodes.class)
875                 .child(Node.class, new NodeKey(new NodeId("openflow:" + dpId))).build());
876     }
877
878     static InstanceIdentifier<Group> buildGroupInstanceIdentifier(long groupId, Uint64 dpId) {
879         return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:" + dpId)))
880                 .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
881     }
882
883     static Buckets buildBuckets(List<BucketInfo> listBucketInfo) {
884         long index = 0;
885         BucketsBuilder bucketsBuilder = new BucketsBuilder();
886         if (listBucketInfo != null) {
887             List<Bucket> bucketList = new ArrayList<>();
888
889             for (BucketInfo bucketInfo : listBucketInfo) {
890                 BucketBuilder bucketBuilder = new BucketBuilder();
891                 bucketBuilder.setAction(bucketInfo.buildActions());
892                 bucketBuilder.setWeight(bucketInfo.getWeight());
893                 bucketBuilder.setBucketId(new BucketId(index++));
894                 bucketBuilder.setWeight(bucketInfo.getWeight()).setWatchPort(bucketInfo.getWatchPort())
895                         .setWatchGroup(bucketInfo.getWatchGroup());
896                 bucketList.add(bucketBuilder.build());
897             }
898
899             bucketsBuilder.setBucket(bucketList);
900         }
901         return bucketsBuilder.build();
902     }
903
904     static String getFlowRef(Uint64 dpnId, short tableId, Uint32 label, int priority) {
905         return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + label
906                 + NwConstants.FLOWID_SEPARATOR + priority;
907     }
908
909     static String getFlowRef(Uint64 dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
910         return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + rd
911                 + NwConstants.FLOWID_SEPARATOR + priority + NwConstants.FLOWID_SEPARATOR + destPrefix.getHostAddress();
912     }
913
914     static String getL3VpnGatewayFlowRef(short l3GwMacTable, Uint64 dpId, Uint32 vpnId, String gwMacAddress) {
915         return gwMacAddress + NwConstants.FLOWID_SEPARATOR + vpnId + NwConstants.FLOWID_SEPARATOR + dpId
916                 + NwConstants.FLOWID_SEPARATOR + l3GwMacTable;
917     }
918
919     static Node buildDpnNode(Uint64 dpnId) {
920         return new NodeBuilder().setId(new NodeId("openflow:" + dpnId))
921                 .withKey(new NodeKey(new NodeId("openflow:" + dpnId))).build();
922     }
923
924     public static String getBroadcastAddressFromCidr(String cidr) {
925         String[] ipaddressValues = cidr.split("/");
926         int address = InetAddresses.coerceToInteger(InetAddresses.forString(ipaddressValues[0]));
927         int cidrPart = Integer.parseInt(ipaddressValues[1]);
928         int netmask = 0;
929         for (int j = 0; j < cidrPart; ++j) {
930             netmask |= 1 << 31 - j;
931         }
932         int network = address & netmask;
933         int broadcast = network | ~netmask;
934         return InetAddresses.toAddrString(InetAddresses.fromInteger(broadcast));
935     }
936
937     public static boolean lockCluster(LockManagerService lockManager, String lockName, long tryLockPeriod) {
938         TryLockInput input = new TryLockInputBuilder().setLockName(lockName).setTime(tryLockPeriod)
939                 .setTimeUnit(TimeUnits.Milliseconds).build();
940         Future<RpcResult<TryLockOutput>> result = lockManager.tryLock(input);
941         boolean lockAcquired;
942         try {
943             if (result != null && result.get().isSuccessful()) {
944                 LOG.debug("lockCluster: Acquired lock for {}", lockName);
945                 lockAcquired = true;
946             } else {
947                 LOG.error("lockCluster: Unable to getLock for {}", lockName);
948                 lockAcquired = false;
949             }
950         } catch (InterruptedException | ExecutionException e) {
951             LOG.error("lockCluster: Exception while trying to getLock for {}", lockName, e);
952             lockAcquired = false;
953         }
954
955         return lockAcquired;
956     }
957
958     public static void unlockCluster(LockManagerService lockManager, String lockName) {
959         UnlockInput input = new UnlockInputBuilder().setLockName(lockName).build();
960         Future<RpcResult<UnlockOutput>> result = lockManager.unlock(input);
961         try {
962             if (result != null && result.get().isSuccessful()) {
963                 LOG.debug("unlockCluster: Unlocked {}", lockName);
964             } else {
965                 LOG.error("unlockCluster: Unable to release lock for {}", lockName);
966             }
967         } catch (InterruptedException | ExecutionException e) {
968             LOG.error("unlockCluster: Unable to unlock {}", lockName, e);
969         }
970     }
971
972     public boolean isInterfacePresentInDpn(String vpnName, Uint64 dpnId) {
973         InstanceIdentifier<VpnToDpnList> vpnToDpnListId = InstanceIdentifier.builder(VpnInstanceOpData.class)
974                 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(vpnName))
975                 .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
976         try {
977             VpnToDpnList vpnToDpnList = SingleTransactionDataBroker.syncRead(dataBroker,
978                     LogicalDatastoreType.OPERATIONAL, vpnToDpnListId);
979             if (!(vpnToDpnList == null) && !(vpnToDpnList.getVpnInterfaces() == null)
980                     && !vpnToDpnList.getVpnInterfaces().isEmpty()) {
981                 return true;
982             }
983         } catch (ExpectedDataObjectNotFoundException e) {
984             LOG.warn("Failed to read interfaces with error {}", e.getMessage());
985         }
986         return false;
987     }
988
989     public static boolean checkFibEntryExist(DataBroker broker, String rd, String prefix, String nextHopIp) {
990         InstanceIdentifier<VrfEntry> vrfEntryId =
991                 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
992                         .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
993         Optional<VrfEntry> entry;
994         try {
995             entry = SingleTransactionDataBroker.syncReadOptional(broker,
996                     LogicalDatastoreType.CONFIGURATION, vrfEntryId);
997         } catch (ExecutionException | InterruptedException e) {
998             LOG.error("checkFibEntryExist: Exception while reading vrfEntry DS for the prefix {} rd {} nexthop {}",
999                     prefix, rd, nextHopIp, e);
1000             return false;
1001         }
1002         if (entry.isPresent()) {
1003             List<RoutePaths> paths = entry.get().getRoutePaths();
1004             for (RoutePaths path: paths) {
1005                 if (path.getNexthopAddress().equals(nextHopIp)) {
1006                     return true;
1007                 }
1008             }
1009         }
1010         return false;
1011     }
1012 }