natservice-impl: propagate upstream non-null annotations
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatTunnelInterfaceStateListener.java
index 297dcf9eb8fb64b4ecf417e9d0f565d307e7a820..f299bd1c2f20764456d7e5377eb2f0e90bc692bc 100644 (file)
@@ -9,31 +9,49 @@
 package org.opendaylight.netvirt.natservice.internal;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Strings;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.Future;
+import javax.annotation.Nonnull;
+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.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.GroupEntity;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 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.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
@@ -48,6 +66,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.R
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
@@ -57,22 +78,27 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Singleton
 public class NatTunnelInterfaceStateListener
     extends AsyncDataTreeChangeListenerBase<StateTunnelList, NatTunnelInterfaceStateListener>
     implements AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(NatTunnelInterfaceStateListener.class);
     private final DataBroker dataBroker;
-    private IFibManager fibManager;
-    private SNATDefaultRouteProgrammer defaultRouteProgrammer;
-    private NaptSwitchHA naptSwitchHA;
-    private IMdsalApiManager mdsalManager;
-    private IdManagerService idManager;
-    private IBgpManager bgpManager;
-    private ExternalRoutersListener externalRouterListner;
-    private OdlInterfaceRpcService interfaceService;
-    private FloatingIPListener floatingIPListener;
-    private FibRpcService fibRpcService;
+    private final IFibManager fibManager;
+    private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
+    private final NaptSwitchHA naptSwitchHA;
+    private final IMdsalApiManager mdsalManager;
+    private final IdManagerService idManager;
+    private final IBgpManager bgpManager;
+    private final ExternalRoutersListener externalRouterListner;
+    private final SnatServiceManager natServiceManager;
+    private final OdlInterfaceRpcService interfaceService;
+    private final FloatingIPListener floatingIPListener;
+    private final FibRpcService fibRpcService;
+    private final IElanService elanManager;
+    private final IInterfaceManager interfaceManager;
+    private NatMode natMode = NatMode.Controller;
 
     protected enum TunnelAction {
         TUNNEL_EP_ADD,
@@ -94,7 +120,9 @@ public class NatTunnelInterfaceStateListener
      * @param interfaceService       - Interface Service
      * @param floatingIPListener     -  Floating IP Listner
      * @param fibRpcService          - FIB RPC Service
+     * @param elanManager            - Elan Manager
      */
+    @Inject
     public NatTunnelInterfaceStateListener(final DataBroker dataBroker,
                                            final IBgpManager bgpManager,
                                            final IFibManager fibManager,
@@ -103,9 +131,13 @@ public class NatTunnelInterfaceStateListener
                                            final IMdsalApiManager mdsalManager,
                                            final IdManagerService idManager,
                                            final ExternalRoutersListener externalRouterListner,
+                                           final SnatServiceManager natServiceManager,
                                            final OdlInterfaceRpcService interfaceService,
                                            final FloatingIPListener floatingIPListener,
-                                           final FibRpcService fibRpcService) {
+                                           final FibRpcService fibRpcService,
+                                           final NatserviceConfig config,
+                                           final IElanService elanManager,
+                                           final IInterfaceManager interfaceManager) {
         super(StateTunnelList.class, NatTunnelInterfaceStateListener.class);
         this.dataBroker = dataBroker;
         this.bgpManager = bgpManager;
@@ -115,12 +147,19 @@ public class NatTunnelInterfaceStateListener
         this.mdsalManager = mdsalManager;
         this.idManager = idManager;
         this.externalRouterListner = externalRouterListner;
+        this.natServiceManager = natServiceManager;
         this.interfaceService = interfaceService;
         this.floatingIPListener = floatingIPListener;
         this.fibRpcService = fibRpcService;
+        this.elanManager = elanManager;
+        this.interfaceManager = interfaceManager;
+        if (config != null) {
+            this.natMode = config.getNatMode();
+        }
     }
 
     @Override
+    @PostConstruct
     public void init() {
         LOG.info("{} init", getClass().getSimpleName());
         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
@@ -177,17 +216,22 @@ public class NatTunnelInterfaceStateListener
         //remove miss entry to NAPT switch
         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
 
-        //get ExternalIpIn prior
-        List<String> externalIpCache;
-        //HashMap Label
-        HashMap<String, Long> externalIpLabel;
         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
         if (routerId == NatConstants.INVALID_ID) {
             LOG.error("NAT Service : SNAT -> Invalid routerId returned for routerName {}", routerName);
             return;
         }
-        externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-        externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
+        Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
+        if (extNwProvType == null) {
+            return;
+        }
+        Map<String, Long> externalIpLabel;
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            externalIpLabel = null;
+        } else {
+            externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
+        }
         try {
             final String externalVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
             if (externalVpnName == null) {
@@ -227,8 +271,8 @@ public class NatTunnelInterfaceStateListener
                 GroupEntity groupEntity = null;
                 try {
                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
-                        GroupTypes.GroupAll, null);
-                    LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{}", groupEntity);
+                        GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
+                    LOG.info("NAT Service : SNAT -> Removing NAPT GroupEntity:{} on Dpn {}", groupEntity, dpnId);
                     mdsalManager.removeGroup(groupEntity);
                 } catch (Exception ex) {
                     LOG.debug("NAT Service : SNAT -> Failed to remove group entity {} : {}", groupEntity, ex);
@@ -278,9 +322,7 @@ public class NatTunnelInterfaceStateListener
         LOG.trace("NAT Service : Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp,
             destTepIp);
         int tunTypeVal = getTunnelType(stateTunnelList);
-
         LOG.trace("NAT Service : tunTypeVal is {}", tunTypeVal);
-
         try {
             String srcTepId = stateTunnelList.getSrcInfo().getTepDeviceId();
             String tunnelType = stateTunnelList.getTransportType().toString();
@@ -295,7 +337,8 @@ public class NatTunnelInterfaceStateListener
 
             switch (tunnelAction) {
                 case TUNNEL_EP_ADD:
-                    if (!hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
+                    if (isTunnelInLogicalGroup(stateTunnelList)
+                            || !hndlTepAddForAllRtrs(srcDpnId, tunnelType, tunnelName, srcTepIp, destTepIp)) {
                         LOG.debug("NAT Service : Unable to process TEP ADD");
                     }
                     break;
@@ -320,8 +363,9 @@ public class NatTunnelInterfaceStateListener
             + " : {} and DEST IP: {}", fibManager.getTransportTypeStr(tunnelType), srcTepIp, destTepIp);
 
         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
-        Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
-            .OPERATIONAL, dpnRoutersListId);
+        Optional<DpnRoutersList> optionalRouterDpnList =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
         if (!optionalRouterDpnList.isPresent()) {
             LOG.warn("NAT Service : RouterDpnList model is empty for DPN {}. Hence ignoring TEP add event for the ITM "
                     + "TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and TUNNEL NAME {} ",
@@ -379,8 +423,9 @@ public class NatTunnelInterfaceStateListener
 
         List<RoutersList> routersList = null;
         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
-        Optional<DpnRoutersList> optionalRouterDpnList = NatUtil.read(dataBroker, LogicalDatastoreType
-            .OPERATIONAL, dpnRoutersListId);
+        Optional<DpnRoutersList> optionalRouterDpnList =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
         if (optionalRouterDpnList.isPresent()) {
             routersList = optionalRouterDpnList.get().getRoutersList();
         } else {
@@ -406,7 +451,7 @@ public class NatTunnelInterfaceStateListener
     }
 
     private void hndlTepAddForSnatInEachRtr(RoutersList router, final BigInteger srcDpnId, String tunnelType,
-                                            String srcTepIp, String destTepIp, String tunnelName, String nextHopIp) {
+            String srcTepIp, String destTepIp, String tunnelName, String nextHopIp) {
 
         /*SNAT : Remove the old routes to the external IP having the old TEP IP as the next hop IP
                  Advertise to the BGP about the new route to the external IP having the new TEP IP
@@ -416,11 +461,12 @@ public class NatTunnelInterfaceStateListener
 
         // Check if this is externalRouter else ignore
         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
-        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
-            .CONFIGURATION, extRoutersId);
+        Optional<Routers> routerData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, extRoutersId);
         if (!routerData.isPresent()) {
             LOG.debug("NAT Service : SNAT -> Ignoring TEP add for router {} since its not External Router",
-                routerName);
+                    routerName);
             return;
         }
 
@@ -428,29 +474,33 @@ public class NatTunnelInterfaceStateListener
         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
         if (naptId == null || naptId.equals(BigInteger.ZERO)) {
             LOG.warn("NAT Service : SNAT -> Ignoring TEP add for the DPN {} having the router {} since"
-                + " the router is not part of the NAT service  - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
-                + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
+                    + " the router is not part of the NAT service  - the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
+                    + "TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
             return;
         }
-
-        //Check if the DPN having the router is the NAPT switch
-        if (!naptId.equals(srcDpnId)) {
-            /*
+        if (natMode == NatMode.Conntrack) {
+            natServiceManager.notify(routerData.get(), naptId, srcDpnId,
+                    SnatServiceManager.Action.SNAT_ROUTER_ENBL);
+        } else {
+            //Check if the DPN having the router is the NAPT switch
+            if (!naptId.equals(srcDpnId)) {
+                /*
             1) Install default NAT rule from table 21 to 26
             2) Install the group which forward packet to the tunnel port for the NAPT switch.
             3) Install the flow 26 which forwards the packet to the group.
-            */
-            if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
-                routerName, routerId)) {
-                LOG.debug("NAT Service : Unable to process the TEP add event on NON-NAPT switch {}", srcDpnId);
+                 */
+                if (!hndlTepAddOnNonNaptSwitch(srcDpnId, naptId, tunnelType, srcTepIp, destTepIp, tunnelName,
+                        routerName, routerId)) {
+                    LOG.debug("NAT Service : Unable to process the TEP add event on NON-NAPT switch {}", srcDpnId);
+                    return;
+                }
+                return;
+            }
+            if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
+                    routerData, nextHopIp)) {
+                LOG.debug("NAT Service : Unable to process the TEP add event on NAPT switch {}", srcDpnId);
                 return;
             }
-            return;
-        }
-        if (!hndlTepAddOnNaptSwitch(srcDpnId, tunnelType, srcTepIp, destTepIp, tunnelName, routerId,
-            routerData, nextHopIp)) {
-            LOG.debug("NAT Service : Unable to process the TEP add event on NAPT switch {}", srcDpnId);
-            return;
         }
         return;
     }
@@ -504,9 +554,9 @@ public class NatTunnelInterfaceStateListener
                 + "with vpnId {}...", srcDpnId, routerId, vpnId);
             defaultRouteProgrammer.installDefNATRouteInDPN(srcDpnId, vpnId, routerId);
 
