Convert to JobCoordinator in natservice-impl
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / RouterDpnChangeListener.java
index 8284dda1aab53a18160f0b86907c4d5ca7666748..709492b04a3edc16ed29b8e7c3d15a02262e6a21 100644 (file)
@@ -8,51 +8,76 @@
 package org.opendaylight.netvirt.natservice.internal;
 
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
-import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.mdsalutil.BucketInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.GroupEntity;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
+import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
+import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
 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.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalSubnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.SubnetsKey;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Singleton
 public class RouterDpnChangeListener
-    extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
-    implements AutoCloseable {
+        extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
+        implements AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
-    private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker dataBroker;
     private final IMdsalApiManager mdsalManager;
     private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
     private final NaptSwitchHA naptSwitchHA;
     private final IdManagerService idManager;
+    private final INeutronVpnManager nvpnManager;
     private final ExternalNetworkGroupInstaller extNetGroupInstaller;
+    private final IElanService elanManager;
+    private final JobCoordinator coordinator;
+    private final SnatServiceManager natServiceManager;
+    private NatMode natMode = NatMode.Controller;
 
+    @Inject
     public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
                                    final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
                                    final NaptSwitchHA naptSwitchHA,
                                    final IdManagerService idManager,
-                                   final ExternalNetworkGroupInstaller extNetGroupInstaller) {
+                                   final ExternalNetworkGroupInstaller extNetGroupInstaller,
+                                   final INeutronVpnManager nvpnManager,
+                                   final SnatServiceManager natServiceManager,
+                                   final NatserviceConfig config,
+                                   final IElanService elanManager,
+                                   final JobCoordinator coordinator) {
         super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalManager;
@@ -60,9 +85,17 @@ public class RouterDpnChangeListener
         this.naptSwitchHA = naptSwitchHA;
         this.idManager = idManager;
         this.extNetGroupInstaller = extNetGroupInstaller;
+        this.nvpnManager = nvpnManager;
+        this.elanManager = elanManager;
+        this.natServiceManager = natServiceManager;
+        this.coordinator = coordinator;
+        if (config != null) {
+            this.natMode = config.getNatMode();
+        }
     }
 
     @Override
