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