MRI version bumpup for Aluminium
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalRoutersListener.java
index ea51ec2c3e745fab8e32b2cc0fe39a08a95c8d36..3280c781c26824c2cc83964802865169cf76bccd 100644 (file)
@@ -7,15 +7,13 @@
  */
 package org.opendaylight.netvirt.natservice.internal;
 
-import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
 
-import com.google.common.base.Optional;
 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 com.google.common.util.concurrent.MoreExecutors;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.math.BigInteger;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -29,18 +27,16 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
 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.ReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.infra.Datastore.Configuration;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
@@ -57,7 +53,6 @@ import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.NwConstants.NxmOfFieldType;
-import org.opendaylight.genius.mdsalutil.UpgradeState;
 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
 import org.opendaylight.genius.mdsalutil.actions.ActionLearn;
@@ -78,21 +73,21 @@ import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 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.CentralizedSwitchScheduler;
-import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
 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.inventory.rev130819.tables.table.Flow;
 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.AllocateIdInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
@@ -120,6 +115,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
 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.ext.routers.RoutersKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
@@ -148,18 +144,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.R
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 @Singleton
-public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
+public class ExternalRoutersListener extends AbstractAsyncDataTreeChangeListener<Routers> {
     private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
 
-    private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
-    private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
+    private static final Uint64 COOKIE_TUNNEL = Uint64.valueOf("9000000", 16).intern();
+    private static final Uint64 COOKIE_VM_LFIB_TABLE = Uint64.valueOf("8000022", 16).intern();
 
     private final DataBroker dataBroker;
     private final ManagedNewTransactionRunner txRunner;
@@ -178,13 +176,11 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     private final IFibManager fibManager;
     private final IVpnManager vpnManager;
     private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
-    private final CentralizedSwitchScheduler  centralizedSwitchScheduler;
     private final NatMode natMode;
-    private final INeutronVpnManager nvpnManager;
     private final IElanService elanManager;
     private final JobCoordinator coordinator;
-    private final UpgradeState upgradeState;
     private final IInterfaceManager interfaceManager;
+    private final NatOverVxlanUtil natOverVxlanUtil;
     private final int snatPuntTimeout;
 
     @Inject
@@ -203,14 +199,14 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                    final IFibManager fibManager,
                                    final IVpnManager vpnManager,
                                    final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer,
-                                   final INeutronVpnManager nvpnManager,
-                                   final CentralizedSwitchScheduler centralizedSwitchScheduler,
                                    final NatserviceConfig config,
                                    final IElanService elanManager,
                                    final JobCoordinator coordinator,
-                                   final UpgradeState upgradeState,
+                                   final NatOverVxlanUtil natOverVxlanUtil,
                                    final IInterfaceManager interfaceManager) {
-        super(Routers.class, ExternalRoutersListener.class);
+        super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(ExtRouters.class)
+                .child(Routers.class),
+                Executors.newListeningSingleThreadExecutor("ExternalRoutersListener", LOG));
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
@@ -228,12 +224,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         this.fibManager = fibManager;
         this.vpnManager = vpnManager;
         this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
-        this.nvpnManager = nvpnManager;
         this.elanManager = elanManager;
-        this.centralizedSwitchScheduler = centralizedSwitchScheduler;
         this.coordinator = coordinator;
-        this.upgradeState = upgradeState;
         this.interfaceManager = interfaceManager;
+        this.natOverVxlanUtil = natOverVxlanUtil;
         if (config != null) {
             this.natMode = config.getNatMode();
             this.snatPuntTimeout = config.getSnatPuntTimeout().intValue();
@@ -241,65 +235,66 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             this.natMode = NatMode.Controller;
             this.snatPuntTimeout = 0;
         }
+        init();
     }
 
-    @Override
-    @PostConstruct
     public void init() {
         LOG.info("{} init", getClass().getSimpleName());
         // This class handles ExternalRouters for Controller SNAT mode.
         // For Conntrack SNAT mode, its handled in SnatExternalRoutersListener.java
         if (natMode == NatMode.Controller) {
-            registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
             NatUtil.createGroupIdPool(idManager);
         }
     }
 
     @Override
-    protected InstanceIdentifier<Routers> getWildCardPath() {
-        return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
+    @PreDestroy
+    public void close() {
+        super.close();
+        Executors.shutdownAndAwaitTermination(getExecutorService());
     }
 
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
+    public void add(InstanceIdentifier<Routers> identifier, Routers routers) {
+        if (natMode != NatMode.Controller) {
+            return;
+        }
         // Populate the router-id-name container
         String routerName = routers.getRouterName();
         LOG.info("add : external router event for {}", routerName);
-        long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
         NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
         try {
-            coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
-                () -> Collections.singletonList(
-                    txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
-                        LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
-                        long bgpVpnId = NatConstants.INVALID_ID;
-                        if (bgpVpnUuid != null) {
-                            bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
-                        }
-                        addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
-                        // Allocate Primary Napt Switch for this router
-                        BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName);
-                        if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
-                            if (!routers.isEnableSnat()) {
-                                LOG.info("add : SNAT is disabled for external router {} ", routerName);
-                                /* If SNAT is disabled on ext-router though L3_FIB_TABLE(21) -> PSNAT_TABLE(26) flow
-                                 * is required for DNAT. Hence writeFlowInvTx object submit is required.
-                                 */
-                                return;
+            if (routers.isEnableSnat()) {
+                coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routers.key(),
+                    () -> Collections.singletonList(
+                        txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
+                            LOG.info("add : Installing NAT default route on all dpns part of router {}", routerName);
+                            Uint32 bgpVpnId = NatConstants.INVALID_ID;
+                            if (bgpVpnUuid != null) {
+                                bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+                            }
+                            addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid, true, confTx);
+                            // Allocate Primary Napt Switch for this router
+                            Uint64 primarySwitchId = getPrimaryNaptSwitch(routerName);
+                            if (primarySwitchId != null && !primarySwitchId.equals(Uint64.ZERO)) {
+                                handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
                             }
-                            handleEnableSnat(routers, routerId, primarySwitchId, bgpVpnId, confTx);
                         }
-                    })), NatConstants.NAT_DJC_MAX_RETRIES);
+                    )), NatConstants.NAT_DJC_MAX_RETRIES);
+            } else {
+                LOG.info("add : SNAT is disabled for external router {} ", routerName);
+            }
         } catch (Exception ex) {
             LOG.error("add : Exception while Installing NAT flows on all dpns as part of router {}",
                     routerName, ex);
         }
     }
 