+    @PostConstruct
     public void init() {
         LOG.info("{} init", getClass().getSimpleName());
         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
@@ -81,117 +114,188 @@ public class RouterDpnChangeListener
 
     @Override
     protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
-        LOG.trace("Add event - key: {}, value: {}", identifier, dpnInfo);
-        final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
+        LOG.trace("add : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
+        final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
         BigInteger dpnId = dpnInfo.getDpnId();
         //check router is associated to external network
-        InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
-        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
+        Optional<Routers> routerData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, id);
         if (routerData.isPresent()) {
             Routers router = routerData.get();
             Uuid networkId = router.getNetworkId();
             if (networkId != null) {
-                LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
-                Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
-                Long vpnId;
-                if (vpnName == null) {
-                    LOG.debug("Internal vpn associated to router {}", routerId);
-                    vpnId = NatUtil.getVpnId(dataBroker, routerId);
-                    if (vpnId == NatConstants.INVALID_ID) {
-                        LOG.error("Invalid vpnId returned for routerName {}", routerId);
+                if (natMode == NatMode.Conntrack) {
+                    BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
+                    if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+                        LOG.warn("add : NAPT switch is not selected.");
                         return;
                     }
-                    LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
-                    //Install default entry in FIB to SNAT table
-                    LOG.debug("Installing default route in FIB on dpn {} for router {} with vpn {}...",
-                        dpnId, routerId, vpnId);
-                    installDefaultNatRouteForRouterExternalSubnets(dpnId,
-                            NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
-                    snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId);
-                } else {
-                    LOG.debug("External BGP vpn associated to router {}", routerId);
-                    vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
-                    if (vpnId == NatConstants.INVALID_ID) {
-                        LOG.error("Invalid vpnId returned for routerName {}", routerId);
+                    //If it is for NAPT switch skip as the flows would be already programmed.
+                    if (naptSwitch.equals(dpnId)) {
+                        LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
                         return;
                     }
-                    Long routId = NatUtil.getVpnId(dataBroker, routerId);
-                    if (routId == NatConstants.INVALID_ID) {
-                        LOG.error("Invalid routId returned for routerName {}", routerId);
-                        return;
-                    }
-                    LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
-                    //Install default entry in FIB to SNAT table
-                    LOG.debug("Installing default route in FIB on dpn {} for routerId {} with vpnId {}...",
-                        dpnId, routerId, vpnId);
-                    installDefaultNatRouteForRouterExternalSubnets(dpnId,
-                            NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
-                    snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId);
-                }
-                extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
-
-                if (router.isEnableSnat()) {
-                    LOG.info("SNAT enabled for router {}", routerId);
-                    handleSNATForDPN(dpnId, routerId, vpnId);
+                    natServiceManager.notify(router, naptSwitch, dpnId,
+                            SnatServiceManager.Action.SNAT_ROUTER_ENBL);
                 } else {
-                    LOG.info("SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
-                }
+                    coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + dpnInfo.getKey(), () -> {
+                        WriteTransaction writeFlowInvTx = dataBroker.newWriteOnlyTransaction();
+                        WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
+                        LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
+                        Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
+                        Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
+                        List<ListenableFuture<Void>> futures = new ArrayList<>();
+                        if (routerId == NatConstants.INVALID_ID) {
+                            LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
+                            writeFlowInvTx.cancel();
+                            removeFlowInvTx.cancel();
+                            return futures;
+                        }
+                        extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
+                        Long vpnId;
+                        if (vpnName == null) {
+                            LOG.debug("add : Internal vpn associated to router {}", routerUuid);
+                            vpnId = routerId;
+                            if (vpnId == NatConstants.INVALID_ID) {
+                                LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
+                                writeFlowInvTx.cancel();
+                                removeFlowInvTx.cancel();
+                                return futures;
+                            }
+                            LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
+                            //Install default entry in FIB to SNAT table
+                            LOG.info("add : Installing default route in FIB on dpn {} for router {} with vpn {}",
+                                    dpnId, routerUuid, vpnId);
+                            installDefaultNatRouteForRouterExternalSubnets(dpnId,
+                                    NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
+                            snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, writeFlowInvTx);
+                        } else {
+                            LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
+                            vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+                            if (vpnId == NatConstants.INVALID_ID) {
+                                LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
+                                writeFlowInvTx.cancel();
+                                removeFlowInvTx.cancel();
+                                return futures;
+                            }
+
+                            LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
+                            //Install default entry in FIB to SNAT table
+                            LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
+                                    + "vpnId {}...", dpnId, routerUuid, vpnId);
+                            installDefaultNatRouteForRouterExternalSubnets(dpnId,
+                                    NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
+                            snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, writeFlowInvTx);
+                        }
+
+
+                        if (router.isEnableSnat()) {
+                            LOG.info("add : SNAT enabled for router {}", routerUuid);
+                            ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
+                                    routerUuid, networkId);
+                            if (extNwProvType == null) {
+                                LOG.error("add : External Network Provider Type missing");
+                                writeFlowInvTx.cancel();
+                                removeFlowInvTx.cancel();
+                                return futures;
+                            }
+                            handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, writeFlowInvTx, removeFlowInvTx,
+                                    extNwProvType);
+                        } else {
+                            LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
+                                    routerUuid, dpnId);
+                        }
+                        futures.add(NatUtil.waitForTransactionToComplete(writeFlowInvTx));
+                        futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
+                        return futures;
+                    }, NatConstants.NAT_DJC_MAX_RETRIES);
+                } // end of controller based SNAT
             }
         } else {
-            LOG.debug("Router {} is not associated with External network", routerId);
+            LOG.debug("add : Router {} is not associated with External network", routerUuid);
         }
     }
 
     @Override
     protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
