Bump odlparent->6.0.0,mdsal->5.0.3
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NaptSwitchHA.java
index f0fe1d71e13c42d734880404aeade9e5e31b8a4e..cdb1fea05ad72bb826662e4df16dcbe26ea87cf2 100644 (file)
@@ -8,9 +8,8 @@
 package org.opendaylight.netvirt.natservice.internal;
 
 import com.google.common.base.Optional;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -19,9 +18,10 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
-import javax.annotation.Nonnull;
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
@@ -38,7 +38,6 @@ import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
-import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
@@ -58,10 +57,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.G
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
@@ -84,6 +79,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
 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;
 
@@ -104,6 +101,7 @@ public class NaptSwitchHA {
     private final SnatServiceManager natServiceManager;
     private final NatMode natMode;
     private final IInterfaceManager interfaceManager;
+    private final NatOverVxlanUtil natOverVxlanUtil;
 
     private volatile Collection<String> externalIpsCache;
 
@@ -120,7 +118,8 @@ public class NaptSwitchHA {
                         final SnatServiceManager natServiceManager,
                         final NatserviceConfig config,
                         final NaptEventHandler naptEventHandler,
-                        final IInterfaceManager interfaceManager) {
+                        final IInterfaceManager interfaceManager,
+                        final NatOverVxlanUtil natOverVxlanUtil) {
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalManager;
         this.externalRouterListener = externalRouterListener;
@@ -139,272 +138,220 @@ public class NaptSwitchHA {
         } else {
             this.natMode = NatMode.Controller;
         }
+        this.natOverVxlanUtil = natOverVxlanUtil;
     }
 
-    /* This method checks the switch that gone down is a NaptSwitch for a router.
-       If it is a NaptSwitch
-          1) selects new NAPT switch
-          2) installs nat flows in new NAPT switch
-          table 21(FIB)->26(PSNAT)->group(resubmit/napttunnel)->36(Terminating)->46(outbound)->47(resubmit)->21
-          3) modify the group and miss entry flow in other vSwitches pointing to newNaptSwitch
-          4) Remove nat flows in oldNaptSwitch
-     */
-    /*public void handleNaptSwitchDown(BigInteger dpnId){
+    protected void removeSnatFlowsInOldNaptSwitch(String routerName, Uint32 routerId, Uint64 naptSwitch,
+                                                  @Nullable Map<String, Uint32> externalIpmap, String externalVpnName,
+                                                  TypedReadWriteTransaction<Configuration> confTx)
+            throws ExecutionException, InterruptedException {
 
-        LOG.debug("handleNaptSwitchDown method is called with dpnId {}",dpnId);
-        BigInteger naptSwitch;
-        try {
-            NaptSwitches naptSwitches = NatUtil.getNaptSwitch(dataBroker);
-            if (naptSwitches == null || naptSwitches.getRouterToNaptSwitch() == null
-             || naptSwitches.getRouterToNaptSwitch().isEmpty()) {
-                LOG.debug("NaptSwitchDown: NaptSwitch is not allocated for none of the routers");
-                return;
-            }
-            for (RouterToNaptSwitch routerToNaptSwitch : naptSwitches.getRouterToNaptSwitch()) {
-                String routerName = routerToNaptSwitch.getRouterName();
-                naptSwitch = routerToNaptSwitch.getPrimarySwitchId();
-                boolean naptStatus = isNaptSwitchDown(routerName,dpnId,naptSwitch);
-                if (!naptStatus) {
-                    LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
-                            dpnId, routerName);
-                } else {
-                    removeSnatFlowsInOldNaptSwitch(routerName,naptSwitch);
-                    return;
-                }
-            }
-        } catch (Exception ex) {
-            LOG.error("Exception in handleNaptSwitchDown method {}",ex);
-        }
-    }*/
-
-    // TODO skitt Fix the exception handling here
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    @SuppressFBWarnings("REC_CATCH_EXCEPTION")
-    protected void removeSnatFlowsInOldNaptSwitch(String routerName, Long routerId, BigInteger naptSwitch,
-                                                  Map<String, Long> externalIpmap,
-                                                  TypedReadWriteTransaction<Configuration> confTx) {
-
-        try {
-            //remove SNAT flows in old NAPT SWITCH
-            Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
-            String vpnName = getExtNetworkVpnName(routerName, networkId);
-            if (vpnName == null) {
-                LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
-                    routerName);
-                return;
-            }
-            ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, networkId);
-            if (extNwProvType == null) {
-                LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
-                    + "for Router {}", routerName);
-                return;
-            }
-            if (extNwProvType == ProviderTypes.VXLAN) {
-                evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch, confTx);
-            } else {
-                //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
-                long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerId,
-                    routerName);
-                String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
-                    tunnelId);
-                FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
-                    tsFlowRef);
-
-                LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
-                    + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
-                mdsalManager.removeFlow(confTx, tsNatFlowEntity);
-            }
-            if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
-                //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
-                NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, naptSwitch);
-            }
-            //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
-            LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
-                NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
-
-            String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
-                NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
-            FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
-                NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
-            mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
-
-            String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
-                NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
-            FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
-                NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
-            mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
-
-            String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
-                NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
-            FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
-                icmpDropFlowRef);
-            mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
-
-            //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
-            // External Subnet Vpn Id.
-            Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
+        //remove SNAT flows in old NAPT SWITCH
+        Uuid extNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
+        String vpnName = getExtNetworkVpnName(routerName, extNetworkId);
+        if (vpnName == null) {
+            LOG.error("removeSnatFlowsInOldNaptSwitch : Vpn is not associated to externalN/w of router {}",
                 routerName);
-            for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
-                long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
-                if (subnetVpnId != -1 && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
-                    dataBroker, externalSubnetId, routerName, naptSwitch)) {
-                    String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
-                        NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
-                    FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
-                        natPfibSubnetFlowRef);
-                    mdsalManager.removeFlow(confTx, natPfibFlowEntity);
-                    LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
-                              + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
-                        subnetVpnId, naptSwitch);
-                }
-            }
+            return;
+        }
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
+        if (extNwProvType == null) {
+            LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the External Network Provider Type "
+                + "for Router {}", routerName);
+            return;
+        }
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            evpnNaptSwitchHA.evpnRemoveSnatFlowsInOldNaptSwitch(routerName, routerId, vpnName, naptSwitch, confTx);
+        } else {
+            //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table
+            Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
+                    idManager, routerId, routerName);
+            String tsFlowRef = externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
+                Uint32.valueOf(tunnelId));
+            FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.INTERNAL_TUNNEL_TABLE,
+                tsFlowRef);
 
