Convert vpnmanager-impl to use blueprint annotations
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInstanceListener.java
index ed4fef35d3e4f67592dd23eced48e4480506f894..37a82ec50395030383aebcff1d52121df46991bf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2015 - 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -8,68 +8,89 @@
 package org.opendaylight.netvirt.vpnmanager;
 
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-
+import com.google.common.util.concurrent.MoreExecutors;
+import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
-
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
-import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
-import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
-import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.genius.mdsalutil.FlowEntity;
+import org.opendaylight.genius.mdsalutil.InstructionInfo;
+import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MatchInfo;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NWUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
+import org.opendaylight.genius.utils.SystemPropertyReader;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
-import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
-import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.LayerType;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.vpntargets.VpnTarget;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnTargetsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTargetKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.Vpn;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInstance, VpnInstanceListener>
-    implements AutoCloseable {
+@Singleton
+public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInstance, VpnInstanceListener> {
     private static final Logger LOG = LoggerFactory.getLogger(VpnInstanceListener.class);
+    private static final String LOGGING_PREFIX_ADD = "VPN-ADD:";
+    private static final String LOGGING_PREFIX_DELETE = "VPN-REMOVE:";
     private final DataBroker dataBroker;
-    private final IBgpManager bgpManager;
     private final IdManagerService idManager;
     private final VpnInterfaceManager vpnInterfaceManager;
     private final IFibManager fibManager;
     private final VpnOpDataSyncer vpnOpDataNotifier;
-
-    public VpnInstanceListener(final DataBroker dataBroker, final IBgpManager bgpManager,
-        final IdManagerService idManager, final VpnInterfaceManager vpnInterfaceManager, final IFibManager fibManager,
-        final VpnOpDataSyncer vpnOpDataSyncer) {
+    private final IMdsalApiManager mdsalManager;
+    private final JobCoordinator jobCoordinator;
+
+    @Inject
+    public VpnInstanceListener(final DataBroker dataBroker, final IdManagerService idManager,
+            final VpnInterfaceManager vpnInterfaceManager, final IFibManager fibManager,
+            final VpnOpDataSyncer vpnOpDataSyncer, final IMdsalApiManager mdsalManager,
+            final JobCoordinator jobCoordinator) {
         super(VpnInstance.class, VpnInstanceListener.class);
         this.dataBroker = dataBroker;
-        this.bgpManager = bgpManager;
         this.idManager = idManager;
         this.vpnInterfaceManager = vpnInterfaceManager;
         this.fibManager = fibManager;
         this.vpnOpDataNotifier = vpnOpDataSyncer;
+        this.mdsalManager = mdsalManager;
+        this.jobCoordinator = jobCoordinator;
     }
 
+    @PostConstruct
     public void start() {
         LOG.info("{} start", getClass().getSimpleName());
         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
@@ -85,119 +106,11 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         return VpnInstanceListener.this;
     }
 
-    private void waitForOpRemoval(String rd, String vpnName) {
-        //wait till DCN for update on VPN Instance Op Data signals that vpn interfaces linked to this vpn instance is
-        // zero
-        //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
-        VpnInstanceOpDataEntry vpnOpEntry = null;
-        Long intfCount = 0L;
-        Long currentIntfCount = 0L;
-        Integer retryCount = 3;
-        long timeout = VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
-        Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
-        vpnOpValue = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-            VpnUtil.getVpnInstanceOpDataIdentifier(rd));
-
-        if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
-            vpnOpEntry = vpnOpValue.get();
-            List<VpnToDpnList> dpnToVpns = vpnOpEntry.getVpnToDpnList();
-            if (dpnToVpns != null) {
-                for (VpnToDpnList dpn : dpnToVpns) {
-                    if (dpn.getVpnInterfaces() != null) {
-                        intfCount = intfCount + dpn.getVpnInterfaces().size();
-                    }
-                }
-            }
-            //intfCount = vpnOpEntry.getVpnInterfaceCount();
-            while (true) {
-                if (intfCount > 0) {
-                    // Minimum wait time of 5 seconds for one VPN Interface clearance (inclusive of full trace on)
-                    timeout = intfCount * VpnConstants.MIN_WAIT_TIME_IN_MILLISECONDS;
-                    // Maximum wait time of 90 seconds for all VPN Interfaces clearance (inclusive of full trace on)
-                    if (timeout > VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS) {
-                        timeout = VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS;
-                    }
-                    LOG.info("VPNInstance removal count of interface at {} for for rd {}, vpnname {}",
-                        intfCount, rd, vpnName);
-                }
-                LOG.info("VPNInstance removal thread waiting for {} seconds for rd {}, vpnname {}",
-                    (timeout / 1000), rd, vpnName);
-
-                try {
-                    Thread.sleep(timeout);
-                } catch (InterruptedException e) {
-                    // Ignored
-                }
-
-                // Check current interface count
-                vpnOpValue = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                    VpnUtil.getVpnInstanceOpDataIdentifier(rd));
-                if ((vpnOpValue != null) && (vpnOpValue.isPresent())) {
-                    vpnOpEntry = vpnOpValue.get();
-                    dpnToVpns = vpnOpEntry.getVpnToDpnList();
-                    currentIntfCount = 0L;
-                    if (dpnToVpns != null) {
-                        for (VpnToDpnList dpn : dpnToVpns) {
-                            if (dpn.getVpnInterfaces() != null) {
-                                currentIntfCount = currentIntfCount + dpn.getVpnInterfaces().size();
-                            }
-                        }
-                    }
-                    if ((currentIntfCount == 0) || (currentIntfCount >= intfCount)) {
-                        // Either the FibManager completed its job to cleanup all vpnInterfaces in VPN
-                        // OR
-                        // There is no progress by FibManager in removing all the interfaces even after good time!
-                        // In either case, let us quit and take our chances.
-                        //TODO(vpnteam): L3VPN refactoring to take care of this case.
-                        if ((dpnToVpns == null) || dpnToVpns.size() <= 0) {
-                            LOG.info("VPN Instance vpn {} rd {} ready for removal, exiting wait loop", vpnName, rd);
-                            break;
-                        } else {
-                            if (retryCount > 0) {
-                                retryCount--;
-                                LOG.info(
-                                    "Retrying clearing vpn with vpnname {} rd {} since current interface count {} ",
-                                    vpnName, rd, currentIntfCount);
-                                if (currentIntfCount > 0) {
-                                    intfCount = currentIntfCount;
-                                } else {
-                                    LOG.info(
-                                        "Current interface count is zero, but instance Op for vpn {} and rd {} not "
-                                            + "cleared yet. Waiting for 5 more seconds.",
-                                        vpnName, rd);
-                                    intfCount = 1L;
-                                }
-                            } else {
-                                LOG.info(
-                                    "VPNInstance bailing out of wait loop as current interface count is {} and max "
-                                        + "retries exceeded for for vpnName {}, rd {}",
-                                    currentIntfCount, vpnName, rd);
-                                break;
-                            }
-                        }
-                    } else {
-                        LOG.info("Retrying clearing because not all vpnInterfaces removed : current interface count {},"
-                                + " initial count {} for rd {}, vpnname {}", currentIntfCount, intfCount, rd, vpnName);
-                        intfCount = currentIntfCount;
-                    }
-                } else {
-                    // There is no VPNOPEntry.  Something else happened on the system !
-                    // So let us quit and take our chances.
-                    //TODO(vpnteam): L3VPN refactoring to take care of this case.
-                    LOG.error("VpnInstanceOpData is not present in the operational DS for rd {}, vpnname {}", rd,
-                            vpnName);
-                    break;
-                }
-            }
-        }
-        LOG.info("Returned out of waiting for  Op Data removal for rd {}, vpnname {}", rd, vpnName);
-    }
-
     @Override
     protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