-            LOG.debug("NAT Service : Install group in non NAPT switch {}", srcDpnId);
+            LOG.debug("NAT Service : Install group in non NAPT switch {} for router {}", srcDpnId, routerName);
             List<BucketInfo> bucketInfoForNonNaptSwitches =
-                externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, srcDpnId, routerName);
+                externalRouterListner.getBucketInfoForNonNaptSwitches(srcDpnId, primaryDpnId, routerName);
             long groupId = externalRouterListner.installGroup(srcDpnId, routerName, bucketInfoForNonNaptSwitches);
 
             LOG.debug("NAT Service : SNAT -> in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
@@ -525,12 +575,13 @@ public class NatTunnelInterfaceStateListener
             LOG.warn("hndlTepAddOnNaptSwitch: routerData is not present");
             return false;
         }
-        String routerName = routerData.get().getRouterName();
+        Routers router = routerData.get();
+        String routerName = router.getRouterName();
         LOG.debug("NAT Service : SNAT -> Processing TEP add for the DPN {} having the router {} since "
             + "its THE NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} "
             + "and TUNNEL NAME {} ", srcDpnId, routerName, tunnelType, srcTepIp, destTepIp, tunnelName);
 
-        Uuid networkId = routerData.get().getNetworkId();
+        Uuid networkId = router.getNetworkId();
         if (networkId == null) {
             LOG.warn("NAT Service : SNAT -> Ignoring TEP add since the router {} is not associated to the "
                 + "external network", routerName);
@@ -542,8 +593,8 @@ public class NatTunnelInterfaceStateListener
         Long vpnId;
         if (vpnName == null) {
             LOG.debug("NAT Service : SNAT -> Internal VPN associated to router {}", routerId);
-            vpnId = NatUtil.getVpnId(dataBroker, routerId);
-            if (vpnId == null || vpnId == NatConstants.INVALID_ID) {
+            vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
+            if (vpnId == NatConstants.INVALID_ID) {
                 LOG.error("Invalid External VPN-ID returned for routerName {}", routerName);
                 return false;
             }
@@ -574,14 +625,12 @@ public class NatTunnelInterfaceStateListener
                 networkId, routerId);
             return false;
         }
-        List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-        if (externalIps != null) {
-            LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
-            for (String externalIp : externalIps) {
-                String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
-                LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
-                fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
-            }
+        Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+        LOG.debug("NAT Service : Clearing the FIB entries but not the BGP routes");
+        for (String externalIp : externalIps) {
+            String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
+            LOG.debug("NAT Service : Removing Fib entry rd {} prefix {}", rd, externalIp);
+            fibManager.removeFibEntry(dataBroker, rd, externalIp, null);
         }
 
         /*
@@ -591,35 +640,94 @@ public class NatTunnelInterfaceStateListener
         FIB manager.
         */
         String rd = NatUtil.getVpnRd(dataBroker, externalVpnName);
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
+        if (extNwProvType == null) {
+            return false;
+        }
+        String gwMacAddress = null;
+        long l3Vni = 0;
+        WriteTransaction writeTx = null;
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
+            gwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+            if (gwMacAddress != null) {
+                LOG.debug("External Gateway MAC address {} found for External Router ID {}", gwMacAddress,
+                        routerId);
+            } else {
+                LOG.error("No External Gateway MAC address found for External Router ID {}", routerId);
+                return false;
+            }
+            //get l3Vni value for external VPN
+            l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
+            if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
+                LOG.debug("NAT Service : L3VNI value is not configured in Internet VPN {} and RD {} "
+                        + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
+                        + "NAT flows", vpnName, rd);
+                l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, externalVpnName, routerId).longValue();
+            }
+            //Create writeTx Object
+            writeTx = dataBroker.newWriteOnlyTransaction();
+        }
         if (externalIps != null) {
             for (final String externalIp : externalIps) {
-                Long label = externalRouterListner.checkExternalIpLabel(routerId,
-                    externalIp);
-                if (label == null || label == NatConstants.INVALID_ID) {
-                    LOG.debug("NAT Service : SNAT -> Unable to advertise to the DC GW since label is invalid");
-                    return false;
+                long serviceId = 0;
+                String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
+                if (extNwProvType == ProviderTypes.VXLAN) {
+                    LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
+                            externalIp, nextHopIp);
+                    NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, externalVpnName, rd,
+                            externalIp, nextHopIp, l3Vni, tunnelName, gwMacAddress, writeTx, RouteOrigin.STATIC,
+                            srcDpnId);
+                    serviceId = l3Vni;
+                } else {
+
+                    Long label = externalRouterListner.checkExternalIpLabel(routerId,
+                            externalIp);
+                    if (label == null || label == NatConstants.INVALID_ID) {
+                        LOG.debug("NAT Service : SNAT -> Unable to advertise to the DC GW since label is invalid");
+                        return false;
+                    }
+                    LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
+                            externalIp, nextHopIp);
+                    long l3vni = 0;
+                    if (elanManager.isOpenStackVniSemanticsEnforced()) {
+                        l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, externalVpnName, l3vni).longValue();
+                    }
+                    Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(dataBroker, externalIp,
+                            router);
+                    NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, externalVpnName, rd, externalSubnetId,
+                            fibExternalIp, nextHopIp, networkId.getValue(), null /* mac-address */, label, l3vni, LOG,
+                            RouteOrigin.STATIC, srcDpnId);
+                    serviceId = label;
                 }
 
