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