Refactor Ipv6Service module.
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnUtil.java
old mode 100755 (executable)
new mode 100644 (file)
index e210f4a..1cf07c8
@@ -11,9 +11,7 @@ package org.opendaylight.netvirt.vpnmanager;
 import com.google.common.base.Optional;
 import com.google.common.collect.Iterators;
 import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
 import java.math.BigInteger;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
@@ -24,9 +22,12 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -35,13 +36,17 @@ 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.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 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.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
-import org.opendaylight.genius.mdsalutil.MDSALDataStoreUtils;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
@@ -52,17 +57,21 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.genius.utils.SystemPropertyReader;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
+import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
 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;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
@@ -75,6 +84,7 @@ import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev14081
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames.AssociatedSubnetType;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNamesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
@@ -89,6 +99,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.IfIndexesInterfaceMap;
@@ -99,13 +110,30 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpc
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.Ipv6NdUtilService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationToOfGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationToOfGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.SendNeighborSolicitationToOfGroupOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TimeUnits;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanTagNameMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
+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.interfaces.ElanInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
@@ -124,6 +152,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adj
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOpBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventAction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortEventData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RouterInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.SubnetOpData;
@@ -138,6 +168,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adj
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPortBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPortKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.event.data.LearntVpnVipToPortEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.event.data.LearntVpnVipToPortEventBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.event.data.LearntVpnVipToPortEventKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
@@ -175,6 +208,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev16011
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.SubnetsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronVpnPortipPortData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterInterfacesMap;
@@ -190,6 +224,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.ext.rev150712.NetworkL3Extension;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.Subnets;
@@ -197,26 +232,49 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.s
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.impl.schema.tree.SchemaValidationFailedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public final class VpnUtil {
+
     private static final Logger LOG = LoggerFactory.getLogger(VpnUtil.class);
-    private static final int DEFAULT_PREFIX_LENGTH = 32;
-    private static final String PREFIX_SEPARATOR = "/";
+
+    static final int SINGLE_TRANSACTION_BROKER_NO_RETRY = 1;
+
+    /**
+     * Class to generate timestamps with microsecond precision.
+     * For example: MicroTimestamp.INSTANCE.get() = "2012-10-21 19:13:45.267128"
+     */
+    public enum MicroTimestamp {
+        INSTANCE ;
+
+        private long              startDate ;
+        private long              startNanoseconds ;
+        private SimpleDateFormat  dateFormat ;
+
+        MicroTimestamp() {
+            this.startDate = System.currentTimeMillis() ;
+            this.startNanoseconds = System.nanoTime() ;
+            this.dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") ;
+        }
+
+        public String get() {
+            long microSeconds = (System.nanoTime() - this.startNanoseconds) / 1000 ;
+            long date = this.startDate + microSeconds / 1000 ;
+            return this.dateFormat.format(date) + String.format("%03d", microSeconds % 1000) ;
+        }
+    }
 
     private VpnUtil() {
     }
 
-    static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
+    public static InstanceIdentifier<VpnInterface> getVpnInterfaceIdentifier(String vpnInterfaceName) {
         return InstanceIdentifier.builder(VpnInterfaces.class)
             .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).build();
     }
 
