Ethernet VPN Flow Programming for VMs in different Data Centers
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInstanceListener.java
index 23f88943f0d34f2ac2557008edd3b00dae68e206..688b5f36ff916d261696b5a2ff28f65c93d0cf2b 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,
@@ -12,10 +12,14 @@ 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 java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
+
 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;
@@ -24,14 +28,31 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFaile
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+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.netvirt.bgpmanager.api.IBgpManager;
 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;
@@ -39,7 +60,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
 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.extraroute.Vpn;
+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;
@@ -53,10 +74,11 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
     private final VpnInterfaceManager vpnInterfaceManager;
     private final IFibManager fibManager;
     private final VpnOpDataSyncer vpnOpDataNotifier;
+    private final IMdsalApiManager mdsalManager;
 
     public VpnInstanceListener(final DataBroker dataBroker, final IBgpManager bgpManager,
         final IdManagerService idManager, final VpnInterfaceManager vpnInterfaceManager, final IFibManager fibManager,
-        final VpnOpDataSyncer vpnOpDataSyncer) {
+        final VpnOpDataSyncer vpnOpDataSyncer, final IMdsalApiManager mdsalManager) {
         super(VpnInstance.class, VpnInstanceListener.class);
         this.dataBroker = dataBroker;
         this.bgpManager = bgpManager;
@@ -64,6 +86,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         this.vpnInterfaceManager = vpnInterfaceManager;
         this.fibManager = fibManager;
         this.vpnOpDataNotifier = vpnOpDataSyncer;
+        this.mdsalManager = mdsalManager;
     }
 
     public void start() {
@@ -193,18 +216,13 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
     protected void remove(InstanceIdentifier<VpnInstance> identifier, VpnInstance del) {
         LOG.trace("Remove VPN event key: {}, value: {}", identifier, del);
         final String vpnName = del.getVpnInstanceName();
-        final String rd = del.getIpv4Family().getRouteDistinguisher();
         Optional<VpnInstanceOpDataEntry> vpnOpValue = null;
+        String primaryRd = VpnUtil.getPrimaryRd(del);
 
         //TODO(vpnteam): Entire code would need refactoring to listen only on the parent object - VPNInstance
         try {
-            if ((rd != null) && (!rd.isEmpty())) {
-                vpnOpValue = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                    VpnUtil.getVpnInstanceOpDataIdentifier(rd));
-            } else {
-                vpnOpValue = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                    VpnUtil.getVpnInstanceOpDataIdentifier(vpnName));
-            }
+            vpnOpValue = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd));
         } catch (ReadFailedException e) {
             LOG.error("Exception when attempting to retrieve VpnInstanceOpDataEntry for VPN {}. ", vpnName, e);
             return;
@@ -233,60 +251,40 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             this.vpnInstance = value;
         }
 
