Datastore txes: natservice, part 3
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatUtil.java
index 3c4f16f1813a0a5945b390b095f3d4617f0d04b0..26e9035b274e8d5a9cc6b80adad384e57573f469 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright © 2016, 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -8,8 +8,11 @@
 
 package org.opendaylight.netvirt.natservice.internal;
 
+import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.base.Preconditions;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.math.BigInteger;
 import java.net.InetAddress;
@@ -22,19 +25,24 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.infra.Datastore.Configuration;
+import org.opendaylight.genius.infra.Datastore.Operational;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.TypedReadTransaction;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
+import org.opendaylight.genius.infra.TypedWriteTransaction;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
@@ -60,7 +68,9 @@ import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.netvirt.natservice.ha.NatDataUtil;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
+import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
@@ -82,6 +92,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
@@ -97,7 +110,13 @@ 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.GetEgressActionsForTunnelOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfacesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
@@ -201,6 +220,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev15060
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.RouterKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
@@ -213,6 +233,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev14
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.add.group.input.buckets.bucket.action.action.NxActionResubmitRpcAddGroupCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nodes.node.table.flow.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.NxActionRegLoadNodesNodeTableFlowApplyActionsCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowplugin.extension.nicira.action.rev140714.nx.action.reg.load.grouping.NxRegLoad;
+import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
@@ -268,6 +289,22 @@ public final class NatUtil {
         return vpnId;
     }
 
+    public static long getVpnId(TypedReadTransaction<Configuration> confTx, String vpnName) {
+        if (vpnName == null) {
+            return NatConstants.INVALID_ID;
+        }
+
+        try {
+            return confTx.read(getVpnInstanceToVpnIdIdentifier(vpnName)).get().toJavaUtil().map(
+                org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
+                    .VpnInstance::getVpnId).orElse(NatConstants.INVALID_ID);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error retrieving VPN id for {}", vpnName, e);
+        }
+
+        return NatConstants.INVALID_ID;
+    }
+
     public static Long getNetworkVpnIdFromRouterId(DataBroker broker, long routerId) {
         //Get the external network ID from the ExternalRouter model
         Uuid networkId = NatUtil.getNetworkIdFromRouterId(broker, routerId);
@@ -308,7 +345,7 @@ public final class NatUtil {
             .child(InternalToExternalPortMap.class, new InternalToExternalPortMapKey(internalIp)).build();
     }
 
-    static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
+    public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
         .instance.to.vpn.id.VpnInstance> getVpnInstanceToVpnIdIdentifier(String vpnName) {
         return InstanceIdentifier.builder(VpnInstanceToVpnId.class)
             .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
@@ -393,12 +430,33 @@ public final class NatUtil {
                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Networks::getVpnid).orElse(null);
     }
 
+    @Nullable
+    public static Uuid getVpnIdfromNetworkId(TypedReadTransaction<Configuration> tx, Uuid networkId) {
+        try {
+            return tx.read(buildNetworkIdentifier(networkId)).get().toJavaUtil().map(Networks::getVpnid).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error reading network VPN id for {}", networkId, e);
+            return null;
+        }
+    }
+
     public static ProviderTypes getProviderTypefromNetworkId(DataBroker broker, Uuid networkId) {
         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Networks::getProviderNetworkType).orElse(null);
     }
 
+    @Nullable
+    public static ProviderTypes getProviderTypefromNetworkId(TypedReadTransaction<Configuration> tx, Uuid networkId) {
+        InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
+        try {
+            return tx.read(id).get().toJavaUtil().map(Networks::getProviderNetworkType).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error retrieving provider type for {}", networkId, e);
+            return null;
+        }
+    }
+
     @Nonnull
     public static List<Uuid> getRouterIdsfromNetworkId(DataBroker broker, Uuid networkId) {
         InstanceIdentifier<Networks> id = buildNetworkIdentifier(networkId);
@@ -514,6 +572,17 @@ public final class NatUtil {
                         .VpnInstance::getVrfId).orElse(null);
     }
 