-                LOG.debug("NAT Service : SNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
-                    externalIp, nextHopIp);
-                NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp, nextHopIp,
-                    label, LOG, RouteOrigin.STATIC);
-
                 LOG.debug("NAT Service : SNAT -> Install custom FIB routes "
-                    + "( Table 21 -> Push MPLS label to Tunnel port");
+                    + "(Table 21 -> Push MPLS label to Tunnel port");
                 List<Instruction> customInstructions = new ArrayList<>();
-                customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE).buildInstruction(0));
+                int customInstructionIndex = 0;
+                long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker, externalIp,
+                        router);
+                if (externalSubnetVpnId != NatConstants.INVALID_ID) {
+                    LOG.debug("NAT Service : Will install custom FIB router with external subnet VPN ID {}",
+                            externalSubnetVpnId);
+                    BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
+                    customInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
+                            MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(customInstructionIndex));
+                    customInstructionIndex++;
+                }
+                customInstructions.add(new InstructionGotoTable(NwConstants.INBOUND_NAPT_TABLE)
+                        .buildInstruction(customInstructionIndex));
                 CreateFibEntryInput input =
                     new CreateFibEntryInputBuilder().setVpnName(externalVpnName).setSourceDpid(srcDpnId)
-                        .setInstruction(customInstructions).setIpAddress(externalIp + "/32")
-                        .setServiceId(label).setInstruction(customInstructions).build();
+                        .setInstruction(customInstructions).setIpAddress(fibExternalIp)
+                        .setServiceId(serviceId).setInstruction(customInstructions).build();
                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
 
                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
 
                     @Override