-    static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
+    public static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
                                                              String vpnInterfaceName, String vpnName) {
         return InstanceIdentifier.builder(VpnInterfaceOpData.class)
             .child(VpnInterfaceOpDataEntry.class,
@@ -237,7 +295,7 @@ public final class VpnUtil {
     static VpnInterfaceOpDataEntry getVpnInterfaceOpDataEntry(String intfName, String vpnName,
                                         AdjacenciesOp aug, BigInteger dpnId,
                                         Boolean isSheduledForRemove, long lportTag, String gwMac) {
-        return new VpnInterfaceOpDataEntryBuilder().setKey(new VpnInterfaceOpDataEntryKey(intfName, vpnName))
+        return new VpnInterfaceOpDataEntryBuilder().withKey(new VpnInterfaceOpDataEntryKey(intfName, vpnName))
             .setDpnId(dpnId).setScheduledForRemove(isSheduledForRemove).addAugmentation(AdjacenciesOp.class, aug)
                 .setLportTag(lportTag).setGatewayMacAddress(gwMac).build();
     }
@@ -267,7 +325,7 @@ public final class VpnUtil {
     }
 
     static VpnIds getPrefixToInterface(long vpnId) {
-        return new VpnIdsBuilder().setKey(new VpnIdsKey(vpnId)).setVpnId(vpnId).build();
+        return new VpnIdsBuilder().withKey(new VpnIdsKey(vpnId)).setVpnId(vpnId).build();
     }
 
     static Prefixes getPrefixToInterface(BigInteger dpId, String vpnInterfaceName, String ipPrefix, Uuid subnetId,
@@ -360,7 +418,7 @@ public final class VpnUtil {
         .instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> getDpnVpnInterfaces(DataBroker broker,
         VpnInstance vpnInstance, BigInteger dpnId) {
         String primaryRd = getPrimaryRd(vpnInstance);
-        InstanceIdentifier<VpnToDpnList> dpnToVpnId = getVpnToDpnListIdentifier(primaryRd, dpnId);
+        InstanceIdentifier<VpnToDpnList> dpnToVpnId = VpnHelper.getVpnToDpnListIdentifier(primaryRd, dpnId);
         Optional<VpnToDpnList> dpnInVpn = VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, dpnToVpnId);
         return dpnInVpn.isPresent() ? dpnInVpn.get().getVpnInterfaces() : Collections.emptyList();
     }
@@ -388,7 +446,7 @@ public final class VpnUtil {
         return null;
     }
 
-    static List<Adjacency> getAdjacenciesForVpnInterfaceFromConfig(DataBroker broker, String intfName) {
+    public static List<Adjacency> getAdjacenciesForVpnInterfaceFromConfig(DataBroker broker, String intfName) {
         final InstanceIdentifier<VpnInterface> identifier = getVpnInterfaceIdentifier(intfName);
         InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
         Optional<Adjacencies> adjacencies = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, path);
@@ -422,10 +480,10 @@ public final class VpnUtil {
     }
 
     static AllocatedRdsBuilder getRdsBuilder(String nexthop, String rd) {
-        return new AllocatedRdsBuilder().setKey(new AllocatedRdsKey(nexthop)).setNexthop(nexthop).setRd(rd);
+        return new AllocatedRdsBuilder().withKey(new AllocatedRdsKey(nexthop)).setNexthop(nexthop).setRd(rd);
     }
 
-    static Adjacencies getVpnInterfaceAugmentation(List<Adjacency> nextHopList) {
+    public static Adjacencies getVpnInterfaceAugmentation(List<Adjacency> nextHopList) {
         return new AdjacenciesBuilder().setAdjacency(nextHopList).build();
     }
 
@@ -448,12 +506,6 @@ public final class VpnUtil {
             .child(Interface.class, new InterfaceKey(interfaceName)).build();
     }
 
-    static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
-        return InstanceIdentifier.builder(VpnInstanceOpData.class)
-            .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
-            .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
-    }
-
     public static BigInteger getCookieArpFlow(int interfaceTag) {
         return VpnConstants.COOKIE_L3_BASE.add(new BigInteger("0110000", 16)).add(
             BigInteger.valueOf(interfaceTag));
@@ -490,8 +542,7 @@ public final class VpnUtil {
     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
         ReleaseIdInput idInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
         try {
-            Future<RpcResult<Void>> result = idManager.releaseId(idInput);
-            RpcResult<Void> rpcResult = result.get();
+            RpcResult<ReleaseIdOutput> rpcResult = idManager.releaseId(idInput).get();
             if (!rpcResult.isSuccessful()) {
                 LOG.error("releaseId: RPC Call to release Id for key {} from pool {} returned with Errors {}",
                         idKey, poolName, rpcResult.getErrors());
@@ -589,14 +640,15 @@ public final class VpnUtil {
         Optional<VrfTables> vrfTablesOpc = read(broker, LogicalDatastoreType.CONFIGURATION, vpnVrfTableIid);
         if (vrfTablesOpc.isPresent()) {
             VrfTables vrfTables = vrfTablesOpc.get();
-            WriteTransaction tx = broker.newWriteOnlyTransaction();
-            for (VrfEntry vrfEntry : vrfTables.getVrfEntry()) {
-                if (origin == RouteOrigin.value(vrfEntry.getOrigin())) {
-                    tx.delete(LogicalDatastoreType.CONFIGURATION,
-                            vpnVrfTableIid.child(VrfEntry.class, vrfEntry.getKey()));
-                }
-            }
-            tx.submit();
+            ListenableFutures.addErrorLogging(
+                    new ManagedNewTransactionRunnerImpl(broker).callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+                        for (VrfEntry vrfEntry : vrfTables.getVrfEntry()) {
+                            if (origin == RouteOrigin.value(vrfEntry.getOrigin())) {
+                                tx.delete(LogicalDatastoreType.CONFIGURATION,
+                                        vpnVrfTableIid.child(VrfEntry.class, vrfEntry.key()));
+                            }
+                        }
+                    }), LOG, "Error removing VRF entries by origin");
         }
     }
 
@@ -621,11 +673,13 @@ public final class VpnUtil {
     public static void removeVrfEntries(DataBroker broker, String rd, List<VrfEntry> vrfEntries) {
         InstanceIdentifier<VrfTables> vpnVrfTableIid =
             InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).build();
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        for (VrfEntry vrfEntry : vrfEntries) {
-            tx.delete(LogicalDatastoreType.CONFIGURATION, vpnVrfTableIid.child(VrfEntry.class, vrfEntry.getKey()));
-        }
-        tx.submit();
+        ListenableFutures.addErrorLogging(
+                new ManagedNewTransactionRunnerImpl(broker).callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+                    for (VrfEntry vrfEntry : vrfEntries) {
+                        tx.delete(LogicalDatastoreType.CONFIGURATION,
+                                vpnVrfTableIid.child(VrfEntry.class, vrfEntry.key()));
+                    }
+                }), LOG, "Error removing VRF entries");
     }
 
     // TODO Clean up the exception handling
@@ -710,7 +764,7 @@ public final class VpnUtil {
     }
 
     static RouterInterface getRouterInterface(String interfaceName, String routerName) {
-        return new RouterInterfaceBuilder().setKey(new RouterInterfaceKey(interfaceName))
+        return new RouterInterfaceBuilder().withKey(new RouterInterfaceKey(interfaceName))
             .setInterfaceName(interfaceName).setRouterName(routerName).build();
     }
 
@@ -760,7 +814,8 @@ public final class VpnUtil {
         return read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId).isPresent();
     }
 
-    static Optional<List<String>> getVpnHandlingIpv4AssociatedWithInterface(DataBroker broker, String interfaceName) {
+    public static Optional<List<String>> getVpnHandlingAssociatedWithInterface(DataBroker broker,
+            String interfaceName) {
         InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
         Optional<List<String>> vpnOptional = Optional.absent();
         Optional<VpnInterface> optConfiguredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION,
@@ -772,9 +827,6 @@ public final class VpnUtil {
             if (optVpnInstanceList.isPresent()) {
                 List<String> vpnList = new ArrayList<>();
                 for (VpnInstanceNames vpnInstance : optVpnInstanceList.get()) {
-                    if (vpnInstance.getAssociatedSubnetType().equals(AssociatedSubnetType.V6Subnet)) {
-                        continue;
-                    }
                     vpnList.add(vpnInstance.getVpnName());
                 }
                 vpnOptional = Optional.of(vpnList);
@@ -786,7 +838,7 @@ public final class VpnUtil {
     public static String getIpPrefix(String prefix) {
         String[] prefixValues = prefix.split("/");
         if (prefixValues.length == 1) {
-            prefix = prefix + PREFIX_SEPARATOR + DEFAULT_PREFIX_LENGTH;
+            prefix = NWUtil.toIpPrefix(prefix);
         }
         return prefix;
     }
@@ -805,87 +857,34 @@ public final class VpnUtil {
 
         };
 
-    public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
+    @Deprecated
+    private 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 <T extends DataObject> void asyncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
-        InstanceIdentifier<T> path, T data) {
-        asyncUpdate(broker, datastoreType, path, data, DEFAULT_CALLBACK);
-    }
-
-    public static <T extends DataObject> void asyncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
-        InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.merge(datastoreType, path, data, true);
-        Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor());
-    }
-
-    public static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
-        InstanceIdentifier<T> path, T data) {
-        asyncWrite(broker, datastoreType, path, data, DEFAULT_CALLBACK);
-    }
-
-    public static <T extends DataObject> void asyncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
-        InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.put(datastoreType, path, data, WriteTransaction.CREATE_MISSING_PARENTS);
-        Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor());
-    }
-
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static <T extends DataObject> void tryDelete(DataBroker broker, LogicalDatastoreType datastoreType,
-        InstanceIdentifier<T> path) {
         try {
-            delete(broker, datastoreType, path, DEFAULT_CALLBACK);
-        } catch (SchemaValidationFailedException sve) {
-            LOG.info("tryDelete: Could not delete {}. SchemaValidationFailedException: {}", path, sve.getMessage());
-        } catch (Exception e) {
-            LOG.info("tryDelete: Could not delete {}. Unhandled error: {}", path, e.getMessage());
+            return SingleTransactionDataBroker.syncReadOptional(broker, datastoreType, path);
+        } catch (ReadFailedException e) {
+            throw new RuntimeException(e);
         }
     }
 
-    public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-        InstanceIdentifier<T> path) {
-        delete(broker, datastoreType, path, DEFAULT_CALLBACK);
-    }
-
-
-    public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-        InstanceIdentifier<T> path, FutureCallback<Void> callback) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.delete(datastoreType, path);
-        Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor());
-    }
-
+    @Deprecated
     public static <T extends DataObject> void syncWrite(DataBroker broker, LogicalDatastoreType datastoreType,
         InstanceIdentifier<T> path, T data) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.put(datastoreType, path, data, WriteTransaction.CREATE_MISSING_PARENTS);
-
         try {
-            tx.submit().get();
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("syncWrite: Error writing to datastore (path, data) : ({}, {})", path, data);
+            SingleTransactionDataBroker.syncWrite(broker, datastoreType, path, data);
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("syncWrite: Error writing to datastore (path, data) : ({}, {})", path, data, e);
             throw new RuntimeException(e.getMessage(), e);
         }
     }
 
+    @Deprecated
     public static <T extends DataObject> void syncUpdate(DataBroker broker, LogicalDatastoreType datastoreType,
         InstanceIdentifier<T> path, T data) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.merge(datastoreType, path, data, true);
-
         try {
-            tx.submit().get();
-        } catch (InterruptedException | ExecutionException e) {
-            LOG.error("syncUpdate: Error writing to datastore (path, data) : ({}, {})", path, data);
+            SingleTransactionDataBroker.syncUpdate(broker, datastoreType, path, data);
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("syncUpdate: Error writing to datastore (path, data) : ({}, {})", path, data, e);
             throw new RuntimeException(e.getMessage(), e);
         }
     }