-        LOG.trace("Remove event - key: {}, value: {}", identifier, dpnInfo);
-        final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
+        LOG.trace("remove : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
+        final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
+        Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
+        if (routerId == NatConstants.INVALID_ID) {
+            LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
+            return;
+        }
         BigInteger dpnId = dpnInfo.getDpnId();
         //check router is associated to external network
-        InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
-        Optional<Routers> routerData = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+        InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
+        Optional<Routers> routerData =
+                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, id);
         if (routerData.isPresent()) {
             Routers router = routerData.get();
             Uuid networkId = router.getNetworkId();
             if (networkId != null) {
-                LOG.debug("Router {} is associated with ext nw {}", routerId, networkId);
-                Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
-                Long vpnId;
-                if (vpnName == null) {
-                    LOG.debug("Internal vpn associated to router {}", routerId);
-                    vpnId = NatUtil.getVpnId(dataBroker, routerId);
-                    if (vpnId == NatConstants.INVALID_ID) {
-                        LOG.error("Invalid vpnId returned for routerName {}", routerId);
+                if (natMode == NatMode.Conntrack) {
+                    BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
+                    if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
+                        LOG.warn("remove : NAPT switch is not selected.");
                         return;
                     }
-                    LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
-                    //Remove default entry in FIB
-                    LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
-                    snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId);
-                } else {
-                    LOG.debug("External vpn associated to router {}", routerId);
-                    vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
-                    if (vpnId == NatConstants.INVALID_ID) {
-                        LOG.error("Invalid vpnId returned for routerName {}", routerId);
+                    //If it is for NAPT switch skip as the flows would be already programmed.
+                    if (naptSwitch.equals(dpnId)) {
+                        LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
                         return;
                     }
-                    Long routId = NatUtil.getVpnId(dataBroker, routerId);
-                    if (routId == NatConstants.INVALID_ID) {
-                        LOG.error("Invalid routId returned for routerName {}", routerId);
-                        return;
-                    }
-                    LOG.debug("Retrieved vpnId {} for router {}", vpnId, routerId);
-                    //Remove default entry in FIB
-                    LOG.debug("Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
-                    snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routId);
-                }
-
-                if (router.isEnableSnat()) {
-                    LOG.info("SNAT enabled for router {}", routerId);
-                    removeSNATFromDPN(dpnId, routerId, vpnId);
+                    natServiceManager.notify(router, naptSwitch, dpnId,
+                            SnatServiceManager.Action.SNAT_ROUTER_DISBL);
                 } else {
-                    LOG.info("SNAT is not enabled for router {} to handle removeDPN event {}", routerId, dpnId);
-                }
+                    coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + dpnInfo.getKey(), () -> {
+                        WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
+                        LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
+                        Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
+                        Long vpnId;
+                        List<ListenableFuture<Void>> futures = new ArrayList<>();
+                        if (vpnName == null) {
+                            LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
+                            vpnId = routerId;
+                            if (vpnId == NatConstants.INVALID_ID) {
+                                LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
+                                removeFlowInvTx.cancel();
+                                return futures;
+                            }
+                            LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
+                            //Remove default entry in FIB
+                            LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
+                                    vpnName);
+                            snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, removeFlowInvTx);
+                        } else {
+                            LOG.debug("remove : External vpn associated to router {}", routerUuid);
+                            vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
+                            if (vpnId == NatConstants.INVALID_ID) {
+                                LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
+                                removeFlowInvTx.cancel();
+                                return futures;
+                            }
+                            LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
+                            //Remove default entry in FIB
+                            LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
+                                    vpnName);
+                            snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, removeFlowInvTx);
+                        }
+
+                        if (router.isEnableSnat()) {
+                            LOG.info("remove : SNAT enabled for router {}", routerUuid);
+                            removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, removeFlowInvTx);
+                        } else {
+                            LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
+                                    routerUuid, dpnId);
+                        }
+                        futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
+                        return futures;
+                    }, NatConstants.NAT_DJC_MAX_RETRIES);
+                } // end of controller based SNAT
             }
         }
     }
@@ -199,67 +303,73 @@ public class RouterDpnChangeListener
     @Override
     protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
                           DpnVpninterfacesList update) {
-        LOG.trace("Update event - key: {}, original: {}, update: {}", identifier, original, update);
+        LOG.trace("Update key: {}, original: {}, update: {}", update.getKey(), original, update);
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    void handleSNATForDPN(BigInteger dpnId, String routerName, Long routerVpnId) {
-        //Check if primary and secondary switch are selected, If not select the role
+    void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
+            WriteTransaction writeFlowInvTx, WriteTransaction removeFlowInvTx, ProviderTypes extNwProvType) {
+       //Check if primary and secondary switch are selected, If not select the role
         //Install select group to NAPT switch
         //Install default miss entry to NAPT switch
         BigInteger naptSwitch;
         try {
-            Long routerId = NatUtil.getVpnId(dataBroker, routerName);
-            if (routerId == NatConstants.INVALID_ID) {
-                LOG.error("Invalid routerId returned for routerName {}", routerName);
-                return;
-            }
             BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
             if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
-                LOG.debug("No NaptSwitch is selected for router {}", routerName);
-
+                LOG.debug("handleSNATForDPN : No NaptSwitch is selected for router {}", routerName);
                 naptSwitch = dpnId;
                 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
                 if (!naptstatus) {
-                    LOG.error("Failed to update newNaptSwitch {} for routername {}", naptSwitch, routerName);
+                    LOG.error("handleSNATForDPN : Failed to update newNaptSwitch {} for routername {}",
+                            naptSwitch, routerName);
                     return;
                 }
-                LOG.debug("Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
+                LOG.debug("handleSNATForDPN : Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
+
+                // When NAPT switch is elected during first VM comes up for the given Router
+                if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
+                    NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
+                            idManager, NatConstants.ODL_VNI_POOL_NAME);
+                }
 
                 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
                 if (extRouters != null) {
-                    NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
+                    NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
                     naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
                 }
-                naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId);
+
+                naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, writeFlowInvTx);
 
                 // Install miss entry (table 26) pointing to table 46
                 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
-                    routerVpnId, NatConstants.ADD_FLOW);
+                        routerVpnId, NatConstants.ADD_FLOW);
                 if (flowEntity == null) {
-                    LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
+                    LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {}",
+                            routerName, dpnId);
                     return;
                 }
