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