-            // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
-            // matching on the router ID.
-            String naptPFibflowRef =
-                externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
-            FlowEntity naptPFibFlowEntity =
-                NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
             LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
-                + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
-            mdsalManager.removeFlow(confTx, naptPFibFlowEntity);
+                + "with the DPN ID {} and router ID {}", NwConstants.INTERNAL_TUNNEL_TABLE, naptSwitch, routerId);
+            mdsalManager.removeFlow(confTx, tsNatFlowEntity);
+        }
+        if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
+            //Remove the flow table 25->44 If there is no FIP Match on table 25 (PDNAT_TABLE)
+            NatUtil.removePreDnatToSnatTableEntry(confTx, mdsalManager, naptSwitch);
+        }
+        //Remove the Outbound flow entry which forwards the packet to Outbound NAPT Table
+        LOG.info("Remove the flow in table {} for the old napt switch with the DPN ID {} and router ID {}",
+            NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
+
+        String outboundTcpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
+            NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_TCP);
+        FlowEntity outboundTcpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
+            NwConstants.OUTBOUND_NAPT_TABLE, outboundTcpNatFlowRef);
+        mdsalManager.removeFlow(confTx, outboundTcpNatFlowEntity);
+
+        String outboundUdpNatFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
+            NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_UDP);
+        FlowEntity outboundUdpNatFlowEntity = NatUtil.buildFlowEntity(naptSwitch,
+            NwConstants.OUTBOUND_NAPT_TABLE, outboundUdpNatFlowRef);
+        mdsalManager.removeFlow(confTx, outboundUdpNatFlowEntity);
+
+        String icmpDropFlowRef = externalRouterListener.getFlowRefOutbound(naptSwitch,
+            NwConstants.OUTBOUND_NAPT_TABLE, routerId, NwConstants.IP_PROT_ICMP);
+        FlowEntity icmpDropFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
+            icmpDropFlowRef);
+        mdsalManager.removeFlow(confTx, icmpDropFlowEntity);
+
+        //Remove the NAPT PFIB TABLE (47->21) which forwards the incoming packet to FIB Table matching on the
+        // External Subnet Vpn Id.
+        Collection<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
+            routerName);
+        for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
+            Uint32 subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
+            if (subnetVpnId != NatConstants.INVALID_ID && !NatUtil.checkForRoutersWithSameExtSubnetAndNaptSwitch(
+                dataBroker, externalSubnetId, routerName, naptSwitch)) {
+                String natPfibSubnetFlowRef = externalRouterListener.getFlowRefTs(naptSwitch,
+                    NwConstants.NAPT_PFIB_TABLE, subnetVpnId);
+                FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE,
+                    natPfibSubnetFlowRef);
+                mdsalManager.removeFlow(confTx, natPfibFlowEntity);
+                LOG.debug("removeSnatFlowsInOldNaptSwitch : Removed the flow in table {} with external subnet "
+                          + "Vpn Id {} as metadata on Napt Switch {}", NwConstants.NAPT_PFIB_TABLE,
+                    subnetVpnId, naptSwitch);
+            }
+        }
 