-    public void handleEnableSnat(Routers routers, long routerId, BigInteger primarySwitchId, long bgpVpnId,
+    public void handleEnableSnat(Routers routers, Uint32 routerId, Uint64 primarySwitchId, Uint32 bgpVpnId,
                                  TypedWriteTransaction<Configuration> confTx) {
         String routerName = routers.getRouterName();
         LOG.info("handleEnableSnat : Handling SNAT for router {}", routerName);
@@ -318,21 +313,19 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
 
         if (bgpVpnId != NatConstants.INVALID_ID) {
-            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, false, confTx,
-                    extNwProvType);
+            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId,
+                routers.getNetworkId(),false, confTx, extNwProvType);
         } else {
             // write metadata and punt
             installOutboundMissEntry(routerName, routerId, primarySwitchId, confTx);
+            handlePrimaryNaptSwitch(primarySwitchId, routerName, routerId, routers.getNetworkId(), confTx);
             // Now install entries in SNAT tables to point to Primary for each router
-            List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
-            for (BigInteger dpnId : switches) {
+            List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+            for (Uint64 dpnId : switches) {
                 // Handle switches and NAPT switches separately
                 if (!dpnId.equals(primarySwitchId)) {
                     LOG.debug("handleEnableSnat : Handle Ordinary switch");
                     handleSwitches(dpnId, routerName, routerId, primarySwitchId);
-                } else {
-                    LOG.debug("handleEnableSnat : Handle NAPT switch");
-                    handlePrimaryNaptSwitch(dpnId, routerName, routerId, confTx);
                 }
             }
         }
@@ -345,6 +338,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             for (String externalIpAddrPrefix : externalIps) {
                 LOG.debug("handleEnableSnat : Calling handleSnatReverseTraffic for primarySwitchId {}, "
                     + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
+                externalIpAddrPrefix = NatUtil.validateAndAddNetworkMask(externalIpAddrPrefix);
                 handleSnatReverseTraffic(confTx, primarySwitchId, routers, routerId, routerName, externalIpAddrPrefix
                 );
             }
@@ -352,29 +346,29 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         LOG.debug("handleEnableSnat : Exit");
     }
 
-    private BigInteger getPrimaryNaptSwitch(String routerName) {
+    private Uint64 getPrimaryNaptSwitch(String routerName) {
         // Allocate Primary Napt Switch for this router
-        BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-        if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
-            LOG.debug("handleEnableSnat : Primary NAPT switch with DPN ID {} is already elected for router {}",
+        Uint64 primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+        if (primarySwitchId != null && !primarySwitchId.equals(Uint64.ZERO)) {
+            LOG.debug("getPrimaryNaptSwitch : Primary NAPT switch with DPN ID {} is already elected for router {}",
                 primarySwitchId, routerName);
             return primarySwitchId;
         }
-        // Validating and creating VNI pool during when NAPT switch is selected.
-        // With Assumption this might be the first NAT service comes up.
-        NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager, idManager,
-                NatConstants.ODL_VNI_POOL_NAME);
+        return selectNewNAPTSwitch(routerName);
+    }
+
+    private Uint64 selectNewNAPTSwitch(String routerName) {
         // Allocated an id from VNI pool for the Router.
-        NatOverVxlanUtil.getRouterVni(idManager, routerName, NatConstants.INVALID_ID);
-        primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
-        LOG.debug("handleEnableSnat : Primary NAPT switch DPN ID {}", primarySwitchId);
+        natOverVxlanUtil.getRouterVni(routerName, NatConstants.INVALID_ID);
+        Uint64 primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName, null);
+        LOG.debug("getPrimaryNaptSwitch : Primary NAPT switch DPN ID {}", primarySwitchId);
 
         return primarySwitchId;
     }
 
-    protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId,
+    protected void installNaptPfibExternalOutputFlow(String routerName, Uint32 routerId, Uint64 dpnId,
                                                      TypedWriteTransaction<Configuration> confTx) {
-        Long extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
+        Uint32 extVpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
         if (extVpnId == NatConstants.INVALID_ID) {
             LOG.error("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
             extVpnId = routerId;
@@ -388,14 +382,16 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         for (String ip : externalIps) {
             Uuid subnetId = getSubnetIdForFixedIp(ip);
             if (subnetId != null) {
-                long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
+                Uint32 subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
                 if (subnetVpnId != NatConstants.INVALID_ID) {
                     extVpnId = subnetVpnId;
                 }
                 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
                     dpnId, extVpnId, subnetId);
                 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
-                mdsalManager.addFlow(confTx, postNaptFlowEntity);
+                if (postNaptFlowEntity != null) {
+                    mdsalManager.addFlow(confTx, postNaptFlowEntity);
+                }
             }
         }
     }
@@ -411,21 +407,32 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return null;
     }
 
-    protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
+    protected void subnetRegisterMapping(Routers routerEntry, Uint32 segmentId) {
         LOG.debug("subnetRegisterMapping : Fetching values from extRouters model");
-        List<Uuid> subnetList = routerEntry.getSubnetIds();
-        List<String> externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
+        List<String> externalIps = NatUtil.getIpsListFromExternalIps(
+                new ArrayList<ExternalIps>(routerEntry.getExternalIps().values()));
         int counter = 0;
         int extIpCounter = externalIps.size();
         LOG.debug("subnetRegisterMapping : counter values before looping counter {} and extIpCounter {}",
                 counter, extIpCounter);
-        for (Uuid subnet : subnetList) {
+        @Nullable List<Uuid> subnetIds = routerEntry.getSubnetIds();
+        if (subnetIds == null) {
+            return;
+        }
+        for (Uuid subnet : subnetIds) {
             LOG.debug("subnetRegisterMapping : Looping internal subnets for subnet {}", subnet);
             InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
                 .builder(Subnetmaps.class)
                 .child(Subnetmap.class, new SubnetmapKey(subnet))
                 .build();
-            Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
+            Optional<Subnetmap> sn;
+            try {
+                sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                                LogicalDatastoreType.CONFIGURATION, subnetmapId);
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.error("Failed to read SubnetMap for  subnetmap Id {}", subnetmapId, e);
+                sn = Optional.empty();
+            }
             if (sn.isPresent()) {
                 // subnets
                 Subnetmap subnetmapEntry = sn.get();
@@ -493,8 +500,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    private void addOrDelDefFibRouteToSNAT(String routerName, long routerId, long bgpVpnId,
-            Uuid bgpVpnUuid, boolean create, TypedReadWriteTransaction<Configuration> confTx) {
+    private void addOrDelDefFibRouteToSNAT(String routerName, Uint32 routerId, Uint32 bgpVpnId,
+            Uuid bgpVpnUuid, boolean create, TypedReadWriteTransaction<Configuration> confTx)
+            throws ExecutionException, InterruptedException {
         //Check if BGP VPN exists. If exists then invoke the new method.
         if (bgpVpnId != NatConstants.INVALID_ID) {
             if (bgpVpnUuid != null) {
@@ -503,7 +511,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     bgpVpnId, bgpVpnName);
                 RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(bgpVpnId))
                     .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
-                confTx.put(getRoutersIdentifier(bgpVpnId), rtrs, CREATE_MISSING_PARENTS);
+                confTx.mergeParentStructurePut(getRoutersIdentifier(bgpVpnId), rtrs);
             }
             if (create) {
                 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, confTx);
@@ -517,9 +525,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         addOrDelDefaultFibRouteForSNAT(routerName, routerId, create, confTx);
     }
 
-    private void addOrDelDefaultFibRouteForSNAT(String routerName, long routerId, boolean create,
-            TypedReadWriteTransaction<Configuration> confTx) {
-        List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
+    private void addOrDelDefaultFibRouteForSNAT(String routerName, Uint32 routerId, boolean create,
+            TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
+        List<Uint64> switches = naptSwitchSelector.getDpnsForVpn(routerName);
         if (switches.isEmpty()) {
             LOG.info("addOrDelDefaultFibRouteForSNAT : No switches found for router {}", routerName);
             return;
@@ -529,7 +537,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     + "default NAT route in FIB", routerName);
             return;
         }
-        for (BigInteger dpnId : switches) {
+        for (Uint64 dpnId : switches) {
             if (create) {
                 LOG.debug("addOrDelDefaultFibRouteForSNAT : installing default NAT route for router {} in dpn {} "
                         + "for the internal vpn-id {}", routerId, dpnId, routerId);
@@ -542,15 +550,15 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    private void addDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
-        long bgpVpnId, TypedWriteTransaction<Configuration> confTx) {
-        List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
+    private void addDefaultFibRouteForSnatWithBgpVpn(String routerName, Uint32 routerId,
+                                                     Uint32 bgpVpnId, TypedWriteTransaction<Configuration> confTx) {
+        List<Uint64> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
         if (dpnIds.isEmpty()) {
             LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
                 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
             return;
         }
-        for (BigInteger dpnId : dpnIds) {
+        for (Uint64 dpnId : dpnIds) {
             if (bgpVpnId != NatConstants.INVALID_ID) {
                 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : installing default NAT route for router {} "
                     + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
@@ -563,15 +571,16 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    private void removeDefaultFibRouteForSnatWithBgpVpn(String routerName, long routerId,
-        long bgpVpnId, TypedReadWriteTransaction<Configuration> confTx) {
-        List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
+    private void removeDefaultFibRouteForSnatWithBgpVpn(String routerName, Uint32 routerId, Uint32 bgpVpnId,
+                                                        TypedReadWriteTransaction<Configuration> confTx)
+            throws ExecutionException, InterruptedException {
+        List<Uint64> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
         if (dpnIds.isEmpty()) {
             LOG.error("addOrDelDefaultFibRouteForSNATWIthBgpVpn: No dpns are part of router {} to program "
                 + "default NAT flows for BGP-VPN {}", routerName, bgpVpnId);
             return;
         }
-        for (BigInteger dpnId : dpnIds) {
+        for (Uint64 dpnId : dpnIds) {
             if (bgpVpnId != NatConstants.INVALID_ID) {
                 LOG.debug("addOrDelDefaultFibRouteForSnatWithBgpVpn : removing default NAT route for router {} "
                     + "in dpn {} for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
@@ -584,20 +593,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
-                                                          InstanceIdentifier<T> path) {
-        ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
-
-        try {
-            return tx.read(datastoreType, path).get();
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    protected void installOutboundMissEntry(String routerName, long routerId, BigInteger primarySwitchId,
+    protected void installOutboundMissEntry(String routerName, Uint32 routerId, Uint64 primarySwitchId,
         TypedWriteTransaction<Configuration> confTx) {
         LOG.debug("installOutboundMissEntry : Router ID from getVpnId {}", routerId);
         if (routerId != NatConstants.INVALID_ID) {
@@ -610,22 +606,22 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID, int protocol) {
+    public String getFlowRefOutbound(Uint64 dpnId, short tableId, Uint32 routerID, int protocol) {
         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
                 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + protocol;
     }
 
-    private String getFlowRefNaptPreFib(BigInteger dpnId, short tableId, long vpnId) {
+    private String getFlowRefNaptPreFib(Uint64 dpnId, short tableId, Uint32 vpnId) {
         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
                 .FLOWID_SEPARATOR + vpnId;
     }
 
-    public BigInteger getCookieOutboundFlow(long routerId) {
-        return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
-            BigInteger.valueOf(routerId));
+    public Uint64 getCookieOutboundFlow(Uint32 routerId) {
+        return Uint64.valueOf((NwConstants.COOKIE_OUTBOUND_NAPT_TABLE).toJava().add(
+                new BigInteger("0110001", 16)).add(BigInteger.valueOf(routerId.longValue())));
     }
 
-    private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, BigInteger cookie) {
+    private ActionLearn getLearnActionForPunt(int protocol, int hardTimeout, Uint64 cookie) {
         long l4SrcPortField;
         long l4DstPortField;
         int l4portFieldLen = NxmOfFieldType.NXM_OF_TCP_SRC.getFlowModHeaderLenInt();
@@ -657,11 +653,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 NwConstants.OUTBOUND_NAPT_TABLE, 0, 0, flowMods);
     }
 
-    private FlowEntity buildIcmpDropFlow(BigInteger dpnId, long routerId, long vpnId) {
+    private FlowEntity buildIcmpDropFlow(Uint64 dpnId, Uint32 routerId, Uint32 vpnId) {
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
         matches.add(MatchIpProtocol.ICMP);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         List<ActionInfo> actionInfos = new ArrayList<>();
         actionInfos.add(new ActionDrop());
@@ -677,13 +674,14 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flow;
     }
 
-    protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId, int protocol) {
+    protected FlowEntity buildOutboundFlowEntity(Uint64 dpId, Uint32 routerId, int protocol) {
         LOG.debug("buildOutboundFlowEntity : called for dpId {} and routerId{}", dpId, routerId);
-        BigInteger cookie = getCookieOutboundFlow(routerId);
+        Uint64 cookie = getCookieOutboundFlow(routerId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
         matches.add(new MatchIpProtocol((short)protocol));
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
@@ -701,7 +699,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
-    public void createOutboundTblEntry(BigInteger dpnId, long routerId, TypedWriteTransaction<Configuration> confTx) {
+    public void createOutboundTblEntry(Uint64 dpnId, Uint32 routerId, TypedWriteTransaction<Configuration> confTx) {
         LOG.debug("createOutboundTblEntry : called for dpId {} and routerId {}", dpnId, routerId);
         FlowEntity tcpflowEntity = buildOutboundFlowEntity(dpnId, routerId, NwConstants.IP_PROT_TCP);
         LOG.debug("createOutboundTblEntry : Installing tcp flow {}", tcpflowEntity);
@@ -716,7 +714,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         mdsalManager.addFlow(confTx, icmpDropFlow);
     }
 
-    protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
+    @Nullable
+    protected String getTunnelInterfaceName(Uint64 srcDpId, Uint64 dstDpId) {
         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
         try {
@@ -754,7 +753,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return null;
     }
 
-    protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName, long routerId,
+    protected void installSnatMissEntryForPrimrySwch(Uint64 dpnId, String routerName, Uint32 routerId,
         TypedWriteTransaction<Configuration> confTx) {
 
         LOG.debug("installSnatMissEntry : called for for the primary NAPT switch dpnId {} ", dpnId);
@@ -763,14 +762,19 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         mdsalManager.addFlow(confTx, flowEntity);
     }
 
-    protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo,
-            String routerName, long routerId) {
+    protected void installSnatMissEntry(Uint64 dpnId, List<BucketInfo> bucketInfo,
+            String routerName, Uint32 routerId) {
         LOG.debug("installSnatMissEntry : called for dpnId {} with primaryBucket {} ",
             dpnId, bucketInfo.get(0));
         // Install the select group
-        long groupId = createGroupId(getGroupIdKey(routerName));
+        Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
+            NatUtil.getGroupIdKey(routerName));
+        if (groupId == NatConstants.INVALID_ID) {
+            LOG.error("installSnatMissEntry: Unable to obtain group ID for Key: {}", routerName);
+            return;
+        }
         GroupEntity groupEntity =
-            MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
+            MDSALUtil.buildGroupEntity(dpnId, groupId.longValue(), routerName, GroupTypes.GroupAll, bucketInfo);
         LOG.debug("installSnatMissEntry : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
         mdsalManager.syncInstallGroup(groupEntity);
         // Install miss entry pointing to group
@@ -784,28 +788,27 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         mdsalManager.installFlow(flowEntity);
     }
 
-    long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
-        long groupId = createGroupId(getGroupIdKey(routerName));
+    void installGroup(Uint64 dpnId, String routerName, Uint32 groupId, List<BucketInfo> bucketInfo) {
         GroupEntity groupEntity =
-            MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
+            MDSALUtil.buildGroupEntity(dpnId, groupId.longValue(), routerName, GroupTypes.GroupAll, bucketInfo);
         LOG.debug("installGroup : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
         mdsalManager.syncInstallGroup(groupEntity);
-        return groupId;
     }
 
-    private FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long routerId, long groupId) {
+    private FlowEntity buildSnatFlowEntity(Uint64 dpId, String routerName, Uint32 routerId, Uint32 groupId) {
         LOG.debug("buildSnatFlowEntity : called for dpId {}, routerName {} and groupId {}",
                 dpId, routerName, groupId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         List<ActionInfo> actionsInfo = new ArrayList<>();
-        long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
-                routerName);
-        actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
+        Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager, idManager,
+                routerId, routerName);
+        actionsInfo.add(new ActionSetFieldTunnelId(tunnelId));
         LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
-        actionsInfo.add(new ActionGroup(groupId));
+        actionsInfo.add(new ActionGroup(groupId.longValue()));
         List<InstructionInfo> instructions = new ArrayList<>();
         instructions.add(new InstructionApplyActions(actionsInfo));
         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
@@ -817,13 +820,14 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
-    private FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName, long routerId) {
+    private FlowEntity buildSnatFlowEntityForPrmrySwtch(Uint64 dpId, String routerName, Uint32 routerId) {
 
         LOG.debug("buildSnatFlowEntityForPrmrySwtch : called for primary NAPT switch dpId {}, routerName {}", dpId,
             routerName);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         List<InstructionInfo> instructions = new ArrayList<>();
         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
@@ -838,7 +842,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     }
 
     // TODO : Replace this with ITM Rpc once its available with full functionality
-    protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName, long routerId,
+    protected void installTerminatingServiceTblEntry(Uint64 dpnId, String routerName, Uint32 routerId,
         TypedWriteTransaction<Configuration> confTx) {
 
         LOG.debug("installTerminatingServiceTblEntry : for switch {}, routerName {}",
@@ -855,52 +859,34 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     }
 
-    private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName, long routerId) {
+    private FlowEntity buildTsFlowEntity(Uint64 dpId, String routerName, Uint32 routerId) {
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
-                routerName);
-        matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
-        String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
+        Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
+                idManager, routerId, routerName);
+        matches.add(new MatchTunnelId(tunnelId));
+        String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, Uint32.valueOf(tunnelId.longValue()));
         List<InstructionInfo> instructions = new ArrayList<>();
-        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
+        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId.longValue()),
                 MetaDataUtil.METADATA_MASK_VRFID));
         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
-                NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
-                instructions);
+                NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
+                NwConstants.COOKIE_TS_TABLE, matches, instructions);
         return flowEntity;
     }
 
-    public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
+    public String getFlowRefTs(Uint64 dpnId, short tableId, Uint32 routerID) {
         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
                 .FLOWID_SEPARATOR + routerID;
     }
 
-    public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
+    public static String getFlowRefSnat(Uint64 dpnId, short tableId, String routerID) {
         return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
                 .FLOWID_SEPARATOR + routerID;
     }
 
-    private String getGroupIdKey(String routerName) {
-        return "snatmiss." + routerName;
-    }
-
-    protected long createGroupId(String groupIdKey) {
-        AllocateIdInput getIdInput = new AllocateIdInputBuilder()
-            .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
-            .build();
-        try {
-            Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
-            RpcResult<AllocateIdOutput> rpcResult = result.get();
-            return rpcResult.getResult().getIdValue();
-        } catch (NullPointerException | InterruptedException | ExecutionException e) {
-            LOG.error("Exception While allocating id for group: {}", groupIdKey, e);
-        }
-        return 0;
-    }
-
-    protected void handleSwitches(BigInteger dpnId, String routerName, long routerId, BigInteger primarySwitchId) {
+    protected void handleSwitches(Uint64 dpnId, String routerName, Uint32 routerId, Uint64 primarySwitchId) {
         LOG.debug("handleSwitches : Installing SNAT miss entry in switch {}", dpnId);
         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
         String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
@@ -925,8 +911,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         installSnatMissEntry(dpnId, listBucketInfo, routerName, routerId);
     }
 
-    List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
-                                                     BigInteger primarySwitchId, String routerName, long routerId) {
+    List<BucketInfo> getBucketInfoForNonNaptSwitches(Uint64 nonNaptSwitchId,
+                                                     Uint64 primarySwitchId, String routerName, Uint32 routerId) {
         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
         String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
         List<BucketInfo> listBucketInfo = new ArrayList<>();
@@ -951,7 +937,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return listBucketInfo;
     }
 
-    protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName, long routerId,
+    protected void handlePrimaryNaptSwitch(Uint64 dpnId, String routerName, Uint32 routerId, Uuid externalNwUuid,
         TypedWriteTransaction<Configuration> confTx) {
 
        /*
@@ -976,12 +962,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         if (networkId != null) {
             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
             if (vpnUuid != null) {
-                Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+                Uint32 extVpnId = NatUtil.getExternalVpnIdForExtNetwork(dataBroker, externalNwUuid);
                 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
                     installNaptPfibEntriesForExternalSubnets(routerName, dpnId, null);
                     //Install the NAPT PFIB TABLE which forwards outgoing packet to FIB Table matching on the VPN ID.
-                    if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
-                        installNaptPfibEntry(dpnId, vpnId, null);
+                    if (extVpnId != null && extVpnId != NatConstants.INVALID_ID) {
+                        installNaptPfibEntry(dpnId, extVpnId, null);
                     }
                     return Collections.emptyList();
                 });
@@ -993,16 +979,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    List<BucketInfo> getBucketInfoForPrimaryNaptSwitch() {
-        List<BucketInfo> listBucketInfo = new ArrayList<>();
-        List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
-        listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
-        BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
-        listBucketInfo.add(0, bucketPrimary);
-        return listBucketInfo;
-    }
-
-    public void installNaptPfibEntry(BigInteger dpnId, long segmentId, TypedWriteTransaction<Configuration> confTx) {
+    public void installNaptPfibEntry(Uint64 dpnId, Uint32 segmentId,
+            @Nullable TypedWriteTransaction<Configuration> confTx) {
         LOG.debug("installNaptPfibEntry : called for dpnId {} and segmentId {} ", dpnId, segmentId);
         FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
         if (confTx != null) {
@@ -1012,16 +990,17 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
+    public FlowEntity buildNaptPfibFlowEntity(Uint64 dpId, Uint32 segmentId) {
 
         LOG.debug("buildNaptPfibFlowEntity : called for dpId {}, segmentId {}", dpId, segmentId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
-        listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
+        listActionInfo.add(new ActionNxLoadInPort(Uint64.valueOf(BigInteger.ZERO)));
         listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
         instructionInfo.add(new InstructionApplyActions(listActionInfo));
 
@@ -1033,8 +1012,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
-    public void handleSnatReverseTraffic(TypedWriteTransaction<Configuration> confTx, BigInteger dpnId, Routers router,
-        long routerId, String routerName, String externalIp) {
+    public void handleSnatReverseTraffic(TypedWriteTransaction<Configuration> confTx, Uint64 dpnId, Routers router,
+                                         Uint32 routerId, String routerName, String externalIp) {
         LOG.debug("handleSnatReverseTraffic : entry for DPN ID {}, routerId {}, externalIp: {}",
             dpnId, routerId, externalIp);
         Uuid networkId = router.getNetworkId();
@@ -1042,6 +1021,31 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             LOG.error("handleSnatReverseTraffic : networkId is null for the router ID {}", routerId);
             return;
         }
+        Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(
+                new ArrayList<ExternalIps>(router.getExternalIps().values()));
+        // FLAT/VLAN case having external-subnet as VPN
+        String externalSubnetVpn = null;
+        if (externalSubnetList != null && !externalSubnetList.isEmpty()) {
+            Boolean isExternalIpsAdvertized = Boolean.FALSE;
+            for (Uuid externalSubnetId : externalSubnetList) {
+                Optional<Subnets> externalSubnet = NatUtil
+                    .getOptionalExternalSubnets(dataBroker, externalSubnetId);
+                // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
+                if (externalSubnet.isPresent()) {
+                    externalSubnetVpn = externalSubnetId.getValue();
+                    advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
+                        externalSubnetVpn, routerId, routerName,
+                        externalIp, networkId, router, confTx);
+                    isExternalIpsAdvertized = Boolean.TRUE;
+                }
+            }
+            if (isExternalIpsAdvertized) {
+                LOG.trace("External Ips {} advertized for Router {}", router.getExternalIps(), routerName);
+                return;
+            }
+        }
+
+        // VXVLAN/GRE case having Internet-VPN
         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
         if (vpnName == null) {
             LOG.error("handleSnatReverseTraffic : No VPN associated with ext nw {} to handle add external ip "
@@ -1054,9 +1058,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             dpnId, routerId, externalIp);
     }
 
-    public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
-                                                final long routerId, final String routerName, final String externalIp,
-                                                final Uuid extNetworkId, final Routers router,
+    public void advToBgpAndInstallFibAndTsFlows(final Uint64 dpnId, final short tableId, final String vpnName,
+                                                final Uint32 routerId, final String routerName, final String externalIp,
+                                                final Uuid extNetworkId, @Nullable final Routers router,
                                                 final TypedWriteTransaction<Configuration> confTx) {
         LOG.debug("advToBgpAndInstallFibAndTsFlows : entry for DPN ID {}, tableId {}, vpnname {} "
                 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
@@ -1073,7 +1077,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
         if (extNwProvType == ProviderTypes.VXLAN) {
             evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
-                nextHopIp, routerId, routerName, confTx);
+                nextHopIp, routerId, routerName, extNetworkId, confTx);
             return;
         }
         //Generate VPN label for the external IP
@@ -1086,49 +1090,42 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             if (result.isSuccessful()) {
                 LOG.debug("advToBgpAndInstallFibAndTsFlows : inside apply with result success");
                 GenerateVpnLabelOutput output = result.getResult();
-                final long label = output.getLabel();
+                final Uint32 label = output.getLabel();
 
                 int externalIpInDsFlag = 0;
                 //Get IPMaps from the DB for the router ID
                 List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
-                if (dbIpMaps != null) {
-                    for (IpMap dbIpMap : dbIpMaps) {
-                        String dbExternalIp = dbIpMap.getExternalIp();
-                        //Select the IPMap, whose external IP is the IP for which FIB is installed
-                        if (dbExternalIp.contains(externalIp)) {
-                            String dbInternalIp = dbIpMap.getInternalIp();
-                            IpMapKey dbIpMapKey = dbIpMap.key();
-                            LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
-                                    + "and externalIp {}", label, dbInternalIp, externalIp);
-                            IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
-                                .setExternalIp(dbExternalIp).setLabel(label).build();
-                            MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                                naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
-                            externalIpInDsFlag++;
-                        }
-                    }
-                    if (externalIpInDsFlag <= 0) {
-                        LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
-                                + "Failed to update label {} for routerId {} in DS",
-                                externalIp, label, routerId);
-                        String errMsg = String.format("Failed to update label %s due to external Ip %s not"
-                            + " found in DS for router %s", label, externalIp, routerId);
-                        return Futures.immediateFailedFuture(new Exception(errMsg));
+                for (IpMap dbIpMap : dbIpMaps) {
+                    String dbExternalIp = dbIpMap.getExternalIp();
+                    //Select the IPMap, whose external IP is the IP for which FIB is installed
+                    if (dbExternalIp.contains(externalIp)) {
+                        String dbInternalIp = dbIpMap.getInternalIp();
+                        IpMapKey dbIpMapKey = dbIpMap.key();
+                        LOG.debug("advToBgpAndInstallFibAndTsFlows : Setting label {} for internalIp {} "
+                                + "and externalIp {}", label, dbInternalIp, externalIp);
+                        IpMap newIpm = new IpMapBuilder().withKey(dbIpMapKey).setInternalIp(dbInternalIp)
+                            .setExternalIp(dbExternalIp).setLabel(label).build();
+                        MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                            naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
+                        externalIpInDsFlag++;
                     }
-                } else {
-                    LOG.error("advToBgpAndInstallFibAndTsFlows : Failed to write label {} for externalIp {} for"
-                            + " routerId {} in DS", label, externalIp, routerId);
+                }
+                if (externalIpInDsFlag <= 0) {
+                    LOG.debug("advToBgpAndInstallFibAndTsFlows : External Ip {} not found in DS, "
+                            + "Failed to update label {} for routerId {} in DS",
+                            externalIp, label, routerId);
+                    String errMsg = String.format("Failed to update label %s due to external Ip %s not"
+                        + " found in DS for router %s", label, externalIp, routerId);
+                    return Futures.immediateFailedFuture(new Exception(errMsg));
                 }
                 //Inform BGP
-                long l3vni = 0;
+                Uint32 l3vni = Uint32.ZERO;
                 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
-                    l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
+                    l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni);
                 }
                 Routers extRouter = router != null ? router :
                     NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
-                Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
-                        extRouter);
-                NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, externalSubnetId,
+                NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
                     externalIp, nextHopIp, extRouter.getNetworkId().getValue(), null, label, l3vni,
                     RouteOrigin.STATIC, dpnId);
 
@@ -1146,13 +1143,16 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     //Install the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
                     NatUtil.makePreDnatToSnatTableEntry(mdsalManager, dpnId, NwConstants.INBOUND_NAPT_TABLE, confTx);
                 }
-                String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
-                Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
-                        externalSubnetId);
                 String externalVpn = vpnName;
-                if (externalSubnet.isPresent()) {
-                    externalVpn =  externalSubnetId.getValue();
+                Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp, extRouter);
+                if (extNwProvType == ProviderTypes.VLAN || extNwProvType == ProviderTypes.FLAT) {
+                    Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
+                            externalSubnetId);
+                    if (externalSubnet.isPresent()) {
+                        externalVpn =  externalSubnetId.getValue();
+                    }
                 }
+                String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
                 CreateFibEntryInput input = new CreateFibEntryInputBuilder()
                     .setVpnName(externalVpn)
                     .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
@@ -1170,12 +1170,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
 
             @Override
-            public void onFailure(@Nonnull Throwable error) {
+            public void onFailure(@NonNull Throwable error) {
                 LOG.error("advToBgpAndInstallFibAndTsFlows : Error in generate label or fib install process", error);
             }
 
             @Override
-            public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
+            public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
                 if (result.isSuccessful()) {
                     LOG.info("advToBgpAndInstallFibAndTsFlows : Successfully installed custom FIB routes for prefix {}",
                             externalIp);
@@ -1191,11 +1191,11 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             String externalIp) {
         List<Instruction> fibTableCustomInstructions = new ArrayList<>();
         Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
-        long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
+        Uint32 externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
                 externalIp, router);
         int instructionIndex = 0;
         if (externalSubnetVpnId != NatConstants.INVALID_ID) {
-            BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
+            Uint64 subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId.longValue());
             fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
                     MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
             instructionIndex++;
@@ -1205,33 +1205,35 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return fibTableCustomInstructions;
     }
 
-    private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId,
+    private void makeLFibTableEntry(Uint64 dpId, Uint32 serviceId, short tableId,
         TypedWriteTransaction<Configuration> confTx) {
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.MPLS_UNICAST);
-        matches.add(new MatchMplsLabel(serviceId));
+        matches.add(new MatchMplsLabel(serviceId.longValue()));
 
-        List<Instruction> instructions = new ArrayList<>();
+        Map<InstructionKey, Instruction> instructionsMap = new HashMap<InstructionKey, Instruction>();
+        int instructionKey = 0;
         List<ActionInfo> actionsInfos = new ArrayList<>();
         //NAT is required for IPv4 only. Hence always etherType will be IPv4
         actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
         Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
-        instructions.add(writeInstruction);
-        instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
+        instructionsMap.put(new InstructionKey(++instructionKey), writeInstruction);
+        instructionsMap.put(new InstructionKey(++instructionKey),
+                new InstructionGotoTable(tableId).buildInstruction(1));
 
         // Install the flow entry in L3_LFIB_TABLE
         String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
 
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
             10, flowRef, 0, 0,
-            COOKIE_VM_LFIB_TABLE, matches, instructions);
+            COOKIE_VM_LFIB_TABLE, matches, instructionsMap);
 
         mdsalManager.addFlow(confTx, dpId, flowEntity);
 
         LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
     }
 
-    private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, long l3Vni,
+    private void makeTunnelTableEntry(Uint64 dpnId, Uint32 serviceId, Uint32 l3Vni,
         List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx,
         ProviderTypes extNwProvType) {
 
@@ -1241,118 +1243,128 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             dpnId, serviceId, customInstructions);
 
         if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
-            mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
+            mkMatches.add(new MatchTunnelId(Uint64.valueOf(l3Vni)));
         } else {
-            mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
+            mkMatches.add(new MatchTunnelId(Uint64.valueOf(serviceId)));
+        }
+        Map<InstructionKey, Instruction> customInstructionsMap = new HashMap<InstructionKey, Instruction>();
+        int instructionKey = 0;
+        for (Instruction instructionObj : customInstructions) {
+            customInstructionsMap.put(new InstructionKey(++instructionKey), instructionObj);
         }
-
         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
-            getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
-            String.format("%s:%d", "TST Flow Entry ", serviceId),
-            0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
+            getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+                NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY,
+                String.format("%s:%s", "TST Flow Entry ", serviceId), 0, 0,
+                Uint64.valueOf(COOKIE_TUNNEL.toJava().add(BigInteger.valueOf(serviceId.longValue()))),
+                mkMatches, customInstructionsMap);
 
         mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
     }
 
-    protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
+    protected InstanceIdentifier<RouterIds> getRoutersIdentifier(Uint32 routerId) {
         return InstanceIdentifier.builder(RouterIdName.class).child(RouterIds.class,
             new RouterIdsKey(routerId)).build();
     }
 
-    private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
-        return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
-                .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
+    private String getFlowRef(Uint64 dpnId, short tableId, Uint32 id, String ipAddress) {
+        return NatConstants.SNAT_FLOWID_PREFIX + dpnId.toString() + NwConstants.FLOWID_SEPARATOR + tableId
+                + NwConstants.FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
     }
 
     @Override
-    protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
+    public void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
+        if (natMode != NatMode.Controller) {
+            return;
+        }
+        LOG.trace("update : origRouter: {} updatedRouter: {}", original, update);
         String routerName = original.getRouterName();
-        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+        Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
         if (routerId == NatConstants.INVALID_ID) {
             LOG.error("update : external router event - Invalid routerId for routerName {}", routerName);
             return;
         }
-        // Check if its update on SNAT flag
-        boolean originalSNATEnabled = original.isEnableSnat();
-        boolean updatedSNATEnabled = update.isEnableSnat();
-        LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
-            + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
-        /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
-         * if dpnId value is null or zero then go for electing new Napt switch for existing router.
-         */
-        long bgpVpnId = NatConstants.INVALID_ID;
-        Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
-        if (bgpVpnUuid != null) {
-            bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
-        }
-        BigInteger dpnId = getPrimaryNaptSwitch(routerName);
-        if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
-            // Router has no interface attached
-            return;
-        }
-        final long finalBgpVpnId = bgpVpnId;
         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + update.key(), () -> {
             List<ListenableFuture<Void>> futures = new ArrayList<>();
-            futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, writeFlowInvTx -> {
+            futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeFlowInvTx -> {
                 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, removeFlowInvTx -> {
+                    Uint32 bgpVpnId = NatConstants.INVALID_ID;
+                    Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
+                    if (bgpVpnUuid != null) {
+                        bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
+                    }
+                    //BigInteger dpnId = getPrimaryNaptSwitch(routerName);
+                    /* Get Primary Napt Switch for existing router from "router-to-napt-switch" DS.
+                     * if dpnId value is null or zero then go for electing new Napt switch for existing router.
+                     */
+                    Uint64 dpnId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+                    boolean isPrimaryNaptSwitchNotSelected = (dpnId == null || dpnId.equals(Uint64
+                            .valueOf(BigInteger.ZERO)));
                     Uuid networkId = original.getNetworkId();
-                    if (originalSNATEnabled != updatedSNATEnabled) {
-                        if (originalSNATEnabled) {
+                    // Check if its update on SNAT flag
+                    boolean originalSNATEnabled = original.isEnableSnat();
+                    boolean updatedSNATEnabled = update.isEnableSnat();
+                    LOG.debug("update :called with originalFlag and updatedFlag for SNAT enabled "
+                            + "as {} and {} with Elected Dpn {}(isPrimaryNaptSwitchNotSelected:{})",
+                        originalSNATEnabled, updatedSNATEnabled, dpnId, isPrimaryNaptSwitchNotSelected);
+                    // Cluster Reboot Case Handling
+                    // 1. DPN not elected during add event(due to none of the OVS connected)
+                    // 2. Update event called with changes of parameters(but enableSnat is not changed)
+                    // 3. First Elect dpnId and process other changes with valid dpnId
+                    if (originalSNATEnabled != updatedSNATEnabled || isPrimaryNaptSwitchNotSelected) {
+                        if (originalSNATEnabled && !updatedSNATEnabled) {
+                            if (isPrimaryNaptSwitchNotSelected) {
+                                LOG.info("No Action to be taken when SNAT is disabled "
+                                    + "with no Napt Switch Election for Router {}", routerName);
+                                return;
+                            }
                             //SNAT disabled for the router
                             Uuid networkUuid = original.getNetworkId();
                             LOG.info("update : SNAT disabled for Router {}", routerName);
                             Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-                            handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId, routerId,
-                                    removeFlowInvTx);
-                        } else {
-                            LOG.info("update : SNAT enabled for Router {}", original.getRouterName());
-                            handleEnableSnat(original, routerId, dpnId, finalBgpVpnId, removeFlowInvTx);
+                            final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
+                            handleDisableSnat(original, networkUuid, externalIps, false, vpnName,
+                                    dpnId, routerId, removeFlowInvTx);
+                        }  else if (updatedSNATEnabled) {
+                            LOG.info("update : SNAT enabled for Router {}", routerName);
+                            addOrDelDefFibRouteToSNAT(routerName, routerId, bgpVpnId, bgpVpnUuid,
+                                true, writeFlowInvTx);
+                            if (isPrimaryNaptSwitchNotSelected) {
+                                dpnId = selectNewNAPTSwitch(routerName);
+                                if (dpnId != null && !dpnId.equals(Uint64.valueOf(BigInteger.ZERO))) {
+                                    handleEnableSnat(update, routerId, dpnId, bgpVpnId, removeFlowInvTx);
+                                } else {
+                                    LOG.error("update : Failed to elect Napt Switch During update event"
+                                        + " of router {}", routerName);
+                                }
+                            }
                         }
+                        LOG.info("update : no need to process external/subnet changes as it's will taken care"
+                            + "in handleDisableSnat/handleEnableSnat");
+                        return;
                     }
                     if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
                         NatUtil.installRouterGwFlows(txRunner, vpnManager, original, dpnId, NwConstants.DEL_FLOW);
                         NatUtil.installRouterGwFlows(txRunner, vpnManager, update, dpnId, NwConstants.ADD_FLOW);
                     }
 
-                    //Check if the Update is on External IPs
-                    LOG.debug("update : Checking if this is update on External IPs");
-                    List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
-                    List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
-
-                    //Check if the External IPs are added during the update.
-                    Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
-                    addedExternalIps.removeAll(originalExternalIps);
-                    if (addedExternalIps.size() != 0) {
-                        LOG.debug("update : Start processing of the External IPs addition during the update "
-                                + "operation");
-                        vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
-                                update.getExtGwMacAddress(), dpnId,
-                                update.getNetworkId());
-
-                        for (String addedExternalIp : addedExternalIps) {
-                /*
-                    1) Do nothing in the IntExtIp model.
-                    2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
-                 */
-                            String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
-                            String externalIp = externalIpParts[0];
-                            String externalIpPrefix = externalIpParts[1];
-                            String externalpStr = externalIp + "/" + externalIpPrefix;
-                            LOG.debug("update : Initialise the count mapping of the external IP {} for the "
-                                            + "router ID {} in the ExternalIpsCounter model.",
-                                    externalpStr, routerId);
-                            naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
-                        }
-                        LOG.debug(
-                                "update : End processing of the External IPs addition during the update operation");
+                    if (updatedSNATEnabled != originalSNATEnabled) {
+                        LOG.info("update : no need to process external/subnet changes as it's will taken care in "
+                                + "handleDisableSnat/handleEnableSnat");
+                        return;
                     }
+                    //Check if the Update is on External IPs
+                    LOG.debug("update : Checking if this is update on External IPs for router {}", routerName);
+                    List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(
+                            new ArrayList<ExternalIps>(original.getExternalIps().values()));
+                    List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(
+                            new ArrayList<ExternalIps>(update.getExternalIps().values()));
 
                     //Check if the External IPs are removed during the update.
                     Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
                     removedExternalIps.removeAll(updatedExternalIps);
                     if (removedExternalIps.size() > 0) {
-                        LOG.debug("update : Start processing of the External IPs removal during the update "
-                                + "operation");
+                        LOG.debug("update : Start processing of the External IPs removal for router {}", routerName);
                         vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
                                 removedExternalIps, original.getExtGwMacAddress(),
                                 dpnId, networkId);
@@ -1416,27 +1428,30 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                 allocateExternalIp(dpnId, update, routerId, routerName, networkId,
                                         removedInternalIp, writeFlowInvTx);
                             }
-
                             LOG.debug("update : Remove the NAPT translation entries from "
                                     + "Inbound and Outbound NAPT tables for the removed external IPs.");
                             //Get the internalIP and internal Port which were associated to the removed external IP.
-                            List<Integer> externalPorts = new ArrayList<>();
                             Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
                             InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier
                                     .builder(IntextIpPortMap.class)
                                     .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
-                            Optional<IpPortMapping> ipPortMapping =
-                                    MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
+                            Optional<IpPortMapping> ipPortMapping;
+                            try {
+                                ipPortMapping = SingleTransactionDataBroker
+                                            .syncReadOptional(dataBroker,
+                                                    LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
+                            } catch (InterruptedException | ExecutionException e) {
+                                LOG.error("Failed to read ipPortMapping for router id {}", routerId, e);
+                                ipPortMapping = Optional.empty();
+                            }
+
                             if (ipPortMapping.isPresent()) {
-                                List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get()
-                                        .getIntextIpProtocolType();
-                                for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
+                                for (IntextIpProtocolType intextIpProtocolType :
+                                        ipPortMapping.get().nonnullIntextIpProtocolType().values()) {
                                     ProtocolTypes protoType = intextIpProtocolType.getProtocol();
-                                    List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
-                                    for (IpPortMap ipPortMap : ipPortMaps) {
+                                    for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
                                         IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
                                         if (ipPortExternal.getIpAddress().equals(externalIp)) {
-                                            externalPorts.add(ipPortExternal.getPortNum());
                                             List<String> removedInternalIpPorts =
                                                     protoTypesIntIpPortsMap.get(protoType);
                                             if (removedInternalIpPorts != null) {
@@ -1478,10 +1493,37 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                         if (removedInternalPortsList != null) {
                                             removedInternalPortsList.add(removedInternalPort);
                                             internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
+                                            naptPacketInHandler.removeIncomingPacketMap(routerId
+                                                + NatConstants.COLON_SEPARATOR + removedInternalIp
+                                                + NatConstants.COLON_SEPARATOR + removedInternalPort);
+                                            //Remove the NAPT translation entries from Outbound NAPT table
+                                            naptEventHandler.removeNatFlows(dpnId,
+                                                NwConstants.OUTBOUND_NAPT_TABLE,
+                                                routerId, removedInternalIp,
+                                                Integer.parseInt(removedInternalPort),
+                                                protocolType.getName());
+                                            naptEventHandler.removeNatFlows(dpnId,
+                                                NwConstants.INBOUND_NAPT_TABLE,
+                                                routerId, removedInternalIp,
+                                                Integer.parseInt(removedInternalPort),
+                                                protocolType.getName());
                                         } else {
                                             removedInternalPortsList = new ArrayList<>();
                                             removedInternalPortsList.add(removedInternalPort);
                                             internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
+                                            naptPacketInHandler.removeIncomingPacketMap(routerId
+                                                + NatConstants.COLON_SEPARATOR + removedInternalIp
+                                                + NatConstants.COLON_SEPARATOR + removedInternalPort);
+                                            //Remove the NAPT translation entries from Outbound NAPT table
+                                            naptEventHandler.removeNatFlows(dpnId,
+                                                NwConstants.OUTBOUND_NAPT_TABLE,
+                                                routerId, removedInternalIp,
+                                                Integer.parseInt(removedInternalPort),
+                                                protocolType.getName());
+                                            naptEventHandler.removeNatFlows(dpnId,
+                                                NwConstants.INBOUND_NAPT_TABLE, routerId, removedInternalIp,
+                                                Integer.parseInt(removedInternalPort),
+                                                protocolType.getName());
                                         }
                                     }
                                 }
@@ -1496,46 +1538,56 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                             }
 
                             naptManager.removeNaptPortPool(externalIp);
+                        }
+                        LOG.debug(
+                                "update : End processing of the External IPs removal for router {}", routerName);
+                    }
 
-                            LOG.debug("update : Remove the NAPT translation entries from Inbound NAPT tables for "
-                                    + "the removed external IP {}", externalIp);
-                            for (Integer externalPort : externalPorts) {
-                                //Remove the NAPT translation entries from Inbound NAPT table
-                                naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
-                                        routerId, externalIp, externalPort);
-                            }
+                    //Check if the External IPs are added during the update.
+                    Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
+                    addedExternalIps.removeAll(originalExternalIps);
+                    if (addedExternalIps.size() != 0) {
+                        LOG.debug("update : Start processing of the External IPs addition for router {}",
+                            routerName);
+                        vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
+                                update.getExtGwMacAddress(), dpnId,
+                                update.getNetworkId());
 
-                            Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
-                            for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
-                                String internalIp = internalIpPort.getKey();
-                                LOG.debug("update : Remove the NAPT translation entries from Outbound NAPT tables "
-                                        + "for the removed internal IP {}", internalIp);
-                                List<String> internalPorts = internalIpPort.getValue();
-                                for (String internalPort : internalPorts) {
-                                    //Remove the NAPT translation entries from Outbound NAPT table
-                                    naptPacketInHandler.removeIncomingPacketMap(
-                                            routerId + NatConstants.COLON_SEPARATOR + internalIp
-                                                    + NatConstants.COLON_SEPARATOR + internalPort);
-                                    naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
-                                            routerId, internalIp, Integer.parseInt(internalPort));
-                                }
-                            }
+                        for (String addedExternalIp : addedExternalIps) {
+                /*
+                    1) Do nothing in the IntExtIp model.
+                    2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
+                 */
+                            String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
+                            String externalIp = externalIpParts[0];
+                            String externalIpPrefix = externalIpParts[1];
+                            String externalpStr = externalIp + "/" + externalIpPrefix;
+                            LOG.debug("update : Initialise the count mapping of the external IP {} for the "
+                                            + "router ID {} in the ExternalIpsCounter model.",
+                                    externalpStr, routerId);
+                            naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
+                            subnetRegisterMapping(update, routerId);
+                            LOG.info("update : Installing fib flow fo newly added Ips");
+                            handleSnatReverseTraffic(writeFlowInvTx, dpnId, update, routerId, routerName, externalpStr);
                         }
                         LOG.debug(
-                                "update : End processing of the External IPs removal during the update operation");
+                                "update : End processing of the External IPs addition during the update operation");
                     }
 
                     //Check if its Update on subnets
-                    LOG.debug("update : Checking if this is update on subnets");
+                    LOG.debug("update : Checking if this is update on subnets for router {}", routerName);
                     List<Uuid> originalSubnetIds = original.getSubnetIds();
                     List<Uuid> updatedSubnetIds = update.getSubnetIds();
-                    Set<Uuid> addedSubnetIds = new HashSet<>(updatedSubnetIds);
-                    addedSubnetIds.removeAll(originalSubnetIds);
+                    Set<Uuid> addedSubnetIds =
+                        updatedSubnetIds != null ? new HashSet<>(updatedSubnetIds) : new HashSet<>();
+                    if (originalSubnetIds != null) {
+                        addedSubnetIds.removeAll(originalSubnetIds);
+                    }
 
                     //Check if the Subnet IDs are added during the update.
                     if (addedSubnetIds.size() != 0) {
                         LOG.debug(
-                                "update : Start processing of the Subnet IDs addition during the update operation");
+                                "update : Start processing of the Subnet IDs addition for router {}", routerName);
                         for (Uuid addedSubnetId : addedSubnetIds) {
                 /*
                     1) Select the least loaded external IP for the subnet and store the mapping of the
@@ -1550,7 +1602,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                         writeFlowInvTx);
                             }
                         }
-                        LOG.debug("update : End processing of the Subnet IDs addition during the update operation");
+                        LOG.debug("update : End processing of the Subnet IDs addition for router {}", routerName);
                     }
 
                     //Check if the Subnet IDs are removed during the update.
@@ -1558,7 +1610,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     removedSubnetIds.removeAll(updatedSubnetIds);
                     if (removedSubnetIds.size() != 0) {
                         LOG.debug(
-                                "update : Start processing of the Subnet IDs removal during the update operation");
+                                "update : Start processing of the Subnet IDs removal for router {}", routerName);
                         for (Uuid removedSubnetId : removedSubnetIds) {
                             String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
                             if (subnetAddr != null) {
@@ -1596,7 +1648,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                                 naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
                             }
                         }
-                        LOG.debug("update : End processing of the Subnet IDs removal during the update operation");
+                        LOG.debug("update : End processing of the Subnet IDs removal for router {}", routerName);
                     }
                 }));
             }));
@@ -1606,15 +1658,20 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     private boolean isExternalIpAllocated(String externalIp) {
         InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
-        Optional<ExternalIpsCounter> externalCountersData =
-            MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        Optional<ExternalIpsCounter> externalCountersData;
+        try {
+            externalCountersData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, id);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to read external counters data for ExternalIp {}", externalIp, e);
+            externalCountersData = Optional.empty();
+        }
         if (externalCountersData.isPresent()) {
             ExternalIpsCounter externalIpsCounters = externalCountersData.get();
-            List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
-            for (ExternalCounters ext : externalCounters) {
-                for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
+            for (ExternalCounters ext : externalIpsCounters.nonnullExternalCounters().values()) {
+                for (ExternalIpCounter externalIpCount : ext.nonnullExternalIpCounter().values()) {
                     if (externalIpCount.getExternalIp().equals(externalIp)) {
-                        if (externalIpCount.getCounter() != 0) {
+                        if (externalIpCount.getCounter().toJava() != 0) {
                             return true;
                         }
                         break;
@@ -1625,7 +1682,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return false;
     }
 
-    private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
+    private void allocateExternalIp(Uint64 dpnId, Routers router, Uint32 routerId, String routerName,
             Uuid networkId, String subnetIp, TypedWriteTransaction<Configuration> writeFlowInvTx) {
         String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
         try {
@@ -1657,7 +1714,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             // allocated to any of the subnets)
             // If external IP is already assigned a route, (, do not re-advertise to the BGP
             String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
-            Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
+            Uint32 label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
             if (label != null) {
                 //update
                 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
@@ -1677,11 +1734,11 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
             if (vpnName != null) {
                 LOG.debug("allocateExternalIp : Retrieved vpnName {} for networkId {}", vpnName, networkId);
-                if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
+                if (dpnId == null || dpnId.equals(Uint64.valueOf(BigInteger.ZERO))) {
                     LOG.debug("allocateExternalIp : Best effort for getting primary napt switch when router i/f are"
                         + "added after gateway-set");
                     dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
-                    if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
+                    if (dpnId == null || dpnId.equals(Uint64.valueOf(BigInteger.ZERO))) {
                         LOG.error("allocateExternalIp : dpnId is null or Zero for the router {}", routerName);
                         return;
                     }
@@ -1693,7 +1750,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    protected Long checkExternalIpLabel(long routerId, String externalIp) {
+    @Nullable
+    protected Uint32 checkExternalIpLabel(Uint32 routerId, String externalIp) {
         List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
         for (IpMap ipMap : ipMaps) {
             if (ipMap.getExternalIp().equals(externalIp)) {
@@ -1707,7 +1765,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     }
 
     @Override
-    protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
+    public void remove(InstanceIdentifier<Routers> identifier, Routers router) {
+        if (natMode != NatMode.Controller) {
+            return;
+        }
         LOG.trace("remove : Router delete method");
         /*
         ROUTER DELETE SCENARIO
@@ -1733,13 +1794,13 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
                 LOG.info("remove : Removing default NAT route from FIB on all dpns part of router {} ",
                         routerName);
-                Long routerId = NatUtil.getVpnId(dataBroker, routerName);
+                Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
                 if (routerId == NatConstants.INVALID_ID) {
                     LOG.error("remove : Remove external router event - Invalid routerId for routerName {}",
                             routerName);
                     return;
                 }
-                long bgpVpnId = NatConstants.INVALID_ID;
+                Uint32 bgpVpnId = NatConstants.INVALID_ID;
                 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
                 if (bgpVpnUuid != null) {
                     bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
@@ -1748,8 +1809,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                         tx);
                 Uuid networkUuid = router.getNetworkId();
 
-                BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-                if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
+                Uint64 primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+                if (primarySwitchId == null || primarySwitchId.equals(Uint64.ZERO)) {
                     // No NAPT switch for external router, probably because the router is not attached to
                     // any
                     // internal networks
@@ -1760,32 +1821,34 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     return;
                 } else {
                     Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-                    handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId,
+                    final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid);
+                    handleDisableSnat(router, networkUuid, externalIps, true, vpnName, primarySwitchId,
                             routerId, tx);
                 }
-                NatOverVxlanUtil.releaseVNI(routerName, idManager);
+                if (NatUtil.releaseId(idManager, NatConstants.ODL_VNI_POOL_NAME, routerName)
+                    == NatConstants.INVALID_ID) {
+                    LOG.error("remove: Unable to release VNI for router - {}", routerName);
+                }
             })), NatConstants.NAT_DJC_MAX_RETRIES);
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public void handleDisableSnat(Routers router, Uuid networkUuid, @Nonnull Collection<String> externalIps,
-                                  boolean routerFlag, String vpnName, BigInteger naptSwitchDpnId,
-                                  long routerId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
+    public void handleDisableSnat(Routers router, Uuid networkUuid, @NonNull Collection<String> externalIps,
+                                  boolean routerFlag, @Nullable String vpnName, Uint64 naptSwitchDpnId,
+                                  Uint32 routerId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
         LOG.info("handleDisableSnat : Entry");
         String routerName = router.getRouterName();
         try {
             if (routerFlag) {
                 removeNaptSwitch(routerName);
             } else {
-                updateNaptSwitch(routerName, BigInteger.ZERO);
+                updateNaptSwitch(routerName, Uint64.valueOf(BigInteger.ZERO));
             }
 
             LOG.debug("handleDisableSnat : Remove the ExternalCounter model for the router ID {}", routerId);
             naptManager.removeExternalCounter(routerId);
 
             LOG.debug("handleDisableSnat : got primarySwitch as dpnId {}", naptSwitchDpnId);
-            if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
+            if (naptSwitchDpnId == null || naptSwitchDpnId.equals(Uint64.valueOf(BigInteger.ZERO))) {
                 LOG.error("handleDisableSnat : Unable to retrieve the primary NAPT switch for the "
                     + "router ID {} from RouterNaptSwitch model", routerId);
                 return;
@@ -1796,53 +1859,55 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 LOG.error("handleDisableSnat : External Network Provider Type missing");
                 return;
             }
-            Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps());
+            Collection<Uuid> externalSubnetList = NatUtil.getExternalSubnetIdsFromExternalIps(
+                    new ArrayList<ExternalIps>(router.getExternalIps().values()));
             removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnName, externalIps,
                     externalSubnetList, removeFlowInvTx, extNwProvType);
             removeFlowsFromNonActiveSwitches(routerId, routerName, naptSwitchDpnId, removeFlowInvTx);
-            try {
-                String externalSubnetVpn = null;
-                for (Uuid externalSubnetId : externalSubnetList) {
-                    Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
-                    // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
-                    if (externalSubnet.isPresent()) {
-                        externalSubnetVpn =  externalSubnetId.getValue();
-                        clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
-                                router.getExtGwMacAddress(), removeFlowInvTx);
-                    }
-                }
-                if (externalSubnetVpn == null) {
-                    clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
+            String externalSubnetVpn = null;
+            for (Uuid externalSubnetId : externalSubnetList) {
+                Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, externalSubnetId);
+                // externalSubnet data model will exist for FLAT/VLAN external netowrk UCs.
+                if (externalSubnet.isPresent()) {
+                    externalSubnetVpn =  externalSubnetId.getValue();
+                    clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, externalSubnetVpn,
                             router.getExtGwMacAddress(), removeFlowInvTx);
                 }
-            } catch (Exception ex) {
-                LOG.error("handleDisableSnat : Failed to remove fib entries for routerId {} in naptSwitchDpnId {}",
-                    routerId, naptSwitchDpnId, ex);
+            }
+            if (externalSubnetVpn == null) {
+                clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnName,
+                        router.getExtGwMacAddress(), removeFlowInvTx);
             }
             // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
             // for the router ID.
             LOG.debug("handleDisableSnat : Remove the Internal to external IP address maintained for the "
                     + "router ID {} in the DS", routerId);
             naptManager.removeMapping(routerId);
-        } catch (Exception ex) {
-            LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, ex);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("handleDisableSnat : Exception while handling disableSNAT for router :{}", routerName, e);
         }
         LOG.info("handleDisableSnat : Exit");
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public void handleDisableSnatInternetVpn(String routerName, long routerId, Uuid networkUuid,
-                                             @Nonnull Collection<String> externalIps,
+    public void handleDisableSnatInternetVpn(String routerName, Uint32 routerId, Uuid networkUuid,
+                                             @NonNull Collection<String> externalIps,
                                              String vpnId, TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
         LOG.debug("handleDisableSnatInternetVpn: Started to process handle disable snat for router {} "
                 + "with internet vpn {}", routerName, vpnId);
         try {
-            BigInteger naptSwitchDpnId = null;
+            Uint64 naptSwitchDpnId = null;
             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
                 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
-            Optional<RouterToNaptSwitch> rtrToNapt =
-                read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
+            Optional<RouterToNaptSwitch> rtrToNapt;
+            try {
+                rtrToNapt = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                                LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
+            } catch (InterruptedException | ExecutionException e) {
+                LOG.error("Failed to read NAPT switch for router {}", routerName, e);
+                rtrToNapt = Optional.empty();
+            }
             if (rtrToNapt.isPresent()) {
                 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
             }
@@ -1866,10 +1931,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 LOG.error("handleDisableSnatInternetVpn : Failed to remove fib entries for routerId {} "
                         + "in naptSwitchDpnId {}", routerId, naptSwitchDpnId, ex);
             }
-            NatOverVxlanUtil.releaseVNI(vpnId, idManager);
-        } catch (Exception ex) {
+            if (NatUtil.releaseId(idManager, NatConstants.ODL_VNI_POOL_NAME, vpnId) == NatConstants.INVALID_ID) {
+                LOG.error("handleDisableSnatInternetVpn : Unable to release VNI for vpnId {} ", vpnId);
+            }
+        } catch (InterruptedException | ExecutionException e) {
             LOG.error("handleDisableSnatInternetVpn: Exception while handling disableSNATInternetVpn for router {} "
-                    + "with internet vpn {}", routerName, vpnId, ex);
+                    + "with internet vpn {}", routerName, vpnId, e);
         }
         LOG.debug("handleDisableSnatInternetVpn: Processed handle disable snat for router {} with internet vpn {}",
                 routerName, vpnId);
@@ -1877,7 +1944,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
+    public void updateNaptSwitch(String routerName, Uint64 naptSwitchId) {
         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
             .setPrimarySwitchId(naptSwitchId).build();
         try {
@@ -1902,112 +1969,116 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
     }
 
-    // TODO skitt Fix the exception handling here
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    @SuppressFBWarnings("REC_CATCH_EXCEPTION")
-    public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
-                                                BigInteger dpnId, Uuid networkId, String vpnName,
-                                                @Nonnull Collection<String> externalIps,
+    public void removeNaptFlowsFromActiveSwitch(Uint32 routerId, String routerName,
+                                                Uint64 dpnId, Uuid networkId, String vpnName,
+                                                @NonNull Collection<String> externalIps,
                                                 Collection<Uuid> externalSubnetList,
                                                 TypedReadWriteTransaction<Configuration> confTx,
-                                                ProviderTypes extNwProvType) {
-        try {
-            LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
-            BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
-
-            //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
-            // traffic which comes from the  VMs of the NAPT switches)
-            String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
-            FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
-
-            LOG.info(
-                "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
-                    + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
-            mdsalManager.removeFlow(confTx, preSnatFlowEntity);
-
-            //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
-            // traffic which comes from the VMs of the non NAPT switches)
-            long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
-                routerName);
-            String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
-            FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
-            LOG.info(
-                "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
-                    + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
-            mdsalManager.removeFlow(confTx, tsNatFlowEntity);
-
-            //Remove the flow table 25->44 from NAPT Switch
-            if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
-                NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, dpnId);
-            }
-
-            //Remove the Outbound flow entry which forwards the packet to FIB Table
-            LOG.info(
-                "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
-                    + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
-
-            String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
-                NwConstants.IP_PROT_TCP);
-            FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
-                outboundTcpNatFlowRef);
-            mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
-
-            String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
-                NwConstants.IP_PROT_UDP);
-            FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
-                outboundUdpNatFlowRef);
-            mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
-
-            String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
-                NwConstants.IP_PROT_ICMP);
-            FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
-                icmpDropFlowRef);
-            mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
-
+                                                ProviderTypes extNwProvType)
+            throws InterruptedException, ExecutionException {
+
+        LOG.debug("removeNaptFlowsFromActiveSwitch : Remove NAPT flows from Active switch");
+        Uint64 cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+
+        //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
+        // traffic which comes from the  VMs of the NAPT switches)
+        String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
+        FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
+
+        LOG.info(
+            "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
+                + "and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
+        mdsalManager.removeFlow(confTx, preSnatFlowEntity);
+
+        //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
+        // traffic which comes from the VMs of the non NAPT switches)
+        Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
+                elanManager, idManager, routerId, routerName);
+        String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, Uint32.valueOf(tunnelId.longValue()));
+        FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
+        LOG.info(
+            "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
+                + "and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
+        mdsalManager.removeFlow(confTx, tsNatFlowEntity);
+
+        //Remove the flow table 25->44 from NAPT Switch
+        if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
+            NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, dpnId);
+        }
+
+        //Remove the Outbound flow entry which forwards the packet to FIB Table
+        LOG.info(
+            "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {}"
+                + " and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
+
+        String outboundTcpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
+            NwConstants.IP_PROT_TCP);
+        FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
+            outboundTcpNatFlowRef);
+        mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
+
+        String outboundUdpNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
+            NwConstants.IP_PROT_UDP);
+        FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
+            outboundUdpNatFlowRef);
+        mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
+
+        String icmpDropFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId,
+            NwConstants.IP_PROT_ICMP);
+        FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
+            icmpDropFlowRef);
+        mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
+        boolean lastRouterOnExternalNetwork =
+            !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(dataBroker, networkId, routerName, dpnId);
+        if (lastRouterOnExternalNetwork) {
             removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps, confTx);
-            //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
-            // External Subnet Vpn Id.
-            for (Uuid externalSubnetId : externalSubnetList) {
-                long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
-                if (subnetVpnId != -1) {
-                    String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
-                    FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
-                        natPfibSubnetFlowRef);
-                    mdsalManager.removeFlow(confTx, natPfibFlowEntity);
-                    LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
-                            + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
-                        subnetVpnId, dpnId);
-                }
+        }
+        //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
+        // External Subnet Vpn Id.
+        for (Uuid externalSubnetId : externalSubnetList) {
+            Uint32 subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
+            if (subnetVpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
+                dataBroker, externalSubnetId, routerName, dpnId)) {
+                String natPfibSubnetFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
+                FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE,
+                    natPfibSubnetFlowRef);
+                mdsalManager.removeFlow(confTx, natPfibFlowEntity);
+                LOG.debug("removeNaptFlowsFromActiveSwitch : Removed the flow in table {} with external subnet "
+                          + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
+                    subnetVpnId, dpnId);
             }
+        }
 
-            //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
-            String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
-            FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
+        //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
+        String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
+        FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
 
-            LOG.info(
-                "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
-                    + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
-            mdsalManager.removeFlow(confTx, natPfibFlowEntity);
+        LOG.info(
+            "removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch with the DPN ID {} "
+            + "and router ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
+        mdsalManager.removeFlow(confTx, natPfibFlowEntity);
 
+        if (lastRouterOnExternalNetwork) {
             // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
             // - This does not work since ext-routers is deleted already - no network info
             //Get the VPN ID from the ExternalNetworks model
-            long vpnId = -1;
+            Uint32 vpnId = NatConstants.INVALID_ID;
             if (vpnName == null || vpnName.isEmpty()) {
                 // ie called from router delete cases
                 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
                 LOG.debug("removeNaptFlowsFromActiveSwitch : vpnUuid is {}", vpnUuid);
                 if (vpnUuid != null) {
                     vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
-                    LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external  network {} router delete or "
-                        + "disableSNAT scenario", vpnId, networkId);
+                    LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId {} for external  network {} router delete "
+                              + "or disableSNAT scenario", vpnId, networkId);
                 }
             } else {
                 // ie called from disassociate vpn case
                 LOG.debug("removeNaptFlowsFromActiveSwitch : This is disassociate nw with vpn case with vpnName {}",
                     vpnName);
                 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
-                LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}", vpnId);
+                LOG.debug("removeNaptFlowsFromActiveSwitch : vpnId for disassociate nw with vpn scenario {}",
+                    vpnId);
             }
 
             if (vpnId != NatConstants.INVALID_ID) {
@@ -2015,72 +2086,61 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
                 FlowEntity natPfibVpnFlowEntity =
                     NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
-                LOG.info(
-                    "removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the DPN ID {} "
-                        + "and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
+                LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in {} for the active switch with the "
+                         + "DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
                 mdsalManager.removeFlow(confTx, natPfibVpnFlowEntity);
             }
+        }
 
-            //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
-            IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
-            if (ipPortMapping == null) {
-                LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
-                return;
-            }
-
-            List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
-            for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
-                List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
-                for (IpPortMap ipPortMap : ipPortMaps) {
-                    String ipPortInternal = ipPortMap.getIpPortInternal();
-                    String[] ipPortParts = ipPortInternal.split(":");
-                    if (ipPortParts.length != 2) {
-                        LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
-                        return;
-                    }
-                    String internalIp = ipPortParts[0];
-                    String internalPort = ipPortParts[1];
-
-                    //Build the flow for the outbound NAPT table
-                    naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
-                        + NatConstants.COLON_SEPARATOR + internalPort);
-                    String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
-                        String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
-                    FlowEntity outboundNaptFlowEntity =
-                        NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
-
-                    LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
-                        + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
-                    mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
-
-                    IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
-                    String externalIp = ipPortExternal.getIpAddress();
-                    int externalPort = ipPortExternal.getPortNum();
-
-                    //Build the flow for the inbound NAPT table
-                    switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
-                        String.valueOf(routerId), externalIp, externalPort);
-                    FlowEntity inboundNaptFlowEntity =
-                        NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+        //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
+        IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
+        if (ipPortMapping == null) {
+            LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the IpPortMapping");
+            return;
+        }
 
-                    LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
-                        + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
-                    mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
+        for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType().values()) {
+            String protocol = intextIpProtocolType.getProtocol().name();
+            for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
+                String ipPortInternal = ipPortMap.getIpPortInternal();
+                String[] ipPortParts = ipPortInternal.split(":");
+                if (ipPortParts.length != 2) {
+                    LOG.error("removeNaptFlowsFromActiveSwitch : Unable to retrieve the Internal IP and port");
+                    return;
                 }
+                String internalIp = ipPortParts[0];
+                String internalPort = ipPortParts[1];
+
+                //Build the flow for the outbound NAPT table
+                naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
+                    + NatConstants.COLON_SEPARATOR + internalPort);
+                String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
+                    String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
+                FlowEntity outboundNaptFlowEntity =
+                    NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+                LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active switch "
+                    + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
+                mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
+
+                 //Build the flow for the inbound NAPT table
+                switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
+                    String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
+                FlowEntity inboundNaptFlowEntity =
+                    NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
+
+                LOG.info("removeNaptFlowsFromActiveSwitch : Remove the flow in the {} for the active active switch "
+                    + "with the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
+                mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
             }
-        } catch (Exception e) {
-            LOG.error("Error removing flow", e);
-            throw new RuntimeException("Error removing flow", e);
         }
     }
 
-    // TODO skitt Fix the exception handling here
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    @SuppressFBWarnings("REC_CATCH_EXCEPTION")
-    protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
-                                                    @Nonnull Collection<String> externalIps,
-                                                    TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
-        long extVpnId = NatConstants.INVALID_ID;
+    protected void removeNaptFibExternalOutputFlows(Uint32 routerId, Uint64 dpnId, Uuid networkId,
+                                                    @NonNull Collection<String> externalIps,
+                                                    TypedReadWriteTransaction<Configuration> writeFlowInvTx)
+            throws ExecutionException, InterruptedException {
+        Uint32 extVpnId = NatConstants.INVALID_ID;
         if (networkId != null) {
             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
             if (vpnUuid != null) {
@@ -2103,12 +2163,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 + " with the DPN ID {} and router ID {} and IP {} flowRef {}",
                 NwConstants.NAPT_PFIB_TABLE, dpnId, routerId, extIp, naptFlowRef);
             FlowEntity natPfibVpnFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef);
-            try {
-                mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
-            } catch (Exception e) {
-                LOG.error("Error removing flow", e);
-                throw new RuntimeException("Error removing flow", e);
-            }
+            mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
         }
     }
 
@@ -2119,17 +2174,15 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return ip;
     }
 
-    // TODO skitt Fix the exception handling here
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    @SuppressFBWarnings("REC_CATCH_EXCEPTION")
-    public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
-                                                           BigInteger dpnId, Uuid networkId, String vpnName,
-                                                           TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
+    public void removeNaptFlowsFromActiveSwitchInternetVpn(Uint32 routerId, String routerName,
+                                                           Uint64 dpnId, Uuid networkId, String vpnName,
+                                                           TypedReadWriteTransaction<Configuration> writeFlowInvTx)
+            throws ExecutionException, InterruptedException {
         LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : Remove NAPT flows from Active switch Internet Vpn");
-        BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+        Uint64 cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
 
         //Remove the NAPT PFIB TABLE entry
-        long vpnId = -1;
+        Uint32 vpnId = NatConstants.INVALID_ID;
         if (vpnName != null) {
             // ie called from disassociate vpn case
             LOG.debug("removeNaptFlowsFromActiveSwitchInternetVpn : This is disassociate nw with vpn case "
@@ -2147,12 +2200,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
             LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the active switch "
                     + "with the DPN ID {} and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
-            try {
-                mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
-            } catch (Exception e) {
-                LOG.error("Error removing flow", e);
-                throw new RuntimeException("Error removing flow", e);
-            }
+            mdsalManager.removeFlow(writeFlowInvTx, natPfibVpnFlowEntity);
 
             // Remove IP-PORT active NAPT entries and release port from IdManager
             // For the router ID get the internal IP , internal port and the corresponding
@@ -2162,10 +2210,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 LOG.error("removeNaptFlowsFromActiveSwitchInternetVpn : Unable to retrieve the IpPortMapping");
                 return;
             }
-            List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
-            for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
-                List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
-                for (IpPortMap ipPortMap : ipPortMaps) {
+            for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType().values()) {
+                String protocol = intextIpProtocolType.getProtocol().name();
+                for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
                     String ipPortInternal = ipPortMap.getIpPortInternal();
                     String[] ipPortParts = ipPortInternal.split(":");
                     if (ipPortParts.length != 2) {
@@ -2180,39 +2227,28 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     naptPacketInHandler.removeIncomingPacketMap(routerId + NatConstants.COLON_SEPARATOR + internalIp
                             + NatConstants.COLON_SEPARATOR + internalPort);
                     String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
-                        String.valueOf(routerId), internalIp, Integer.parseInt(internalPort));
+                        String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
                     FlowEntity outboundNaptFlowEntity =
                         NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
 
                     LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
                             + "active switch with the DPN ID {} and router ID {}",
                             NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
-                    try {
-                        mdsalManager.removeFlow(writeFlowInvTx, outboundNaptFlowEntity);
-                    } catch (Exception e) {
-                        LOG.error("Error removing flow", e);
-                        throw new RuntimeException("Error removing flow", e);
-                    }
+                    mdsalManager.removeFlow(writeFlowInvTx, outboundNaptFlowEntity);
 
                     IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
-                    String externalIp = ipPortExternal.getIpAddress();
-                    int externalPort = ipPortExternal.getPortNum();
+                    final String externalIp = ipPortExternal.getIpAddress();
 
                     //Build the flow for the inbound NAPT table
                     switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
-                        String.valueOf(routerId), externalIp, externalPort);
+                        String.valueOf(routerId), internalIp, Integer.parseInt(internalPort), protocol);
                     FlowEntity inboundNaptFlowEntity =
                         NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
 
                     LOG.info("removeNaptFlowsFromActiveSwitchInternetVpn : Remove the flow in the {} for the "
                             + "active active switch with the DPN ID {} and router ID {}",
                             NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
-                    try {
-                        mdsalManager.removeFlow(writeFlowInvTx, inboundNaptFlowEntity);
-                    } catch (Exception e) {
-                        LOG.error("Error removing flow", e);
-                        throw new RuntimeException("Error removing flow", e);
-                    }
+                    mdsalManager.removeFlow(writeFlowInvTx, inboundNaptFlowEntity);
 
                     // Finally release port from idmanager
                     String internalIpPort = internalIp + ":" + internalPort;
@@ -2228,55 +2264,50 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    // TODO skitt Fix the exception handling here
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    @SuppressFBWarnings("REC_CATCH_EXCEPTION")
-    public void removeFlowsFromNonActiveSwitches(long routerId, String routerName,
-            BigInteger naptSwitchDpnId, TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
+    public void removeFlowsFromNonActiveSwitches(Uint32 routerId, String routerName,
+            Uint64 naptSwitchDpnId, TypedReadWriteTransaction<Configuration> removeFlowInvTx)
+            throws ExecutionException, InterruptedException {
         LOG.debug("removeFlowsFromNonActiveSwitches : Remove NAPT related flows from non active switches");
 
         // Remove the flows from the other switches which points to the primary and secondary switches
         // for the flows related the router ID.
-        List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
+        List<Uint64> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
         if (allSwitchList.isEmpty()) {
             LOG.error("removeFlowsFromNonActiveSwitches : Unable to get the swithces for the router {}", routerName);
             return;
         }
-        try {
-            for (BigInteger dpnId : allSwitchList) {
-                if (!naptSwitchDpnId.equals(dpnId)) {
-                    LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
-
-                    //Remove the PSNAT entry which forwards the packet to Terminating Service table
-                    String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
-                    FlowEntity preSnatFlowEntity =
-                        NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
-
-                    LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
-                        + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
-                    mdsalManager.removeFlow(removeFlowInvTx, preSnatFlowEntity);
-
-                    //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
-                    long groupId = createGroupId(getGroupIdKey(routerName));
-                    List<BucketInfo> listBucketInfo = new ArrayList<>();
-                    GroupEntity preSnatGroupEntity =
-                        MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
-
-                    LOG.info("removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
-                        + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
-                    mdsalManager.removeGroup(removeFlowInvTx, preSnatGroupEntity);
-
+        for (Uint64 dpnId : allSwitchList) {
+            if (!naptSwitchDpnId.equals(dpnId)) {
+                LOG.info("removeFlowsFromNonActiveSwitches : Handle Ordinary switch");
+
+                //Remove the PSNAT entry which forwards the packet to Terminating Service table
+                String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
+                FlowEntity preSnatFlowEntity =
+                    NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
+
+                LOG.info("removeFlowsFromNonActiveSwitches : Remove the flow in the {} for the non active switch "
+                    + "with the DPN ID {} and router ID {}", NwConstants.PSNAT_TABLE, dpnId, routerId);
+                mdsalManager.removeFlow(removeFlowInvTx, preSnatFlowEntity);
+
+                //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
+                Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
+                    NatUtil.getGroupIdKey(routerName));
+                if (groupId != NatConstants.INVALID_ID) {
+                    LOG.info(
+                        "removeFlowsFromNonActiveSwitches : Remove the group {} for the non active switch with "
+                            + "the DPN ID {} and router ID {}", groupId, dpnId, routerId);
+                    mdsalManager.removeGroup(removeFlowInvTx, dpnId, groupId.longValue());
+                } else {
+                    LOG.error("removeFlowsFromNonActiveSwitches: Unable to obtained groupID for router:{}", routerName);
                 }
             }
-        } catch (Exception e) {
-            LOG.error("Error removing flow", e);
-            throw new RuntimeException("Error removing flow", e);
         }
     }
 
-    public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid,
-                                         @Nonnull Collection<String> externalIps, String vpnName,
-                                         String extGwMacAddress, TypedReadWriteTransaction<Configuration> confTx) {
+    public void clrRtsFromBgpAndDelFibTs(final Uint64 dpnId, Uint32 routerId, @Nullable Uuid networkUuid,
+                                         @NonNull Collection<String> externalIps, @Nullable String vpnName,
+                                         String extGwMacAddress, TypedReadWriteTransaction<Configuration> confTx)
+            throws ExecutionException, InterruptedException {
         //Withdraw the corresponding routes from the BGP.
         //Get the network ID using the router ID.
         LOG.debug("clrRtsFromBgpAndDelFibTs : Advertise to BGP and remove routes for externalIps {} with routerId {},"
@@ -2305,24 +2336,27 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         //Remove custom FIB routes
         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
         for (String extIp : externalIps) {
+            extIp = NatUtil.validateAndAddNetworkMask(extIp);
             clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, confTx);
         }
     }
 
-    protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
+    protected void clrRtsFromBgpAndDelFibTs(final Uint64 dpnId, Uint32 routerId, String extIp, final String vpnName,
                                             final Uuid networkUuid, String extGwMacAddress,
-                                            TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
+                                            TypedReadWriteTransaction<Configuration> removeFlowInvTx)
+            throws ExecutionException, InterruptedException {
         clearBgpRoutes(extIp, vpnName);
         delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName, networkUuid, extGwMacAddress, false,
                 removeFlowInvTx);
     }
 
-    protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp,
-                                             final String vpnName, Uuid extNetworkId, long tempLabel,
+    protected void delFibTsAndReverseTraffic(final Uint64 dpnId, String routerName, Uint32 routerId, String extIp,
+                                             String vpnName, Uuid extNetworkId, Uint32 tempLabel,
                                              String gwMacAddress, boolean switchOver,
-                                             TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
+                                             TypedReadWriteTransaction<Configuration> removeFlowInvTx)
+            throws ExecutionException, InterruptedException {
         LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
-        String routerName = NatUtil.getRouterName(dataBroker,routerId);
+        //String routerName = NatUtil.getRouterName(dataBroker,routerId);
         if (routerName == null) {
             LOG.error("delFibTsAndReverseTraffic : Could not retrieve Router Name from Router ID {} ", routerId);
             return;
@@ -2340,17 +2374,41 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             );
             return;
         }
-        if (tempLabel < 0) {
+        if (tempLabel.longValue() < 0) {
             LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
                     extIp, routerId);
             return;
         }
-
-        final long label = tempLabel;
+        final Uint32 label = tempLabel;
         final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
-        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
+        RemoveFibEntryInput input = null;
+        if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
+            LOG.debug("delFibTsAndReverseTraffic : Using extSubnetId as vpnName for FLAT/VLAN use-cases");
+            Routers extRouter = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
+            Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIp,
+                    extRouter);
+
+            Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker,
+                    externalSubnetId);
+
+            if (externalSubnet.isPresent()) {
+                vpnName =  externalSubnetId.getValue();
+            }
+        }
+        final String externalVpn = vpnName;
+        if (label != null && label.toJava() <= 0) {
+            LOG.error("delFibTsAndReverseTraffic : Label not found for externalIp {} with router id {}",
+                extIp, routerId);
+            input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
+                .setSourceDpid(dpnId).setIpAddress(externalIp)
+                .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
+        } else {
+            input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
                 .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label)
                 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.ExternalFixedIP).build();
+            removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
+            removeLFibTableEntry(dpnId, label, removeFlowInvTx);
+        }
         ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
 
         removeTunnelTableEntry(dpnId, label, removeFlowInvTx);
@@ -2363,11 +2421,20 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture =
                 Futures.transformAsync(future, result -> {
                     //Release label
-                    if (result.isSuccessful()) {
+                    if (result.isSuccessful() && label != null && label.toJava() > 0) {
                         NatUtil.removePreDnatToSnatTableEntry(removeFlowInvTx, mdsalManager, dpnId);
                         RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
-                            .setVpnName(vpnName).setIpPrefix(externalIp).build();
-                        return vpnService.removeVpnLabel(labelInput);
+                            .setVpnName(externalVpn).setIpPrefix(externalIp).build();
+                        Future<RpcResult<RemoveVpnLabelOutput>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
+                        if (labelFuture1.get() == null || !labelFuture1.get().isSuccessful()) {
+                            String errMsg = String.format(
+                                    "ExternalRoutersListener: RPC call to remove VPN label "
+                                            + "on dpn %s for prefix %s failed for vpn %s - %s",
+                                    dpnId, externalIp, result.getErrors());
+                            LOG.error(errMsg);
+                            return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                        }
+                        return JdkFutureAdapters.listenInPoolThread(labelFuture1);
                     } else {
                         String errMsg =
                             String.format("RPC call to remove custom FIB entries on dpn %s for "
@@ -2380,19 +2447,19 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
 
                 @Override
-                public void onFailure(@Nonnull Throwable error) {
+                public void onFailure(@NonNull Throwable error) {
                     LOG.error("delFibTsAndReverseTraffic : Error in removing the label:{} or custom fib entries"
                         + "got external ip {}", label, extIp, error);
                 }
 
                 @Override
-                public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
+                public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
                     if (result.isSuccessful()) {
                         LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
-                            + "from VPN {}", externalIp, vpnName);
+                            + "from VPN {}", externalIp, externalVpn);
                     } else {
                         LOG.error("delFibTsAndReverseTraffic : Error in removing the label for prefix {} "
-                            + " from VPN {}, {}", externalIp, vpnName, result.getErrors());
+                            + " from VPN {}, {}", externalIp, externalVpn, result.getErrors());
                     }
                 }
             }, MoreExecutors.directExecutor());
@@ -2402,9 +2469,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName,
+    private void delFibTsAndReverseTraffic(final Uint64 dpnId, Uint32 routerId, String extIp, final String vpnName,
                                            final Uuid networkUuid, String extGwMacAddress, boolean switchOver,
-                                           TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
+                                           TypedReadWriteTransaction<Configuration> removeFlowInvTx)
+            throws ExecutionException, InterruptedException {
         LOG.debug("delFibTsAndReverseTraffic : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
         String routerName = NatUtil.getRouterName(dataBroker,routerId);
         if (routerName == null) {
@@ -2432,7 +2500,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             return;
         }
 
-        long tempLabel = NatConstants.INVALID_ID;
+        Uint32 tempLabel = NatConstants.INVALID_ID;
         for (IpMap dbIpMap : dbIpMaps) {
             String dbExternalIp = dbIpMap.getExternalIp();
             LOG.debug("delFibTsAndReverseTraffic : Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
@@ -2450,7 +2518,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             return;
         }
 
-        final long label = tempLabel;
+        final Uint32 label = tempLabel;
         final String externalIp = NatUtil.validateAndAddNetworkMask(extIp);
         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
                 .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp)
@@ -2470,7 +2538,17 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                         if (result.isSuccessful()) {
                             RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
                                     .setVpnName(vpnName).setIpPrefix(externalIp).build();
-                            return vpnService.removeVpnLabel(labelInput);
+                            Future<RpcResult<RemoveVpnLabelOutput>> labelFuture1 = vpnService
+                                    .removeVpnLabel(labelInput);
+                            if (labelFuture1.get() == null || !labelFuture1.get().isSuccessful()) {
+                                String errMsg = String.format(
+                                        "RPC call to remove VPN label on dpn %s for prefix %s "
+                                                + "failed for vpn %s - %s", dpnId, externalIp, vpnName,
+                                        result.getErrors());
+                                LOG.error(errMsg);
+                                return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+                            }
+                            return JdkFutureAdapters.listenInPoolThread(labelFuture1);
                         } else {
                             String errMsg =
                                     String.format("RPC call to remove custom FIB entries on dpn %s for "
@@ -2484,12 +2562,12 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
 
                 @Override
-                public void onFailure(@Nonnull Throwable error) {
+                public void onFailure(@NonNull Throwable error) {
                     LOG.error("delFibTsAndReverseTraffic : Error in removing the label or custom fib entries", error);
                 }
 
                 @Override
-                public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
+                public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
                     if (result.isSuccessful()) {
                         LOG.debug("delFibTsAndReverseTraffic : Successfully removed the label for the prefix {} "
                             + "from VPN {}", externalIp, vpnName);
@@ -2505,9 +2583,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
-                                               List<String> externalIps, String vpnName, String extGwMacAddress,
-                                               TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
+    protected void clearFibTsAndReverseTraffic(final Uint64 dpnId, Uint32 routerId, Uuid networkUuid,
+            List<String> externalIps, @Nullable String vpnName, String extGwMacAddress,
+            TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
         //Withdraw the corresponding routes from the BGP.
         //Get the network ID using the router ID.
         LOG.debug("clearFibTsAndReverseTraffic : for externalIps {} with routerId {},"
@@ -2545,55 +2623,23 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         //Inform BGP about the route removal
         LOG.info("clearBgpRoutes : Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
-        NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName, LOG);
+        NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName);
+        NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, vpnName), externalIp);
     }
 
-    // TODO skitt Fix the exception handling here
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    @SuppressFBWarnings("REC_CATCH_EXCEPTION")
-    private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
-        TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
+    private void removeTunnelTableEntry(Uint64 dpnId, Uint32 serviceId,
+            TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
         LOG.info("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
-        List<MatchInfo> mkMatches = new ArrayList<>();
-        // Matching metadata
-        mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
-        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
-            getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
-            5, String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
-            COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
-        try {
-            mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowEntity);
-        } catch (Exception e) {
-            LOG.error("Error removing flow", e);
-            throw new RuntimeException("Error removing flow", e);
-        }
+        mdsalManager.removeFlow(writeFlowInvTx, dpnId,
+            getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), NwConstants.INTERNAL_TUNNEL_TABLE);
         LOG.debug("removeTunnelTableEntry : dpID {} : label : {} removed successfully", dpnId, serviceId);
     }
 
-    // TODO skitt Fix the exception handling here
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    @SuppressFBWarnings("REC_CATCH_EXCEPTION")
-    private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
-        TypedReadWriteTransaction<Configuration> writeFlowInvTx) {
-        List<MatchInfo> matches = new ArrayList<>();
-        matches.add(MatchEthernetType.MPLS_UNICAST);
-        matches.add(new MatchMplsLabel(serviceId));
-
+    private void removeLFibTableEntry(Uint64 dpnId, Uint32 serviceId,
+            TypedReadWriteTransaction<Configuration> writeFlowInvTx) throws ExecutionException, InterruptedException {
         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
-
         LOG.debug("removeLFibTableEntry : with flow ref {}", flowRef);
-
-        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
-            10, flowRef, 0, 0,
-            COOKIE_VM_LFIB_TABLE, matches, null);
-
-        try {
-            mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowEntity);
-        } catch (Exception e) {
-            LOG.error("Error removing flow", e);
-            throw new RuntimeException("Error removing flow", e);
-        }
-
+        mdsalManager.removeFlow(writeFlowInvTx, dpnId, flowRef, NwConstants.L3_LFIB_TABLE);
         LOG.debug("removeLFibTableEntry : dpID : {} label : {} removed successfully", dpnId, serviceId);
     }
 
@@ -2604,11 +2650,11 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
      * @param routerId - router id
      * @param bgpVpnName BGP VPN name
      */
-    public void changeLocalVpnIdToBgpVpnId(String routerName, long routerId, String bgpVpnName,
+    public void changeLocalVpnIdToBgpVpnId(String routerName, Uint32 routerId, String extNetwork, String bgpVpnName,
             TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
         LOG.debug("changeLocalVpnIdToBgpVpnId : Router associated to BGP VPN");
         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
-            long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
+            Uint32 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
 
             LOG.debug("changeLocalVpnIdToBgpVpnId : BGP VPN ID value {} ", bgpVpnId);
 
@@ -2621,17 +2667,14 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     getRoutersIdentifier(bgpVpnId), rtrs);
 
                 // Get the allocated Primary NAPT Switch for this router
-                LOG.debug("changeLocalVpnIdToBgpVpnId : Router ID value {} ", routerId);
-
                 LOG.debug("changeLocalVpnIdToBgpVpnId : Update the Router ID {} to the BGP VPN ID {} ",
                         routerId, bgpVpnId);
                 addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, bgpVpnId, writeFlowInvTx);
 
                 // Get the group ID
-                BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-                createGroupId(getGroupIdKey(routerName));
-                installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true, writeFlowInvTx,
-                        extNwProvType);
+                Uint64 primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+                installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, new Uuid(extNetwork),
+                    true, writeFlowInvTx, extNwProvType);
             }
         }
     }
@@ -2643,11 +2686,11 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
      * @param routerId - router id
      * @param bgpVpnName BGP VPN name
      */
-    public void changeBgpVpnIdToLocalVpnId(String routerName, long routerId, String bgpVpnName,
+    public void changeBgpVpnIdToLocalVpnId(String routerName, Uint32 routerId, String bgpVpnName, String extNetwork,
             TypedWriteTransaction<Configuration> writeFlowInvTx, ProviderTypes extNwProvType) {
         LOG.debug("changeBgpVpnIdToLocalVpnId : Router dissociated from BGP VPN");
         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
-            long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
+            Uint32 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
             LOG.debug("changeBgpVpnIdToLocalVpnId : BGP VPN ID value {} ", bgpVpnId);
 
             // Get the allocated Primary NAPT Switch for this router
@@ -2657,10 +2700,9 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
             addDefaultFibRouteForSnatWithBgpVpn(routerName, routerId, NatConstants.INVALID_ID, writeFlowInvTx);
 
             // Get the group ID
-            createGroupId(getGroupIdKey(routerName));
-            BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true,
-                    writeFlowInvTx, extNwProvType);
+            Uint64 primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+            installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId,
+                new Uuid(extNetwork), true, writeFlowInvTx, extNwProvType);
         }
     }
 
@@ -2668,41 +2710,54 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         InstanceIdentifier<Routers> routerInstanceIndentifier =
             InstanceIdentifier.builder(ExtRouters.class)
                 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
-        Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
-        return routerData.isPresent() && routerData.get().isEnableSnat();
+        try {
+            Optional<Routers> routerData = SingleTransactionDataBroker
+                    .syncReadOptional(dataBroker,
+                            LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
+            return routerData.isPresent() && routerData.get().isEnableSnat();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to read data for router id {}", routerUuid, e);
+            return false;
+        }
     }
 
-    public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
-        long routerId, boolean isSnatCfgd, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
+    public void installFlowsWithUpdatedVpnId(Uint64 primarySwitchId, String routerName, Uint32 bgpVpnId,
+                                             Uint32 routerId, Uuid extNwUuid, boolean isSnatCfgd,
+                                             TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
 
-        long changedVpnId = bgpVpnId;
+        Uint32 changedVpnId = bgpVpnId;
         String idType = "BGP VPN";
         if (bgpVpnId == NatConstants.INVALID_ID) {
             changedVpnId = routerId;
             idType = "router";
         }
 
-        List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
+        List<Uint64> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
         if (switches.isEmpty()) {
             LOG.error("installFlowsWithUpdatedVpnId : No switches found for router {}", routerName);
             return;
         }
-        for (BigInteger dpnId : switches) {
+        for (Uint64 dpnId : switches) {
             // Update the BGP VPN ID in the SNAT miss entry to group
             if (!dpnId.equals(primarySwitchId)) {
                 LOG.debug("installFlowsWithUpdatedVpnId : Install group in non NAPT switch {}", dpnId);
                 List<BucketInfo> bucketInfoForNonNaptSwitches =
                     getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName, routerId);
-                long groupId = createGroupId(getGroupIdKey(routerName));
-                if (!isSnatCfgd) {
-                    groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
-                }
-
-                LOG.debug(
+                Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
+                    NatUtil.getGroupIdKey(routerName));
+                if (groupId != NatConstants.INVALID_ID) {
+                    if (!isSnatCfgd) {
+                        installGroup(dpnId, routerName, groupId, bucketInfoForNonNaptSwitches);
+                    }
+                    LOG.debug(
                         "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
-                                + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
-                FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
-                mdsalManager.addFlow(confTx, flowEntity);
+                            + "{} in the non NAPT switch {}", idType, changedVpnId, groupId, dpnId);
+                    FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName,
+                        groupId, changedVpnId);
+                    mdsalManager.addFlow(confTx, flowEntity);
+                } else {
+                    LOG.error("installFlowsWithUpdatedVpnId: Unable to get groupId for router:{}", routerName);
+                }
             } else {
                 LOG.debug(
                         "installFlowsWithUpdatedVpnId : Update the {} ID {} in the SNAT miss entry pointing to group "
@@ -2738,16 +2793,23 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
 
                 LOG.debug("installFlowsWithUpdatedVpnId : Installing SNAT PFIB flow in the primary switch {}",
                         primarySwitchId);
-                Long vpnId = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
-                //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
-                if (vpnId != NatConstants.INVALID_ID) {
-                    installNaptPfibEntry(primarySwitchId, vpnId, confTx);
+                //Get the VPN ID from the ExternalNetworks model
+                Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, extNwUuid);
+                if (vpnUuid != null) {
+                    Uint32 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+                    //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table
+                    // matching on the VPN ID.
+                    if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
+                        installNaptPfibEntry(primarySwitchId, vpnId, confTx);
+                    }
+                } else {
+                    LOG.error("NAT Service : vpnUuid is null");
                 }
             }
         }
     }
 
-    public void updateNaptFlowsWithVpnId(BigInteger dpnId, String routerName, long routerId, long bgpVpnId) {
+    public void updateNaptFlowsWithVpnId(Uint64 dpnId, String routerName, Uint32 routerId, Uint32 bgpVpnId) {
         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
         if (ipPortMapping == null) {
@@ -2764,10 +2826,8 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                     routerId);
             return;
         }
-        List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
-        for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
-            List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
-            for (IpPortMap ipPortMap : ipPortMaps) {
+        for (IntextIpProtocolType intextIpProtocolType : ipPortMapping.nonnullIntextIpProtocolType().values()) {
+            for (IpPortMap ipPortMap : intextIpProtocolType.nonnullIpPortMap().values()) {
                 String ipPortInternal = ipPortMap.getIpPortInternal();
                 String[] ipPortParts = ipPortInternal.split(":");
                 if (ipPortParts.length != 2) {
@@ -2793,7 +2853,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.parseInt(internalPort));
                 SessionAddress externalAddress =
                         naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
-                long internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
+                Uint32 internetVpnid = NatUtil.getNetworkVpnIdFromRouterId(dataBroker, routerId);
                 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
                         routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
                 naptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
@@ -2802,22 +2862,23 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         }
     }
 
-    public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
-                                                          long changedVpnId) {
+    public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(Uint64 dpId, String routerName, Uint32 groupId,
+                                                          Uint32 changedVpnId) {
 
         LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : called for dpId {}, routerName {} groupId {} "
             + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         List<ActionInfo> actionsInfo = new ArrayList<>();
-        long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, changedVpnId,
-                routerName);
-        actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
+        Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil,
+                elanManager, idManager, changedVpnId, routerName);
+        actionsInfo.add(new ActionSetFieldTunnelId(tunnelId));
         LOG.debug("buildSnatFlowEntityWithUpdatedVpnId : Setting the tunnel to the list of action infos {}",
                 actionsInfo);
-        actionsInfo.add(new ActionGroup(groupId));
+        actionsInfo.add(new ActionGroup(groupId.longValue()));
         List<InstructionInfo> instructions = new ArrayList<>();
         instructions.add(new InstructionApplyActions(actionsInfo));
         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
@@ -2829,14 +2890,15 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
-    public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
-                                                                        long changedVpnId) {
+    public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(Uint64 dpId, String routerName,
+                                                                        Uint32 changedVpnId) {
 
         LOG.debug("buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch : called for dpId {}, routerName {} "
                 + "changed VPN ID {}", dpId, routerName, changedVpnId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         List<InstructionInfo> instructions = new ArrayList<>();
         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
@@ -2851,8 +2913,10 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
     }
 
     // TODO : Replace this with ITM Rpc once its available with full functionality
-    protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
-        long routerId, long changedVpnId, TypedWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
+    protected void installTerminatingServiceTblEntryWithUpdatedVpnId(Uint64 dpnId, String routerName,
+                                                                     Uint32 routerId, Uint32 changedVpnId,
+                                                                     TypedWriteTransaction<Configuration> confTx,
+                                                                     ProviderTypes extNwProvType) {
 
         LOG.debug("installTerminatingServiceTblEntryWithUpdatedVpnId : called for switch {}, "
             + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
@@ -2861,32 +2925,33 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         mdsalManager.addFlow(confTx, flowEntity);
     }
 
-    private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName,
-            long routerIdLongVal, long changedVpnId, ProviderTypes extNwProvType) {
+    private FlowEntity buildTsFlowEntityWithUpdatedVpnId(Uint64 dpId, String routerName,
+                                                         Uint32 routerIdLongVal, Uint32 changedVpnId,
+                                                         ProviderTypes extNwProvType) {
         LOG.debug("buildTsFlowEntityWithUpdatedVpnId : called for switch {}, routerName {}, BGP VPN ID {}",
             dpId, routerName, changedVpnId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
 
-        BigInteger tunnelId = BigInteger.valueOf(changedVpnId);
+        Uint64 tunnelId = Uint64.valueOf(changedVpnId);
         if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
-            tunnelId = NatOverVxlanUtil.getRouterVni(idManager, routerName, changedVpnId);
+            tunnelId = natOverVxlanUtil.getRouterVni(routerName, changedVpnId);
         }
         matches.add(new MatchTunnelId(tunnelId));
 
         List<InstructionInfo> instructions = new ArrayList<>();
-        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
+        instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId.longValue()),
             MetaDataUtil.METADATA_MASK_VRFID));
         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
-        BigInteger routerId = BigInteger.valueOf(routerIdLongVal);
-        String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
+        Uint32 routerId = routerIdLongVal;
+        String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId);
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
             NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
             NwConstants.COOKIE_TS_TABLE, matches, instructions);
         return flowEntity;
     }
 
-    public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId,
+    public void createOutboundTblEntryWithBgpVpn(Uint64 dpnId, Uint32 routerId, Uint32 changedVpnId,
                                                  TypedWriteTransaction<Configuration> writeFlowInvTx) {
         LOG.debug("createOutboundTblEntryWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
             dpnId, routerId, changedVpnId);
@@ -2905,15 +2970,16 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         mdsalManager.addFlow(writeFlowInvTx, icmpDropFlow);
     }
 
-    protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId,
-                                                           long changedVpnId, int protocol) {
+    protected FlowEntity buildOutboundFlowEntityWithBgpVpn(Uint64 dpId, Uint32 routerId,
+                                                           Uint32 changedVpnId, int protocol) {
         LOG.debug("buildOutboundFlowEntityWithBgpVpn : called for dpId {} and routerId {}, BGP VPN ID {}",
             dpId, routerId, changedVpnId);
-        BigInteger cookie = getCookieOutboundFlow(routerId);
+        Uint64 cookie = getCookieOutboundFlow(routerId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
         matches.add(new MatchIpProtocol((short)protocol));
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
@@ -2930,7 +2996,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
-    public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId,
+    public void installNaptPfibEntryWithBgpVpn(Uint64 dpnId, Uint32 segmentId, Uint32 changedVpnId,
                                                TypedWriteTransaction<Configuration> writeFlowInvTx) {
         LOG.debug("installNaptPfibEntryWithBgpVpn : called for dpnId {} and segmentId {} ,BGP VPN ID {}",
             dpnId, segmentId, changedVpnId);
@@ -2938,17 +3004,18 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         mdsalManager.addFlow(writeFlowInvTx, naptPfibFlowEntity);
     }
 
-    public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
+    public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(Uint64 dpId, Uint32 segmentId, Uint32 changedVpnId) {
 
         LOG.debug("buildNaptPfibFlowEntityWithUpdatedVpnId : called for dpId {}, "
             + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
-        listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
+        listActionInfo.add(new ActionNxLoadInPort(Uint64.valueOf(BigInteger.ZERO)));
         listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
         instructionInfo.add(new InstructionApplyActions(listActionInfo));
 
@@ -2960,18 +3027,13 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
         return flowEntity;
     }
 
-    @Override
-    protected ExternalRoutersListener getDataTreeChangeListener() {
-        return ExternalRoutersListener.this;
-    }
-
-    protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId,
-                                                            TypedWriteTransaction<Configuration> writeFlowInvTx) {
+    protected void installNaptPfibEntriesForExternalSubnets(String routerName, Uint64 dpnId,
+                                                        @Nullable TypedWriteTransaction<Configuration> writeFlowInvTx) {
         Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
                 routerName);
         for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
-            long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
-            if (subnetVpnId != -1) {
+            Uint32 subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
+            if (subnetVpnId != NatConstants.INVALID_ID) {
                 LOG.debug("installNaptPfibEntriesForExternalSubnets : called for dpnId {} "
                     + "and vpnId {}", dpnId, subnetVpnId);
                 installNaptPfibEntry(dpnId, subnetVpnId, writeFlowInvTx);