-        LOG.trace("Remove VPN event key: {}, value: {}", identifier, del);
+        LOG.trace("{} remove: VPN event key: {}, value: {}", LOGGING_PREFIX_DELETE, identifier, del);
         final String vpnName = del.getVpnInstanceName();
-        Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
+        Optional<VpnInstanceOpDataEntry> vpnOpValue;
         String primaryRd = VpnUtil.getPrimaryRd(del);
 
         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
@@ -205,106 +118,56 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             vpnOpValue = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd));
         } catch (ReadFailedException e) {
-            LOG.error("Exception when attempting to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName, e);
+            LOG.error("{} remove: Exception when attempting to retrieve VpnInstanceOpDataEntry for VPN {}. ",
+                    LOGGING_PREFIX_DELETE,  vpnName, e);
             return;
         }
 
-        if (vpnOpValue == null || !vpnOpValue.isPresent()) {
-            LOG.error("Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName);
+        if (!vpnOpValue.isPresent()) {
+            LOG.error("{} remove: Unable to retrieve VpnInstanceOpDataEntry for VPN {}. ", LOGGING_PREFIX_DELETE,
+                    vpnName);
             return;
-        }
-
-        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-        dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
-            new DeleteVpnInstanceWorker(idManager, dataBroker, del));
-    }
-
-    private class DeleteVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
-        IdManagerService idManager;
-        DataBroker broker;
-        VpnInstance vpnInstance;
-
-        DeleteVpnInstanceWorker(IdManagerService idManager,
-            DataBroker broker,
-            VpnInstance value) {
-            this.idManager = idManager;
-            this.broker = broker;
-            this.vpnInstance = value;
-        }
-
-        @Override
-        public List<ListenableFuture<Void>> call() {
-            final String vpnName = vpnInstance.getVpnInstanceName();
-            final List<String> rds = vpnInstance.getIpv4Family().getRouteDistinguisher();
-            String primaryRd = VpnUtil.getPrimaryRd(vpnInstance);
-            final long vpnId = VpnUtil.getVpnId(broker, vpnName);
-            WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
-            waitForOpRemoval(primaryRd, vpnName);
-
-            // Clean up VpnInstanceToVpnId from Config DS
-            VpnUtil.removeVpnIdToVpnInstance(broker, vpnId, writeTxn);
-            VpnUtil.removeVpnInstanceToVpnId(broker, vpnName, writeTxn);
-            LOG.trace("Removed vpnIdentifier for  rd{} vpnname {}", primaryRd, vpnName);
-            // Clean up FIB Entries Config DS
-            synchronized (vpnName.intern()) {
-                fibManager.removeVrfTable(broker, primaryRd, null);
-            }
-            if (VpnUtil.isBgpVpn(vpnName, primaryRd)) {
-                rds.parallelStream().forEach(rd -> bgpManager.deleteVrf(rd, false));
-            }
-            // Clean up VPNExtraRoutes Operational DS
-            InstanceIdentifier<Vpn> vpnToExtraroute = VpnExtraRouteHelper.getVpnToExtrarouteVpnIdentifier(vpnName);
-            Optional<Vpn> optVpnToExtraroute = VpnUtil.read(broker,
-                    LogicalDatastoreType.OPERATIONAL, vpnToExtraroute);
-            if (optVpnToExtraroute.isPresent()) {
-                VpnUtil.removeVpnExtraRouteForVpn(broker, vpnName, writeTxn);
-            }
-
-            // Clean up VPNInstanceOpDataEntry
-            VpnUtil.removeVpnOpInstance(broker, primaryRd, writeTxn);
-            // Clean up PrefixToInterface Operational DS
-            VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId, writeTxn);
-
-            // Clean up L3NextHop Operational DS
-            VpnUtil.removeL3nexthopForVpnId(broker, vpnId, writeTxn);
-
-            // Release the ID used for this VPN back to IdManager
-            VpnUtil.releaseId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnName);
-
-            List<ListenableFuture<Void>> futures = new ArrayList<>();
-            futures.add(writeTxn.submit());
-            return futures;
+        } else {
+            jobCoordinator.enqueueJob("VPN-" + vpnName, () -> {
+                VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd)
+                        .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
+                InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd);
+                WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
+                writeTxn.merge(LogicalDatastoreType.OPERATIONAL, id, builder.build());
+
+                LOG.info("{} call: Operational status set to PENDING_DELETE for vpn {} with rd {}",
+                        LOGGING_PREFIX_DELETE, vpnName, primaryRd);
+                return Collections.singletonList(writeTxn.submit());
+            }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
         }
     }
 
     @Override
     protected void update(InstanceIdentifier<VpnInstance> identifier,
         VpnInstance original, VpnInstance update) {
-        LOG.trace("Update VPN event key: {}, value: {}", identifier, update);
+        LOG.trace("VPN-UPDATE: update: VPN event key: {}, value: {}. Ignoring", identifier, update);
+        String vpnName = update.getVpnInstanceName();
+        vpnInterfaceManager.updateVpnInterfacesForUnProcessAdjancencies(dataBroker,vpnName);
     }
 
     @Override
     protected void add(final InstanceIdentifier<VpnInstance> identifier, final VpnInstance value) {
-        LOG.trace("Add VPN event key: {}, value: {}", identifier, value);
+        LOG.trace("{} add: Add VPN event key: {}, value: {}", LOGGING_PREFIX_ADD, identifier, value);
         final String vpnName = value.getVpnInstanceName();
-
-        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-        dataStoreCoordinator.enqueueJob("VPN-" + vpnName,
-            new AddVpnInstanceWorker(idManager, vpnInterfaceManager, dataBroker, value));
+        jobCoordinator.enqueueJob("VPN-" + vpnName,
+            new AddVpnInstanceWorker(idManager, dataBroker, value));
     }
 
     private class AddVpnInstanceWorker implements Callable<List<ListenableFuture<Void>>> {
+        private final Logger log = LoggerFactory.getLogger(AddVpnInstanceWorker.class);
         IdManagerService idManager;
-        VpnInterfaceManager vpnInterfaceManager;
         VpnInstance vpnInstance;
         DataBroker broker;
 
         AddVpnInstanceWorker(IdManagerService idManager,
-            VpnInterfaceManager vpnInterfaceManager,
             DataBroker broker,
             VpnInstance value) {
             this.idManager = idManager;
-            this.vpnInterfaceManager = vpnInterfaceManager;
             this.broker = broker;
             this.vpnInstance = value;
         }
@@ -313,22 +176,21 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         public List<ListenableFuture<Void>> call() throws Exception {
             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
             // to call the respective helpers.
-            final VpnAfConfig config = vpnInstance.getIpv4Family();
             WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
             WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
             addVpnInstance(vpnInstance, writeConfigTxn, writeOperTxn);
-            CheckedFuture<Void, TransactionCommitFailedException> checkFutures = writeOperTxn.submit();
             try {
-                checkFutures.get();
+                writeOperTxn.submit().get();
             } catch (InterruptedException | ExecutionException e) {
-                LOG.error("Error creating vpn {} ", vpnInstance.getVpnInstanceName());
+                log.error("{} call: Error creating vpn {} ", LOGGING_PREFIX_ADD, vpnInstance.getVpnInstanceName());
                 throw new RuntimeException(e.getMessage());
             }
             List<ListenableFuture<Void>> futures = new ArrayList<>();
             futures.add(writeConfigTxn.submit());
             ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
             Futures.addCallback(listenableFuture,
-                new PostAddVpnInstanceWorker(config, vpnInstance.getVpnInstanceName()));
+                                new PostAddVpnInstanceWorker(vpnInstance , vpnInstance.getVpnInstanceName()),
+                                MoreExecutors.directExecutor());
             return futures;
         }
     }
