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