-                    public void onFailure(Throwable error) {
+                    public void onFailure(@Nonnull Throwable error) {
                         LOG.error("NAT Service : SNAT -> Error in generate label or fib install process", error);
                     }
 
@@ -636,6 +744,9 @@ public class NatTunnelInterfaceStateListener
                     }
                 });
             }
+            if (writeTx != null) {
+                writeTx.submit();
+            }
         }
         return true;
     }
@@ -653,8 +764,6 @@ public class NatTunnelInterfaceStateListener
             return;
         }
         RouterPorts routerPorts = optRouterPorts.get();
-        List<Ports> interfaces = routerPorts.getPorts();
-
         Uuid extNwId = routerPorts.getExternalNetworkId();
         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
         if (vpnName == null) {
@@ -664,6 +773,36 @@ public class NatTunnelInterfaceStateListener
         }
 
         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
+        if (extNwProvType == null) {
+            return;
+        }
+        String gwMacAddress = null;
+        long l3Vni = 0;
+        WriteTransaction writeTx = null;
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            // Get the External Gateway MAC Address which is Router gateway MAC address for SNAT
+            gwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+            if (gwMacAddress != null) {
+                LOG.debug("External Gateway MAC address {} found for External Router ID {}", gwMacAddress,
+                        routerId);
+            } else {
+                LOG.error("No External Gateway MAC address found for External Router ID {}", routerId);
+                return;
+            }
+            //get l3Vni value for external VPN
+            l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
+            if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
+                LOG.debug("NAT Service : L3VNI value is not configured in Internet VPN {} and RD {} "
+                        + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
+                        + "NAT flows", vpnName, rd);
+                l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
+            }
+            //Create writeTx Object
+            writeTx = dataBroker.newWriteOnlyTransaction();
+        }
+        List<Ports> interfaces = routerPorts.getPorts();
         for (Ports port : interfaces) {
             //Get the DPN on which this interface resides
             final String interfaceName = port.getPortName();
@@ -686,27 +825,48 @@ public class NatTunnelInterfaceStateListener
                 LOG.debug("NAT Service : DNAT -> Advertising the FIB route to the floating IP {} configured "
                     + "for the port: {}",
                     externalIp, interfaceName);
-                long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
-                if (label == NatConstants.INVALID_ID) {
-                    LOG.debug("NAT Service : DNAT -> Unable to advertise to the DC GW since label is invalid");
-                    return;
+                long serviceId = 0;
+                String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
+
+                if (extNwProvType == ProviderTypes.VXLAN) {
+                    LOG.debug("NAT Service : DNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
+                            externalIp, nextHopIp);
+                    NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd,
+                            externalIp, nextHopIp, l3Vni, interfaceName, gwMacAddress, writeTx, RouteOrigin.STATIC,
+                            fipCfgdDpnId);
+                    serviceId = l3Vni;
+                } else {
+                    long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
+                    if (label == NatConstants.INVALID_ID) {
+                        LOG.debug("NAT Service : DNAT -> Unable to advertise to the DC GW since label is invalid");
+                        return;
+                    }
+                    LOG.debug("NAT Service : DNAT -> Advertise the route to the externalIp {} having nextHopIp {}",
+                            externalIp, nextHopIp);
+                    long l3vni = 0;
+                    if (elanManager.isOpenStackVniSemanticsEnforced()) {
+                        l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
+                    }
+                    NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, null,
+                            fibExternalIp, nextHopIp, null, null, label, l3vni, LOG, RouteOrigin.STATIC,
+                            fipCfgdDpnId);
+                    serviceId = label;
                 }
