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