@@ -947,138 +946,37 @@ public final class VpnUtil {
                 .build();
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static void removePrefixToInterfaceForVpnId(DataBroker broker, long vpnId, WriteTransaction writeTxn) {
-        try {
-            // Clean up PrefixToInterface Operational DS
-            if (writeTxn != null) {
-                writeTxn.delete(LogicalDatastoreType.OPERATIONAL,
-                    InstanceIdentifier.builder(PrefixToInterface.class).child(
-                        VpnIds.class, new VpnIdsKey(vpnId)).build());
-            } else {
-                delete(broker, LogicalDatastoreType.OPERATIONAL,
-                    InstanceIdentifier.builder(PrefixToInterface.class).child(VpnIds.class,
-                        new VpnIdsKey(vpnId)).build(),
-                    DEFAULT_CALLBACK);
-            }
-        } catch (Exception e) {
-            LOG.error("removePrefixToInterfaceForVpnId: Exception during cleanup of PrefixToInterface for VPN ID {}",
-                    vpnId, e);
-        }
-    }
-
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static void removeVpnExtraRouteForVpn(DataBroker broker, String vpnName, WriteTransaction writeTxn) {
-        try {
-            // Clean up VPNExtraRoutes Operational DS
-            if (writeTxn != null) {
-                writeTxn.delete(LogicalDatastoreType.OPERATIONAL,
-                        InstanceIdentifier.builder(VpnToExtraroutes.class)
-                                .child(Vpn.class, new VpnKey(vpnName)).build());
-            } else {
-                delete(broker, LogicalDatastoreType.OPERATIONAL,
-                        InstanceIdentifier.builder(VpnToExtraroutes.class)
-                                .child(Vpn.class, new VpnKey(vpnName)).build(),
-                        DEFAULT_CALLBACK);
-            }
-        } catch (Exception e) {
-            LOG.error("removeVpnExtraRouteForVpna: Exception during cleanup of VPNToExtraRoute for VPN {}",
-                    vpnName, e);
-        }
+    public static void removePrefixToInterfaceForVpnId(long vpnId, @Nonnull WriteTransaction operTx) {
+        // Clean up PrefixToInterface Operational DS
+        operTx.delete(LogicalDatastoreType.OPERATIONAL,
+            InstanceIdentifier.builder(PrefixToInterface.class).child(VpnIds.class, new VpnIdsKey(vpnId)).build());
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static void removeVpnOpInstance(DataBroker broker, String vpnName, WriteTransaction writeTxn) {
-        try {
-            // Clean up VPNInstanceOpDataEntry
-            if (writeTxn != null) {
-                writeTxn.delete(LogicalDatastoreType.OPERATIONAL, getVpnInstanceOpDataIdentifier(vpnName));
-            } else {
-                delete(broker, LogicalDatastoreType.OPERATIONAL, getVpnInstanceOpDataIdentifier(vpnName),
-                    DEFAULT_CALLBACK);
-            }
-        } catch (Exception e) {
-            LOG.error("removeVpnOpInstance: Exception during cleanup of VPNInstanceOpDataEntry for VPN {}",
-                    vpnName, e);
-        }
+    public static void removeVpnExtraRouteForVpn(String vpnName, @Nonnull WriteTransaction operTx) {
+        // Clean up VPNExtraRoutes Operational DS
+        operTx.delete(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.builder(VpnToExtraroutes.class).child(Vpn.class, new VpnKey(vpnName)).build());
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public static void removeVpnInstanceToVpnId(DataBroker broker, String vpnName, WriteTransaction writeTxn) {
-        try {
-            if (writeTxn != null) {
-                writeTxn.delete(LogicalDatastoreType.CONFIGURATION,
-                                VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnName));
-            } else {
-                delete(broker, LogicalDatastoreType.CONFIGURATION,
-                       VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnName),
-                    DEFAULT_CALLBACK);
-            }
-        } catch (Exception e) {
-            LOG.error("removeVpnInstanceToVpnId: Exception during clean up of VpnInstanceToVpnId for VPN {}",
-                    vpnName, e);
-        }
+    public static void removeVpnOpInstance(String vpnName, @Nonnull WriteTransaction operTx) {
+        // Clean up VPNInstanceOpDataEntry
+        operTx.delete(LogicalDatastoreType.OPERATIONAL, getVpnInstanceOpDataIdentifier(vpnName));
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static void removeVpnIdToVpnInstance(DataBroker broker, long vpnId, WriteTransaction writeTxn) {
-        try {
-            if (writeTxn != null) {
-                writeTxn.delete(LogicalDatastoreType.CONFIGURATION, getVpnIdToVpnInstanceIdentifier(vpnId));
-            } else {
-                delete(broker, LogicalDatastoreType.CONFIGURATION, getVpnIdToVpnInstanceIdentifier(vpnId),
-                    DEFAULT_CALLBACK);
-            }
-        } catch (Exception e) {
-            LOG.error("removeVpnIdToVpnInstance: Exception during clean up of VpnIdToVpnInstance for VPNID {}",
-                    vpnId, e);
-        }
+    public static void removeVpnInstanceToVpnId(String vpnName, @Nonnull WriteTransaction confTx) {
+        confTx.delete(LogicalDatastoreType.CONFIGURATION, VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnName));
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static void removeVrfTableForVpn(DataBroker broker, String vpnName, WriteTransaction writeTxn) {
-        // Clean up FIB Entries Config DS
-        try {
-            if (writeTxn != null) {
-                writeTxn.delete(LogicalDatastoreType.CONFIGURATION,
-                    InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class,
-                        new VrfTablesKey(vpnName)).build());
-            } else {
-                delete(broker, LogicalDatastoreType.CONFIGURATION,
-                    InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class,
-                        new VrfTablesKey(vpnName)).build(),
-                    DEFAULT_CALLBACK);
-            }
-        } catch (Exception e) {
-            LOG.error("removeVrfTableForVpn: Exception during clean up of VrfTable from FIB for VPN {}",
-                    vpnName, e);
-        }
+    public static void removeVpnIdToVpnInstance(long vpnId, @Nonnull WriteTransaction confTx) {
+        confTx.delete(LogicalDatastoreType.CONFIGURATION, getVpnIdToVpnInstanceIdentifier(vpnId));
     }
 
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public static void removeL3nexthopForVpnId(DataBroker broker, long vpnId, WriteTransaction writeTxn) {
-        try {
-            // Clean up L3NextHop Operational DS
-            if (writeTxn != null) {
-                writeTxn.delete(LogicalDatastoreType.OPERATIONAL,
-                    InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
-                        new VpnNexthopsKey(vpnId)).build());
-            } else {
-                delete(broker, LogicalDatastoreType.OPERATIONAL,
-                    InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
-                        new VpnNexthopsKey(vpnId)).build(),
-                    DEFAULT_CALLBACK);
-            }
-        } catch (Exception e) {
-            LOG.error("removeL3nexthopForVpnId: Exception during cleanup of L3NextHop for VPN ID {}", vpnId, e);
-        }
+    public static void removeL3nexthopForVpnId(long vpnId, @Nonnull WriteTransaction operTx) {
+        // Clean up L3NextHop Operational DS
+        operTx.delete(LogicalDatastoreType.OPERATIONAL,
+            InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class, new VpnNexthopsKey(vpnId)).build());
     }
 
     public static void scheduleVpnInterfaceForRemoval(DataBroker broker,String interfaceName, BigInteger dpnId,
@@ -1087,7 +985,7 @@ public final class VpnUtil {
         InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
             VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnInstanceName);
         VpnInterfaceOpDataEntry interfaceToUpdate =
-            new VpnInterfaceOpDataEntryBuilder().setKey(new VpnInterfaceOpDataEntryKey(interfaceName,
+            new VpnInterfaceOpDataEntryBuilder().withKey(new VpnInterfaceOpDataEntryKey(interfaceName,
             vpnInstanceName)).setName(interfaceName).setDpnId(dpnId).setVpnInstanceName(vpnInstanceName)
             .setScheduledForRemove(isScheduledToRemove).build();
         if (writeOperTxn != null) {
@@ -1097,35 +995,136 @@ public final class VpnUtil {
         }
     }
 
-    protected static void createLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp, String
-            portName, String macAddress) {
+    public static void createLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp, String
+            portName, String macAddress, WriteTransaction writeOperTxn) {
         synchronized ((vpnName + fixedIp).intern()) {
             InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
             LearntVpnVipToPortBuilder builder =
-                    new LearntVpnVipToPortBuilder().setKey(new LearntVpnVipToPortKey(fixedIp, vpnName)).setVpnName(
+                    new LearntVpnVipToPortBuilder().withKey(new LearntVpnVipToPortKey(fixedIp, vpnName)).setVpnName(
                             vpnName).setPortFixedip(fixedIp).setPortName(portName)
                             .setMacAddress(macAddress.toLowerCase(Locale.getDefault()))
                             .setCreationTime(new SimpleDateFormat("MM/dd/yyyy h:mm:ss a").format(new Date()));
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, builder.build());
-            LOG.debug("createLearntVpnVipToPort: ARP learned for fixedIp: {}, vpn {}, interface {}, mac {},"
-                    + " isSubnetIp {} added to VpnPortipToPort DS", fixedIp, vpnName, portName, macAddress);
+            if (writeOperTxn != null) {
+                writeOperTxn.put(LogicalDatastoreType.OPERATIONAL, id, builder.build(), true);
+            } else {
+                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, builder.build());
+            }
+            LOG.debug("createLearntVpnVipToPort: ARP/NA learned for fixedIp: {}, vpn {}, interface {}, mac {},"
+                    + " added to LearntVpnVipToPort DS", fixedIp, vpnName, portName, macAddress);
         }
     }
 
     private static InstanceIdentifier<LearntVpnVipToPort> buildLearntVpnVipToPortIdentifier(String vpnName,
             String fixedIp) {
-        InstanceIdentifier<LearntVpnVipToPort> id =
-                InstanceIdentifier.builder(LearntVpnVipToPortData.class).child(LearntVpnVipToPort.class,
-                        new LearntVpnVipToPortKey(fixedIp, vpnName)).build();
-        return id;
+        return InstanceIdentifier.builder(LearntVpnVipToPortData.class).child(LearntVpnVipToPort.class,
+                new LearntVpnVipToPortKey(fixedIp, vpnName)).build();
     }
 
-    protected static void removeLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp) {
+    public static void removeLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp,
+            WriteTransaction writeOperTxn) {
         synchronized ((vpnName + fixedIp).intern()) {
             InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
+            if (writeOperTxn != null) {
+                writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, id);
+            } else {
+                MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
+            }
+            LOG.debug("removeLearntVpnVipToPort: Deleted LearntVpnVipToPort entry for fixedIp: {}, vpn {}",
+                fixedIp, vpnName);
+        }
+    }
+
+    protected static void removeVpnPortFixedIpToPort(DataBroker broker, String vpnName, String fixedIp,
+                                                     WriteTransaction writeConfigTxn) {
+        synchronized ((vpnName + fixedIp).intern()) {
+            InstanceIdentifier<VpnPortipToPort> id = buildVpnPortipToPortIdentifier(vpnName, fixedIp);
+            if (writeConfigTxn != null) {
+                writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, id);
+            } else {
+                MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, id);
+            }
+            LOG.debug("removeVpnPortFixedIpToPort: Deleted VpnPortipToPort entry for fixedIp: {}, vpn {}",
+                fixedIp, vpnName);
+        }
+    }
+
+    public static void createLearntVpnVipToPortEvent(DataBroker broker, String vpnName, String srcIp, String destIP,
+                                                        String portName, String macAddress,
+                                                        LearntVpnVipToPortEventAction action,
+                                                        WriteTransaction writeOperTxn) {
+        String eventId = MicroTimestamp.INSTANCE.get();
+
+        InstanceIdentifier<LearntVpnVipToPortEvent> id = buildLearntVpnVipToPortEventIdentifier(eventId);
+        LearntVpnVipToPortEventBuilder builder = new LearntVpnVipToPortEventBuilder().withKey(
+                new LearntVpnVipToPortEventKey(eventId)).setVpnName(vpnName).setSrcFixedip(srcIp)
+                .setDestFixedip(destIP).setPortName(portName)
+                .setMacAddress(macAddress.toLowerCase(Locale.getDefault())).setEventAction(action);
+        if (writeOperTxn != null) {
+            writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, id);
+        } else {
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, id, builder.build());
+        }
+        LOG.info("createLearntVpnVipToPortEvent: ARP learn event created for fixedIp: {}, vpn {}, interface {},"
+                + " mac {} action {} eventId {}", srcIp, vpnName, portName, macAddress, action, eventId);
+    }
+
+    private static InstanceIdentifier<LearntVpnVipToPortEvent> buildLearntVpnVipToPortEventIdentifier(String eventId) {
+        InstanceIdentifier<LearntVpnVipToPortEvent> id = InstanceIdentifier.builder(LearntVpnVipToPortEventData.class)
+                .child(LearntVpnVipToPortEvent.class, new LearntVpnVipToPortEventKey(eventId)).build();
+        return id;
+    }
+
+    protected static void removeLearntVpnVipToPortEvent(DataBroker broker, String eventId,
+                                                        WriteTransaction writeOperTxn) {
+        InstanceIdentifier<LearntVpnVipToPortEvent> id = buildLearntVpnVipToPortEventIdentifier(eventId);
+        if (writeOperTxn != null) {
+            writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, id);
+        } else {
             MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, id);
