Migrate ListenableFutures.addErrorLogging() users
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInstanceListener.java
1 /*
2  * Copyright (c) 2015 - 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 package org.opendaylight.netvirt.vpnmanager;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
12
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Optional;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.locks.ReentrantLock;
27 import javax.annotation.PreDestroy;
28 import javax.inject.Inject;
29 import javax.inject.Singleton;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
32 import org.opendaylight.genius.infra.Datastore.Configuration;
33 import org.opendaylight.genius.infra.Datastore.Operational;
34 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
35 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
36 import org.opendaylight.genius.infra.TypedWriteTransaction;
37 import org.opendaylight.genius.mdsalutil.FlowEntity;
38 import org.opendaylight.genius.mdsalutil.InstructionInfo;
39 import org.opendaylight.genius.mdsalutil.MDSALUtil;
40 import org.opendaylight.genius.mdsalutil.MatchInfo;
41 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
42 import org.opendaylight.genius.mdsalutil.NWUtil;
43 import org.opendaylight.genius.mdsalutil.NwConstants;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
45 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
46 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
47 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
48 import org.opendaylight.genius.utils.JvmGlobalLocks;
49 import org.opendaylight.genius.utils.SystemPropertyReader;
50 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
51 import org.opendaylight.infrautils.utils.concurrent.Executors;
52 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
53 import org.opendaylight.mdsal.binding.api.DataBroker;
54 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
55 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
56 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnelKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIp;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIpKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnTargetsBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInstances;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.VpnInstance;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.VpnTargets;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.vpn.instance.vpntargets.VpnTarget;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.common.Uint32;
76 import org.opendaylight.yangtools.yang.common.Uint64;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
79
80 @Singleton
81 public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<VpnInstance> {
82     private static final Logger LOG = LoggerFactory.getLogger(VpnInstanceListener.class);
83     private static final String LOGGING_PREFIX_ADD = "VPN-ADD:";
84     private static final String LOGGING_PREFIX_UPDATE = "VPN-UPDATE:";
85     private static final String LOGGING_PREFIX_DELETE = "VPN-REMOVE:";
86     private final DataBroker dataBroker;
87     private final ManagedNewTransactionRunner txRunner;
88     private final IdManagerService idManager;
89     private final VpnInterfaceManager vpnInterfaceManager;
90     private final IFibManager fibManager;
91     private final VpnOpDataSyncer vpnOpDataNotifier;
92     private final IMdsalApiManager mdsalManager;
93     private final JobCoordinator jobCoordinator;
94     private final VpnUtil vpnUtil;
95
96     @Inject
97     public VpnInstanceListener(final DataBroker dataBroker, final IdManagerService idManager,
98             final VpnInterfaceManager vpnInterfaceManager, final IFibManager fibManager,
99             final VpnOpDataSyncer vpnOpDataSyncer, final IMdsalApiManager mdsalManager,
100             final JobCoordinator jobCoordinator, VpnUtil vpnUtil) {
101         super(dataBroker, LogicalDatastoreType.CONFIGURATION,
102                 InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class),
103                 Executors.newListeningSingleThreadExecutor("VpnInstanceListener", LOG));
104         this.dataBroker = dataBroker;
105         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
106         this.idManager = idManager;
107         this.vpnInterfaceManager = vpnInterfaceManager;
108         this.fibManager = fibManager;
109         this.vpnOpDataNotifier = vpnOpDataSyncer;
110         this.mdsalManager = mdsalManager;
111         this.jobCoordinator = jobCoordinator;
112         this.vpnUtil = vpnUtil;
113         start();
114     }
115
116     public void start() {
117         LOG.info("{} start", getClass().getSimpleName());
118     }
119
120     @Override
121     @PreDestroy
122     public void close() {
123         super.close();
124         Executors.shutdownAndAwaitTermination(getExecutorService());
125     }
126
127
128     @Override
129     public void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
130         LOG.trace("{} : VPN event key: {}, value: {}", LOGGING_PREFIX_DELETE, identifier, del);
131         final String vpnName = del.getVpnInstanceName();
132         Optional<VpnInstanceOpDataEntry> vpnOpValue;
133         String primaryRd = vpnUtil.getVpnRd(vpnName);
134         if (primaryRd == null) {
135             LOG.error("{}, failed to remove VPN: primaryRd is null for vpn {}", LOGGING_PREFIX_DELETE, vpnName);
136             return;
137         }
138
139         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
140         try {
141             vpnOpValue = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
142                     VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd));
143         } catch (InterruptedException | ExecutionException e) {
144             LOG.error("{}, failed to remove VPN: Exception while retrieving VpnInstanceOpDataEntry for VPN {}. ",
145                     LOGGING_PREFIX_DELETE,  vpnName, e);
146             return;
147         }
148
149         if (!vpnOpValue.isPresent()) {
150             LOG.error("{}, failed to remove VPN: Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ",
151                 LOGGING_PREFIX_DELETE, vpnName);
152             return;
153         } else {
154             jobCoordinator.enqueueJob("VPN-" + vpnName, () ->
155                 Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
156                     VpnInstanceOpDataEntryBuilder builder = null;
157                     InstanceIdentifier<VpnInstanceOpDataEntry> id = null;
158                     if (primaryRd != null) {
159                         builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd)
160                                 .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
161                         id = VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd);
162                     } else {
163                         builder = new VpnInstanceOpDataEntryBuilder().setVrfId(vpnName)
164                                 .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
165                         id = VpnUtil.getVpnInstanceOpDataIdentifier(vpnName);
166                     }
167                     tx.merge(id, builder.build());
168
169                     LOG.info("{} call: Operational status set to PENDING_DELETE for vpn {} with rd {}",
170                             LOGGING_PREFIX_DELETE, vpnName, primaryRd);
171                 })), SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
172         }
173     }
174
175     @Override
176     public void update(InstanceIdentifier<VpnInstance> identifier,
177         VpnInstance original, VpnInstance update) {
178         LOG.trace("VPN-UPDATE: update: VPN event key: {}, value: {}.", identifier, update);
179         String vpnName = update.getVpnInstanceName();
180         if (original != null && update != null
181                 && original.getRouteDistinguisher() != null
182                 && update.getRouteDistinguisher() != null
183                 && original.getRouteDistinguisher().size()
184                 !=  update.getRouteDistinguisher().size()) {
185             LOG.debug("VPN-UPDATE: VpnInstance:{} updated with new RDs: {} from old RDs: {}", vpnName,
186                     update.getRouteDistinguisher(),  original.getRouteDistinguisher());
187             vpnUtil.updateVpnInstanceWithRdList(vpnName, update.getRouteDistinguisher());
188         }
189         vpnInterfaceManager.updateVpnInterfacesForUnProcessAdjancencies(vpnName);
190     }
191
192     @Override
193     public void add(final InstanceIdentifier<VpnInstance> identifier, final VpnInstance value) {
194         LOG.trace("{} add: Add VPN event key: {}, value: {}", LOGGING_PREFIX_ADD, identifier, value);
195         final String vpnName = value.getVpnInstanceName();
196         jobCoordinator.enqueueJob("VPN-" + vpnName, new AddVpnInstanceWorker(dataBroker, value),
197                 SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
198     }
199
200     private class AddVpnInstanceWorker implements Callable<List<? extends ListenableFuture<?>>> {
201         private final Logger log = LoggerFactory.getLogger(AddVpnInstanceWorker.class);
202         VpnInstance vpnInstance;
203         DataBroker broker;
204
205         AddVpnInstanceWorker(DataBroker broker,
206                 VpnInstance value) {
207             this.broker = broker;
208             this.vpnInstance = value;
209         }
210
211         @Override
212         public List<ListenableFuture<Void>> call() {
213             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
214             // to call the respective helpers.
215             List<ListenableFuture<Void>> futures = new ArrayList<>(2);
216             futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
217                 ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx ->
218                         addVpnInstance(vpnInstance, confTx, operTx));
219                 LoggingFutures.addErrorLogging(future, LOG, "{} call: error creating VPN {} rd {}",
220                         LOGGING_PREFIX_ADD, vpnInstance.getVpnInstanceName(),
221                         vpnInstance.getRouteDistinguisher());
222                 futures.add(future);
223             }));
224             Futures.addCallback(Futures.allAsList(futures),
225                                 new PostAddVpnInstanceWorker(vpnInstance , vpnInstance.getVpnInstanceName()),
226                                 MoreExecutors.directExecutor());
227             return futures;
228         }
229     }
230
231     // TODO Clean up the exception handling
232     @SuppressWarnings("checkstyle:IllegalCatch")
233     private void addVpnInstance(VpnInstance value, TypedWriteTransaction<Configuration> writeConfigTxn,
234             TypedWriteTransaction<Operational> writeOperTxn) {
235         if (writeConfigTxn == null) {
236             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
237                 addVpnInstance(value, tx, writeOperTxn)), LOG, "Error adding VPN instance {}", value);
238             return;
239         }
240         if (writeOperTxn == null) {
241             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx ->
242                 addVpnInstance(value, writeConfigTxn, tx)), LOG, "Error adding VPN instance {}", value);
243             return;
244         }
245         String vpnInstanceName = value.getVpnInstanceName();
246
247         Uint32 vpnId = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
248         if (vpnId.longValue() == 0) {
249             LOG.error("{} addVpnInstance: Unable to fetch label from Id Manager. Bailing out of adding operational"
250                     + " data for Vpn Instance {}", LOGGING_PREFIX_ADD, value.getVpnInstanceName());
251             return;
252         }
253         LOG.info("{} addVpnInstance: VPN Id {} generated for VpnInstanceName {}", LOGGING_PREFIX_ADD, vpnId,
254                 vpnInstanceName);
255         String primaryRd = VpnUtil.getPrimaryRd(value);
256         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
257             vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, primaryRd);
258
259         writeConfigTxn.mergeParentStructurePut(VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
260             vpnInstanceToVpnId);
261
262         VpnIds vpnIdToVpnInstance = VpnUtil.getVpnIdToVpnInstance(vpnId, value.getVpnInstanceName(),
263             primaryRd, VpnUtil.isBgpVpn(vpnInstanceName, primaryRd));
264
265         writeConfigTxn.mergeParentStructurePut(VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId), vpnIdToVpnInstance);
266
267         try {
268             String cachedTransType = fibManager.getConfTransType();
269             if (cachedTransType.equals("Invalid")) {
270                 try {
271                     fibManager.setConfTransType("L3VPN", "VXLAN");
272                 } catch (Exception e) {
273                     LOG.error("{} addVpnInstance: Exception caught setting the L3VPN tunnel transportType for vpn {}",
274                             LOGGING_PREFIX_ADD, vpnInstanceName, e);
275                 }
276             } else {
277                 LOG.debug("{} addVpnInstance: Configured tunnel transport type for L3VPN {} as {}", LOGGING_PREFIX_ADD,
278                         vpnInstanceName, cachedTransType);
279             }
280         } catch (Exception e) {
281             LOG.error("{} addVpnInstance: Error when trying to retrieve tunnel transport type for L3VPN {}",
282                     LOGGING_PREFIX_ADD, vpnInstanceName, e);
283         }
284
285         VpnInstanceOpDataEntryBuilder builder =
286                 new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd).setVpnId(vpnId)
287                         .setVpnInstanceName(vpnInstanceName)
288                         .setVpnState(VpnInstanceOpDataEntry.VpnState.Created);
289         if (VpnUtil.isBgpVpn(vpnInstanceName, primaryRd)) {
290             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
291                 .instance.op.data.entry.vpntargets.VpnTarget> opVpnTargetList = new ArrayList<>();
292             builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal);
293             if (value.getL3vni() != null) {
294                 builder.setL3vni(value.getL3vni());
295             }
296             if (value.isL2vpn()) {
297                 builder.setType(VpnInstanceOpDataEntry.Type.L2);
298             }
299             VpnTargets vpnTargets = value.getVpnTargets();
300             if (vpnTargets != null) {
301                 @Nullable Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn
302                         .instances.vpn.instance.vpntargets.VpnTargetKey, VpnTarget> vpnTargetListMap
303                         = vpnTargets.nonnullVpnTarget();
304                 if (vpnTargetListMap != null) {
305                     for (VpnTarget vpnTarget : vpnTargetListMap.values()) {
306                         VpnTargetBuilder vpnTargetBuilder =
307                             new VpnTargetBuilder().withKey(new VpnTargetKey(vpnTarget.key().getVrfRTValue()))
308                                 .setVrfRTType(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
309                                     .instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget.VrfRTType
310                                     .forValue(vpnTarget.getVrfRTType().getIntValue())).setVrfRTValue(
311                                 vpnTarget.getVrfRTValue());
312                         opVpnTargetList.add(vpnTargetBuilder.build());
313                     }
314                 }
315             }
316             VpnTargetsBuilder vpnTargetsBuilder = new VpnTargetsBuilder().setVpnTarget(opVpnTargetList);
317             builder.setVpnTargets(vpnTargetsBuilder.build());
318
319             List<String> rds = value.getRouteDistinguisher();
320             builder.setRd(rds);
321         } else {
322             builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.VPN);
323         }
324         writeOperTxn.mergeParentStructureMerge(VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd), builder.build());
325         LOG.info("{} addVpnInstance: VpnInstanceOpData populated successfully for vpn {} rd {}", LOGGING_PREFIX_ADD,
326                 vpnInstanceName, primaryRd);
327     }
328
329     private class PostAddVpnInstanceWorker implements FutureCallback<List<Void>> {
330         private final Logger log = LoggerFactory.getLogger(PostAddVpnInstanceWorker.class);
331         VpnInstance vpnInstance;
332         String vpnName;
333
334         PostAddVpnInstanceWorker(VpnInstance vpnInstance, String vpnName) {
335             this.vpnInstance = vpnInstance;
336             this.vpnName = vpnName;
337         }
338
339         /**
340          * This implies that all the future instances have returned success. -- TODO: Confirm this
341          */
342         @Override
343         public void onSuccess(List<Void> voids) {
344             /*
345             if rd is null, then its either a router vpn instance (or) a vlan external network vpn instance.
346             if rd is non-null, then it is a bgpvpn instance
347              */
348             List<String> rd = vpnInstance.getRouteDistinguisher();
349             if (rd == null || addBgpVrf()) {
350                 notifyTask();
351                 vpnInterfaceManager.vpnInstanceIsReady(vpnName);
352             }
353             log.info("{} onSuccess: Vpn Instance Op Data addition for {} successful.", LOGGING_PREFIX_ADD, vpnName);
354             VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(
355                     VpnUtil.getPrimaryRd(vpnInstance));
356
357             // bind service on each tunnel interface
358             //TODO (KIRAN): Add a new listener to handle creation of new DC-GW binding and deletion of existing DC-GW.
359             if (VpnUtil.isL3VpnOverVxLan(vpnInstance.getL3vni())) { //Handled for L3VPN Over VxLAN
360                 for (String tunnelInterfaceName: getDcGatewayTunnelInterfaceNameList()) {
361                     vpnUtil.bindService(vpnInstance.getVpnInstanceName(), tunnelInterfaceName,
362                             true/*isTunnelInterface*/);
363                 }
364
365                 // install flow
366                 List<MatchInfo> mkMatches = new ArrayList<>();
367                 mkMatches.add(new MatchTunnelId(Uint64.valueOf(vpnInstance.getL3vni())));
368
369                 List<InstructionInfo> instructions =
370                         Arrays.asList(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnInstanceOpDataEntry
371                                 .getVpnId().toJava()), MetaDataUtil.METADATA_MASK_VRFID),
372                                 new InstructionGotoTable(NwConstants.L3_GW_MAC_TABLE));
373                 try {
374                     for (Uint64 dpnId: NWUtil.getOperativeDPNs(dataBroker)) {
375                         String flowRef = getFibFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
376                                 vpnName, VpnConstants.DEFAULT_FLOW_PRIORITY);
377                         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId,
378                                 NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE, flowRef,
379                                 VpnConstants.DEFAULT_FLOW_PRIORITY, "VxLAN VPN Tunnel Bind Service",
380                                 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, mkMatches, instructions);
381                         mdsalManager.installFlow(dpnId, flowEntity);
382                     }
383                 } catch (ExecutionException | InterruptedException e) {
384                     LOG.error("PostAddVpnInstanceWorker: Exception while getting the list of Operative DPNs for Vpn {}",
385                             vpnName, e);
386                 }
387
388                 ///////////////////////
389             }
390         }
391
392         // TODO Clean up the exception handling
393         @SuppressWarnings("checkstyle:IllegalCatch")
394         private boolean addBgpVrf() {
395             String primaryRd = vpnUtil.getPrimaryRd(vpnName);
396             @Nullable Map<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn
397                     .instances.vpn.instance.vpntargets.VpnTargetKey, VpnTarget> vpnTargetList
398                     = vpnInstance.getVpnTargets().getVpnTarget();
399
400             if (vpnTargetList == null) {
401                 log.error("{} addBgpVrf: vpn target list is empty for vpn {} RD {}", LOGGING_PREFIX_ADD,
402                         this.vpnName, primaryRd);
403                 return false;
404             }
405             // FIXME: separate out to somehow?
406             final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
407             lock.lock();
408             try {
409                 fibManager.addVrfTable(primaryRd, null);
410             } finally {
411                 lock.unlock();
412             }
413             vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, primaryRd);
414             return true;
415         }
416
417         private void notifyTask() {
418             vpnOpDataNotifier.notifyVpnOpDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpnName);
419             vpnOpDataNotifier.notifyVpnOpDataReady(VpnOpDataSyncer.VpnOpDataType.vpnOpData, vpnName);
420         }
421
422         /**
423          * This method is used to handle failure callbacks.
424          * If more retry needed, the retrycount is decremented and mainworker is executed again.
425          * After retries completed, rollbackworker is executed.
426          * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
427          */
428
429         @Override
430         public void onFailure(Throwable throwable) {
431             log.error("{} onFailure: Job for vpnInstance: {} failed with exception:", LOGGING_PREFIX_ADD, vpnName,
432                     throwable);
433             vpnInterfaceManager.vpnInstanceFailed(vpnName);
434         }
435     }
436
437     @Nullable
438     protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
439         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
440         try {
441             return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
442                     id).orElse(null);
443         } catch (InterruptedException | ExecutionException e) {
444             throw new RuntimeException("Error reading VPN instance data for " + rd, e);
445         }
446     }
447
448     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
449             justification = "https://github.com/spotbugs/spotbugs/issues/811")
450     private List<String> getDcGatewayTunnelInterfaceNameList() {
451         List<String> tunnelInterfaceNameList = new ArrayList<>();
452         try {
453             InstanceIdentifier<DcGatewayIpList> dcGatewayIpListInstanceIdentifier = InstanceIdentifier
454                     .create(DcGatewayIpList.class);
455             Optional<DcGatewayIpList> dcGatewayIpListOptional = SingleTransactionDataBroker.syncReadOptional(
456                     dataBroker, LogicalDatastoreType.CONFIGURATION, dcGatewayIpListInstanceIdentifier);
457             if (!dcGatewayIpListOptional.isPresent()) {
458                 LOG.info("No DC gateways configured.");
459                 return tunnelInterfaceNameList;
460             }
461             Map<DcGatewayIpKey, DcGatewayIp> keyDcGatewayIpMap = dcGatewayIpListOptional.get().nonnullDcGatewayIp();
462             InstanceIdentifier<ExternalTunnelList> externalTunnelListId = InstanceIdentifier
463                     .create(ExternalTunnelList.class);
464             Optional<ExternalTunnelList> externalTunnelListOptional = SingleTransactionDataBroker.syncReadOptional(
465                     dataBroker, LogicalDatastoreType.OPERATIONAL, externalTunnelListId);
466             if (externalTunnelListOptional.isPresent()) {
467                 Map<ExternalTunnelKey, ExternalTunnel> keyExternalTunnelMap
468                         = externalTunnelListOptional.get().nonnullExternalTunnel();
469                 List<String> externalTunnelIpList = new ArrayList<>();
470                 for (ExternalTunnel externalTunnel: keyExternalTunnelMap.values()) {
471                     externalTunnelIpList.add(externalTunnel.getDestinationDevice());
472                 }
473                 List<String> dcGatewayIpList = new ArrayList<>();
474                 for (DcGatewayIp dcGatewayIp: keyDcGatewayIpMap.values()) {
475                     dcGatewayIpList.add(dcGatewayIp.getIpAddress().getIpv4Address().toString());
476                 }
477                 // Find all externalTunnelIps present in dcGateWayIpList
478                 List<String> externalTunnelIpsInDcGatewayIpList = new ArrayList<>();
479                 for (String externalTunnelIp: externalTunnelIpList) {
480                     for (String dcGateWayIp: dcGatewayIpList) {
481                         if (externalTunnelIp.contentEquals(dcGateWayIp)) {
482                             externalTunnelIpsInDcGatewayIpList.add(externalTunnelIp);
483                         }
484                     }
485                 }
486                 for (String externalTunnelIpsInDcGatewayIp: externalTunnelIpsInDcGatewayIpList) {
487                     for (ExternalTunnel externalTunnel: keyExternalTunnelMap.values()) {
488                         if (externalTunnel.getDestinationDevice().contentEquals(externalTunnelIpsInDcGatewayIp)) {
489                             tunnelInterfaceNameList.add(externalTunnel.getTunnelInterfaceName());
490                         }
491                     }
492                 }
493
494             }
495         } catch (InterruptedException | ExecutionException e) {
496             LOG.error("getDcGatewayTunnelInterfaceNameList: Failed to read data store");
497         }
498         return tunnelInterfaceNameList;
499     }
500
501     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
502             justification = "https://github.com/spotbugs/spotbugs/issues/811")
503     private String getFibFlowRef(Uint64 dpnId, short tableId, String vpnName, int priority) {
504         return VpnConstants.FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
505                 + NwConstants.FLOWID_SEPARATOR + vpnName + NwConstants.FLOWID_SEPARATOR + priority;
506     }
507 }