@@ -342,26 +204,23 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
 
         long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
         if (vpnId == 0) {
-            LOG.error(
-                "Unable to fetch label from Id Manager. Bailing out of adding operational data for Vpn Instance {}",
-                value.getVpnInstanceName());
-            LOG.error(
-                "Unable to fetch label from Id Manager. Bailing out of adding operational data for Vpn Instance {}",
-                value.getVpnInstanceName());
+            LOG.error("{} addVpnInstance: Unable to fetch label from Id Manager. Bailing out of adding operational"
+                    + " data for Vpn Instance {}", LOGGING_PREFIX_ADD, value.getVpnInstanceName());
             return;
         }
-        LOG.info("VPN Id {} generated for VpnInstanceName {}", vpnId, vpnInstanceName);
+        LOG.info("{} addVpnInstance: VPN Id {} generated for VpnInstanceName {}", LOGGING_PREFIX_ADD, vpnId,
+                vpnInstanceName);
         String primaryRd = VpnUtil.getPrimaryRd(value);
         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
             vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, primaryRd);
 
         if (writeConfigTxn != null) {
             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
-                VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
-                vpnInstanceToVpnId, true);
+                VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
+                vpnInstanceToVpnId, WriteTransaction.CREATE_MISSING_PARENTS);
         } else {
             TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                VpnUtil.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
+                VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
                 vpnInstanceToVpnId, TransactionUtil.DEFAULT_CALLBACK);
         }
 