-            LOG.debug("removeLearntVpnVipToPort: Delete learned ARP for fixedIp: {}, vpn {} removed from"
-                    + " VpnPortipToPort DS", fixedIp, vpnName);
+        }
+        LOG.info("removeLearntVpnVipToPortEvent: Deleted Event {}", eventId);
+
+    }
+
+    public static void removeMipAdjacency(DataBroker dataBroker, String vpnName, String vpnInterface, String prefix,
+                                          WriteTransaction writeConfigTxn) {
+        String ip = VpnUtil.getIpPrefix(prefix);
+        LOG.trace("Removing {} adjacency from Old VPN Interface {} ", ip, vpnInterface);
+        InstanceIdentifier<VpnInterface> vpnIfId = VpnUtil.getVpnInterfaceIdentifier(vpnInterface);
+        InstanceIdentifier<Adjacencies> path = vpnIfId.augmentation(Adjacencies.class);
+        //TODO: Remove synchronized?
+
+        Optional<Adjacencies> adjacencies = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
+        if (adjacencies.isPresent()) {
+            InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class)
+                    .child(VpnInterface.class, new VpnInterfaceKey(vpnInterface)).augmentation(Adjacencies.class)
+                    .child(Adjacency.class, new AdjacencyKey(ip)).build();
+            writeConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
+            LOG.error("removeMipAdjacency: Successfully Deleted Adjacency {} from interface {} vpn {}", ip,
+                    vpnInterface, vpnName);
+        }
+    }
+
+    public static void removeMipAdjAndLearntIp(DataBroker dataBroker, String vpnName,
+                                               String vpnInterface, String prefix) {
+        synchronized ((vpnName + prefix).intern()) {
+            InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, prefix);
+            MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+            LOG.info("removeMipAdjAndLearntIp: Delete learned ARP for fixedIp: {}, vpn {} removed from"
+                            + "VpnPortipToPort DS", prefix, vpnName);
+            String ip = VpnUtil.getIpPrefix(prefix);
+            InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpId = VpnUtil
+                    .getVpnInterfaceOpDataEntryIdentifier(vpnInterface, vpnName);
+            InstanceIdentifier<AdjacenciesOp> path = vpnInterfaceOpId.augmentation(AdjacenciesOp.class);
+            Optional<AdjacenciesOp> adjacenciesOp = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
+            if (adjacenciesOp.isPresent()) {
+                InstanceIdentifier<Adjacency> adjacencyIdentifier = InstanceIdentifier.builder(VpnInterfaces.class)
+                        .child(VpnInterface.class, new VpnInterfaceKey(vpnInterface)).augmentation(Adjacencies.class)
+                        .child(Adjacency.class, new AdjacencyKey(ip)).build();
+                MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, adjacencyIdentifier);
+                LOG.info("removeMipAdjAndLearntIp: Successfully Deleted Adjacency {} from interface {} vpn {}", ip,
+                        vpnInterface, vpnName);
+            }
         }
     }
 
@@ -1153,7 +1152,7 @@ public final class VpnUtil {
         return null;
     }
 