-                LOG.debug("Successfully installed flow for dpnId {} router {}", dpnId, routerName);
-                mdsalManager.installFlow(flowEntity);
+                LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {}", dpnId, routerName);
+                mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
                 //Removing primary flows from old napt switch
                 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
-                    LOG.debug("Removing primary flows from old napt switch {} for router {}", naptId, routerName);
-                    naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptId, null);
+                    LOG.debug("handleSNATForDPN : Removing primary flows from old napt switch {} for router {}",
+                            naptId, routerName);
+                    naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptId, null, removeFlowInvTx);
                 }
             } else if (naptId.equals(dpnId)) {
-                LOG.debug("NaptSwitch {} gone down during cluster reboot came alive", naptId);
+                LOG.debug("handleSNATForDPN : NaptSwitch {} gone down during cluster reboot came alive", naptId);
             } else {
-
-                LOG.debug("Napt switch with Id {} is already elected for router {}", naptId, routerName);
                 naptSwitch = naptId;
+                LOG.debug("handleSNATForDPN : Napt switch with Id {} is already elected for router {}",
+                        naptId, routerName);
 
                 //installing group
-                List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId, routerName, naptSwitch);
+                List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId,
+                        routerName, routerId, naptSwitch);
                 if (bucketInfo == null) {
-                    LOG.debug("Failed to populate bucketInfo for dpnId {} routername {} naptSwitch {}",
-                        dpnId, routerName, naptSwitch);
+                    LOG.error("handleSNATForDPN:Failed to populate bucketInfo for dpnId {},routername {},naptSwitch {}",
+                            dpnId, routerName, naptSwitch);
                     return;
                 }
                 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
@@ -267,48 +377,54 @@ public class RouterDpnChangeListener
                 // Install miss entry (table 26) pointing to group
                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
                 FlowEntity flowEntity =
-                    naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId, NatConstants.ADD_FLOW);
+                        naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
+                                routerVpnId, NatConstants.ADD_FLOW);
                 if (flowEntity == null) {
-                    LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupId {}",
-                        routerName, dpnId, groupId);
+                    LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
+                            routerName, dpnId, groupId);
                     return;
                 }
-                LOG.debug("Successfully installed flow for dpnId {} router {} group {}", dpnId, routerName, groupId);
-                mdsalManager.installFlow(flowEntity);
+                LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
+                        dpnId, routerName, groupId);
+                mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
             }
+
         } catch (Exception ex) {
-            LOG.error("Exception in handleSNATForDPN method : {}", ex);
+            LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", ex);
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId) {
+    void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
+            Uuid extNetworkId, WriteTransaction removeFlowInvTx) {
         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
         //remove miss entry to NAPT switch
         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
 
-        //get ExternalIpIn prior
-        List<String> externalIpCache;
-        //HashMap Label
-        HashMap<String, Long> externalIpLabel;
-        Long routerId = NatUtil.getVpnId(dataBroker, routerName);
-        if (routerId == NatConstants.INVALID_ID) {
-            LOG.error("Invalid routerId returned for routerName {}", routerName);
+        Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
+        ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
+        if (extNwProvType == null) {
             return;
         }
-        externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
-        externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
+        //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
+        Map<String, Long> externalIpLabel;
+        if (extNwProvType == ProviderTypes.VXLAN) {
+            externalIpLabel = null;
+        } else {
+            externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
+        }
         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
-            LOG.debug("No naptSwitch is selected for router {}", routerName);
+            LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
             return;
         }
         try {
             boolean naptStatus =
-                naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache);
+                naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
+                        externalIpCache, removeFlowInvTx);
             if (!naptStatus) {
-                LOG.debug("NaptSwitchDown: Switch with DpnId {} is not naptSwitch for router {}",
+                LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
                     dpnId, routerName);
                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
                 FlowEntity flowEntity = null;
@@ -316,90 +432,88 @@ public class RouterDpnChangeListener
                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
                         NatConstants.DEL_FLOW);
                     if (flowEntity == null) {
-                        LOG.debug("Failed to populate flowentity for router {} with dpnId {} groupIs {}",
-                            routerName, dpnId, groupId);
+                        LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
+                                + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
                         return;
                     }