-                NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32",
-                    nextHopIp, label, LOG, RouteOrigin.STATIC);
 
-                //Install custom FIB routes ( Table 21 -> Push MPLS label to Tunnel port
+                //Install custom FIB routes (Table 21 -> Push MPLS label to Tunnel port
                 List<Instruction> customInstructions = new ArrayList<>();
                 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
                 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
                     .setSourceDpid(fipCfgdDpnId).setInstruction(customInstructions)
-                    .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
+                    .setIpAddress(fibExternalIp).setServiceId(serviceId).setInstruction(customInstructions)
+                        .build();
                 Future<RpcResult<Void>> future = fibRpcService.createFibEntry(input);
                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
 
                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
 
                     @Override
-                    public void onFailure(Throwable error) {
+                    public void onFailure(@Nonnull Throwable error) {
                         LOG.error("NAT Service : DNAT -> Error in generate label or fib install process", error);
                     }
 
@@ -722,12 +882,15 @@ public class NatTunnelInterfaceStateListener
                     }
                 });
             }
+            if (writeTx != null) {
+                writeTx.submit();
+            }
         }
     }
 
     private void hndlTepDelForSnatInEachRtr(RoutersList router, BigInteger dpnId, String tunnelType,
                                             String srcTepIp, String destTepIp, String tunnelName) {
-        /*SNAT :
+       /*SNAT :
             1) Elect a new switch as the primary NAPT
             2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
             3) This will make sure old routes are withdrawn and new routes are advertised.
@@ -735,15 +898,16 @@ public class NatTunnelInterfaceStateListener
 
         String routerName = router.getRouter();
         LOG.debug("NAT Service : SNAT -> Trying to clear routes to the External fixed IP associated to the router"
-            + " {}", routerName);
+                + " {}", routerName);
 
         // Check if this is externalRouter else ignore
         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
-        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType
-            .CONFIGURATION, extRoutersId);
+        Optional<Routers> routerData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, extRoutersId);
         if (!routerData.isPresent()) {
             LOG.debug("NAT Service : SNAT -> Ignoring TEP del for router {} since its not External Router",
-                routerName);
+                    routerName);
             return;
         }
 
@@ -758,71 +922,82 @@ public class NatTunnelInterfaceStateListener
         BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
         if (naptId == null || naptId.equals(BigInteger.ZERO) || (!naptId.equals(dpnId))) {
             LOG.warn("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} since"
-                + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
-                + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
-            return;
-        }
-
-        Uuid networkId = routerData.get().getNetworkId();
-        if (networkId == null) {
-            LOG.debug("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} having the router {} "
-                + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST IP {} "
-                + "and TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
+                    + " its NOT a NAPT switch for the TUNNEL TYPE {} b/w SRC IP {} and DST IP {} and"
+                    + "TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
             return;
         }
+        if (natMode == NatMode.Conntrack) {
+            natServiceManager.notify(routerData.get(), naptId, dpnId, SnatServiceManager.Action.SNAT_ROUTER_DISBL);
+        } else {
 
-        LOG.debug("NAT Service : SNAT -> Router {} is associated with ext nw {}", routerId, networkId);
-        Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
-        Long vpnId;
-        if (vpnName == null) {
-            LOG.debug("NAT Service : SNAT -> Internal VPN-ID {} associated to router {}", routerId, routerName);
-            vpnId = routerId;
 
-            //Install default entry in FIB to SNAT table
-            LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with"
-                + " vpn {}...", dpnId, routerName, vpnId);
-            defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
-        } else {
-            vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
-            if (vpnId == NatConstants.INVALID_ID) {
-                LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}", routerName);
+            Uuid networkId = routerData.get().getNetworkId();
+            if (networkId == null) {
+                LOG.debug("NAT Service : SNAT -> Ignoring TEP delete for the DPN {} having the router {} "
+                        + "since the Router instance {} not found in ExtRouters model b/w SRC IP {} and DST IP {} "
+                        + "and TUNNEL NAME {} ", dpnId, tunnelType, srcTepIp, destTepIp, tunnelName);
                 return;
             }
-            LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) {} associated to router {}",
-                vpnId, routerName);
-            //Install default entry in FIB to SNAT table
-            LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} "
-                + "with vpnId {}...", dpnId, routerId, vpnId);
-            defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId);
-        }
-
-        if (routerData.get().isEnableSnat()) {
-            LOG.info("NAT Service : SNAT enabled for router {}", routerId);
 
-            long routerVpnId = routerId;
-            long bgpVpnId = NatConstants.INVALID_ID;
-            Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
-            if (bgpVpnUuid != null) {
-                bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+            LOG.debug("NAT Service : SNAT -> Router {} is associated with ext nw {}", routerId, networkId);
+            Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerName);
+            Long vpnId;
+            if (vpnName == null) {
+                LOG.debug("NAT Service : SNAT -> Internal VPN-ID {} associated to router {}", routerId, routerName);
+                vpnId = routerId;
+
+                //Install default entry in FIB to SNAT table
+                LOG.debug("NAT Service : Installing default route in FIB on DPN {} for router {} with"
+                        + " vpn {}...", dpnId, routerName, vpnId);
+                defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
+            } else {
+                vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+                if (vpnId == NatConstants.INVALID_ID) {
+                    LOG.error("NAT Service : SNAT -> Invalid Private BGP VPN ID returned for routerName {}",
+                            routerName);
+                    return;
+                }
+                LOG.debug("NAT Service : SNAT -> External BGP VPN (Private BGP) {} associated to router {}",
+                        vpnId, routerName);
+                //Install default entry in FIB to SNAT table
+                LOG.debug("NAT Service : Installing default route in FIB on dpn {} for routerId {} "
+                        + "with vpnId {}...", dpnId, routerId, vpnId);
+                defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId);
             }
-            if (bgpVpnId != NatConstants.INVALID_ID) {
-                LOG.debug("NAT Service : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} associated "
-                    + "to the router {}", bgpVpnId, routerName);
-                routerVpnId = bgpVpnId;
+
+            if (routerData.get().isEnableSnat()) {
+                LOG.info("NAT Service : SNAT enabled for router {}", routerId);
+
+                long routerVpnId = routerId;
+                long bgpVpnId = NatConstants.INVALID_ID;
+                Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+                if (bgpVpnUuid != null) {
+                    bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+                }
+                if (bgpVpnId != NatConstants.INVALID_ID) {
+                    LOG.debug("NAT Service : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} associated "
+                            + "to the router {}", bgpVpnId, routerName);
+                    routerVpnId = bgpVpnId;
+                } else {
+                    LOG.debug("NAT Service : SNAT -> Internal L3 VPN ID (Router ID) {} associated to the router {}",
+                            routerVpnId, routerName);
+                }
+                //Re-elect the other available switch as the NAPT switch and program the NAT flows.
+                removeSNATFromDPN(dpnId, routerName, routerVpnId, networkId);
             } else {
-                LOG.debug("NAT Service : SNAT -> Internal L3 VPN ID (Router ID) {} associated to the router {}",
-                    routerVpnId, routerName);
+                LOG.info("NAT Service : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
             }
-            //Re-elect the other available switch as the NAPT switch and program the NAT flows.
-            removeSNATFromDPN(dpnId, routerName, routerVpnId, networkId);
-        } else {
-            LOG.info("NAT Service : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
         }
     }
 
     private void hndlTepDelForDnatInEachRtr(RoutersList router, BigInteger tepDeletedDpnId) {
         //DNAT : Withdraw the routes from the BGP
         String routerName = router.getRouter();
+        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.warn("Unable to get RouterId from RouterName {}", routerName);
+            return;
+        }
         LOG.debug("NAT Service : DNAT -> Trying to clear routes to the Floating IP associated to the router {}",
             routerName);
 
@@ -836,7 +1011,6 @@ public class NatTunnelInterfaceStateListener
             return;
         }
         RouterPorts routerPorts = optRouterPorts.get();
-        List<Ports> interfaces = routerPorts.getPorts();
         Uuid extNwId = routerPorts.getExternalNetworkId();
         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId, LOG);
         if (vpnName == null) {
@@ -845,6 +1019,22 @@ public class NatTunnelInterfaceStateListener
             return;
         }
         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
+        if (extNwProvType == null) {
+            return;
+        }
+        long l3Vni = 0;
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            //get l3Vni value for external VPN
+            l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
+            if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
+                LOG.debug("NAT Service : L3VNI value is not configured in Internet VPN {} and RD {} "
+                        + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
+                        + "NAT flows", vpnName, rd);
+                l3Vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, routerId).longValue();
+            }
+        }
+        List<Ports> interfaces = routerPorts.getPorts();
         for (Ports port : interfaces) {
             //Get the DPN on which this interface resides
             String interfaceName = port.getPortName();
@@ -864,25 +1054,34 @@ public class NatTunnelInterfaceStateListener
             for (InternalToExternalPortMap intExtPortMap : intExtPortMapList) {
                 String internalIp = intExtPortMap.getInternalIp();
                 String externalIp = intExtPortMap.getExternalIp();
+                externalIp = NatUtil.validateAndAddNetworkMask(externalIp);
                 LOG.debug("NAT Service : DNAT -> Withdrawing the FIB route to the floating IP {} "
                     + "configured for the port: {}",
                     externalIp, interfaceName);
-                NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
-                long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
-                if (label == NatConstants.INVALID_ID) {
-                    LOG.debug("NAT Service : DNAT -> Unable to remove the table 21 entry pushing the "
-                        + "MPLS label to the tunnel since label is invalid");
-                    return;
+                NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp, vpnName, LOG);
+                long serviceId = 0;
+                if (extNwProvType == ProviderTypes.VXLAN) {
+                    serviceId = l3Vni;
+                } else {
+                    long label = floatingIPListener.getOperationalIpMapping(routerName, interfaceName, internalIp);
+                    if (label == NatConstants.INVALID_ID) {
+                        LOG.debug("NAT Service : DNAT -> Unable to remove the table 21 entry pushing the "
+                                + "MPLS label to the tunnel since label is invalid");
+                        return;
+                    }
+                    serviceId = label;
                 }
+
                 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
-                    .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
+                    .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp).setServiceId(serviceId)
+                    .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
                 Future<RpcResult<Void>> future = fibRpcService.removeFibEntry(input);
                 ListenableFuture<RpcResult<Void>> listenableFuture = JdkFutureAdapters.listenInPoolThread(future);
 
                 Futures.addCallback(listenableFuture, new FutureCallback<RpcResult<Void>>() {
 
                     @Override
-                    public void onFailure(Throwable error) {
+                    public void onFailure(@Nonnull Throwable error) {
                         LOG.error("NAT Service : DNAT -> Error in removing the table 21 entry pushing "
                             + "the MPLS label to the tunnel since label is invalid ", error);
                     }
@@ -901,4 +1100,20 @@ public class NatTunnelInterfaceStateListener
             }
         }
     }
+
+    protected boolean isTunnelInLogicalGroup(StateTunnelList stateTunnelList) {
+        String ifaceName = stateTunnelList.getTunnelInterfaceName();
+        if (getTunnelType(stateTunnelList) == NatConstants.ITMTunnelLocType.Internal.getValue()) {
+            Interface configIface = interfaceManager.getInterfaceInfoFromConfigDataStore(ifaceName);
+            IfTunnel ifTunnel = (configIface != null) ? configIface.getAugmentation(IfTunnel.class) : null;
+            if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
+                ParentRefs refs = configIface.getAugmentation(ParentRefs.class);
+                if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
+                    return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
+                }
+            }
+        }
+        LOG.trace("MULTIPLE_VxLAN_TUNNELS: ignoring the tunnel event for {}", ifaceName);
+        return false;
+    }
 }