+    public static String getVpnRd(TypedReadTransaction<Configuration> tx, String vpnName) {
+        try {
+            return tx.read(getVpnInstanceToVpnIdIdentifier(vpnName)).get().toJavaUtil().map(
+                org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id
+                    .VpnInstance::getVrfId).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error reading the VPN VRF id for {}", vpnName, e);
+            return null;
+        }
+    }
+
     public static IpPortExternal getExternalIpPortMap(DataBroker broker, Long routerId, String internalIpAddress,
                                                       String internalPort, NAPTEntryEvent.Protocol protocol) {
         ProtocolTypes protocolType = NatUtil.getProtocolType(protocol);
@@ -565,15 +634,35 @@ public final class NatUtil {
     }
 
     public static String getRouterIdfromVpnInstance(DataBroker broker, String vpnName) {
+        // returns only router, attached to IPv4 networks
         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
             .child(VpnMap.class, new VpnMapKey(new Uuid(vpnName))).build();
         Optional<VpnMap> optionalVpnMap =
                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
                         LogicalDatastoreType.CONFIGURATION, vpnMapIdentifier);
-        if (optionalVpnMap.isPresent()) {
-            Uuid routerId = optionalVpnMap.get().getRouterId();
-            if (routerId != null) {
-                return routerId.getValue();
+        if (!optionalVpnMap.isPresent()) {
+            LOG.error("getRouterIdfromVpnInstance : Router not found for vpn : {}", vpnName);
+            return null;
+        }
+        List<Uuid> routerIdsList = NeutronUtils.getVpnMapRouterIdsListUuid(optionalVpnMap.get().getRouterIds());
+        if (routerIdsList != null && !routerIdsList.isEmpty()) {
+            for (Uuid routerUuid : routerIdsList) {
+                InstanceIdentifier<Router> routerIdentifier = buildNeutronRouterIdentifier(routerUuid);
+                Optional<Router> optRouter = SingleTransactionDataBroker
+                    .syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
+                            LogicalDatastoreType.CONFIGURATION, routerIdentifier);
+                if (!optRouter.isPresent()) {
+                    continue;
+                }
+                List<Routes> routes = optRouter.get().getRoutes();
+                if (routes == null || routes.isEmpty()) {
+                    continue;
+                }
+                for (Routes r : routes) {
+                    if (r.getDestination().getIpv4Prefix() != null) {
+                        return routerUuid.getValue();
+                    }
+                }
             }
         }
         LOG.info("getRouterIdfromVpnInstance : Router not found for vpn : {}", vpnName);
@@ -581,19 +670,23 @@ public final class NatUtil {
     }
 
     static Uuid getVpnForRouter(DataBroker broker, String routerId) {
+        Preconditions.checkNotNull(routerId, "dissociateRouter: routerId not found!");
         InstanceIdentifier<VpnMaps> vpnMapsIdentifier = InstanceIdentifier.builder(VpnMaps.class).build();
         Optional<VpnMaps> optionalVpnMaps =
                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
                         LogicalDatastoreType.CONFIGURATION, vpnMapsIdentifier);
         if (optionalVpnMaps.isPresent() && optionalVpnMaps.get().getVpnMap() != null) {
             List<VpnMap> allMaps = optionalVpnMaps.get().getVpnMap();
-            if (routerId != null) {
-                for (VpnMap vpnMap : allMaps) {
-                    if (vpnMap.getRouterId() != null
-                        && routerId.equals(vpnMap.getRouterId().getValue())
-                        && !routerId.equals(vpnMap.getVpnId().getValue())) {
-                        return vpnMap.getVpnId();
-                    }
+            for (VpnMap vpnMap: allMaps) {
+                if (routerId.equals(vpnMap.getVpnId().getValue())) {
+                    continue;
+                }
+                List<Uuid> routerIdsList = NeutronUtils.getVpnMapRouterIdsListUuid(vpnMap.getRouterIds());
+                if (routerIdsList == null || routerIdsList.isEmpty()) {
+                    return null;
+                }
+                if (routerIdsList.contains(new Uuid(routerId))) {
+                    return vpnMap.getVpnId();
                 }
             }
         }
@@ -617,6 +710,15 @@ public final class NatUtil {
         return vpnUuid.getValue();
     }
 
+    public static String getAssociatedVPN(TypedReadTransaction<Configuration> tx, Uuid networkId) {
+        Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(tx, networkId);
+        if (vpnUuid == null) {
+            LOG.error("getAssociatedVPN : No VPN instance associated with ext network {}", networkId);
+            return null;
+        }
+        return vpnUuid.getValue();
+    }
+
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public static void addPrefixToBGP(DataBroker broker,
@@ -960,8 +1062,8 @@ public final class NatUtil {
                     .RouterInterfaceKey(interfaceName)).build();
     }
 
-    public static void addToNeutronRouterDpnsMap(DataBroker broker, String routerName, String interfaceName,
-            BigInteger dpId , WriteTransaction writeOperTxn) {
+    public static void addToNeutronRouterDpnsMap(String routerName, String interfaceName, BigInteger dpId,
+        TypedReadWriteTransaction<Operational> operTx) throws ExecutionException, InterruptedException {
 
         if (dpId.equals(BigInteger.ZERO)) {
             LOG.warn("addToNeutronRouterDpnsMap : Could not retrieve dp id for interface {} "
@@ -973,20 +1075,18 @@ public final class NatUtil {
                 + "ODL-L3VPN : NeutronRouterDpn map", routerName, dpId, interfaceName);
         InstanceIdentifier<DpnVpninterfacesList> dpnVpnInterfacesListIdentifier = getRouterDpnId(routerName, dpId);
 
-        Optional<DpnVpninterfacesList> optionalDpnVpninterfacesList =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                        LogicalDatastoreType.OPERATIONAL, dpnVpnInterfacesListIdentifier);
+        Optional<DpnVpninterfacesList> optionalDpnVpninterfacesList = operTx.read(dpnVpnInterfacesListIdentifier).get();
         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns
             .router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces routerInterface =
-            new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(interfaceName))
+            new RouterInterfacesBuilder().withKey(new RouterInterfacesKey(interfaceName))
             .setInterface(interfaceName).build();
         if (optionalDpnVpninterfacesList.isPresent()) {
             LOG.debug("addToNeutronRouterDpnsMap : RouterDpnList already present for the Router {} and DPN {} for the "
                     + "Interface {} in the ODL-L3VPN : NeutronRouterDpn map", routerName, dpId, interfaceName);
-            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, dpnVpnInterfacesListIdentifier
+            operTx.merge(dpnVpnInterfacesListIdentifier
                     .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
                             .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces.class,
-                            new RouterInterfacesKey(interfaceName)), routerInterface, true);
+                            new RouterInterfacesKey(interfaceName)), routerInterface, CREATE_MISSING_PARENTS);
         } else {
             LOG.debug("addToNeutronRouterDpnsMap : Building new RouterDpnList for the Router {} and DPN {} for the "
                     + "Interface {} in the ODL-L3VPN : NeutronRouterDpn map", routerName, dpId, interfaceName);
@@ -998,14 +1098,12 @@ public final class NatUtil {
             routerInterfaces.add(routerInterface);
             dpnVpnList.setRouterInterfaces(routerInterfaces);
             routerDpnListBuilder.setDpnVpninterfacesList(Collections.singletonList(dpnVpnList.build()));
-            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
-                    getRouterId(routerName),
-                    routerDpnListBuilder.build(), true);
+            operTx.merge(getRouterId(routerName), routerDpnListBuilder.build(), CREATE_MISSING_PARENTS);
         }
     }
 
-    public static void addToDpnRoutersMap(DataBroker broker, String routerName, String interfaceName,
-            BigInteger dpId, WriteTransaction writeOperTxn) {
+    public static void addToDpnRoutersMap(String routerName, String interfaceName, BigInteger dpId,
+        TypedReadWriteTransaction<Operational> operTx) throws ExecutionException, InterruptedException {
         if (dpId.equals(BigInteger.ZERO)) {
             LOG.error("addToDpnRoutersMap : Could not retrieve dp id for interface {} to handle router {} "
                     + "association model", interfaceName, routerName);
@@ -1016,20 +1114,17 @@ public final class NatUtil {
                 + "DPNRouters map", dpId, routerName, interfaceName);
         InstanceIdentifier<DpnRoutersList> dpnRoutersListIdentifier = getDpnRoutersId(dpId);
 
-        Optional<DpnRoutersList> optionalDpnRoutersList =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                        LogicalDatastoreType.OPERATIONAL, dpnRoutersListIdentifier);
+        Optional<DpnRoutersList> optionalDpnRoutersList = operTx.read(dpnRoutersListIdentifier).get();
 
         if (optionalDpnRoutersList.isPresent()) {
-            RoutersList routersList = new RoutersListBuilder().setKey(new RoutersListKey(routerName))
+            RoutersList routersList = new RoutersListBuilder().withKey(new RoutersListKey(routerName))
                     .setRouter(routerName).build();
             List<RoutersList> routersListFromDs = optionalDpnRoutersList.get().getRoutersList();
             if (!routersListFromDs.contains(routersList)) {
                 LOG.debug("addToDpnRoutersMap : Router {} not present for the DPN {}"
                         + " in the ODL-L3VPN : DPNRouters map", routerName, dpId);
-                writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
-                        dpnRoutersListIdentifier
-                        .child(RoutersList.class, new RoutersListKey(routerName)), routersList, true);
+                operTx.merge(dpnRoutersListIdentifier
+                        .child(RoutersList.class, new RoutersListKey(routerName)), routersList, CREATE_MISSING_PARENTS);
             } else {
                 LOG.debug("addToDpnRoutersMap : Router {} already mapped to the DPN {} in the ODL-L3VPN : "
                         + "DPNRouters map", routerName, dpId);
@@ -1042,69 +1137,31 @@ public final class NatUtil {
             RoutersListBuilder routersListBuilder = new RoutersListBuilder();
             routersListBuilder.setRouter(routerName);
             dpnRoutersListBuilder.setRoutersList(Collections.singletonList(routersListBuilder.build()));
-            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
-                    getDpnRoutersId(dpId),
-                    dpnRoutersListBuilder.build(), true);
+            operTx.merge(getDpnRoutersId(dpId), dpnRoutersListBuilder.build(), CREATE_MISSING_PARENTS);
         }
     }
 
-
-    public static void removeFromNeutronRouterDpnsMap(DataBroker broker, String routerName, String interfaceName,
-                                               BigInteger dpId, WriteTransaction writeOperTxn) {
-        if (dpId.equals(BigInteger.ZERO)) {
-            LOG.error("removeFromNeutronRouterDpnsMap : Could not retrieve dp id for interface {} to handle router {} "
-                    + "dissociation model", interfaceName, routerName);
-            return;
-        }
-        InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
-        Optional<DpnVpninterfacesList> optionalRouterDpnList =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                        LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
-        if (optionalRouterDpnList.isPresent()) {
-            List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
-                .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces> routerInterfaces =
-                optionalRouterDpnList.get().getRouterInterfaces();
-            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
-                .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces routerInterface =
-                new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(interfaceName))
-                    .setInterface(interfaceName).build();
-            if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
-                if (routerInterfaces.isEmpty()) {
-                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
-                } else {
-                    writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
-                        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
-                            .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces.class,
-                        new RouterInterfacesKey(interfaceName)));
-                }
-            }
-        }
-    }
-
-    public static void removeFromNeutronRouterDpnsMap(DataBroker broker, String routerName,
-                                               BigInteger dpId, WriteTransaction writeOperTxn) {
+    public static void removeFromNeutronRouterDpnsMap(String routerName, BigInteger dpId,
+        TypedReadWriteTransaction<Operational> operTx) throws ExecutionException, InterruptedException {
         if (dpId.equals(BigInteger.ZERO)) {
             LOG.warn("removeFromNeutronRouterDpnsMap : DPN ID is invalid for the router {} ", routerName);
             return;
         }
 
         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
-        Optional<DpnVpninterfacesList> optionalRouterDpnList =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                        LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+        Optional<DpnVpninterfacesList> optionalRouterDpnList = operTx.read(routerDpnListIdentifier).get();
         if (optionalRouterDpnList.isPresent()) {
             LOG.debug("removeFromNeutronRouterDpnsMap : Removing the dpn-vpninterfaces-list from the "
                     + "odl-l3vpn:neutron-router-dpns model for the router {}", routerName);
-            writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+            operTx.delete(routerDpnListIdentifier);
         } else {
             LOG.debug("removeFromNeutronRouterDpnsMap : dpn-vpninterfaces-list does not exist in the "
                     + "odl-l3vpn:neutron-router-dpns model for the router {}", routerName);
         }
     }
 
-    public static void removeFromNeutronRouterDpnsMap(DataBroker broker, String routerName, String vpnInterfaceName,
-                                               OdlInterfaceRpcService ifaceMgrRpcService,
-                                               WriteTransaction writeOperTxn) {
+    public static void removeFromNeutronRouterDpnsMap(String routerName, String vpnInterfaceName,
+        OdlInterfaceRpcService ifaceMgrRpcService, @Nonnull TypedReadWriteTransaction<Operational> operTx) {
         BigInteger dpId = getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
         if (dpId.equals(BigInteger.ZERO)) {
             LOG.debug("removeFromNeutronRouterDpnsMap : Could not retrieve dp id for interface {} to handle router {}"
@@ -1112,44 +1169,38 @@ public final class NatUtil {
             return;
         }
         InstanceIdentifier<DpnVpninterfacesList> routerDpnListIdentifier = getRouterDpnId(routerName, dpId);
-        Optional<DpnVpninterfacesList> optionalRouterDpnList =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                        LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
+        Optional<DpnVpninterfacesList> optionalRouterDpnList;
+        try {
+            optionalRouterDpnList = operTx.read(routerDpnListIdentifier).get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error reading the router DPN list for {}", routerDpnListIdentifier, e);
+            optionalRouterDpnList = Optional.absent();
+        }
         if (optionalRouterDpnList.isPresent()) {
             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns
                 .router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces> routerInterfaces =
                 optionalRouterDpnList.get().getRouterInterfaces();
             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn
                 .list.dpn.vpninterfaces.list.RouterInterfaces routerInterface =
-                new RouterInterfacesBuilder().setKey(new RouterInterfacesKey(vpnInterfaceName))
+                new RouterInterfacesBuilder().withKey(new RouterInterfacesKey(vpnInterfaceName))
                     .setInterface(vpnInterfaceName).build();
 
             if (routerInterfaces != null && routerInterfaces.remove(routerInterface)) {
                 if (routerInterfaces.isEmpty()) {
-                    if (writeOperTxn != null) {
-                        writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
-                    } else {
-                        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier);
-                    }
+                    operTx.delete(routerDpnListIdentifier);
                 } else {
-                    if (writeOperTxn != null) {
-                        writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
-                            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
-                                .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces.class,
-                            new RouterInterfacesKey(vpnInterfaceName)));
-                    } else {
-                        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, routerDpnListIdentifier.child(
-                            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron
-                                .router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces.class,
-                            new RouterInterfacesKey(vpnInterfaceName)));
-                    }
+                    operTx.delete(routerDpnListIdentifier.child(
+                        org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router
+                            .dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces.class,
+                        new RouterInterfacesKey(vpnInterfaceName)));
                 }
             }
         }
     }
 
     public static void removeFromDpnRoutersMap(DataBroker broker, String routerName, String vpnInterfaceName,
-                                        OdlInterfaceRpcService ifaceMgrRpcService, WriteTransaction writeOperTxn) {
+        OdlInterfaceRpcService ifaceMgrRpcService, TypedReadWriteTransaction<Operational> operTx)
+        throws ExecutionException, InterruptedException {
         BigInteger dpId = getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
         if (dpId.equals(BigInteger.ZERO)) {
             LOG.debug("removeFromDpnRoutersMap : removeFromDpnRoutersMap() : "
@@ -1157,12 +1208,12 @@ public final class NatUtil {
                 vpnInterfaceName, routerName);
             return;
         }
-        removeFromDpnRoutersMap(broker, routerName, vpnInterfaceName, dpId, ifaceMgrRpcService, writeOperTxn);
+        removeFromDpnRoutersMap(broker, routerName, vpnInterfaceName, dpId, ifaceMgrRpcService, operTx);
     }
 
     static void removeFromDpnRoutersMap(DataBroker broker, String routerName, String vpnInterfaceName,
-                                        BigInteger curDpnId,
-                                        OdlInterfaceRpcService ifaceMgrRpcService, WriteTransaction writeOperTxn) {
+        BigInteger curDpnId, OdlInterfaceRpcService ifaceMgrRpcService, TypedReadWriteTransaction<Operational> operTx)
+        throws ExecutionException, InterruptedException {
         /*
             1) Get the DpnRoutersList for the DPN.
             2) Get the RoutersList identifier for the DPN and router.
@@ -1176,9 +1227,7 @@ public final class NatUtil {
 
         //Get the dpn-routers-list instance for the current DPN.
         InstanceIdentifier<DpnRoutersList> dpnRoutersListIdentifier = getDpnRoutersId(curDpnId);
-        Optional<DpnRoutersList> dpnRoutersListData =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                        LogicalDatastoreType.OPERATIONAL, dpnRoutersListIdentifier);
+        Optional<DpnRoutersList> dpnRoutersListData = operTx.read(dpnRoutersListIdentifier).get();
 
         if (dpnRoutersListData == null || !dpnRoutersListData.isPresent()) {
             LOG.error("removeFromDpnRoutersMap : dpn-routers-list is not present for DPN {} "
@@ -1188,9 +1237,7 @@ public final class NatUtil {
 
         //Get the routers-list instance for the router on the current DPN only
         InstanceIdentifier<RoutersList> routersListIdentifier = getRoutersList(curDpnId, routerName);
-        Optional<RoutersList> routersListData =
-                SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
-                        LogicalDatastoreType.OPERATIONAL, routersListIdentifier);
+        Optional<RoutersList> routersListData = operTx.read(routersListIdentifier).get();
 
         if (routersListData == null || !routersListData.isPresent()) {
             LOG.error("removeFromDpnRoutersMap : routers-list is not present for the DPN {} "
@@ -1212,7 +1259,7 @@ public final class NatUtil {
             LOG.debug("removeFromDpnRoutersMap : Unable to get the routers list for the DPN {}. Possibly all subnets "
                     + "removed from router {} OR Router {} has been deleted. Hence DPN router model WILL be cleared ",
                 curDpnId, routerName, routerName);
-            writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routersListIdentifier);
+            operTx.delete(routersListIdentifier);
             return;
         }
 
@@ -1246,7 +1293,7 @@ public final class NatUtil {
         LOG.debug("removeFromDpnRoutersMap : Router {} is present in the DPN {} only through the interface {} "
             + "Hence DPN router model WILL be cleared. Possibly last VM for the router "
             + "deleted in the DPN", routerName, curDpnId, vpnInterfaceName);
-        writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, routersListIdentifier);
+        operTx.delete(routersListIdentifier);
     }
 
     private static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn
@@ -1290,52 +1337,47 @@ public final class NatUtil {
     public static List<ActionInfo> getEgressActionsForInterface(OdlInterfaceRpcService odlInterfaceRpcService,
                                                                 ItmRpcService itmRpcService,
                                                                 IInterfaceManager interfaceManager, String ifName,
-                                                                Long tunnelKey) {
+                                                                Long tunnelKey, boolean internalTunnelInterface) {
         return getEgressActionsForInterface(odlInterfaceRpcService, itmRpcService, interfaceManager,
-                ifName, tunnelKey, 0);
+                ifName, tunnelKey, 0, internalTunnelInterface);
     }
 
     @Nonnull
     public static List<ActionInfo> getEgressActionsForInterface(OdlInterfaceRpcService odlInterfaceRpcService,
                                                                 ItmRpcService itmRpcService,
                                                                 IInterfaceManager interfaceManager,
-                                                                String ifName, Long tunnelKey, int pos) {
+                                                                String ifName, Long tunnelKey, int pos,
+                                                                boolean internalTunnelInterface) {
         LOG.debug("getEgressActionsForInterface : called for interface {}", ifName);
         GetEgressActionsForInterfaceInputBuilder egressActionsIfmBuilder =
                 new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName);
-        GetEgressActionsForTunnelInputBuilder egressActionsItmBuilder = new GetEgressActionsForTunnelInputBuilder()
-            .setIntfName(ifName);
+        GetEgressActionsForTunnelInputBuilder egressActionsItmBuilder =
+                new GetEgressActionsForTunnelInputBuilder().setIntfName(ifName);
         if (tunnelKey != null) {
             egressActionsIfmBuilder.setTunnelKey(tunnelKey);
             egressActionsItmBuilder.setTunnelKey(tunnelKey);
-        }
+        } //init builders, ITM/IFM rpc can be called based on type of interface
 
         try {
-            RpcResult<GetEgressActionsForTunnelOutput> rpcResultItm = null;
-            RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = null;
             List<Action> actions = Collections.emptyList();
-            if (interfaceManager.isItmDirectTunnelsEnabled()) {
-                rpcResultItm =
+            if (interfaceManager.isItmDirectTunnelsEnabled() && internalTunnelInterface) {
+                RpcResult<GetEgressActionsForTunnelOutput> rpcResult =
                         itmRpcService.getEgressActionsForTunnel(egressActionsItmBuilder.build()).get();
+                if (!rpcResult.isSuccessful()) {
+                    LOG.error("getEgressActionsForTunnels : RPC Call to Get egress actions for Tunnels {} "
+                            + "returned with Errors {}", ifName, rpcResult.getErrors());
+                } else {
+                    actions = rpcResult.getResult().getAction();
+                }
             } else {
-                rpcResult =
+                RpcResult<GetEgressActionsForInterfaceOutput> rpcResult =
                         odlInterfaceRpcService.getEgressActionsForInterface(egressActionsIfmBuilder.build()).get();
-            }
-
-            if (!interfaceManager.isItmDirectTunnelsEnabled() && rpcResult != null) {
                 if (!rpcResult.isSuccessful()) {
                     LOG.error("getEgressActionsForInterface : RPC Call to Get egress actions for interface {} "
                             + "returned with Errors {}", ifName, rpcResult.getErrors());
                 } else {
                     actions = rpcResult.getResult().getAction();
                 }
-            } else if (interfaceManager.isItmDirectTunnelsEnabled() && rpcResultItm != null) {
-                if (!rpcResultItm.isSuccessful()) {
-                    LOG.error("getEgressActionsForTunnels : RPC Call to Get egress actions for Tunnels {} "
-                            + "returned with Errors {}", ifName, rpcResultItm.getErrors());
-                } else {
-                    actions = rpcResultItm.getResult().getAction();
-                }
             }
             List<ActionInfo> listActionInfo = new ArrayList<>();
             for (Action action : actions) {
@@ -1462,6 +1504,10 @@ public final class NatUtil {
             return null;
         }
 
+        if (null != gatewayIp.getIpv6Address()) {
+            return null;
+        }
+
         InstanceIdentifier<VpnPortipToPort> portIpInst = InstanceIdentifier.builder(NeutronVpnPortipPortData.class)
             .child(VpnPortipToPort.class, new VpnPortipToPortKey(gatewayIp.getIpv4Address().getValue(), vpnName))
             .build();
@@ -1513,6 +1559,17 @@ public final class NatUtil {
                 FloatingIpIdToPortMapping::getFloatingIpPortMacAddress).orElse(null);
     }
 
+    protected static String getFloatingIpPortMacFromFloatingIpId(TypedReadTransaction<Configuration> confTx,
+        Uuid floatingIpId) {
+        try {
+            return confTx.read(buildfloatingIpIdToPortMappingIdentifier(floatingIpId)).get().toJavaUtil().map(
+                FloatingIpIdToPortMapping::getFloatingIpPortMacAddress).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error reading the floating IP port MAC for {}", floatingIpId, e);
+            return null;
+        }
+    }
+
     protected static Uuid getFloatingIpPortSubnetIdFromFloatingIpId(DataBroker broker, Uuid floatingIpId) {
         InstanceIdentifier<FloatingIpIdToPortMapping> id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker,
@@ -1520,6 +1577,18 @@ public final class NatUtil {
                 FloatingIpIdToPortMapping::getFloatingIpPortSubnetId).orElse(null);
     }
 
+    @Nullable
+    protected static Uuid getFloatingIpPortSubnetIdFromFloatingIpId(TypedReadTransaction<Configuration> confTx,
+        Uuid floatingIpId) {
+        try {
+            return confTx.read(buildfloatingIpIdToPortMappingIdentifier(floatingIpId)).get().toJavaUtil().map(
+                FloatingIpIdToPortMapping::getFloatingIpPortSubnetId).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error reading the floating IP port subnet for {}", floatingIpId, e);
+            return null;
+        }
+    }
+
     static InstanceIdentifier<FloatingIpIdToPortMapping> buildfloatingIpIdToPortMappingIdentifier(Uuid floatingIpId) {
         return InstanceIdentifier.builder(FloatingIpPortInfo.class).child(FloatingIpIdToPortMapping.class, new
             FloatingIpIdToPortMappingKey(floatingIpId)).build();
@@ -1549,12 +1618,22 @@ public final class NatUtil {
                 LogicalDatastoreType.CONFIGURATION, routerIdentifier).orNull();
     }
 
+    @Nullable
+    public static Routers getRoutersFromConfigDS(TypedReadTransaction<Configuration> confTx, String routerName) {
+        try {
+            return confTx.read(NatUtil.buildRouterIdentifier(routerName)).get().orNull();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error reading router {}", routerName, e);
+            return null;
+        }
+    }
+
     static void createRouterIdsConfigDS(DataBroker dataBroker, long routerId, String routerName) {
         if (routerId == NatConstants.INVALID_ID) {
             LOG.error("createRouterIdsConfigDS : invalid routerId for routerName {}", routerName);
             return;
         }
-        RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(routerId))
+        RouterIds rtrs = new RouterIdsBuilder().withKey(new RouterIdsKey(routerId))
             .setRouterId(routerId).setRouterName(routerName).build();
         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, buildRouterIdentifier(routerId), rtrs);
     }
@@ -1602,6 +1681,16 @@ public final class NatUtil {
                 LogicalDatastoreType.CONFIGURATION, id).toJavaUtil().map(Routers::getExtGwMacAddress).orElse(null);
     }
 
+    @Nullable
+    static String getExtGwMacAddFromRouterName(TypedReadTransaction<Configuration> tx, String routerName) {
+        try {
+            return tx.read(buildRouterIdentifier(routerName)).get().toJavaUtil().map(
+                Routers::getExtGwMacAddress).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error retrieving external gateway MAC address for router {}", routerName, e);
+            return null;
+        }
+    }
 
     static InstanceIdentifier<Router> buildNeutronRouterIdentifier(Uuid routerUuid) {
         InstanceIdentifier<Router> routerInstanceIdentifier = InstanceIdentifier.create(Neutron.class)
@@ -1699,6 +1788,27 @@ public final class NatUtil {
                 LogicalDatastoreType.CONFIGURATION, subnetsIdentifier);
     }
 
+    @Nonnull
+    protected static Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
+        .subnets.Subnets> getOptionalExternalSubnets(TypedReadTransaction<Configuration> tx, Uuid subnetId) {
+        if (subnetId == null) {
+            LOG.warn("getOptionalExternalSubnets : subnetId is null");
+            return Optional.absent();
+        }
+
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
+            .rev160111.external.subnets.Subnets> subnetsIdentifier =
+            InstanceIdentifier.builder(ExternalSubnets.class)
+                .child(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice
+                    .rev160111.external.subnets.Subnets.class, new SubnetsKey(subnetId)).build();
+        try {
+            return tx.read(subnetsIdentifier).get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error retrieving external subnets on {}", subnetId, e);
+            return Optional.absent();
+        }
+    }
+
     protected static long getExternalSubnetVpnId(DataBroker dataBroker, Uuid subnetId) {
         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
             .subnets.Subnets> optionalExternalSubnets = NatUtil.getOptionalExternalSubnets(dataBroker,
@@ -1710,6 +1820,17 @@ public final class NatUtil {
         return NatConstants.INVALID_ID;
     }
 
+    protected static long getExternalSubnetVpnId(TypedReadTransaction<Configuration> tx, Uuid subnetId) {
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external
+            .subnets.Subnets> optionalExternalSubnets = NatUtil.getOptionalExternalSubnets(tx,
+            subnetId);
+        if (optionalExternalSubnets.isPresent()) {
+            return NatUtil.getVpnId(tx, subnetId.getValue());
+        }
+
+        return NatConstants.INVALID_ID;
+    }
+
     protected static long getExternalSubnetVpnIdForRouterExternalIp(DataBroker dataBroker, String externalIpAddress,
             Routers router) {
         Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(externalIpAddress, router);
@@ -1759,6 +1880,16 @@ public final class NatUtil {
                 LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull();
     }
 
+    @Nullable
+    public static ElanInstance getElanInstanceByName(TypedReadTransaction<Configuration> tx, String elanInstanceName) {
+        try {
+            return tx.read(getElanInstanceConfigurationDataPath(elanInstanceName)).get().orNull();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error retrieving ELAN instance by name {}", elanInstanceName, e);
+            return null;
+        }
+    }
+
     public static InstanceIdentifier<ElanInstance> getElanInstanceConfigurationDataPath(String elanInstanceName) {
         return InstanceIdentifier.builder(ElanInstances.class)
                 .child(ElanInstance.class, new ElanInstanceKey(elanInstanceName)).build();
@@ -1775,7 +1906,7 @@ public final class NatUtil {
     }
 
     public static void makePreDnatToSnatTableEntry(IMdsalApiManager mdsalManager, BigInteger naptDpnId,
-            short tableId, WriteTransaction writeFlowTx) {
+            short tableId, TypedWriteTransaction<Configuration> confTx) {
         LOG.debug("makePreDnatToSnatTableEntry : Create Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ",
                 NwConstants.PDNAT_TABLE, tableId, naptDpnId);
 
@@ -1788,19 +1919,19 @@ public final class NatUtil {
                 5, flowRef, 0, 0,  NwConstants.COOKIE_DNAT_TABLE,
                 matches, preDnatToSnatInstructions);
 
-        mdsalManager.addFlowToTx(naptDpnId, preDnatToSnatTableFlowEntity, writeFlowTx);
+        mdsalManager.addFlow(confTx, naptDpnId, preDnatToSnatTableFlowEntity);
         LOG.debug("makePreDnatToSnatTableEntry : Successfully installed Pre-DNAT flow {} on NAPT DpnId {} ",
                 preDnatToSnatTableFlowEntity,  naptDpnId);
     }
 
-    public static void removePreDnatToSnatTableEntry(IMdsalApiManager mdsalManager, BigInteger naptDpnId,
-                                                     WriteTransaction removeFlowInvTx) {
+    public static void removePreDnatToSnatTableEntry(TypedReadWriteTransaction<Configuration> confTx,
+        IMdsalApiManager mdsalManager, BigInteger naptDpnId) {
         LOG.debug("removePreDnatToSnatTableEntry : Remove Pre-DNAT table {} --> table {} flow on NAPT DpnId {} ",
                 NwConstants.PDNAT_TABLE, NwConstants.INBOUND_NAPT_TABLE, naptDpnId);
         String flowRef = getFlowRefPreDnatToSnat(naptDpnId, NwConstants.PDNAT_TABLE, "PreDNATToSNAT");
         Flow preDnatToSnatTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.PDNAT_TABLE,flowRef,
                 5, flowRef, 0, 0,  NwConstants.COOKIE_DNAT_TABLE, null, null);
-        mdsalManager.removeFlowToTx(naptDpnId, preDnatToSnatTableFlowEntity, removeFlowInvTx);
+        mdsalManager.removeFlow(confTx, naptDpnId, preDnatToSnatTableFlowEntity);
         LOG.debug("removePreDnatToSnatTableEntry: Successfully removed Pre-DNAT flow {} on NAPT DpnId = {}",
                 preDnatToSnatTableFlowEntity, naptDpnId);
     }
@@ -1857,9 +1988,9 @@ public final class NatUtil {
     }
 
     @Nullable
-    public static String getPrimaryRd(String vpnName, ReadTransaction tx) throws ReadFailedException {
-        return tx.read(LogicalDatastoreType.CONFIGURATION,
-                getVpnInstanceIdentifier(vpnName)).checkedGet().toJavaUtil().map(NatUtil::getPrimaryRd).orElse(null);
+    public static String getPrimaryRd(String vpnName, TypedReadTransaction<Configuration> tx)
+        throws ExecutionException, InterruptedException {
+        return tx.read(getVpnInstanceIdentifier(vpnName)).get().toJavaUtil().map(NatUtil::getPrimaryRd).orElse(null);
     }
 
     public static String getPrimaryRd(DataBroker dataBroker, String vpnName) {
@@ -1949,7 +2080,7 @@ public final class NatUtil {
 
     public static void installRouterGwFlows(ManagedNewTransactionRunner txRunner, IVpnManager vpnManager,
             Routers router, BigInteger primarySwitchId, int addOrRemove) {
-        ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+        ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
             List<ExternalIps> externalIps = router.getExternalIps();
             List<String> externalIpsSting = new ArrayList<>();
 
@@ -1966,7 +2097,7 @@ public final class NatUtil {
                         router.getNetworkId(), subnetVpnName.getValue(), tx);
                 vpnManager.addArpResponderFlowsToExternalNetworkIps(router.getRouterName(), externalIpsSting,
                         router.getExtGwMacAddress(), primarySwitchId,
-                        router.getNetworkId(), tx);
+                        router.getNetworkId());
             } else {
                 vpnManager.removeRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
                         router.getNetworkId(), subnetVpnName.getValue(), tx);
@@ -1977,17 +2108,6 @@ public final class NatUtil {
         }), LOG, "Error installing router gateway flows");
     }
 
-    public static CheckedFuture<Void, TransactionCommitFailedException> waitForTransactionToComplete(
-            WriteTransaction tx) {
-        CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
-        try {
-            futures.get();
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Error writing to datastore {}", e);
-        }
-        return futures;
-    }
-
     public static Boolean isOpenStackVniSemanticsEnforcedForGreAndVxlan(IElanService elanManager,
                                                                         ProviderTypes extNwProvType) {
         if (elanManager.isOpenStackVniSemanticsEnforced() && (extNwProvType == ProviderTypes.GRE
@@ -1996,4 +2116,155 @@ public final class NatUtil {
         }
         return false;
     }
+
+    public static void addPseudoPortToElanDpn(String elanInstanceName, String pseudoPortId,
+            BigInteger dpnId, DataBroker dataBroker) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
+                elanInstanceName,dpnId);
+        try {
+            synchronized (elanInstanceName.intern()) {
+                Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+                List<String> elanInterfaceList;
+                DpnInterfaces dpnInterface;
+                if (!dpnInElanInterfaces.isPresent()) {
+                    elanInterfaceList = new ArrayList<>();
+                } else {
+                    dpnInterface = dpnInElanInterfaces.get();
+                    elanInterfaceList = dpnInterface.getInterfaces();
+                }
+                if (!elanInterfaceList.contains(pseudoPortId)) {
+                    elanInterfaceList.add(pseudoPortId);
+                    dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                            .withKey(new DpnInterfacesKey(dpnId)).build();
+                    SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                            elanDpnInterfaceId, dpnInterface);
+                }
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to add elanDpnInterface with error {}", e.getMessage());
+        }
+    }
+
+    public static void removePseudoPortFromElanDpn(String elanInstanceName, String pseudoPortId,
+            BigInteger dpnId, DataBroker dataBroker) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
+                elanInstanceName,dpnId);
+        try {
+            synchronized (elanInstanceName.intern()) {
+                Optional<DpnInterfaces> dpnInElanInterfaces = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+                List<String> elanInterfaceList;
+                DpnInterfaces dpnInterface;
+                if (!dpnInElanInterfaces.isPresent()) {
+                    LOG.info("No interface in any dpn for {}", elanInstanceName);
+                    return;
+                } else {
+                    dpnInterface = dpnInElanInterfaces.get();
+                    elanInterfaceList = dpnInterface.getInterfaces();
+                }
+                if (!elanInterfaceList.contains(pseudoPortId)) {
+                    LOG.info("Router port not present in DPN {} for VPN {}", dpnId, elanInstanceName);
+                    return;
+                }
+                elanInterfaceList.remove(pseudoPortId);
+                dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                        .withKey(new DpnInterfacesKey(dpnId)).build();
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                        elanDpnInterfaceId, dpnInterface);
+            }
+        } catch (ReadFailedException e) {
+            LOG.warn("Failed to read elanDpnInterface with error {}", e.getMessage());
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to remove elanDpnInterface with error {}", e.getMessage());
+        }
+
+    }
+
+    public static DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId,
+            DataBroker broker) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId =
+                getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
+        DpnInterfaces dpnInterfaces = null;
+        try {
+            dpnInterfaces = SingleTransactionDataBroker.syncRead(broker, LogicalDatastoreType.OPERATIONAL,
+                    elanDpnInterfacesId);
+        }
+        catch (ReadFailedException e) {
+            LOG.warn("Failed to read ElanDpnInterfacesList with error {}", e.getMessage());
+        }
+        return dpnInterfaces;
+    }
+
+    public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+            InstanceIdentifier<T> path) {
+        try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
+            return tx.read(datastoreType, path).get();
+        } catch (InterruptedException | ExecutionException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static boolean isLastExternalRouter(String networkid, String routerName, NatDataUtil natDataUtil) {
+        Set<Map.Entry<String,Routers>> extRouter = natDataUtil.getAllRouters();
+        for (Map.Entry<String,Routers> router : extRouter) {
+            if (!router.getKey().equals(routerName) && router.getValue().getNetworkId().getValue()
+                    .equals(networkid)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static InstanceIdentifier<ExtRouters> buildExtRouters() {
+        InstanceIdentifier<ExtRouters> extRouterInstanceIndentifier = InstanceIdentifier.builder(ExtRouters.class)
+                .build();
+        return extRouterInstanceIndentifier;
+    }
+
+    public static LearntVpnVipToPortData getLearntVpnVipToPortData(DataBroker dataBroker) {
+        InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = getLearntVpnVipToPortDataId();
+        LearntVpnVipToPortData learntVpnVipToPortData = null;
+        try {
+            learntVpnVipToPortData = SingleTransactionDataBroker.syncRead(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL, learntVpnVipToPortDataId);
+        }
+        catch (ReadFailedException e) {
+            LOG.warn("Failed to read LearntVpnVipToPortData with error {}", e.getMessage());
+        }
+        return learntVpnVipToPortData;
+    }
+
+    public static InstanceIdentifier<LearntVpnVipToPortData> getLearntVpnVipToPortDataId() {
+        InstanceIdentifier<LearntVpnVipToPortData> learntVpnVipToPortDataId = InstanceIdentifier
+                .builder(LearntVpnVipToPortData.class).build();
+        return learntVpnVipToPortDataId;
+    }
+
+    public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
+            BigInteger dpId) {
+        return InstanceIdentifier.builder(ElanDpnInterfaces.class)
+                .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
+                .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
+    }
+
+    public static void createGroupIdPool(IdManagerService idManager) {
+        CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
+                .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
+                .setLow(NatConstants.SNAT_ID_LOW_VALUE)
+                .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
+                .build();
+        try {
+            Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
+            if (result != null && result.get().isSuccessful()) {
+                LOG.debug("createGroupIdPool : GroupIdPool created successfully");
+            } else {
+                LOG.error("createGroupIdPool : Unable to create GroupIdPool");
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("createGroupIdPool : Failed to create PortPool for NAPT Service", e);
+        }
+    }
 }