-        // TODO Clean up the exception handling
-        @SuppressWarnings("checkstyle:IllegalCatch")
         @Override
         public List<ListenableFuture<Void>> call() {
             final String vpnName = vpnInstance.getVpnInstanceName();
-            final String rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
+            final List<String> rds = vpnInstance.getIpv4Family().getRouteDistinguisher();
+            String primaryRd = VpnUtil.getPrimaryRd(vpnInstance);
             final long vpnId = VpnUtil.getVpnId(broker, vpnName);
             WriteTransaction writeTxn = broker.newWriteOnlyTransaction();
-            if ((rd != null) && (!rd.isEmpty())) {
-                waitForOpRemoval(rd, vpnName);
-            } else {
-                waitForOpRemoval(vpnName, vpnName);
-            }
+            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 {}", rd, vpnName);
-            if (rd != null) {
-                synchronized (vpnName.intern()) {
-                    fibManager.removeVrfTable(broker, rd, null);
-                }
-                try {
-                    bgpManager.deleteVrf(rd, false);
-                } catch (Exception e) {
-                    LOG.error("Exception when removing VRF from BGP for RD {} in VPN {} exception " + e, rd, vpnName);
-                }
-
-                // Clean up VPNExtraRoutes Operational DS
-                InstanceIdentifier<Vpn> vpnToExtraroute = VpnUtil.getVpnToExtrarouteIdentifier(rd);
-                Optional<Vpn> optVpnToExtraroute =
-                    VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, vpnToExtraroute);
-                if (optVpnToExtraroute.isPresent()) {
-                    VpnUtil.removeVpnExtraRouteForVpn(broker, rd, writeTxn);
-                }
-
-                // Clean up VPNInstanceOpDataEntry
-                VpnUtil.removeVpnOpInstance(broker, rd, writeTxn);
-            } else {
-                // Clean up FIB Entries Config DS
-                synchronized (vpnName.intern()) {
-                    fibManager.removeVrfTable(broker, vpnName, null);
-                }
-                // Clean up VPNExtraRoutes Operational DS
-                InstanceIdentifier<Vpn> vpnToExtraroute = VpnUtil.getVpnToExtrarouteIdentifier(vpnName);
-                Optional<Vpn> optVpnToExtraroute =
-                    VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, vpnToExtraroute);
-                if (optVpnToExtraroute.isPresent()) {
-                    VpnUtil.removeVpnExtraRouteForVpn(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, vpnName, writeTxn);
+            if (VpnUtil.isL3VpnOverVxLan(vpnInstance.getL3vni())) {
+                removeExternalTunnelDemuxFlows(vpnName);
             }
+
+            // Clean up VPNInstanceOpDataEntry
+            VpnUtil.removeVpnOpInstance(broker, primaryRd, writeTxn);
             // Clean up PrefixToInterface Operational DS
             VpnUtil.removePrefixToInterfaceForVpnId(broker, vpnId, writeTxn);
 
@@ -338,7 +336,6 @@ 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);
@@ -353,7 +350,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             futures.add(writeConfigTxn.submit());
             ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
             Futures.addCallback(listenableFuture,
-                new PostAddVpnInstanceWorker(config, vpnInstance.getVpnInstanceName()));
+                    new PostAddVpnInstanceWorker(vpnInstance , vpnInstance.getVpnInstanceName()));
             return futures;
         }
     }
@@ -363,7 +360,6 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
     private void addVpnInstance(VpnInstance value, WriteTransaction writeConfigTxn,
         WriteTransaction writeOperTxn) {
         VpnAfConfig config = value.getIpv4Family();
-        String rd = config.getRouteDistinguisher();
         String vpnInstanceName = value.getVpnInstanceName();
 
         long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
@@ -377,9 +373,9 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             return;
         }
         LOG.info("VPN Id {} generated for VpnInstanceName {}", 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, (rd != null) ? rd
-            : vpnInstanceName);
+            vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, primaryRd);
 
         if (writeConfigTxn != null) {
             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
@@ -392,7 +388,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         }
 
         VpnIds vpnIdToVpnInstance = VpnUtil.getVpnIdToVpnInstance(vpnId, value.getVpnInstanceName(),
-            (rd != null) ? rd : value.getVpnInstanceName(), (rd != null)/*isExternalVpn*/);
+            primaryRd, VpnUtil.isBgpVpn(vpnInstanceName, primaryRd));
 
         if (writeConfigTxn != null) {
             writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
@@ -419,26 +415,15 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             LOG.error("Error when trying to retrieve tunnel transport type for L3VPN ", e);
         }
 
-        if (rd == null) {
-            VpnInstanceOpDataEntryBuilder builder =
-                new VpnInstanceOpDataEntryBuilder().setVrfId(vpnInstanceName).setVpnId(vpnId)
-                    .setVpnInstanceName(vpnInstanceName);
-            if (writeOperTxn != null) {
-                writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
-                    VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
-                    builder.build(), true);
-            } else {
-                TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                    VpnUtil.getVpnInstanceOpDataIdentifier(vpnInstanceName),
-                    builder.build(), TransactionUtil.DEFAULT_CALLBACK);
-            }
-        } else {
-            VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder()
-                .setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnInstanceName);
-
+        VpnInstanceOpDataEntryBuilder builder =
+                new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd).setVpnId(vpnId)
+                        .setVpnInstanceName(vpnInstanceName);
+        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<>();
+                .instance.op.data.entry.vpntargets.VpnTarget> opVpnTargetList = new ArrayList<>();
+            if (value.getL3vni() != null) {
+                builder.setL3vni(value.getL3vni());
+            }
             VpnTargets vpnTargets = config.getVpnTargets();
             if (vpnTargets != null) {
                 List<VpnTarget> vpnTargetList = vpnTargets.getVpnTarget();
@@ -456,27 +441,25 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             }
             VpnTargetsBuilder vpnTargetsBuilder = new VpnTargetsBuilder().setVpnTarget(opVpnTargetList);
             builder.setVpnTargets(vpnTargetsBuilder.build());