-            // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
-            // matching on the vpn ID.
-            boolean switchSharedByRouters = false;
-            Uuid extNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
-            if (extNetworkId != null && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(
-                dataBroker, networkId, routerName, naptSwitch)) {
-                List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
-                for (String routerNameAssociated : routerNamesAssociated) {
-                    if (!routerNameAssociated.equals(routerName)) {
-                        Long routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
-                        BigInteger naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
-                        if (naptDpn != null && naptDpn.equals(naptSwitch)) {
-                            LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
-                                + "for router {}", naptSwitch, routerIdAssociated);
-                            switchSharedByRouters = true;
-                            break;
-                        }
-                    }
-                }
-                if (!switchSharedByRouters) {
-                    Long vpnId = getVpnIdForRouter(routerId, extNetworkId);
-                    if (vpnId != NatConstants.INVALID_ID) {
-                        String naptFibflowRef =
-                            externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
-                        FlowEntity naptFibFlowEntity =
-                            NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
-                        LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
-                            + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
-                        mdsalManager.removeFlow(confTx, naptFibFlowEntity);
-                    } else {
-                        LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
-                            routerId);
-                        return;
+        // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for inbound traffic
+        // matching on the router ID.
+        String naptPFibflowRef =
+            externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, routerId);
+        FlowEntity naptPFibFlowEntity =
+            NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptPFibflowRef);
+        LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch "
+            + "with the DPN ID {} and router ID {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, routerId);
+        mdsalManager.removeFlow(confTx, naptPFibFlowEntity);
+
+        // Remove the NAPT_PFIB_TABLE(47) flow entry forwards the packet to Fib Table for outbound traffic
+        // matching on the vpn ID.
+        boolean switchSharedByRouters = false;
+        if (extNetworkId != null && !NatUtil.checkForRoutersWithSameExtNetAndNaptSwitch(
+            dataBroker, extNetworkId, routerName, naptSwitch)) {
+            List<String> routerNamesAssociated = getRouterIdsForExtNetwork(extNetworkId);
+            for (String routerNameAssociated : routerNamesAssociated) {
+                if (!routerNameAssociated.equals(routerName)) {
+                    Uint32 routerIdAssociated = NatUtil.getVpnId(dataBroker, routerNameAssociated);
+                    Uint64 naptDpn = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerNameAssociated);
+                    if (naptDpn != null && naptDpn.equals(naptSwitch)) {
+                        LOG.debug("removeSnatFlowsInOldNaptSwitch : Napt switch {} is also acting as primary "
+                            + "for router {}", naptSwitch, routerIdAssociated);
+                        switchSharedByRouters = true;
+                        break;
                     }
                 }
             }
-
-            //Remove Fib entries,tables 20->44 ,36-> 44
-            String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
-            if (externalIpmap != null && !externalIpmap.isEmpty()) {
-                for (Entry<String, Long> entry : externalIpmap.entrySet()) {
-                    String externalIp = entry.getKey();
-                    Long label = entry.getValue();
-                    externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
-                        extNetworkId, label, gwMacAddress, true, confTx);
-                    LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
-                        + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
-                }
-            } else {
-                List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
-                if (networkId != null) {
-                    externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, networkId,
-                        externalIps, null, gwMacAddress, confTx);
-                    LOG.debug(
-                        "removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
-                            + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, networkId,
-                        externalIps);
+            if (!switchSharedByRouters) {
+                Uint32 vpnId = NatUtil.getVpnId(dataBroker,externalVpnName);
+                if (vpnId != NatConstants.INVALID_ID) {
+                    String naptFibflowRef =
+                        externalRouterListener.getFlowRefTs(naptSwitch, NwConstants.NAPT_PFIB_TABLE, vpnId);
+                    FlowEntity naptFibFlowEntity =
+                        NatUtil.buildFlowEntity(naptSwitch, NwConstants.NAPT_PFIB_TABLE, naptFibflowRef);
+                    LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for the old napt switch"
+                        + " with the DPN ID {} and vpnId {}", NwConstants.NAPT_PFIB_TABLE, naptSwitch, vpnId);
+                    mdsalManager.removeFlow(confTx, naptFibFlowEntity);
                 } else {
-                    LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}",
+                    LOG.error("removeSnatFlowsInOldNaptSwitch : Invalid vpnId retrieved for routerId {}",
                         routerId);
+                    return;
                 }
-                externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
-                    externalIps, confTx);
             }
+        }
 
-            //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 || ipPortMapping.getIntextIpProtocolType() == null
-                || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
-                LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
-                    + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
-                return;
+        //Remove Fib entries,tables 20->44 ,36-> 44
+        String gwMacAddress = NatUtil.getExtGwMacAddFromRouterName(dataBroker, routerName);
+        if (externalIpmap != null && !externalIpmap.isEmpty()) {
+            for (Entry<String, Uint32> entry : externalIpmap.entrySet()) {
+                String externalIp = entry.getKey();
+                Uint32 label = entry.getValue();
+                externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp, vpnName,
+                    extNetworkId, label, gwMacAddress, true, confTx);
+                LOG.debug("removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} "
+                    + "for router {} and externalIps {} label {}", naptSwitch, routerId, externalIp, label);
             }
-            BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
-            List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
-            for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
-                if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
-                    LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
-                            + "no flows need to be removed in oldNaptSwitch {}",
-                        intextIpProtocolType.getProtocol(), routerId, naptSwitch);
-                    break;
-                }
-                List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
-                for (IpPortMap ipPortMap : ipPortMaps) {
-                    String ipPortInternal = ipPortMap.getIpPortInternal();
-                    String[] ipPortParts = ipPortInternal.split(":");
-                    if (ipPortParts.length != 2) {
-                        LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
-                        continue;
-                    }
-                    String internalIp = ipPortParts[0];
-                    String internalPort = ipPortParts[1];
-
-                    //Build and remove flow in outbound NAPT table
-                    String switchFlowRef =
-                        NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
-                            internalIp, Integer.parseInt(internalPort));
-                    FlowEntity outboundNaptFlowEntity =
-                        NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
-                            cookieSnatFlow, switchFlowRef);
-
-                    LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
-                        + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
-                    mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
-
-                    IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
-                    if (ipPortExternal == null) {
-                        LOG.debug(
-                            "removeSnatFlowsInOldNaptSwitch : External Ipport mapping not found for internalIp {} "
-                                + "with port {} for router {}", internalIp, internalPort, routerId);
-                        continue;
-                    }
-                    String externalIp = ipPortExternal.getIpAddress();
-                    int externalPort = ipPortExternal.getPortNum();
-
-                    //Build and remove flow in  inbound NAPT table
-                    switchFlowRef =
-                        NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
-                            externalIp, externalPort);
-                    FlowEntity inboundNaptFlowEntity =
-                        NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
-                            cookieSnatFlow, switchFlowRef);
+        } else {
+            List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
+            if (extNetworkId != null) {
+                externalRouterListener.clearFibTsAndReverseTraffic(naptSwitch, routerId, extNetworkId,
+                    externalIps, null, gwMacAddress, confTx);
+                LOG.debug(
+                    "removeSnatFlowsInOldNaptSwitch : Successfully removed fib entries in old naptswitch {} for "
+                        + "router {} with networkId {} and externalIps {}", naptSwitch, routerId, extNetworkId,
+                    externalIps);
+            } else {
+                LOG.debug("removeSnatFlowsInOldNaptSwitch : External network not associated to router {}",
+                    routerId);
+            }
+            externalRouterListener.removeNaptFibExternalOutputFlows(routerId, naptSwitch, extNetworkId,
+                externalIps, confTx);
+        }
 