@@ -371,7 +230,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         if (writeConfigTxn != null) {
             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
                 VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
-                vpnIdToVpnInstance, true);
+                vpnIdToVpnInstance, WriteTransaction.CREATE_MISSING_PARENTS);
         } else {
             TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
                 VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
@@ -384,24 +243,32 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
                 try {
                     fibManager.setConfTransType("L3VPN", "VXLAN");
                 } catch (Exception e) {
-                    LOG.error("Exception caught setting the L3VPN tunnel transportType", e);
+                    LOG.error("{} addVpnInstance: Exception caught setting the L3VPN tunnel transportType for vpn {}",
+                            LOGGING_PREFIX_ADD, vpnInstanceName, e);
                 }
             } else {
-                LOG.trace("Configured tunnel transport type for L3VPN as {}", cachedTransType);
+                LOG.debug("{} addVpnInstance: Configured tunnel transport type for L3VPN {} as {}", LOGGING_PREFIX_ADD,
+                        vpnInstanceName, cachedTransType);
             }
         } catch (Exception e) {
-            LOG.error("Error when trying to retrieve tunnel transport type for L3VPN ", e);
+            LOG.error("{} addVpnInstance: Error when trying to retrieve tunnel transport type for L3VPN {}",
+                    LOGGING_PREFIX_ADD, vpnInstanceName, e);
         }
 
         VpnInstanceOpDataEntryBuilder builder =
                 new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd).setVpnId(vpnId)