-
-            if (writeOperTxn != null) {
-                writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
-                    VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-                    builder.build(), true);
-            } else {
-                TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                    VpnUtil.getVpnInstanceOpDataIdentifier(rd),
-                    builder.build(), TransactionUtil.DEFAULT_CALLBACK);
-            }
         }
-        LOG.info("VpnInstanceOpData populated successfully for vpn {} rd {}", vpnInstanceName, rd);
+        if (writeOperTxn != null) {
+            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
+                VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd),
+                builder.build(), true);
+        } else {
+            TransactionUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd),
+                builder.build(), TransactionUtil.DEFAULT_CALLBACK);
+        }
+        LOG.info("VpnInstanceOpData populated successfully for vpn {} rd {}", vpnInstanceName, primaryRd);
     }
 
-
     private class PostAddVpnInstanceWorker implements FutureCallback<List<Void>> {
-        VpnAfConfig config;
+        VpnInstance vpnInstance;
         String vpnName;
 
-        PostAddVpnInstanceWorker(VpnAfConfig config, String vpnName) {
-            this.config = config;
+        PostAddVpnInstanceWorker(VpnInstance vpnInstance, String vpnName) {
+            this.vpnInstance = vpnInstance;
             this.vpnName = vpnName;
         }
 
@@ -489,21 +472,56 @@ 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
              */
-            String rd = config.getRouteDistinguisher();
+            VpnAfConfig config = vpnInstance.getIpv4Family();
+            List<String> rd = config.getRouteDistinguisher();
             if ((rd == null) || addBgpVrf(voids)) {
                 notifyTask();
                 vpnInterfaceManager.vpnInstanceIsReady(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*/);
+                }
+
+                // 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) {
-            String rd = config.getRouteDistinguisher();
+            VpnAfConfig config = vpnInstance.getIpv4Family();
+            List<String> rds = config.getRouteDistinguisher();
+            String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName);
             List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
 
-            List<String> ertList = new ArrayList<String>();
-            List<String> irtList = new ArrayList<String>();
+            List<String> ertList = new ArrayList<>();
+            List<String> irtList = new ArrayList<>();
 
             if (vpnTargetList != null) {
                 for (VpnTarget vpnTarget : vpnTargetList) {
@@ -519,16 +537,23 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
                     }
                 }
             } else {
-                LOG.error("vpn target list is empty, cannot add BGP VPN {} VRF {}", this.vpnName, rd);
+                LOG.error("vpn target list is empty, cannot add BGP VPN {} VRF {}", this.vpnName, primaryRd);
                 return false;
             }
-            try {
-                bgpManager.addVrf(rd, irtList, ertList);
-            } catch (Exception e) {
-                LOG.error("Exception when adding VRF to BGP", e);
+            //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) {
                 return false;
             }
-            vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, rd);
+            vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, primaryRd);
             return true;
         }
 
@@ -575,4 +600,76 @@ 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;
+    }
+
+    private void removeExternalTunnelDemuxFlows(String vpnName) {
+        LOG.info("Removing external tunnel flows for vpn {}", vpnName);
+        for (BigInteger dpnId: NWUtil.getOperativeDPNs(dataBroker)) {
+            LOG.debug("Removing external tunnel flows for vpn {} from dpn {}", vpnName, dpnId);
+            String flowRef = getFibFlowRef(dpnId, NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE,
+                    vpnName, VpnConstants.DEFAULT_FLOW_PRIORITY);
+            FlowEntity flowEntity = VpnUtil.buildFlowEntity(dpnId,
+                    NwConstants.L3VNI_EXTERNAL_TUNNEL_DEMUX_TABLE, flowRef);
+            mdsalManager.removeFlow(flowEntity);
+        }
+    }
 }