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