-                        .setVpnInstanceName(vpnInstanceName);
+                        .setVpnInstanceName(vpnInstanceName)
+                        .setVpnState(VpnInstanceOpDataEntry.VpnState.Created)
+                        .setIpv4Configured(false).setIpv6Configured(false);
         if (VpnUtil.isBgpVpn(vpnInstanceName, primaryRd)) {
             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
                 .instance.op.data.entry.vpntargets.VpnTarget> opVpnTargetList = new ArrayList<>();
             if (value.getL3vni() != null) {
                 builder.setL3vni(value.getL3vni());
             }
+            if (value.getType() == VpnInstance.Type.L2) {
+                builder.setType(VpnInstanceOpDataEntry.Type.L2);
+            }
             VpnTargets vpnTargets = config.getVpnTargets();
             if (vpnTargets != null) {
                 List<VpnTarget> vpnTargetList = vpnTargets.getVpnTarget();
@@ -419,6 +286,9 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             }
             VpnTargetsBuilder vpnTargetsBuilder = new VpnTargetsBuilder().setVpnTarget(opVpnTargetList);
             builder.setVpnTargets(vpnTargetsBuilder.build());
+
+            List<String> rds = config.getRouteDistinguisher();
+            builder.setRd(rds);
         }
         if (writeOperTxn != null) {
             writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
@@ -429,15 +299,17 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
                 VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd),
                 builder.build(), TransactionUtil.DEFAULT_CALLBACK);
         }