-                    LOG.debug("NAT Service : Removing default SNAT miss entry flow entity {}", flowEntity);
-                    mdsalManager.removeFlow(flowEntity);
+                    LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
+                    mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
 
                 } catch (Exception ex) {
-                    LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
+                    LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
                         flowEntity, ex);
                     return;
                 }
-                LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
+                LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
                     dpnId, routerName);
 
                 //remove group
                 GroupEntity groupEntity = null;
                 try {
                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
-                        GroupTypes.GroupAll, null);
-                    LOG.info("NAT Service : Removing NAPT GroupEntity:{}", groupEntity);
+                        GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
+                    LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
                     mdsalManager.removeGroup(groupEntity);
                 } catch (Exception ex) {
-                    LOG.debug("NAT Service : Failed to remove group entity {} : {}", groupEntity, ex);
+                    LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
                     return;
                 }
-                LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
+                LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
                     dpnId, routerName);
             } else {
-                naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch, externalIpLabel);
+                naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
+                        externalIpLabel, removeFlowInvTx);
                 //remove table 26 flow ppointing to table46
                 FlowEntity flowEntity = null;
                 try {
                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
                         NatConstants.DEL_FLOW);
                     if (flowEntity == null) {
-                        LOG.debug("Failed to populate flowentity for router {} with dpnId {}", routerName, dpnId);
+                        LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
+                                routerName, dpnId);
                         return;
                     }
-                    LOG.debug("NAT Service : Removing default SNAT miss entry flow entity for router {} with "
+                    LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
                         + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
-                    mdsalManager.removeFlow(flowEntity);
+                    mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
 
                 } catch (Exception ex) {
-                    LOG.debug("NAT Service : Failed to remove default SNAT miss entry flow entity {} : {}",
+                    LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
                         flowEntity, ex);
                     return;
                 }
-                LOG.debug("NAT Service : Removed default SNAT miss entry flow for dpnID {} with routername {}",
+                LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
                     dpnId, routerName);
 
                 //best effort to check IntExt model
-                naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel);
+                naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, removeFlowInvTx);
             }
         } catch (Exception ex) {
-            LOG.debug("Exception while handling naptSwitch down for router {} : {}", routerName, ex);
+            LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
         }
     }
 
-    private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, List<Uuid> externalSubnetIds) {
+    private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
         if (externalSubnetIds == null) {
-            LOG.debug("NAT Service : No external subnets for router");
+            LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
             return;
         }
 
         for (Uuid subnetId : externalSubnetIds) {
-            InstanceIdentifier<Subnets> subnetsIdentifier = InstanceIdentifier.create(ExternalSubnets.class)
-                    .child(Subnets.class, new SubnetsKey(subnetId));
-            Optional<Subnets> externalSubnet = NatUtil.read(dataBroker,
-                    LogicalDatastoreType.CONFIGURATION, subnetsIdentifier);
-            if (externalSubnet.isPresent()) {
-                long vpnIdForSubnet = NatUtil.getVpnId(dataBroker, externalSubnet.get().getVpnId().getValue());
-                if (vpnIdForSubnet != NatConstants.INVALID_ID) {
-                    LOG.debug("NAT Service : Installing default routes in FIB on dpn {} for subnetId {} with vpnId {}",
-                            dpnId, subnetId, vpnIdForSubnet);
-                    snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet,
-                            subnetId.getValue(), idManager);
-                } else {
-                    LOG.debug("NAT Service : No VPN ID for subnetId {}, cannot installing default routes flows in FIB",
-                            subnetId);
-                }
+            long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
+            if (vpnIdForSubnet != NatConstants.INVALID_ID) {
+                LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
+                        + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
+                snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue(),
+                        idManager);
             } else {
-                LOG.warn("NAT Service : No external subnet found for Uuid {}", subnetId);
+                LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);
             }
         }
     }
-}
\ No newline at end of file
+
+    private InstanceIdentifier<Subnetmap> getSubnetMapIdentifier(Uuid subnetId) {
+        return InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
+                new SubnetmapKey(subnetId)).build();
+    }
+}