-    static LearntVpnVipToPort getLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp) {
+    public static LearntVpnVipToPort getLearntVpnVipToPort(DataBroker broker, String vpnName, String fixedIp) {
         InstanceIdentifier<LearntVpnVipToPort> id = buildLearntVpnVipToPortIdentifier(vpnName, fixedIp);
         Optional<LearntVpnVipToPort> learntVpnVipToPort = read(broker, LogicalDatastoreType.OPERATIONAL, id);
         if (learntVpnVipToPort.isPresent()) {
@@ -1234,7 +1233,7 @@ public final class VpnUtil {
         return extNetwork != null ? extNetwork.getVpnid() : null;
     }
 
-    static List<Uuid> getExternalNetworkRouterIds(DataBroker dataBroker, Uuid networkId) {
+    public static List<Uuid> getExternalNetworkRouterIds(DataBroker dataBroker, Uuid networkId) {
         Networks extNetwork = getExternalNetwork(dataBroker, networkId);
         return extNetwork != null ? extNetwork.getRouterIds() : Collections.emptyList();
     }
@@ -1270,43 +1269,58 @@ public final class VpnUtil {
         return InstanceIdentifier.create(Subnetmaps.class);
     }
 
-    public static FlowEntity buildL3vpnGatewayFlow(BigInteger dpId, String gwMacAddress, long vpnId,
+    public static FlowEntity buildL3vpnGatewayFlow(DataBroker broker, BigInteger dpId, String gwMacAddress, long vpnId,
             long subnetVpnId) {
         List<MatchInfo> mkMatches = new ArrayList<>();
+        Subnetmap smap = null;
         mkMatches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
         mkMatches.add(new MatchEthernetDestination(new MacAddress(gwMacAddress)));
         List<InstructionInfo> mkInstructions = new ArrayList<>();
         mkInstructions.add(new InstructionGotoTable(NwConstants.L3_FIB_TABLE));
         if (subnetVpnId != VpnConstants.INVALID_ID) {
+            String vpnName = getVpnName(broker, subnetVpnId);
+            if (vpnName != null) {
+                smap = getSubnetmapFromItsUuid(broker, Uuid.getDefaultInstance(vpnName));
+                if (smap != null && smap.getSubnetIp() != null) {
+                    IpVersionChoice ipVersionChoice = getIpVersionFromString(smap.getSubnetIp());
+                    if (ipVersionChoice == IpVersionChoice.IPV4) {
+                        mkMatches.add(MatchEthernetType.IPV4);
+                    } else {
+                        mkMatches.add(MatchEthernetType.IPV6);
+                    }
+                }
+            }
+
             BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(subnetVpnId);
             mkInstructions.add(new InstructionWriteMetadata(subnetIdMetaData, MetaDataUtil.METADATA_MASK_VRFID));
         }
 
-        String flowId = getL3VpnGatewayFlowRef(NwConstants.L3_GW_MAC_TABLE, dpId, vpnId, gwMacAddress);
+        String flowId = getL3VpnGatewayFlowRef(NwConstants.L3_GW_MAC_TABLE, dpId, vpnId, gwMacAddress, subnetVpnId);
 
         return MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_GW_MAC_TABLE,
                 flowId, 20, flowId, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, mkMatches, mkInstructions);
     }
 
-    private static String getL3VpnGatewayFlowRef(short l3GwMacTable, BigInteger dpId, long vpnId, String gwMacAddress) {
+    private static String getL3VpnGatewayFlowRef(short l3GwMacTable, BigInteger dpId, long vpnId,
+                                                 String gwMacAddress, long subnetVpnId) {
         return gwMacAddress + NwConstants.FLOWID_SEPARATOR + vpnId + NwConstants.FLOWID_SEPARATOR + dpId
-            + NwConstants.FLOWID_SEPARATOR + l3GwMacTable;
+            + NwConstants.FLOWID_SEPARATOR + l3GwMacTable + NwConstants.FLOWID_SEPARATOR + subnetVpnId;
     }
 
     public static void lockSubnet(LockManagerService lockManager, String subnetId) {
         TryLockInput input =
             new TryLockInputBuilder().setLockName(subnetId).setTime(3000L).setTimeUnit(TimeUnits.Milliseconds).build();
-        Future<RpcResult<Void>> result = lockManager.tryLock(input);
-        String errMsg = "Unable to getLock for subnet " + subnetId;
+        Future<RpcResult<TryLockOutput>> result = lockManager.tryLock(input);
         try {
             if (result != null && result.get().isSuccessful()) {
                 LOG.debug("lockSubnet: Acquired lock for {}", subnetId);
             } else {
-                throw new RuntimeException(errMsg);
+                LOG.error("Unable to get lock for subnet {}", subnetId);
+                throw new RuntimeException("Unable to get lock for subnet " + subnetId);
             }
         } catch (InterruptedException | ExecutionException e) {
-            LOG.error(errMsg);
-            throw new RuntimeException(e.getMessage(), e);
+            LOG.error("Unable to get lock for subnet {}", subnetId, e);
+            throw new RuntimeException("Unable to get lock for subnet " + subnetId, e);
         }
     }
 
@@ -1314,7 +1328,7 @@ public final class VpnUtil {
     @SuppressWarnings("checkstyle:AvoidHidingCauseException")
     public static void unlockSubnet(LockManagerService lockManager, String subnetId) {
         UnlockInput input = new UnlockInputBuilder().setLockName(subnetId).build();
-        Future<RpcResult<Void>> result = lockManager.unlock(input);
+        Future<RpcResult<UnlockOutput>> result = lockManager.unlock(input);
         try {
             if (result != null && result.get().isSuccessful()) {
                 LOG.debug("unlockSubnet: Unlocked {}", subnetId);
@@ -1327,16 +1341,21 @@ public final class VpnUtil {
         }
     }
 
-    static Optional<IpAddress> getGatewayIpAddressFromInterface(String srcInterface,
+    static Optional<IpAddress> getIpv4GatewayAddressFromInterface(String srcInterface,
             INeutronVpnManager neutronVpnService) {
         Optional<IpAddress> gatewayIp = Optional.absent();
         if (neutronVpnService != null) {
             //TODO(Gobinath): Need to fix this as assuming port will belong to only one Subnet would be incorrect"
             Port port = neutronVpnService.getNeutronPort(srcInterface);
-            if (port != null && port.getFixedIps() != null && port.getFixedIps().get(0) != null
-                && port.getFixedIps().get(0).getSubnetId() != null) {
-                gatewayIp = Optional.of(
-                    neutronVpnService.getNeutronSubnet(port.getFixedIps().get(0).getSubnetId()).getGatewayIp());
+            if (port != null && port.getFixedIps() != null) {
+                for (FixedIps portIp: port.getFixedIps()) {
+                    if (portIp.getIpAddress().getIpv6Address() != null) {
+                        // Skip IPv6 address
+                        continue;
+                    }
+                    gatewayIp = Optional.of(
+                            neutronVpnService.getNeutronSubnet(portIp.getSubnetId()).getGatewayIp());
+                }
             }
         } else {
             LOG.error("getGatewayIpAddressFromInterface: neutron vpn service is not configured."
@@ -1386,7 +1405,8 @@ public final class VpnUtil {
                         interfaceName, dpnId.toString(), vpnIdsOptional.get().getVpnInstanceName());
                 return;
             }
-            FlowEntity flowEntity = VpnUtil.buildL3vpnGatewayFlow(dpnId, gwMac, vpnId, VpnConstants.INVALID_ID);
+            FlowEntity flowEntity = VpnUtil.buildL3vpnGatewayFlow(dataBroker, dpnId, gwMac, vpnId,
+                    VpnConstants.INVALID_ID);
             if (addOrRemove == NwConstants.ADD_FLOW) {
                 mdsalManager.addFlowToTx(flowEntity, writeInvTxn);
             } else if (addOrRemove == NwConstants.DEL_FLOW) {
@@ -1419,12 +1439,20 @@ public final class VpnUtil {
         if (subnet.isPresent()) {
             Class<? extends IpVersionBase> ipVersionBase = subnet.get().getIpVersion();
             if (ipVersionBase.equals(IpVersionV4.class)) {
-                LOG.trace("getVpnSubnetGatewayIp: Obtained subnet {} for vpn interface",
-                        subnet.get().getUuid().getValue());
-                IpAddress gwIp = subnet.get().getGatewayIp();
-                if (gwIp != null && gwIp.getIpv4Address() != null) {
-                    gwIpAddress = Optional.of(gwIp.getIpv4Address().getValue());
+                Subnetmap subnetmap = getSubnetmapFromItsUuid(dataBroker, subnetUuid);
+                if (subnetmap != null && subnetmap.getRouterInterfaceFixedIp() != null) {
+                    LOG.trace("getVpnSubnetGatewayIp: Obtained subnetMap {} for vpn interface",
+                            subnetmap.getId().getValue());
+                    gwIpAddress = Optional.of(subnetmap.getRouterInterfaceFixedIp());
+                } else {
+                    //For direct L3VPN to network association (no router) continue to use subnet-gateway IP
+                    IpAddress gwIp = subnet.get().getGatewayIp();
+                    if (gwIp != null && gwIp.getIpv4Address() != null) {
+                        gwIpAddress = Optional.of(gwIp.getIpv4Address().getValue());
+                    }
                 }
+                LOG.trace("getVpnSubnetGatewayIp: Obtained subnet-gw ip {} for vpn interface",
+                        gwIpAddress.get());
             }
         }
         return gwIpAddress;
@@ -1509,7 +1537,7 @@ public final class VpnUtil {
         java.util.Optional<String> allocatedRd = VpnExtraRouteHelper
                 .getRdAllocatedForExtraRoute(dataBroker, vpnId, prefix, nextHop);
         if (allocatedRd.isPresent()) {
-            return java.util.Optional.of(allocatedRd.get());
+            return allocatedRd;
         }
 
         //Check if rd is already allocated for this extraroute behind the same CSS. If yes, reuse it
@@ -1537,9 +1565,8 @@ public final class VpnUtil {
             rd = dpnId.toString();
             LOG.debug("Internal vpn {} Returning DpnId {} as rd", vpnName, rd);
         } else {
-            LOG.trace(
-                    "Removing used rds {} from available rds {} vpnid {} . prefix is {} , vpname- {}, dpnId- {},"
-                    + " adj - {}", usedRds, availableRds, vpnId, prefix, vpnName, dpnId);
+            LOG.trace("Removing used rds {} from available rds {} vpnid {} . prefix is {} , vpname- {}, dpnId- {}",
+                    usedRds, availableRds, vpnId, prefix, vpnName, dpnId);
             availableRds.removeAll(usedRds);
             if (availableRds.isEmpty()) {
                 LOG.error("No rd available from VpnInstance to allocate for prefix {}", prefix);
@@ -1575,16 +1602,16 @@ public final class VpnUtil {
     static void bindService(final String vpnInstanceName, final String interfaceName, DataBroker dataBroker,
                             boolean isTunnelInterface, JobCoordinator jobCoordinator) {
         jobCoordinator.enqueueJob(interfaceName,
-            () -> {
-                WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
-                BoundServices serviceInfo = isTunnelInterface
-                        ? VpnUtil.getBoundServicesForTunnelInterface(vpnInstanceName, interfaceName)
-                        : getBoundServicesForVpnInterface(dataBroker, vpnInstanceName, interfaceName);
-                writeTxn.put(LogicalDatastoreType.CONFIGURATION, InterfaceUtils.buildServiceId(interfaceName,
-                        ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
-                        serviceInfo, WriteTransaction.CREATE_MISSING_PARENTS);
-                return Collections.singletonList(writeTxn.submit());
-            }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+            () -> Collections.singletonList(
+                    new ManagedNewTransactionRunnerImpl(dataBroker).callWithNewReadWriteTransactionAndSubmit(tx -> {
+                        BoundServices serviceInfo = isTunnelInterface
+                                ? VpnUtil.getBoundServicesForTunnelInterface(vpnInstanceName, interfaceName)
+                                : getBoundServicesForVpnInterface(dataBroker, vpnInstanceName, interfaceName);
+                        tx.put(LogicalDatastoreType.CONFIGURATION, InterfaceUtils.buildServiceId(interfaceName,
+                                ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
+                                        NwConstants.L3VPN_SERVICE_INDEX)),
+                                serviceInfo, WriteTransaction.CREATE_MISSING_PARENTS);
+                    })), SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
     }
 
     static BoundServices getBoundServicesForVpnInterface(DataBroker broker, String vpnName, String interfaceName) {
@@ -1623,17 +1650,13 @@ public final class VpnUtil {
             JobCoordinator jobCoordinator) {
         if (!isInterfaceStateDown) {
             jobCoordinator.enqueueJob(vpnInterfaceName,
-                () -> {
-                    WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
-                    writeTxn.delete(LogicalDatastoreType.CONFIGURATION,
-                            InterfaceUtils.buildServiceId(vpnInterfaceName,
-                                    ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
-                                            NwConstants.L3VPN_SERVICE_INDEX)));
-
-                    List<ListenableFuture<Void>> futures = new ArrayList<>();
-                    futures.add(writeTxn.submit());
-                    return futures;
-                }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+                () -> Collections.singletonList(new ManagedNewTransactionRunnerImpl(
+                        dataBroker).callWithNewWriteOnlyTransactionAndSubmit(tx ->
+                        tx.delete(LogicalDatastoreType.CONFIGURATION,
+                                InterfaceUtils.buildServiceId(vpnInterfaceName,
+                                        ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
+                                                NwConstants.L3VPN_SERVICE_INDEX))))),
+                SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
         }
     }
 
@@ -1660,7 +1683,7 @@ public final class VpnUtil {
         return optionalSubnets.isPresent() ? optionalSubnets.get() : null;
     }
 
-    static Uuid getSubnetFromExternalRouterByIp(DataBroker dataBroker, Uuid routerId, String ip) {
+    public static Uuid getSubnetFromExternalRouterByIp(DataBroker dataBroker, Uuid routerId, String ip) {
         Routers externalRouter = VpnUtil.getExternalRouter(dataBroker, routerId.getValue());
         if (externalRouter != null && externalRouter.getExternalIps() != null) {
             for (ExternalIps externalIp : externalRouter.getExternalIps()) {
@@ -1677,8 +1700,8 @@ public final class VpnUtil {
     }
 
     static Boolean getIsExternal(Network network) {
-        return network.getAugmentation(NetworkL3Extension.class) != null
-                && network.getAugmentation(NetworkL3Extension.class).isExternal();
+        return network.augmentation(NetworkL3Extension.class) != null
+                && network.augmentation(NetworkL3Extension.class).isExternal();
     }
 
     @SuppressWarnings("checkstyle:linelength")
@@ -1930,11 +1953,383 @@ public final class VpnUtil {
         return ipchoice;
     }
 
-    public static void unsetScheduledToRemoveForVpnInterface(DataBroker dataBroker, String interfaceName) {
-        VpnInterfaceBuilder builder = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(interfaceName))
+    public static ListenableFuture<Void> unsetScheduledToRemoveForVpnInterface(ManagedNewTransactionRunner txRunner,
+            String interfaceName) {
+        VpnInterfaceBuilder builder = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(interfaceName))
                 .setScheduledForRemove(false);
-        MDSALDataStoreUtils.asyncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                VpnUtil.getVpnInterfaceIdentifier(interfaceName), builder.build(), DEFAULT_CALLBACK);
+        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.merge(LogicalDatastoreType.OPERATIONAL,
+                VpnUtil.getVpnInterfaceIdentifier(interfaceName), builder.build(),
+                WriteTransaction.CREATE_MISSING_PARENTS));
+    }
+
+    /**
+     * Adds router port for all elan network of type VLAN which is a part of vpnName in the DPN with dpnId.
+     * This will create the vlan footprint in the DPN's which are member of the VPN.
+     *
+     * @param vpnName the vpnName
+     * @param dpnId  the DPN id
+     * @param dataBroker the data Broker
+     */
+    public static void addRouterPortToElanForVlanInDpn(String vpnName, BigInteger dpnId , DataBroker dataBroker) {
+        Map<String,String> elanInstanceRouterPortMap = VpnUtil.getElanInstanceRouterPortMap(dataBroker, vpnName);
+        for (Entry<String, String> elanInstanceRouterEntry : elanInstanceRouterPortMap.entrySet()) {
+            addRouterPortToElanDpn(elanInstanceRouterEntry.getKey(), elanInstanceRouterEntry.getValue(),
+                    vpnName, dpnId, dataBroker);
+        }
+    }
+
+    /**
+     * Removes router port for all elan network of type VLAN which is a part of vpnName in the DPN with dpnId.
+     * This will remove the  vlan footprint in all the DPN's which are member of the VPN.
+     *
+     * @param vpnName the vpn name
+     * @param dpnId  the DPN id
+     * @param dataBroker the data Broker
+     */
+    public static void removeRouterPortFromElanForVlanInDpn(String vpnName, BigInteger dpnId , DataBroker dataBroker) {
+        Map<String,String> elanInstanceRouterPortMap = VpnUtil.getElanInstanceRouterPortMap(dataBroker, vpnName);
+        for (Entry<String, String> elanInstanceRouterEntry : elanInstanceRouterPortMap.entrySet()) {
+            removeRouterPortFromElanDpn(elanInstanceRouterEntry.getKey(), elanInstanceRouterEntry.getValue(),
+                    vpnName, dpnId, dataBroker);
+        }
+    }
+
+    /**
+     * Adds router port for all elan network of type VLAN which is a part of vpnName in all the DPN which has a port
+     * This will create the vlan footprint in all the DPN's which are member of the VPN.
+     *
+     * @param vpnName the vpn name
+     * @param dataBroker the data broker
+     */
+    public static void addRouterPortToElanDpnListForVlaninAllDpn(String vpnName, DataBroker dataBroker) {
+        Map<String,String> elanInstanceRouterPortMap = getElanInstanceRouterPortMap(dataBroker, vpnName);
+        Set<BigInteger> dpnList = getDpnInElan(dataBroker, elanInstanceRouterPortMap);
+        for (BigInteger dpnId : dpnList) {
+            for (Entry<String, String> elanInstanceRouterEntry : elanInstanceRouterPortMap.entrySet()) {
+                addRouterPortToElanDpn(elanInstanceRouterEntry.getKey(), elanInstanceRouterEntry.getValue(),
+                        vpnName, dpnId, dataBroker);
+            }
+        }
+    }
+
+    /**Removes router port for all elan network of type VLAN which is a part of vpnName in all the DPN which has a port
+     * This will remove the vlan footprint in all the DPN's which are member of the VPN.
+     *
+     * @param routerInterfacePortId this will add the current subnet router port id to the map for removal
+     * @param elanInstanceName the current elanstance being removed this will be added to map for removal
+     * @param vpnName the vpn name
+     * @param dataBroker the databroker
+     */
+    public static void removeRouterPortFromElanDpnListForVlanInAllDpn(String elanInstanceName,
+            String routerInterfacePortId, String vpnName, DataBroker dataBroker) {
+        Map<String,String> elanInstanceRouterPortMap = getElanInstanceRouterPortMap(dataBroker, vpnName);
+        elanInstanceRouterPortMap.put(elanInstanceName, routerInterfacePortId);
+        Set<BigInteger> dpnList = getDpnInElan(dataBroker, elanInstanceRouterPortMap);
+        for (BigInteger dpnId : dpnList) {
+            for (Entry<String, String> elanInstanceRouterEntry : elanInstanceRouterPortMap.entrySet()) {
+                removeRouterPortFromElanDpn(elanInstanceRouterEntry.getKey(), elanInstanceRouterEntry.getValue(),
+                        vpnName, dpnId, dataBroker);
+            }
+        }
+
+    }
+
+    public static Set<BigInteger> getDpnInElan(DataBroker dataBroker,  Map<String,String> elanInstanceRouterPortMap) {
+        Set<BigInteger> dpnIdSet = new HashSet<>();
+        for (String elanInstanceName : elanInstanceRouterPortMap.keySet()) {
+            InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationalDataPath(
+                    elanInstanceName);
+            Optional<ElanDpnInterfacesList> dpnInElanInterfaces = VpnUtil.read(dataBroker,
+                    LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
+            if (dpnInElanInterfaces.isPresent()) {
+                List<DpnInterfaces> dpnInterfaces = dpnInElanInterfaces.get().getDpnInterfaces();
+                for (DpnInterfaces dpnInterface : dpnInterfaces) {
+                    dpnIdSet.add(dpnInterface.getDpId());
+                }
+            }
+        }
+        return dpnIdSet;
+    }
+
+    public static void addRouterPortToElanDpn(String elanInstanceName, String routerInterfacePortId, String vpnName,
+            BigInteger dpnId, DataBroker dataBroker) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
+                elanInstanceName,dpnId);
+        synchronized (elanInstanceName.intern()) {
+            Optional<DpnInterfaces> dpnInElanInterfaces = VpnUtil.read(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(routerInterfacePortId)) {
+                elanInterfaceList.add(routerInterfacePortId);
+                dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                        .withKey(new DpnInterfacesKey(dpnId)).build();
+                VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                        elanDpnInterfaceId, dpnInterface);
+            }
+        }
+
+    }
+
+    public static void removeRouterPortFromElanDpn(String elanInstanceName, String routerInterfacePortId,
+            String vpnName, BigInteger dpnId, DataBroker dataBroker) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfaceId = getElanDpnInterfaceOperationalDataPath(
+                elanInstanceName,dpnId);
+        synchronized (elanInstanceName.intern()) {
+            Optional<DpnInterfaces> dpnInElanInterfaces = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    elanDpnInterfaceId);
+            List<String> elanInterfaceList;
+            DpnInterfaces dpnInterface;
+            if (!dpnInElanInterfaces.isPresent()) {
+                LOG.info("No interface in any dpn for {}", vpnName);
+                return;
+            } else {
+                dpnInterface = dpnInElanInterfaces.get();
+                elanInterfaceList = dpnInterface.getInterfaces();
+            }
+            if (!elanInterfaceList.contains(routerInterfacePortId)) {
+                LOG.info("Router port not present in DPN {} for VPN {}", dpnId, vpnName);
+                return;
+            }
+            elanInterfaceList.remove(routerInterfacePortId);
+            dpnInterface = new DpnInterfacesBuilder().setDpId(dpnId).setInterfaces(elanInterfaceList)
+                    .withKey(new DpnInterfacesKey(dpnId)).build();
+            VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    elanDpnInterfaceId, dpnInterface);
+        }
+
+    }
+
+    public static ElanInterface getElanInterfaceByElanInterfaceName(DataBroker broker, String elanInterfaceName) {
+        InstanceIdentifier<ElanInterface> elanInterfaceId = getElanInterfaceConfigurationDataPathId(elanInterfaceName);
+        return read(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId).orNull();
+    }
+
+    public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
+        return InstanceIdentifier.builder(ElanInterfaces.class)
+                .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
+    }
+
+    public static Optional<Interface> getInterface(DataBroker broker, String interfaceName) {
+        return read(broker, LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
+    }
+
+    public static DpnInterfaces getElanInterfaceInfoByElanDpn(DataBroker broker, String elanInstanceName,
+            BigInteger dpId) {
+        InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
+                dpId);
+        return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orNull();
+    }
+
+    public static String getExternalElanInterface(DataBroker broker, String elanInstanceName, BigInteger dpnId,
+            IInterfaceManager interfaceManager) {
+        DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(broker, elanInstanceName, dpnId);
+        if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
+            LOG.info("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId);
+            return null;
+        }
+
+        for (String dpnInterface : dpnInterfaces.getInterfaces()) {
+            if (interfaceManager.isExternalInterface(dpnInterface)) {
+                return dpnInterface;
+            }
+        }
+        return null;
+    }
+
+    public static boolean isVlan(ElanInstance elanInstance) {
+        return elanInstance != null && elanInstance.getSegmentType() != null
+                && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class)
+                && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
+    }
+
+    public static boolean isVlan(DataBroker databroker , String interfaceName) {
+        ElanInterface elanInterface = getElanInterfaceByElanInterfaceName(databroker, interfaceName);
+        if (elanInterface == null) {
+            return false;
+        }
+        ElanInstance  elanInstance = getElanInstanceByName(databroker, elanInterface.getElanInstanceName());
+        return isVlan(elanInstance);
+    }
+
+    public static ElanInstance getElanInstanceByName(DataBroker broker, String elanInstanceName) {
+        InstanceIdentifier<ElanInstance> elanIdentifierId =
+                ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName);
+        return read(broker, LogicalDatastoreType.CONFIGURATION, elanIdentifierId).orNull();
+    }
+
+    public static String getVpnNameFromElanIntanceName(DataBroker dataBroker, String elanInstanceName) {
+        Optional<Subnetmaps> subnetMapsData =
+                read(dataBroker, LogicalDatastoreType.CONFIGURATION, buildSubnetMapsWildCardPath());
+        if (subnetMapsData.isPresent()) {
+            List<Subnetmap> subnetMapList = subnetMapsData.get().getSubnetmap();
+            if (subnetMapList != null && !subnetMapList.isEmpty()) {
+                for (Subnetmap subnet : subnetMapList) {
+                    if (subnet.getNetworkId().getValue().equals(elanInstanceName)) {
+                        if (subnet.getVpnId() != null) {
+                            return subnet.getVpnId().getValue();
+                        }
+                    }
+                }
+            }
+        }
+        return null;
     }
 
+    public static Map<String, String> getElanInstanceRouterPortMap(DataBroker dataBroker, String vpnName) {
+        Map<String, String> elanInstanceRouterPortMap = new HashMap<>();
+        Optional<Subnetmaps> subnetMapsData =
+                read(dataBroker, LogicalDatastoreType.CONFIGURATION, buildSubnetMapsWildCardPath());
+        if (subnetMapsData.isPresent()) {
+            List<Subnetmap> subnetMapList = subnetMapsData.get().getSubnetmap();
+            if (subnetMapList != null && !subnetMapList.isEmpty()) {
+                for (Subnetmap subnet : subnetMapList) {
+                    if (subnet.getVpnId() != null && subnet.getVpnId().getValue().equals(vpnName)
+                            && subnet.getNetworkType().equals(NetworkType.VLAN)) {
+                        if (subnet.getRouterInterfacePortId() == null || subnet.getNetworkId() == null) {
+                            LOG.warn("The RouterInterfacePortId or NetworkId is null");
+                            continue;
+                        }
+                        String routerInterfacePortUuid = subnet.getRouterInterfacePortId().getValue();
+                        if (routerInterfacePortUuid != null && !routerInterfacePortUuid.isEmpty()) {
+                            elanInstanceRouterPortMap.put(subnet.getNetworkId().getValue(),routerInterfacePortUuid);
+                        }
+                    }
+                }
+            }
+        }
+        return elanInstanceRouterPortMap;
+    }
+
+    public static String getRouterPordIdFromElanInstance(DataBroker dataBroker, String elanInstanceName) {
+        Optional<Subnetmaps> subnetMapsData =
+                read(dataBroker, LogicalDatastoreType.CONFIGURATION, buildSubnetMapsWildCardPath());
+        if (subnetMapsData.isPresent()) {
+            List<Subnetmap> subnetMapList = subnetMapsData.get().getSubnetmap();
+            if (subnetMapList != null && !subnetMapList.isEmpty()) {
+                for (Subnetmap subnet : subnetMapList) {
+                    if (subnet.getNetworkId().getValue().equals(elanInstanceName)) {
+                        if (subnet.getRouterInterfacePortId() != null) {
+                            return subnet.getRouterInterfacePortId().getValue();
+                        }
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public static boolean shouldPopulateFibForVlan(DataBroker dataBroker, String vpnName, String elanInstanceName,
+            BigInteger dpnId, IInterfaceManager interfaceManager) {
+        Map<String,String> elanInstanceRouterPortMap = VpnUtil
+                .getElanInstanceRouterPortMap(dataBroker, vpnName);
+        boolean shouldPopulateFibForVlan = false;
+        if (!elanInstanceRouterPortMap.isEmpty()) {
+            shouldPopulateFibForVlan = true;
+        }
+        for (Entry<String, String> elanInstanceRouterEntry : elanInstanceRouterPortMap
+                .entrySet()) {
+            String currentElanInstance = elanInstanceRouterEntry.getKey();
+            if (elanInstanceName != null && elanInstanceName.equals(currentElanInstance)) {
+                continue;
+            }
+            String externalinterface = VpnUtil.getExternalElanInterface(dataBroker,
+                    currentElanInstance ,dpnId,
+                    interfaceManager);
+            if (externalinterface == null) {
+                shouldPopulateFibForVlan = false;
+                break;
+            }
+        }
+        return shouldPopulateFibForVlan;
+    }
+
+    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 InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationalDataPath(String elanInstanceName) {
+        return InstanceIdentifier.builder(ElanDpnInterfaces.class)
+                .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
+                .build();
+    }
+
+    public static boolean isMatchedPrefixToInterface(Prefixes prefix, VpnInterfaceOpDataEntry vpnInterface) {
+        if (prefix != null && vpnInterface != null) {
+            if (prefix.getDpnId() != null && vpnInterface.getDpnId() != null) {
+                if (prefix.getVpnInterfaceName() != null && vpnInterface.getName() != null) {
+                    return prefix.getDpnId().equals(vpnInterface.getDpnId())
+                            && prefix.getVpnInterfaceName().equalsIgnoreCase(vpnInterface.getName());
+                }
+            }
+        }
+        return false;
+    }
+
+    public static void removePrefixToInterfaceAdj(DataBroker dataBroker, Adjacency adj, long vpnId,
+                                                  VpnInterfaceOpDataEntry vpnInterfaceOpDataEntry,
+                                                  WriteTransaction writeOperTxn) {
+        if (writeOperTxn == null) {
+            ListenableFutures.addErrorLogging(
+                    new ManagedNewTransactionRunnerImpl(dataBroker).callWithNewWriteOnlyTransactionAndSubmit(tx ->
+                        removePrefixToInterfaceAdj(dataBroker, adj, vpnId, vpnInterfaceOpDataEntry, tx)), LOG,
+                    "Error removing prefix");
+            return;
+        }
+
+        Optional<Prefixes> prefix = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                VpnUtil.getPrefixToInterfaceIdentifier(vpnId,
+                        VpnUtil.getIpPrefix(adj.getIpAddress())));
+        List<Prefixes> prefixToInterface = new ArrayList<>();
+        List<Prefixes> prefixToInterfaceLocal = new ArrayList<>();
+        if (prefix.isPresent()) {
+            prefixToInterfaceLocal.add(prefix.get());
+        }
+        if (prefixToInterfaceLocal.isEmpty()) {
+            for (String nh : adj.getNextHopIpList()) {
+                prefix = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                        VpnUtil.getPrefixToInterfaceIdentifier(vpnId,
+                                VpnUtil.getIpPrefix(nh)));
+                if (prefix.isPresent()) {
+                    prefixToInterfaceLocal.add(prefix.get());
+                }
+            }
+        }
+        if (!prefixToInterfaceLocal.isEmpty()) {
+            prefixToInterface.addAll(prefixToInterfaceLocal);
+        }
+        for (Prefixes pref : prefixToInterface) {
+            if (VpnUtil.isMatchedPrefixToInterface(pref, vpnInterfaceOpDataEntry)) {
+                writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
+                        VpnUtil.getPrefixToInterfaceIdentifier(vpnId, pref.getIpAddress()));
+            }
+        }
+    }
+
+    public static void sendNeighborSolicationToOfGroup(Ipv6NdUtilService ipv6NdUtilService, Ipv6Address srcIpv6Address,
+            MacAddress srcMac, Ipv6Address dstIpv6Address, Long ofGroupId, BigInteger dpId) {
+        SendNeighborSolicitationToOfGroupInput input = new SendNeighborSolicitationToOfGroupInputBuilder()
+                .setSourceIpv6(srcIpv6Address).setSourceLlAddress(srcMac).setTargetIpAddress(dstIpv6Address)
+                .setOfGroupId(ofGroupId).setDpId(dpId).build();
+        try {
+            Future<RpcResult<SendNeighborSolicitationToOfGroupOutput>> result = ipv6NdUtilService
+                    .sendNeighborSolicitationToOfGroup(input);
+            RpcResult<SendNeighborSolicitationToOfGroupOutput> rpcResult = result.get();
+            if (!rpcResult.isSuccessful()) {
+                LOG.error("sendNeighborSolicitationToOfGroup: RPC Call failed for input={} and Errors={}", input,
+                        rpcResult.getErrors());
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to send NS packet to ELAN group, input={}", input, e);
+        }
+    }
 }