-        LOG.info("VpnInstanceOpData populated successfully for vpn {} rd {}", vpnInstanceName, primaryRd);
+        LOG.info("{} addVpnInstance: VpnInstanceOpData populated successfully for vpn {} rd {}", LOGGING_PREFIX_ADD,
+                vpnInstanceName, primaryRd);
     }
 
     private class PostAddVpnInstanceWorker implements FutureCallback<List<Void>> {
-        VpnAfConfig config;
+        private final Logger log = LoggerFactory.getLogger(PostAddVpnInstanceWorker.class);
+        VpnInstance vpnInstance;
         String vpnName;
 
-        PostAddVpnInstanceWorker(VpnAfConfig config, String vpnName) {
-            this.config = config;
+        PostAddVpnInstanceWorker(VpnInstance vpnInstance, String vpnName) {
+            this.vpnInstance = vpnInstance;
             this.vpnName = vpnName;
         }
 
@@ -450,51 +322,57 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             if rd is null, then its either a router vpn instance (or) a vlan external network vpn instance.
             if rd is non-null, then it is a bgpvpn instance
              */
+            VpnAfConfig config = vpnInstance.getIpv4Family();
             List<String> rd = config.getRouteDistinguisher();
-            if ((rd == null) || addBgpVrf(voids)) {
+            if (rd == null || addBgpVrf(voids)) {
                 notifyTask();
                 vpnInterfaceManager.vpnInstanceIsReady(vpnName);
             }
+            log.info("{} onSuccess: Vpn Instance Op Data addition for {} successful.", LOGGING_PREFIX_ADD, vpnName);
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(dataBroker,
+                    VpnUtil.getPrimaryRd(vpnInstance));
+
+            // bind service on each tunnel interface
+            //TODO (KIRAN): Add a new listener to handle creation of new DC-GW binding and deletion of existing DC-GW.
+            if (VpnUtil.isL3VpnOverVxLan(vpnInstance.getL3vni())) { //Handled for L3VPN Over VxLAN
+                for (String tunnelInterfaceName: getDcGatewayTunnelInterfaceNameList()) {
+                    VpnUtil.bindService(vpnInstance.getVpnInstanceName(), tunnelInterfaceName, dataBroker,
+                            true/*isTunnelInterface*/, jobCoordinator);
+                }
+
+                // install flow
+                List<MatchInfo> mkMatches = new ArrayList<>();
+                mkMatches.add(new MatchTunnelId(BigInteger.valueOf(vpnInstance.getL3vni())));
+
+                List<InstructionInfo> instructions =
+                        Arrays.asList(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnInstanceOpDataEntry
+                                .getVpnId()), MetaDataUtil.METADATA_MASK_VRFID),
+                                new InstructionGotoTable(NwConstants.L3_GW_MAC_TABLE));
+
+                for (BigInteger dpnId: NWUtil.getOperativeDPNs(dataBroker)) {
+                    String flowRef = getFibFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+                            vpnName, VpnConstants.DEFAULT_FLOW_PRIORITY);
+                    FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId,
+                            NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE, flowRef, VpnConstants.DEFAULT_FLOW_PRIORITY,
+                            "VxLAN VPN Tunnel Bind Service", 0, 0, NwConstants.COOKIE_VM_FIB_TABLE,
+                            mkMatches, instructions);
+                    mdsalManager.installFlow(dpnId, flowEntity);
+                }
+
+                ///////////////////////
+            }
         }
 
         // TODO Clean up the exception handling
         @SuppressWarnings("checkstyle:IllegalCatch")
         private boolean addBgpVrf(List<Void> voids) {
-            List<String> rds = config.getRouteDistinguisher();
+            VpnAfConfig config = vpnInstance.getIpv4Family();
             String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName);
             List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
 
-            List<String> ertList = new ArrayList<>();
-            List<String> irtList = new ArrayList<>();
-
-            if (vpnTargetList != null) {
-                for (VpnTarget vpnTarget : vpnTargetList) {
-                    if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
-                        ertList.add(vpnTarget.getVrfRTValue());
-                    }
-                    if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
-                        irtList.add(vpnTarget.getVrfRTValue());
-                    }
-                    if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
-                        ertList.add(vpnTarget.getVrfRTValue());
-                        irtList.add(vpnTarget.getVrfRTValue());
-                    }
-                }
-            } else {
-                LOG.error("vpn target list is empty, cannot add BGP VPN {} VRF {}", this.vpnName, primaryRd);
-                return false;
-            }
-            //Advertise all the rds and check if primary Rd advertisement fails
-            long primaryRdAddFailed = rds.parallelStream().filter(rd -> {
-                try {
-                    bgpManager.addVrf(rd, irtList, ertList, LayerType.LAYER3);
-                } catch (Exception e) {
-                    LOG.error("Exception when adding VRF {} to BGP {}. Exception {}", rd, vpnName, e);
-                    return rd.equals(primaryRd);
-                }
-                return false;
-            }).count();
-            if (primaryRdAddFailed == 1) {
+            if (vpnTargetList == null) {
+                log.error("{} addBgpVrf: vpn target list is empty for vpn {} RD {}", LOGGING_PREFIX_ADD,
+                        this.vpnName, primaryRd);
                 return false;
             }
             vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, primaryRd);