-                    LOG.info(
-                        "removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
-                            + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
-                    mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
+        //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 || ipPortMapping.getIntextIpProtocolType() == null
+            || ipPortMapping.getIntextIpProtocolType().isEmpty()) {
+            LOG.warn("removeSnatFlowsInOldNaptSwitch : No Internal Ip Port mapping associated to router {}, "
+                + "no flows need to be removed in oldNaptSwitch {}", routerId, naptSwitch);
+            return;
+        }
+        Uint64 cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
+        List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
+        for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
+            if (intextIpProtocolType.getIpPortMap() == null || intextIpProtocolType.getIpPortMap().isEmpty()) {
+                LOG.debug("removeSnatFlowsInOldNaptSwitch : No {} session associated to router {},"
+                        + "no flows need to be removed in oldNaptSwitch {}",
+                    intextIpProtocolType.getProtocol(), routerId, naptSwitch);
+                continue;
+            }
+            String protocol = intextIpProtocolType.getProtocol().name();
+            List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
+            for (IpPortMap ipPortMap : ipPortMaps) {
+                String ipPortInternal = ipPortMap.getIpPortInternal();
+                String[] ipPortParts = ipPortInternal.split(":");
+                if (ipPortParts.length != 2) {
+                    LOG.error("removeSnatFlowsInOldNaptSwitch : Unable to retrieve the Internal IP and port");
+                    continue;
                 }
+                String internalIp = ipPortParts[0];
+                String internalPort = ipPortParts[1];
+
+                //Build and remove flow in outbound NAPT table
+                String switchFlowRef =
+                    NatUtil.getNaptFlowRef(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE, String.valueOf(routerId),
+                        internalIp, Integer.parseInt(internalPort), protocol);
+                FlowEntity outboundNaptFlowEntity =
+                    NatUtil.buildFlowEntity(naptSwitch, NwConstants.OUTBOUND_NAPT_TABLE,
+                        cookieSnatFlow, switchFlowRef);
+
+                LOG.info("removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch "
+                    + "with the DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, naptSwitch, routerId);
+                mdsalManager.removeFlow(confTx, outboundNaptFlowEntity);
+
+                //Build and remove flow in  inbound NAPT table
+                switchFlowRef =
+                    NatUtil.getNaptFlowRef(naptSwitch, NwConstants.INBOUND_NAPT_TABLE, String.valueOf(routerId),
+                        internalIp, Integer.parseInt(internalPort), protocol);
+                FlowEntity inboundNaptFlowEntity =
+                    NatUtil.buildFlowEntity(naptSwitch, NwConstants.INBOUND_NAPT_TABLE,
+                        cookieSnatFlow, switchFlowRef);
+
+                LOG.info(
+                    "removeSnatFlowsInOldNaptSwitch : Remove the flow in table {} for old napt switch with the "
+                        + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, naptSwitch, routerId);
+                mdsalManager.removeFlow(confTx, inboundNaptFlowEntity);
             }
-        } catch (Exception e) {
-            LOG.error("Error removing flow", e);
-            throw new RuntimeException("Error removing flow", e);
         }
     }
 