@@ -515,26 +393,12 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
 
         @Override
         public void onFailure(Throwable throwable) {
-            LOG.error("Job for vpnInstance: {} failed with exception: {}", vpnName ,throwable);
+            log.error("{} onFailure: Job for vpnInstance: {} failed with exception: {}", LOGGING_PREFIX_ADD, vpnName,
+                    throwable);
             vpnInterfaceManager.vpnInstanceFailed(vpnName);
         }
     }
 
-    public boolean isVPNConfigured() {
-
-        InstanceIdentifier<VpnInstances> vpnsIdentifier = InstanceIdentifier.builder(VpnInstances.class).build();
-        Optional<VpnInstances> optionalVpns = TransactionUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
-            vpnsIdentifier);
-        if (!optionalVpns.isPresent()
-            || optionalVpns.get().getVpnInstance() == null
-            || optionalVpns.get().getVpnInstance().isEmpty()) {
-            LOG.trace("No VPNs configured.");
-            return false;
-        }
-        LOG.trace("VPNs are configured on the system.");
-        return true;
-    }
-
     protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
         Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
@@ -544,4 +408,63 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         }
         return null;
     }
+
+    private List<String> getDcGatewayTunnelInterfaceNameList() {
+        List<String> tunnelInterfaceNameList = new ArrayList<>();
+
+        InstanceIdentifier<DcGatewayIpList> dcGatewayIpListInstanceIdentifier = InstanceIdentifier
+                .create(DcGatewayIpList.class);
+        Optional<DcGatewayIpList> dcGatewayIpListOptional = VpnUtil.read(dataBroker,
+                LogicalDatastoreType.CONFIGURATION, dcGatewayIpListInstanceIdentifier);
+        if (!dcGatewayIpListOptional.isPresent()) {
+            LOG.info("No DC gateways configured.");
+            return tunnelInterfaceNameList;
+        }
+        List<DcGatewayIp> dcGatewayIps = dcGatewayIpListOptional.get().getDcGatewayIp();
+
+        InstanceIdentifier<ExternalTunnelList> externalTunnelListId = InstanceIdentifier
+                .create(ExternalTunnelList.class);
+
+        Optional<ExternalTunnelList> externalTunnelListOptional = VpnUtil.read(dataBroker,
+                LogicalDatastoreType.OPERATIONAL, externalTunnelListId);
+        if (externalTunnelListOptional.isPresent()) {
+            List<ExternalTunnel> externalTunnels = externalTunnelListOptional.get().getExternalTunnel();
+
+            List<String> externalTunnelIpList = new ArrayList<>();
+            for (ExternalTunnel externalTunnel: externalTunnels) {
+                externalTunnelIpList.add(externalTunnel.getDestinationDevice());
+            }
+
+            List<String> dcGatewayIpList = new ArrayList<>();
+            for (DcGatewayIp dcGatewayIp: dcGatewayIps) {
+                dcGatewayIpList.add(dcGatewayIp.getIpAddress().getIpv4Address().toString());
+            }
+
+            // Find all externalTunnelIps present in dcGateWayIpList
+            List<String> externalTunnelIpsInDcGatewayIpList = new ArrayList<>();
+            for (String externalTunnelIp: externalTunnelIpList) {
+                for (String dcGateWayIp: dcGatewayIpList) {
+                    if (externalTunnelIp.contentEquals(dcGateWayIp)) {
+                        externalTunnelIpsInDcGatewayIpList.add(externalTunnelIp);
+                    }
+                }
+            }
+
+
+            for (String externalTunnelIpsInDcGatewayIp: externalTunnelIpsInDcGatewayIpList) {
+                for (ExternalTunnel externalTunnel: externalTunnels) {
+                    if (externalTunnel.getDestinationDevice().contentEquals(externalTunnelIpsInDcGatewayIp)) {
+                        tunnelInterfaceNameList.add(externalTunnel.getTunnelInterfaceName());
+                    }
+                }
+            }
+
+        }
+        return tunnelInterfaceNameList;
+    }
+
+    private String getFibFlowRef(BigInteger dpnId, short tableId, String vpnName, int priority) {
+        return VpnConstants.FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
+                + NwConstants.FLOWID_SEPARATOR + vpnName + NwConstants.FLOWID_SEPARATOR + priority;
+    }
 }