-    @Nonnull
+    @NonNull
     private List<String> getRouterIdsForExtNetwork(Uuid extNetworkId) {
         List<String> routerUuidsAsString = new ArrayList<>();
         InstanceIdentifier<Networks> extNetwork = InstanceIdentifier.builder(ExternalNetworks.class)
@@ -423,18 +370,20 @@ public class NaptSwitchHA {
         return routerUuidsAsString;
     }
 
-    public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
-                                    Long routerVpnId, Collection<String> externalIpCache,
-                                    TypedReadWriteTransaction<Configuration> confTx) {
+    public boolean isNaptSwitchDown(String routerName, Uint32 routerId, Uint64 dpnId, Uint64 naptSwitch,
+                                    Uint32 routerVpnId, Collection<String> externalIpCache,
+                                    TypedReadWriteTransaction<Configuration> confTx)
+            throws ExecutionException, InterruptedException {
         return isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId, externalIpCache, true,
                 confTx);
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public boolean isNaptSwitchDown(String routerName, Long routerId, BigInteger dpnId, BigInteger naptSwitch,
-                                    Long routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
-                                    TypedReadWriteTransaction<Configuration> confTx) {
+    public boolean isNaptSwitchDown(String routerName, Uint32 routerId, Uint64 dpnId, Uint64 naptSwitch,
+                                    Uint32 routerVpnId, Collection<String> externalIpCache, boolean isClearBgpRts,
+                                    TypedReadWriteTransaction<Configuration> confTx)
+            throws ExecutionException, InterruptedException {
         externalIpsCache = externalIpCache;
         if (!naptSwitch.equals(dpnId)) {
             LOG.debug("isNaptSwitchDown : DpnId {} is not a naptSwitch {} for Router {}",
@@ -449,14 +398,23 @@ public class NaptSwitchHA {
         Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
         String vpnName = getExtNetworkVpnName(routerName, networkId);
         //elect a new NaptSwitch
-        naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName);
+        naptSwitch = naptSwitchSelector.selectNewNAPTSwitch(routerName, Arrays.asList(naptSwitch));
         if (natMode == NatMode.Conntrack) {
             Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
-            natServiceManager.notify(confTx, extRouters, dpnId, dpnId, SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
-            natServiceManager.notify(confTx, extRouters, naptSwitch, naptSwitch,
-                    SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+            natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
+                    SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_DISBL);
+            if (extRouters.isEnableSnat()) {
+                natServiceManager.notify(confTx, extRouters, null, dpnId, dpnId,
+                        SnatServiceManager.Action.SNAT_ALL_SWITCH_DISBL);
+            }
+            natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
+                    SnatServiceManager.Action.CNT_ROUTER_ALL_SWITCH_ENBL);
+            if (extRouters.isEnableSnat()) {
+                natServiceManager.notify(confTx, extRouters, null, naptSwitch, naptSwitch,
+                        SnatServiceManager.Action.SNAT_ALL_SWITCH_ENBL);
+            }
         } else {
-            if (naptSwitch.equals(BigInteger.ZERO)) {
+            if (naptSwitch.equals(Uint64.ZERO)) {
                 LOG.warn("isNaptSwitchDown : No napt switch is elected since all the switches for router {}"
                         + " are down. SNAT IS NOT SUPPORTED FOR ROUTER {}", routerName, routerName);
                 boolean naptUpdatedStatus = updateNaptSwitch(routerName, naptSwitch);
@@ -492,7 +450,7 @@ public class NaptSwitchHA {
                 return true;
             }
             //checking elected switch health status
-            if (!getSwitchStatus(naptSwitch)) {
+            if (!NatUtil.getSwitchStatus(dataBroker, naptSwitch)) {
                 LOG.error("isNaptSwitchDown : Newly elected Napt switch {} for router {} is down",
                         naptSwitch, routerName);
                 return true;
@@ -521,7 +479,7 @@ public class NaptSwitchHA {
                 mdsalManager.addFlow(confTx, flowEntity);
             }
 
-            installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, confTx);
+            installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, networkId, vpnName, confTx);
 
             boolean flowInstalledStatus = handleNatFlowsInNewNaptSwitch(routerName, routerId, dpnId, naptSwitch,
                     routerVpnId, networkId);
@@ -534,17 +492,25 @@ public class NaptSwitchHA {
             }
 
             //remove group in new naptswitch, coz this switch acted previously as ordinary switch
-            long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
-            try {
-                LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}", naptSwitch);
-                mdsalManager.removeGroup(confTx, naptSwitch, groupId);
-            } catch (Exception ex) {
-                LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}", naptSwitch, ex);
+            Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
+                NatUtil.getGroupIdKey(routerName));
+            if (groupId != NatConstants.INVALID_ID) {
+                try {
+                    LOG.info("isNaptSwitchDown : Removing NAPT Group in new naptSwitch {}",
+                        naptSwitch);
+                    mdsalManager.removeGroup(confTx, naptSwitch, groupId.longValue());
+                } catch (Exception ex) {
+                    LOG.error("isNaptSwitchDown : Failed to remove group in new naptSwitch {}",
+                        naptSwitch, ex);
+                }
+            } else {
+                LOG.error("NAT Service : Unable to obtain groupId for router:{}", routerName);
             }
         }
         return true;
     }
 
+    @Nullable
     private String getExtNetworkVpnName(String routerName, Uuid networkId) {
         if (networkId == null) {
             LOG.error("getExtNetworkVpnName : networkId is null for the router ID {}", routerName);
@@ -563,29 +529,35 @@ public class NaptSwitchHA {
         return null;
     }
 
-    public void updateNaptSwitchBucketStatus(String routerName, long routerId, BigInteger naptSwitch) {
+    public void updateNaptSwitchBucketStatus(String routerName, Uint32 routerId, Uint64 naptSwitch) {
         LOG.debug("updateNaptSwitchBucketStatus : called");
 
-        List<BigInteger> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
+        List<Uint64> dpnList = naptSwitchSelector.getDpnsForVpn(routerName);
         //List<BigInteger> dpnList = getDpnListForRouter(routerName);
         if (dpnList.isEmpty()) {
             LOG.warn("updateNaptSwitchBucketStatus : No switches found for router {}", routerName);
             return;
         }
-        for (BigInteger dpn : dpnList) {
+        for (Uint64 dpn : dpnList) {
             if (!dpn.equals(naptSwitch)) {
                 LOG.debug("updateNaptSwitchBucketStatus : Updating SNAT_TABLE missentry for DpnId {} "
                         + "which is not naptSwitch for router {}", dpn, routerName);
                 List<BucketInfo> bucketInfoList = handleGroupInNeighborSwitches(dpn, routerName, routerId, naptSwitch);
+                if (bucketInfoList.isEmpty()) {
+                    LOG.error("Failed to populate bucketInfo for non-napt switch {} whose naptSwitch:{} for router:{}",
+                        dpn,naptSwitch,routerName);
+                    continue;
+                }
                 modifySnatGroupEntry(dpn, bucketInfoList, routerName);
+                externalRouterListener.installSnatMissEntry(dpn, bucketInfoList, routerName, routerId);
             }
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private boolean handleNatFlowsInNewNaptSwitch(String routerName, Long routerId, BigInteger oldNaptSwitch,
-                                                    BigInteger newNaptSwitch, Long routerVpnId, Uuid networkId) {
+    private boolean handleNatFlowsInNewNaptSwitch(String routerName, Uint32 routerId, Uint64 oldNaptSwitch,
+                                                    Uint64 newNaptSwitch, Uint32 routerVpnId, Uuid networkId) {
         LOG.debug("handleNatFlowsInNewNaptSwitch : Proceeding to install flows in newNaptSwitch {} for routerId {}",
                 newNaptSwitch, routerId);
         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
@@ -596,12 +568,12 @@ public class NaptSwitchHA {
             return true;
         }
         //getvpnId
-        Long vpnId = getVpnIdForRouter(routerId, networkId);
+        Uint32 vpnId = getVpnIdForRouter(routerId, networkId);
         if (vpnId == NatConstants.INVALID_ID) {
             LOG.error("handleNatFlowsInNewNaptSwitch : Invalid vpnId for routerId {}", routerId);
             return false;
         }
-        Long bgpVpnId;
+        Uint32 bgpVpnId;
         if (routerId.equals(routerVpnId)) {
             bgpVpnId = NatConstants.INVALID_ID;
         } else {
@@ -641,7 +613,7 @@ public class NaptSwitchHA {
                     continue;
                 }
                 String externalIpAddress = ipPortExternal.getIpAddress();
-                Integer extportNumber = ipPortExternal.getPortNum();
+                Integer extportNumber = ipPortExternal.getPortNum().toJava();
                 LOG.debug("handleNatFlowsInNewNaptSwitch : ExternalIPport {}:{} mapping for internal ipport {}:{}",
                         externalIpAddress, extportNumber, internalIpAddress, intportnum);
 
@@ -649,7 +621,7 @@ public class NaptSwitchHA {
                 SessionAddress externalAddress = new SessionAddress(externalIpAddress, extportNumber);
 
                 //checking naptSwitch status before installing flows
-                if (getSwitchStatus(newNaptSwitch)) {
+                if (NatUtil.getSwitchStatus(dataBroker, newNaptSwitch)) {
                     //Install the flow in newNaptSwitch Inbound NAPT table.
                     try {
                         naptEventHandler.buildAndInstallNatFlows(newNaptSwitch, NwConstants.INBOUND_NAPT_TABLE,
@@ -692,7 +664,7 @@ public class NaptSwitchHA {
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private Long getVpnIdForRouter(Long routerId, Uuid networkId) {
+    private Uint32 getVpnIdForRouter(Uint32 routerId, Uuid networkId) {
         try {
             //getvpnId
             if (networkId == null) {
@@ -703,8 +675,8 @@ public class NaptSwitchHA {
                     LOG.debug("getVpnIdForRouter : vpn is not associated for network {} in router {}",
                             networkId, routerId);
                 } else {
-                    Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
-                    if (vpnId > 0) {
+                    Uint32 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
+                    if (vpnId.longValue() > 0) {
                         LOG.debug("getVpnIdForRouter : retrieved vpnId {} for router {}", vpnId, routerId);
                         return vpnId;
                     } else {
@@ -718,34 +690,9 @@ public class NaptSwitchHA {
         return NatConstants.INVALID_ID;
     }
 
-    public boolean getSwitchStatus(BigInteger switchId) {
-        NodeId nodeId = new NodeId("openflow:" + switchId);
-        LOG.debug("getSwitchStatus : Querying switch with dpnId {} is up/down", nodeId);
-        InstanceIdentifier<Node> nodeInstanceId = InstanceIdentifier.builder(Nodes.class)
-            .child(Node.class, new NodeKey(nodeId)).build();
-        Optional<Node> nodeOptional =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
-                        LogicalDatastoreType.OPERATIONAL, nodeInstanceId);
-        if (nodeOptional.isPresent()) {
-            LOG.debug("getSwitchStatus : Switch {} is up", nodeId);
-            return true;
-        }
-        LOG.debug("getSwitchStatus : Switch {} is down", nodeId);
-        return false;
-    }
-
-    public List<BucketInfo> handleGroupInPrimarySwitch() {
-        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(bucketPrimary);
-        return listBucketInfo;
-    }
-
-    @Nonnull
-    public List<BucketInfo> handleGroupInNeighborSwitches(BigInteger dpnId, String routerName, long routerId,
-            BigInteger naptSwitch) {
+    @NonNull
+    public List<BucketInfo> handleGroupInNeighborSwitches(Uint64 dpnId, String routerName, Uint32 routerId,
+            Uint64 naptSwitch) {
         List<BucketInfo> listBucketInfo = new ArrayList<>();
         String ifNamePrimary;
         if (routerId == NatConstants.INVALID_ID) {
@@ -770,27 +717,35 @@ public class NaptSwitchHA {
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void installSnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+    protected void installSnatGroupEntry(Uint64 dpnId, List<BucketInfo> bucketInfo, String routerName) {
         GroupEntity groupEntity = null;
         try {
-            long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
-            LOG.debug("installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
+            Uint32 groupId = NatUtil.getUniqueId(idManager, NatConstants.SNAT_IDPOOL_NAME,
+                NatUtil.getGroupIdKey(routerName));
+            if (groupId != NatConstants.INVALID_ID) {
+                LOG.debug(
+                    "installSnatGroupEntry : install SnatMissEntry for groupId {} for dpnId {} for router {}",
                     groupId, dpnId, routerName);
-            groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
-                GroupTypes.GroupAll, bucketInfo);
-            mdsalManager.syncInstallGroup(groupEntity);
-            LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}", groupEntity);
+                groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId.longValue(), routerName,
+                    GroupTypes.GroupAll, bucketInfo);
+                mdsalManager.syncInstallGroup(groupEntity);
+                LOG.debug("installSnatGroupEntry : installed the SNAT to NAPT GroupEntity:{}",
+                    groupEntity);
+            } else {
+                LOG.error("installSnatGroupEntry: Unable to obtain groupId for router:{}", routerName);
+            }
         } catch (Exception ex) {
             LOG.error("installSnatGroupEntry : Failed to install group for groupEntity {}", groupEntity, ex);
         }
     }
 
-    private void modifySnatGroupEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
+    private void modifySnatGroupEntry(Uint64 dpnId, List<BucketInfo> bucketInfo, String routerName) {
         installSnatGroupEntry(dpnId, bucketInfo, routerName);
         LOG.debug("modifySnatGroupEntry : modified SnatMissEntry for dpnId {} of router {}", dpnId, routerName);
     }
 
-    protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
+    @Nullable
+    protected String getTunnelInterfaceName(Uint64 srcDpId, Uint64 dstDpId) {
         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
 
@@ -828,7 +783,7 @@ public class NaptSwitchHA {
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public boolean updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
+    public boolean updateNaptSwitch(String routerName, Uint64 naptSwitchId) {
         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().withKey(new RouterToNaptSwitchKey(routerName))
             .setPrimarySwitchId(naptSwitchId).build();
         try {
@@ -844,20 +799,21 @@ public class NaptSwitchHA {
         return true;
     }
 
-    public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId,
-                                          long routerVpnId, int addordel) {
+    public FlowEntity buildSnatFlowEntity(Uint64 dpId, String routerName, long groupId,
+                                          Uint32 routerVpnId, int addordel) {
         FlowEntity flowEntity;
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
 
         if (addordel == NatConstants.ADD_FLOW) {
             List<ActionInfo> actionsInfo = new ArrayList<>();
-            long tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, elanManager, idManager, routerVpnId,
-                    routerName);
-            actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
+            Uint64 tunnelId = NatUtil.getTunnelIdForNonNaptToNaptFlow(dataBroker, natOverVxlanUtil, elanManager,
+                    idManager, routerVpnId, routerName);
+            actionsInfo.add(new ActionSetFieldTunnelId(tunnelId));
             LOG.debug("buildSnatFlowEntity : Setting the tunnel to the list of action infos {}", actionsInfo);
             actionsInfo.add(new ActionGroup(groupId));
             List<InstructionInfo> instructions = new ArrayList<>();
@@ -874,12 +830,13 @@ public class NaptSwitchHA {
         return flowEntity;
     }
 
-    public FlowEntity buildSnatFlowEntityForNaptSwitch(BigInteger dpId, String routerName,
-                                                       long routerVpnId, int addordel) {
+    public FlowEntity buildSnatFlowEntityForNaptSwitch(Uint64 dpId, String routerName,
+                                                       Uint32 routerVpnId, int addordel) {
         FlowEntity flowEntity;
         List<MatchInfo> matches = new ArrayList<>();
         matches.add(MatchEthernetType.IPV4);
-        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId), MetaDataUtil.METADATA_MASK_VRFID));
+        matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerVpnId.longValue()),
+                MetaDataUtil.METADATA_MASK_VRFID));
 
         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
 
@@ -899,13 +856,13 @@ public class NaptSwitchHA {
         return flowEntity;
     }
 
-    private String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
+    private String getFlowRefSnat(Uint64 dpnId, short tableId, String routerID) {
         return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
                 .FLOWID_SEPARATOR + routerID;
     }
 
-    protected void installSnatFlows(String routerName, Long routerId, BigInteger naptSwitch, Long routerVpnId,
-                                    TypedReadWriteTransaction<Configuration> confTx) {
+    protected void installSnatFlows(String routerName, Uint32 routerId, Uint64 naptSwitch, Uint32 routerVpnId,
+        Uuid networkId, String vpnName, TypedReadWriteTransaction<Configuration> confTx) {
 
         if (routerId.equals(routerVpnId)) {
             LOG.debug("installSnatFlows : Installing flows for router with internalvpnId");
@@ -959,34 +916,40 @@ public class NaptSwitchHA {
             externalRouterListener.installNaptPfibEntryWithBgpVpn(naptSwitch, routerId, routerVpnId, confTx);
         }
 
-        Uuid networkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
-        String vpnName = getExtNetworkVpnName(routerName, networkId);
         if (vpnName != null) {
             //NAPT PFIB point to FIB table for outbound traffic
-            long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
-            boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
-            Collection<Uuid> externalSubnetIds = NatUtil.getExternalSubnetIdsForRouter(dataBroker, routerName);
-            if (!externalSubnetIds.isEmpty()) {
-                //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
-                for (Uuid externalSubnetId : externalSubnetIds) {
-                    long externalSubnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, externalSubnetId);
-                    if (externalSubnetVpnId != NatConstants.INVALID_ID) {
-                        shouldInstallNaptPfibWithExtNetworkVpnId = false;
-                        LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
-                                + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
-                        externalRouterListener.installNaptPfibEntry(naptSwitch, externalSubnetVpnId, confTx);
+            Uint32 vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+            if (vpnName.equals(networkId.getValue())) {
+                // below condition valid only for flat/vlan use-case
+                boolean shouldInstallNaptPfibWithExtNetworkVpnId = true;
+                Collection<Uuid> externalSubnetIds = NatUtil
+                    .getExternalSubnetIdsForRouter(dataBroker, routerName);
+                if (!externalSubnetIds.isEmpty()) {
+                    //NAPT PFIB point to FIB table for outbound traffic - using external subnetID as vpnID.
+                    for (Uuid externalSubnetId : externalSubnetIds) {
+                        Uint32 externalSubnetVpnId = NatUtil
+                            .getExternalSubnetVpnId(dataBroker, externalSubnetId);
+                        if (externalSubnetVpnId != NatConstants.INVALID_ID) {
+                            shouldInstallNaptPfibWithExtNetworkVpnId = false;
+                            LOG.debug(
+                                "installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
+                                    + "BgpVpnId {}", naptSwitch, externalSubnetVpnId);
+                            externalRouterListener
+                                .installNaptPfibEntry(naptSwitch, externalSubnetVpnId, confTx);
+                        }
                     }
                 }
+                if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
+                    //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
+                    LOG.debug(
+                        "installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
+                            + "BgpVpnId {}", naptSwitch, vpnId);
+                    externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, confTx);
+                } else if (vpnId != NatConstants.INVALID_ID) {
+                    LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}",
+                        routerId);
+                }
             }
-            if (vpnId != NatConstants.INVALID_ID && shouldInstallNaptPfibWithExtNetworkVpnId) {
-                //NAPT PFIB table point to FIB table for outbound traffic - using external networkID as vpnID.
-                LOG.debug("installSnatFlows : installNaptPfibEntry fin naptswitch with dpnId {} for "
-                    + "BgpVpnId {}", naptSwitch, vpnId);
-                externalRouterListener.installNaptPfibEntry(naptSwitch, vpnId, confTx);
-            } else if (vpnId != NatConstants.INVALID_ID) {
-                LOG.debug("installSnatFlows : Associated BgpvpnId not found for router {}", routerId);
-            }
-
             //Install Fib entries for ExternalIps & program 36 -> 44
             Collection<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
             String rd = NatUtil.getVpnRd(dataBroker, vpnName);
@@ -1004,8 +967,9 @@ public class NaptSwitchHA {
         }
     }
 
-    protected void bestEffortDeletion(long routerId, String routerName, Map<String, Long> externalIpLabel,
-                                      TypedReadWriteTransaction<Configuration> confTx) {
+    protected void bestEffortDeletion(Uint32 routerId, String routerName, Map<String, Uint32> externalIpLabel,
+                                      TypedReadWriteTransaction<Configuration> confTx)
+            throws ExecutionException, InterruptedException {
         Collection<String> newExternalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
         if (externalIpsCache != null) {
             Set<String> removedExternalIps = new HashSet<>(externalIpsCache);
@@ -1021,8 +985,8 @@ public class NaptSwitchHA {
                 LOG.error("bestEffortDeletion : Vpn is not associated to externalN/w of router {}", routerName);
                 return;
             }
-            BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
-            if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+            Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
+            if (naptSwitch == null || naptSwitch.equals(Uint64.ZERO)) {
                 LOG.error("bestEffortDeletion : No naptSwitch is selected for router {}", routerName);
                 return;
             }
@@ -1042,8 +1006,8 @@ public class NaptSwitchHA {
             if (extNwProvType == ProviderTypes.VXLAN) {
                 for (String externalIp : removedExternalIps) {
                     externalRouterListener.clearBgpRoutes(externalIp, vpnName);
-                    externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
-                        networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, confTx);
+                    externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
+                        vpnName, networkId, NatConstants.DEFAULT_LABEL_VALUE, gwMacAddress, true, confTx);
                     LOG.debug("bestEffortDeletion : Successfully removed fib entry for externalIp {} for routerId {} "
                                     + "on NAPT switch {} ", externalIp, routerId, naptSwitch);
                 }
@@ -1052,7 +1016,7 @@ public class NaptSwitchHA {
                     LOG.error("bestEffortDeletion : ExternalIpLabel map is empty for router {}", routerName);
                     return;
                 }
-                Long label;
+                Uint32 label;
                 for (String externalIp : removedExternalIps) {
                     if (externalIpLabel.containsKey(externalIp)) {
                         label = externalIpLabel.get(externalIp);
@@ -1064,8 +1028,8 @@ public class NaptSwitchHA {
                         continue;
                     }
                     externalRouterListener.clearBgpRoutes(externalIp, vpnName);
-                    externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerId, externalIp, vpnName,
-                        networkId, label, gwMacAddress, true, confTx);
+                    externalRouterListener.delFibTsAndReverseTraffic(naptSwitch, routerName, routerId, externalIp,
+                            vpnName, networkId, label, gwMacAddress, true, confTx);
                     LOG.debug("bestEffortDeletion : Successfully removed fib entries in switch {} for router {} "
                             + "and externalIps {}", naptSwitch, routerId, externalIp);
                 }
@@ -1087,7 +1051,7 @@ public class NaptSwitchHA {
         }
     }
 
-    protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
+    protected void subnetRegisterMapping(Routers routerEntry, Uint32 segmentId) {
         externalRouterListener.subnetRegisterMapping(routerEntry, segmentId);
     }
 }