Migrate ElanUtils to use NamedLocks
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanInterfaceManager.java
index 17fea4c86fa5cd9e6806fc3d465698611c795daf..d0ec7557a63934b3b1b8e348c7dc4292c03d9fd6 100644 (file)
@@ -7,6 +7,11 @@
  */
 package org.opendaylight.netvirt.elan.internal;
 
+import static java.util.Collections.emptyList;
+import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
+import static org.opendaylight.infrautils.utils.concurrent.LoggingFutures.addErrorLogging;
 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
 
 import com.google.common.base.Optional;
@@ -24,18 +29,23 @@ import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
-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.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
+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.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.TransactionAdapter;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
+import org.opendaylight.genius.infra.TypedWriteTransaction;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.itm.globals.ITMConstants;
@@ -58,12 +68,11 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
-import org.opendaylight.genius.srm.RecoverableListener;
-import org.opendaylight.genius.srm.ServiceRecoveryRegistry;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
-import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
-import org.opendaylight.netvirt.elan.ElanException;
+import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
+import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
@@ -79,6 +88,8 @@ import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
+import org.opendaylight.serviceutils.srm.RecoverableListener;
+import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
 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.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
@@ -210,7 +221,15 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     @Override
     protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
         String interfaceName = del.getName();
-        ElanInstance elanInfo = elanInstanceCache.get(del.getElanInstanceName()).orNull();
+        String elanInstanceName = del.getElanInstanceName();
+        Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
+        if (elanInterfaces != null && elanInterfaces.contains(del)) {
+            elanInterfaces.remove(del);
+            if (elanInterfaces.isEmpty()) {
+                unProcessedElanInterfaces.remove(elanInstanceName);
+            }
+        }
+        ElanInstance elanInfo = elanInstanceCache.get(elanInstanceName).orNull();
         /*
          * Handling in case the elan instance is deleted.If the Elan instance is
          * deleted, there is no need to explicitly delete the elan interfaces
@@ -225,74 +244,79 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             // from Operational DS instead
             interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
         }
-        String elanInstanceName = elanInfo.getElanInstanceName();
         InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
                 interfaceName, interfaceInfo, this);
         jobCoordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
-    @SuppressWarnings("checkstyle:ForbiddenMethod")
-    public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
-            InterfaceInfo interfaceInfo) {
-        String elanName = elanInfo.getElanInstanceName();
+    private static class RemoveElanInterfaceHolder {
         boolean isLastElanInterface = false;
         boolean isLastInterfaceOnDpn = false;
         BigInteger dpId = null;
+    }
+
+    @SuppressWarnings("checkstyle:ForbidCertainMethod")
+    public List<ListenableFuture<Void>> removeElanInterface(ElanInstance elanInfo, String interfaceName,
+            InterfaceInfo interfaceInfo) {
+        String elanName = elanInfo.getElanInstanceName();
         long elanTag = elanInfo.getElanTag();
         // We use two transaction so we don't suffer on multiple shards (interfaces and flows)
-        WriteTransaction interfaceTx = broker.newWriteOnlyTransaction();
-        Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
-        if (elanState == null) {
-            interfaceTx.cancel();
-            return Collections.emptyList();
-        }
-        WriteTransaction flowTx = broker.newWriteOnlyTransaction();
-        List<String> elanInterfaces = elanState.getElanInterfaces();
-        if (elanInterfaces.isEmpty()) {
-            isLastElanInterface = true;
-        }
-        if (interfaceInfo != null) {
-            dpId = interfaceInfo.getDpId();
-            DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId,
-                    interfaceName, elanTag, interfaceTx);
-            /*
-             * If there are not elan ports, remove the unknown dmac, terminating
-             * service table flows, remote/local bc group
-             */
-            if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
-                    || dpnInterfaces.getInterfaces().isEmpty()) {
-                // No more Elan Interfaces in this DPN
-                LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
-                if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
-                    removeDefaultTermFlow(dpId, elanInfo.getElanTag());
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        RemoveElanInterfaceHolder holder = new RemoveElanInterfaceHolder();
+        futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
+            Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, interfaceTx);
+            if (elanState == null) {
+                return;
+            }
+            futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
+                List<String> elanInterfaces = elanState.getElanInterfaces();
+                if (elanInterfaces == null || elanInterfaces.isEmpty()) {
+                    holder.isLastElanInterface = true;
                 }
-                removeUnknownDmacFlow(dpId, elanInfo, flowTx, elanInfo.getElanTag());
-                removeEtreeUnknownDmacFlow(dpId, elanInfo, flowTx);
-                removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
-                removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
-                removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
-                if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
-                    if (elanUtils.isOpenstackVniSemanticsEnforced()) {
-                        elanUtils.removeTerminatingServiceAction(dpId,
-                                elanUtils.getVxlanSegmentationId(elanInfo).intValue());
+                if (interfaceInfo != null) {
+                    holder.dpId = interfaceInfo.getDpId();
+                    DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, holder.dpId,
+                        interfaceName, elanTag, interfaceTx);
+                    /*
+                     * If there are not elan ports, remove the unknown dmac, terminating
+                     * service table flows, remote/local bc group
+                     */
+                    if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
+                        || dpnInterfaces.getInterfaces().isEmpty()) {
+                        // No more Elan Interfaces in this DPN
+                        LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(),
+                            holder.dpId);
+                        if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
+                            removeDefaultTermFlow(holder.dpId, elanInfo.getElanTag());
+                        }
+                        removeUnknownDmacFlow(holder.dpId, elanInfo, flowTx, elanInfo.getElanTag());
+                        removeEtreeUnknownDmacFlow(holder.dpId, elanInfo, flowTx);
+                        removeElanBroadcastGroup(elanInfo, interfaceInfo, flowTx);
+                        removeLocalBroadcastGroup(elanInfo, interfaceInfo, flowTx);
+                        removeEtreeBroadcastGrups(elanInfo, interfaceInfo, flowTx);
+                        if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
+                            if (elanUtils.isOpenstackVniSemanticsEnforced()) {
+                                elanUtils.removeTerminatingServiceAction(holder.dpId,
+                                    ElanUtils.getVxlanSegmentationId(elanInfo).intValue());
+                            }
+                            unsetExternalTunnelTable(holder.dpId, elanInfo, flowTx);
+                        }
+                        holder.isLastInterfaceOnDpn = true;
+                    } else {
+                        setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, flowTx);
                     }
-                    unsetExternalTunnelTable(dpId, elanInfo);
                 }
-                isLastInterfaceOnDpn = true;
-            } else {
-                setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
-            }
-        }
-
-        List<ListenableFuture<Void>> futures = new ArrayList<>();
-        futures.add(ElanUtils.waitForTransactionToComplete(interfaceTx));
-        futures.add(ElanUtils.waitForTransactionToComplete(flowTx));
+            }));
+        }));
+        futures.forEach(ElanUtils::waitForTransactionToComplete);
 
-        if (isLastInterfaceOnDpn && dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
-            setElanAndEtreeBCGrouponOtherDpns(elanInfo, dpId);
+        if (holder.isLastInterfaceOnDpn && holder.dpId != null && isVxlanNetworkOrVxlanSegment(elanInfo)) {
+            futures.add(
+                ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                    confTx -> setElanAndEtreeBCGrouponOtherDpns(elanInfo, holder.dpId, confTx))));
         }
         InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
-                interfaceName, elanInfo, interfaceInfo, this, isLastElanInterface);
+                interfaceName, elanInfo, interfaceInfo, this, holder.isLastElanInterface);
         jobCoordinator.enqueueJob(ElanUtils.getElanInterfaceJobKey(interfaceName), removeInterfaceWorker,
                 ElanConstants.JOB_MAX_RETRIES);
 
@@ -300,7 +324,8 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
+            throws ExecutionException, InterruptedException {
         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
         if (etreeLeafTag != null) {
             long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
@@ -309,83 +334,71 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
+            throws ExecutionException, InterruptedException {
         removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
         removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
     }
 
     private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
+            throws ExecutionException, InterruptedException {
         EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
         if (etreeInstance != null) {
             BigInteger dpnId = interfaceInfo.getDpId();
             long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeInstance.getEtreeLeafTagVal().getValue());
-            List<Bucket> listBuckets = new ArrayList<>();
-            int bucketId = 0;
-            listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
-            Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
-                    MDSALUtil.buildBucketLists(listBuckets));
-            LOG.trace("deleted the localBroadCast Group:{}", group);
-            mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+            LOG.trace("deleted the localBroadCast Group:{}", groupId);
+            mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
         }
     }
 
     private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
+            throws ExecutionException, InterruptedException {
         EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
         if (etreeInstance != null) {
             long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
-            int bucketId = 0;
-            int actionKey = 0;
-            List<Bucket> listBuckets = new ArrayList<>();
-            List<Action> listAction = new ArrayList<>();
-            listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeTag)).buildAction(++actionKey));
-            listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
-                    MDSALUtil.WATCH_GROUP));
-            bucketId++;
-            listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
             BigInteger dpnId = interfaceInfo.getDpId();
             long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeTag);
-            Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
-                    MDSALUtil.buildBucketLists(listBuckets));
-            LOG.trace("deleting the remoteBroadCast group:{}", group);
-            mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+            LOG.trace("deleting the remoteBroadCast group:{}", groupId);
+            mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
         }
     }
 
-    private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
+    private static Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName,
+            TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
         String elanName = elanInfo.getElanInstanceName();
-        Elan elanState = ElanUtils.getElanByName(broker, elanName);
+        Elan elanState = ElanUtils.getElanByName(tx, elanName);
         if (elanState == null) {
             return elanState;
         }
         List<String> elanInterfaces = elanState.getElanInterfaces();
-        boolean isRemoved = elanInterfaces.remove(interfaceName);
+        boolean isRemoved = elanInterfaces != null && elanInterfaces.remove(interfaceName);
         if (!isRemoved) {
             return elanState;
         }
 
         if (elanInterfaces.isEmpty()) {
-            tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
-            tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
-            tx.delete(LogicalDatastoreType.OPERATIONAL,
-                    ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
+            tx.delete(ElanUtils.getElanInstanceOperationalDataPath(elanName));
+            tx.delete(ElanUtils.getElanMacTableOperationalDataPath(elanName));
+            tx.delete(ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
+            tx.delete(ElanUtils.getElanDpnOperationDataPath(elanName));
         } else {
             Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
                     .withKey(new ElanKey(elanName)).build();
-            tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
-                    updateElanState);
+            tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
         }
         return elanState;
     }
 
-    private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
+    private void deleteElanInterfaceFromConfigDS(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
+            throws ReadFailedException {
         // removing the ElanInterface from the config data_store if interface is
         // not present in Interface config DS
-        if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null
+        if (interfaceManager.getInterfaceInfoFromConfigDataStore(TransactionAdapter.toReadWriteTransaction(tx),
+            interfaceName) == null
                 && elanInterfaceCache.get(interfaceName).isPresent()) {
-            tx.delete(LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
+            tx.delete(ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
         }
     }
 
@@ -393,12 +406,11 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             interfaceInfo, String interfaceName, boolean isLastElanInterface) {
         String elanName = elanInfo.getElanInstanceName();
         List<ListenableFuture<Void>> futures = new ArrayList<>();
-        futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(flowTx -> {
-            futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(interfaceTx -> {
+        futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, flowTx -> {
+            futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, interfaceTx -> {
                 InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
                         .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
-                Optional<ElanInterfaceMac> existingElanInterfaceMac =
-                        interfaceTx.read(LogicalDatastoreType.OPERATIONAL, elanInterfaceId).checkedGet();
+                Optional<ElanInterfaceMac> existingElanInterfaceMac = interfaceTx.read(elanInterfaceId).get();
                 LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
                 if (interfaceInfo != null) {
                     if (existingElanInterfaceMac.isPresent()) {
@@ -412,8 +424,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                                 Optional<MacEntry> macEntryOptional =
                                         elanUtils.getMacEntryForElanInstance(interfaceTx, elanName, macAddress);
                                 if (!isLastElanInterface && macEntryOptional.isPresent()) {
-                                    interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
-                                            ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
+                                    interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
                                 }
                                 elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, flowTx);
                                 macAddresses.add(macAddress);
@@ -436,17 +447,16 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                         for (MacEntry macEntry : macEntries) {
                             PhysAddress macAddress = macEntry.getMacAddress();
                             if (elanUtils.getMacEntryForElanInstance(elanName, macAddress).isPresent()) {
-                                interfaceTx.delete(LogicalDatastoreType.OPERATIONAL,
-                                        ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
+                                interfaceTx.delete(ElanUtils.getMacEntryOperationalDataPath(elanName, macAddress));
                             }
                         }
                     }
                 }
                 if (existingElanInterfaceMac.isPresent()) {
-                    interfaceTx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
+                    interfaceTx.delete(elanInterfaceId);
                 }
-                unbindService(interfaceName, interfaceTx);
-                deleteElanInterfaceFromConfigDS(interfaceName, interfaceTx);
+                unbindService(interfaceName, flowTx);
+                deleteElanInterfaceFromConfigDS(interfaceName, flowTx);
             }));
         }));
         return futures;
@@ -454,9 +464,12 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
 
     private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
                                                                          String interfaceName, long elanTag,
-                                                                         WriteTransaction tx) {
-        synchronized (elanName.intern()) {
-
+                                                                         TypedReadWriteTransaction<Operational> tx)
+            throws ExecutionException, InterruptedException {
+        // FIXME: pass in and use ElanInstanceKey instead?
+        final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanName);
+        lock.lock();
+        try {
             DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
             if (dpnInterfaces != null) {
                 List<String> interfaceLists = dpnInterfaces.getInterfaces();
@@ -472,38 +485,44 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 }
             }
             return dpnInterfaces;
+        } finally {
+            lock.unlock();
         }
     }
 
     private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
         List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
-        for (DpnInterfaces dpnInterface : dpnInterfaces) {
-            BigInteger currentDpId = dpnInterface.getDpId();
-            if (!currentDpId.equals(dpId)) {
-                for (String elanInterface : dpnInterface.getInterfaces()) {
-                    ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
-                    if (macs == null || macs.getMacEntry() == null) {
-                        continue;
-                    }
-                    for (MacEntry mac : macs.getMacEntry()) {
-                        removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
-                        removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
+        addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
+            for (DpnInterfaces dpnInterface : dpnInterfaces) {
+                BigInteger currentDpId = dpnInterface.getDpId();
+                if (!currentDpId.equals(dpId) && dpnInterface.getInterfaces() != null) {
+                    for (String elanInterface : dpnInterface.getInterfaces()) {
+                        ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+                        if (macs == null || macs.getMacEntry() == null) {
+                            continue;
+                        }
+                        for (MacEntry mac : macs.getMacEntry()) {
+                            removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
+                            removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac, confTx);
+                        }
                     }
                 }
             }
-        }
+        }), LOG, "Error deleting remote MACs in DPN {}", dpId);
     }
 
-    private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
+    private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
+            TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
         if (etreeLeafTag != null) {
-            removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
+            removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac, confTx);
         }
     }
 
-    private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
+    private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac,
+            TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
         mdsalManager
-                .removeFlow(dpId,
+                .removeFlow(confTx, dpId,
                         MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
                                 ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
                                         mac.getMacAddress().getValue(), elanTag)));
@@ -526,7 +545,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         e. if orig = {1,2,3,4} updated={2,3,4,5}
         then 1 should be removed , 5 should be added
     * */
-    @SuppressWarnings("checkstyle:ForbiddenMethod")
+    @SuppressWarnings("checkstyle:ForbidCertainMethod")
     @Override
     protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
         // updating the static-Mac Entries for the existing elanInterface
@@ -546,25 +565,24 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         for (StaticMacEntries staticMacEntry : updatedEntries) {
             InstanceIdentifier<MacEntry> macEntryIdentifier = getMacEntryOperationalDataPath(elanName,
                     staticMacEntry.getMacAddress());
-            Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
-                    LogicalDatastoreType.OPERATIONAL, macEntryIdentifier);
-            WriteTransaction tx = broker.newWriteOnlyTransaction();
-            if (existingMacEntry.isPresent()) {
-                elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
-                        elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
-                        tx);
-            } else {
-                elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
-                        elanName, interfaceName, staticMacEntry, tx);
-            }
-            ListenableFutures.addErrorLogging(ElanUtils.waitForTransactionToComplete(tx), LOG,
-                    "Error in update: identifier={}, original={}, update={}", identifier, original, update);
+            addErrorLogging(ElanUtils.waitForTransactionToComplete(
+                txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
+                    Optional<MacEntry> existingMacEntry = tx.read(macEntryIdentifier).get();
+                    if (existingMacEntry.isPresent()) {
+                        elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
+                            elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
+                            tx);
+                    } else {
+                        elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
+                            elanName, interfaceName, staticMacEntry, tx);
+                    }
+                })), LOG, "Error in update: identifier={}, original={}, update={}", identifier, original, update);
         }
     }
 
     @Override
     protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
-        ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+        addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
             String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
             String interfaceName = elanInterfaceAdded.getName();
             InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
@@ -575,34 +593,37 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             ElanInstance elanInstance = elanInstanceCache.get(elanInstanceName).orNull();
 
             if (elanInstance == null) {
-                elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
-                        .setDescription(elanInterfaceAdded.getDescription()).build();
                 // Add the ElanInstance in the Configuration data-store
                 List<String> elanInterfaces = new ArrayList<>();
                 elanInterfaces.add(interfaceName);
-                elanInstance = ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
+                elanInstance = txRunner.applyWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+                    confTx -> ElanUtils.updateOperationalDataStore(idManager,
+                        new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(
+                            elanInterfaceAdded.getDescription()).build(), elanInterfaces, confTx, operTx)).get();
             }
 
             Long elanTag = elanInstance.getElanTag();
             // If elan tag is not updated, then put the elan interface into
             // unprocessed entry map and entry. Let entries
             // in this map get processed during ELAN update DCN.
-            if (elanTag == null) {
+            if (elanTag == null || elanTag == 0L) {
                 ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
                 if (elanInterfaces == null) {
                     elanInterfaces = new ConcurrentLinkedQueue<>();
                 }
-                elanInterfaces.add(elanInterfaceAdded);
+                if (!elanInterfaces.contains(elanInterfaceAdded)) {
+                    elanInterfaces.add(elanInterfaceAdded);
+                }
                 unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
                 return;
             }
             InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
                     interfaceInfo, elanInstance, this);
             jobCoordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
-        }), LOG, "Error procedding added ELAN interface");
+        }), LOG, "Error processing added ELAN interface");
     }
 
-    List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
+    List<ListenableFuture<Void>> handleunprocessedElanInterfaces(ElanInstance elanInstance) {
         List<ListenableFuture<Void>> futures = new ArrayList<>();
         Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
@@ -613,11 +634,12 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
             futures.addAll(addElanInterface(elanInterface, interfaceInfo, elanInstance));
         }
+        unProcessedElanInterfaces.remove(elanInstance.getElanInstanceName());
         return futures;
     }
 
     void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
-            WriteTransaction writeFlowGroupTx) throws ElanException {
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
                 .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
         List<DpnInterfaces> dpnInterfaceLists = null;
@@ -629,7 +651,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
         for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
             BigInteger dstDpId = interfaceInfo.getDpId();
-            if (dpnInterfaces.getDpId().equals(dstDpId)) {
+            if (Objects.equals(dpnInterfaces.getDpId(), dstDpId)) {
                 continue;
             }
             List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
@@ -654,9 +676,15 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
     }
 
-    @SuppressWarnings("checkstyle:ForbiddenMethod")
+    private static class AddElanInterfaceHolder {
+        private DpnInterfaces dpnInterfaces = null;
+        private boolean isFirstInterfaceInDpn = false;
+        private BigInteger dpId;
+    }
+
+    @SuppressWarnings("checkstyle:ForbidCertainMethod")
     List<ListenableFuture<Void>> addElanInterface(ElanInterface elanInterface,
-            InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
+            InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
         Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
         Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
         Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
@@ -664,148 +692,171 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         String interfaceName = elanInterface.getName();
         String elanInstanceName = elanInterface.getElanInstanceName();
 
-        Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        if (elanInfo == null) {
-            List<String> elanInterfaces = new ArrayList<>();
-            elanInterfaces.add(interfaceName);
-            ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, tx);
-        } else {
-            createElanStateList(elanInstanceName, interfaceName, tx);
-        }
-        boolean isFirstInterfaceInDpn = false;
-        // Specific actions to the DPN where the ElanInterface has been added,
-        // for example, programming the
-        // External tunnel table if needed or adding the ElanInterface to the
-        // DpnInterfaces in the operational DS.
-        BigInteger dpId = interfaceInfo.getDpId();
-        DpnInterfaces dpnInterfaces = null;
-        if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
-            synchronized (elanInstanceName.intern()) {
-                InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
-                        .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
-                Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker,
-                        LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
-                if (ElanUtils.isVlan(elanInstance)) {
-                    isFirstInterfaceInDpn =  checkIfFirstInterface(interfaceName,
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
+        AddElanInterfaceHolder holder = new AddElanInterfaceHolder();
+        futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
+            Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
+            if (elanInfo == null) {
+                List<String> elanInterfaces = new ArrayList<>();
+                elanInterfaces.add(interfaceName);
+                futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                    confTx -> ElanUtils.updateOperationalDataStore(idManager, elanInstance, elanInterfaces, confTx,
+                        operTx)));
+            } else {
+                createElanStateList(elanInstanceName, interfaceName, operTx);
+            }
+            // Specific actions to the DPN where the ElanInterface has been added,
+            // for example, programming the
+            // External tunnel table if needed or adding the ElanInterface to the
+            // DpnInterfaces in the operational DS.
+            holder.dpId = interfaceInfo.getDpId();
+            if (holder.dpId != null && !holder.dpId.equals(ElanConstants.INVALID_DPN)) {
+                // FIXME: use elanInstaince.key() instead?
+                final ReentrantLock lock = JvmGlobalLocks.getLockForString(elanInstanceName);
+                lock.lock();
+                try {
+                    InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
+                        .getElanDpnInterfaceOperationalDataPath(elanInstanceName, holder.dpId);
+                    Optional<DpnInterfaces> existingElanDpnInterfaces = operTx.read(elanDpnInterfaces).get();
+                    if (ElanUtils.isVlan(elanInstance)) {
+                        holder.isFirstInterfaceInDpn =  checkIfFirstInterface(interfaceName,
                             elanInstanceName, existingElanDpnInterfaces);
-                } else {
-                    isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
-                }
-                if (isFirstInterfaceInDpn) {
-                    // ELAN's 1st ElanInterface added to this DPN
-                    if (!existingElanDpnInterfaces.isPresent()) {
-                        dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
                     } else {
-                        List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
-                        elanInterfaces.add(interfaceName);
-                        dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId,
-                                elanInterfaces, tx);
-                    }
-                    // The 1st ElanInterface in a DPN must program the Ext Tunnel
-                    // table, but only if Elan has VNI
-                    if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
-                        setExternalTunnelTable(dpId, elanInstance);
+                        holder.isFirstInterfaceInDpn = !existingElanDpnInterfaces.isPresent();
                     }
-                    elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
-                } else {
-                    List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
-                    elanInterfaces.add(interfaceName);
-                    if (elanInterfaces.size() == 1) { // 1st dpn interface
-                        elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
+                    if (holder.isFirstInterfaceInDpn) {
+                        // ELAN's 1st ElanInterface added to this DPN
+                        if (!existingElanDpnInterfaces.isPresent()) {
+                            holder.dpnInterfaces =
+                                createElanInterfacesList(elanInstanceName, interfaceName, holder.dpId, operTx);
+                        } else {
+                            List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
+                            List<String> elanInterfaces =
+                                existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
+                            elanInterfaces.add(interfaceName);
+                            holder.dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, holder.dpId,
+                                elanInterfaces, operTx);
+                        }
+                        // The 1st ElanInterface in a DPN must program the Ext Tunnel
+                        // table, but only if Elan has VNI
+                        if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
+                            futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                                confTx -> setExternalTunnelTable(holder.dpId, elanInstance, confTx)));
+                        }
+                        elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
+                            interfaceName);
+                    } else {
+                        List<String> existingInterfaces = existingElanDpnInterfaces.get().getInterfaces();
+                        List<String> elanInterfaces =
+                            existingInterfaces != null ? new ArrayList<>(existingInterfaces) : new ArrayList<>();
+                        elanInterfaces.add(interfaceName);
+                        if (elanInterfaces.size() == 1) { // 1st dpn interface
+                            elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(holder.dpId, elanInstance,
+                                interfaceName);
+                        }
+                        holder.dpnInterfaces =
+                            updateElanDpnInterfacesList(elanInstanceName, holder.dpId, elanInterfaces, operTx);
                     }
-                    dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
+                } finally {
+                    lock.unlock();
                 }
             }
-        }
 
-        // add code to install Local/Remote BC group, unknow DMAC entry,
-        // terminating service table flow entry
-        // call bindservice of interfacemanager to create ingress table flow
-        // enty.
-        // Add interface to the ElanInterfaceForwardingEntires Container
-        createElanInterfaceTablesList(interfaceName, tx);
-        List<ListenableFuture<Void>> futures = new ArrayList<>();
-        futures.add(ElanUtils.waitForTransactionToComplete(tx));
-        installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn);
+            // add code to install Local/Remote BC group, unknow DMAC entry,
+            // terminating service table flow entry
+            // call bindservice of interfacemanager to create ingress table flow
+            // enty.
+            // Add interface to the ElanInterfaceForwardingEntires Container
+            createElanInterfaceTablesList(interfaceName, operTx);
+        }));
+        futures.forEach(ElanUtils::waitForTransactionToComplete);
+        futures.add(
+            ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                confTx -> installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, holder.dpnInterfaces,
+                    holder.isFirstInterfaceInDpn, confTx))));
 
         // add the vlan provider interface to remote BC group for the elan
         // for internal vlan networks
         if (ElanUtils.isVlan(elanInstance) && !elanInstance.isExternal()) {
             if (interfaceManager.isExternalInterface(interfaceName)) {
                 LOG.debug("adding vlan prv intf {} to elan {} BC group", interfaceName, elanInstanceName);
-                handleExternalInterfaceEvent(elanInstance, dpnInterfaces, dpId);
+                handleExternalInterfaceEvent(elanInstance, holder.dpnInterfaces, holder.dpId);
             }
         }
 
-        if (isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
+        if (holder.isFirstInterfaceInDpn && isVxlanNetworkOrVxlanSegment(elanInstance)) {
             //update the remote-DPNs remoteBC group entry with Tunnels
-            LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance, dpId);
-            setElanAndEtreeBCGrouponOtherDpns(elanInstance, dpId);
+            LOG.trace("update remote bc group for elan {} on other DPNs for newly added dpn {}", elanInstance,
+                holder.dpId);
+            futures.add(
+                ElanUtils.waitForTransactionToComplete(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                    confTx -> setElanAndEtreeBCGrouponOtherDpns(elanInstance, holder.dpId, confTx))));
         }
 
         String jobKey = ElanUtils.getElanInterfaceJobKey(interfaceName);
         InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(jobKey,
-                elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
+                elanInterface, interfaceInfo, elanInstance, holder.isFirstInterfaceInDpn, this);
         jobCoordinator.enqueueJob(jobKey, addWorker, ElanConstants.JOB_MAX_RETRIES);
         return futures;
     }
 
-    @SuppressWarnings("checkstyle:ForbiddenMethod")
+    @SuppressWarnings("checkstyle:ForbidCertainMethod")
     List<ListenableFuture<Void>> setupEntriesForElanInterface(ElanInstance elanInstance,
-            ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
-            throws ElanException {
+            ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
         String elanInstanceName = elanInstance.getElanInstanceName();
         String interfaceName = elanInterface.getName();
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
         BigInteger dpId = interfaceInfo.getDpId();
-        WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
-        installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
-                isFirstInterfaceInDpn, tx, writeFlowGroupTx);
-
-        List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
-        List<PhysAddress> staticMacAddresses = Lists.newArrayList();
-
         boolean isInterfaceOperational = isOperational(interfaceInfo);
-        if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
-            for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
-                InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
-                        staticMacEntry.getMacAddress());
-                Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
-                        LogicalDatastoreType.OPERATIONAL, macId);
-                if (existingMacEntry.isPresent()) {
-                    elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
-                            elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
-                            existingMacEntry.get(), tx);
-                } else {
-                    elanForwardingEntriesHandler
-                            .addElanInterfaceForwardingTableList(elanInstanceName, interfaceName, staticMacEntry, tx);
-                }
+        futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
+            futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
+                installEntriesForElanInterface(elanInstance, elanInterface, interfaceInfo,
+                    isFirstInterfaceInDpn, confTx);
+
+                List<StaticMacEntries> staticMacEntriesList = elanInterface.getStaticMacEntries();
+                List<PhysAddress> staticMacAddresses = Lists.newArrayList();
+
+                if (ElanUtils.isNotEmpty(staticMacEntriesList)) {
+                    for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
+                        InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName,
+                            staticMacEntry.getMacAddress());
+                        Optional<MacEntry> existingMacEntry = ElanUtils.read(broker,
+                            LogicalDatastoreType.OPERATIONAL, macId);
+                        if (existingMacEntry.isPresent()) {
+                            elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
+                                elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
+                                existingMacEntry.get(), operTx);
+                        } else {
+                            elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstanceName,
+                                interfaceName, staticMacEntry, operTx);
+                        }
 
-                if (isInterfaceOperational) {
-                    // Setting SMAC, DMAC, UDMAC in this DPN and also in other
-                    // DPNs
-                    String macAddress = staticMacEntry.getMacAddress().getValue();
-                    LOG.info("programming smac and dmacs for {} on source and other DPNs for elan {} and interface {}",
-                            macAddress, elanInstanceName, interfaceName);
-                    elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
-                            staticMacEntry.getMacAddress().getValue(), true, writeFlowGroupTx);
-                }
-            }
+                        if (isInterfaceOperational) {
+                            // Setting SMAC, DMAC, UDMAC in this DPN and also in other
+                            // DPNs
+                            String macAddress = staticMacEntry.getMacAddress().getValue();
+                            LOG.info(
+                                "programming smac and dmacs for {} on source and other DPNs for elan {} and interface"
+                                    + " {}",
+                                macAddress, elanInstanceName, interfaceName);
+                            elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
+                                staticMacEntry.getMacAddress().getValue(), true, confTx);
+                        }
+                    }
 
-            if (isInterfaceOperational) {
-                // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
-                // on purpose.
-                for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
-                    staticMacAddresses.add(staticMacEntry.getMacAddress());
+                    if (isInterfaceOperational) {
+                        // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
+                        // on purpose.
+                        for (StaticMacEntries staticMacEntry : staticMacEntriesList) {
+                            staticMacAddresses.add(staticMacEntry.getMacAddress());
+                        }
+                        elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
+                            staticMacAddresses);
+                    }
                 }
-                elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
-                        staticMacAddresses);
-            }
-        }
-        List<ListenableFuture<Void>> futures = new ArrayList<>();
-        futures.add(ElanUtils.waitForTransactionToComplete(tx));
-        futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
+            }));
+        }));
+        futures.forEach(ElanUtils::waitForTransactionToComplete);
         if (isInterfaceOperational && !interfaceManager.isExternalInterface(interfaceName)) {
             //At this point, the interface is operational and D/SMAC flows have been configured, mark the port active
             try {
@@ -848,42 +899,43 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
         DpnInterfaces dpnInterfaces = existingElanDpnInterfaces.get();
         int dummyInterfaceCount =  0;
-        if (dpnInterfaces.getInterfaces().contains(routerPortUuid)) {
-            dummyInterfaceCount++;
+        List<String> interfaces = dpnInterfaces.getInterfaces();
+        if (interfaces == null) {
+            return true;
         }
-        if (dpnInterfaces.getInterfaces().contains(elanInstanceName)) {
+        if (interfaces.contains(routerPortUuid)) {
             dummyInterfaceCount++;
         }
-        if (dpnInterfaces.getInterfaces().size() - dummyInterfaceCount == 0) {
-            return true;
+        if (interfaces.contains(elanInstanceName)) {
+            dummyInterfaceCount++;
         }
-        return false;
+        return interfaces.size() == dummyInterfaceCount;
     }
 
-    private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
+    private static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
+            PhysAddress physAddress) {
         return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
                 .child(MacEntry.class, new MacEntryKey(physAddress)).build();
     }
 
     private void installEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
-            InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, WriteTransaction tx,
-            WriteTransaction writeFlowGroupTx) throws ElanException {
+            InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
         if (!isOperational(interfaceInfo)) {
             return;
         }
         BigInteger dpId = interfaceInfo.getDpId();
         if (!elanUtils.isOpenstackVniSemanticsEnforced()) {
-            elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
+            elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, confTx);
         }
-        setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
+        setupFilterEqualsTable(elanInstance, interfaceInfo, confTx);
         if (isFirstInterfaceInDpn) {
             // Terminating Service , UnknownDMAC Table.
             // The 1st ELAN Interface in a DPN must program the INTERNAL_TUNNEL_TABLE, but only if the network type
             // for ELAN Instance is VxLAN
             if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
-                setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
+                setupTerminateServiceTable(elanInstance, dpId, confTx);
             }
-            setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
+            setupUnknownDMacTable(elanInstance, dpId, confTx);
             /*
              * Install remote DMAC flow. This is required since this DPN is
              * added later to the elan instance and remote DMACs of other
@@ -893,20 +945,20 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             if (!interfaceManager.isExternalInterface(interfaceInfo.getInterfaceName())) {
                 LOG.info("Programming remote dmac flows on the newly connected dpn {} for elan {} ", dpId,
                         elanInstance.getElanInstanceName());
-                programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
+                programRemoteDmacFlow(elanInstance, interfaceInfo, confTx);
             }
         }
         // bind the Elan service to the Interface
-        bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), tx);
+        bindService(elanInstance, elanInterface, interfaceInfo.getInterfaceTag(), confTx);
     }
 
-    public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn) {
+    private void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, TypedWriteTransaction<Configuration> confTx) {
         if (!isOperational(interfaceInfo)) {
             return;
         }
         // LocalBroadcast Group creation with elan-Interfaces
-        setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
+        setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo, confTx);
         if (isFirstInterfaceInDpn) {
             LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
             BigInteger dpId = interfaceInfo.getDpId();
@@ -916,7 +968,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             } catch (InterruptedException e1) {
                 LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
             }
-            elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
+            elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId, confTx);
             try {
                 Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
             } catch (InterruptedException e1) {
@@ -926,7 +978,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            WriteTransaction writeFlowGroupTx) {
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         int ifTag = interfaceInfo.getInterfaceTag();
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
                 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
@@ -934,59 +986,52 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
                 elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
 
-        mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
+        mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flow);
 
         Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
                 getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
                 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
                 getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
 
-        mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
+        mdsalManager.addFlow(writeFlowGroupTx, interfaceInfo.getDpId(), flowEntry);
     }
 
     public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
         int ifTag = interfaceInfo.getInterfaceTag();
-        Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
-                getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"), 9, elanInfo.getElanInstanceName(), 0,
-                0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
-                ElanUtils.getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
-                elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
+        Flow flow = MDSALUtil.buildFlow(NwConstants.ELAN_FILTER_EQUALS_TABLE,
+            getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "group"));
 
-        mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
+        mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flow);
 
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
-                getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
-                0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
-                getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
-
-        mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
-    }
+            getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag, "drop"), 10, elanInfo.getElanInstanceName(), 0,
+            0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
+            getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
 
-    private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
-                                                     InterfaceInfo interfaceInfo, long elanTag) {
-        return elanL2GatewayMulticastUtils.getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(),
-                bucketKeyStart, elanTag);
+        mdsalManager.removeFlow(flowTx, interfaceInfo.getDpId(), flowEntity);
     }
 
-    private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId) {
+    private void setElanAndEtreeBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId,
+            TypedWriteTransaction<Configuration> confTx) {
         int elanTag = elanInfo.getElanTag().intValue();
         long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
-        setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId);
+        setBCGrouponOtherDpns(elanInfo, dpId, elanTag, groupId, confTx);
         EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
         if (etreeInstance != null) {
             int etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().intValue();
             long etreeLeafGroupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
-            setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId);
+            setBCGrouponOtherDpns(elanInfo, dpId, etreeLeafTag, etreeLeafGroupId, confTx);
         }
     }
 
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId) {
+    private void setBCGrouponOtherDpns(ElanInstance elanInfo, BigInteger dpId, int elanTag, long groupId,
+            TypedWriteTransaction<Configuration> confTx) {
         int bucketId = 0;
         ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
         if (elanDpns != null) {
-            List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
+            List<DpnInterfaces> dpnInterfaces = elanDpns.nonnullDpnInterfaces();
             for (DpnInterfaces dpnInterface : dpnInterfaces) {
                 List<Bucket> remoteListBucketInfo = new ArrayList<>();
                 if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpId)
@@ -1005,7 +1050,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                                 List<Action> remoteListActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(
                                         dpnInterface.getDpId(), otherFes.getDpId(),
                                         elanUtils.isOpenstackVniSemanticsEnforced()
-                                                ? elanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
+                                                ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag);
                                 if (!remoteListActionInfo.isEmpty()) {
                                     remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil
                                             .GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
@@ -1030,7 +1075,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                     Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
                             MDSALUtil.buildBucketLists(remoteListBucketInfo));
                     LOG.trace("Installing remote bc group {} on dpnId {}", group, dpnInterface.getDpId());
-                    mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group);
+                    mdsalManager.addGroup(confTx, dpnInterface.getDpId(), group);
                 }
             }
             try {
@@ -1041,28 +1086,20 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
     }
 
-    /**
-     * Returns the bucket info with the given interface as the only bucket.
-     */
-    private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
-        return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
-                MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
-    }
-
-    private List<MatchInfo> buildMatchesForVni(Long vni) {
+    private static List<MatchInfo> buildMatchesForVni(Long vni) {
         List<MatchInfo> mkMatches = new ArrayList<>();
         MatchInfo match = new MatchTunnelId(BigInteger.valueOf(vni));
         mkMatches.add(match);
         return mkMatches;
     }
 
-    private List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
+    private static List<InstructionInfo> getInstructionsForOutGroup(long groupId) {
         List<InstructionInfo> mkInstructions = new ArrayList<>();
         mkInstructions.add(new InstructionWriteActions(Collections.singletonList(new ActionGroup(groupId))));
         return mkInstructions;
     }
 
-    private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
+    private static List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
         List<MatchInfo> mkMatches = new ArrayList<>();
         // Matching metadata
         mkMatches.add(new MatchMetadata(
@@ -1078,7 +1115,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      *            elanTag to be written in metadata when flow is selected
      * @return the instructions ready to be installed in a flow
      */
-    private List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
+    private static List<InstructionInfo> getInstructionsIntOrExtTunnelTable(Long elanTag) {
         List<InstructionInfo> mkInstructions = new ArrayList<>();
         mkInstructions.add(new InstructionWriteMetadata(ElanHelper.getElanMetadataLabel(elanTag), ElanHelper
                 .getElanMetadataMask()));
@@ -1090,30 +1127,31 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     // Install DMAC entry on dst DPN
-    @SuppressWarnings("checkstyle:ForbiddenMethod")
     public List<ListenableFuture<Void>> installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            BigInteger dstDpId) throws ElanException {
+            BigInteger dstDpId) {
         String interfaceName = interfaceInfo.getInterfaceName();
         ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
         if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
             List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
-            WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
-            for (MacEntry macEntry : macEntries) {
-                String macAddress = macEntry.getMacAddress().getValue();
-                LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress, interfaceName);
-                synchronized (ElanUtils.getElanMacDPNKey(elanInfo.getElanTag(), macAddress,
-                        interfaceInfo.getDpId())) {
-                    LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation", macAddress);
-                    elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress,
-                            writeFlowTx);
-                }
-            }
-            return Collections.singletonList(ElanUtils.waitForTransactionToComplete(writeFlowTx));
+            return Collections.singletonList(ElanUtils.waitForTransactionToComplete(
+                txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+                    for (MacEntry macEntry : macEntries) {
+                        String macAddress = macEntry.getMacAddress().getValue();
+                        LOG.info("Installing remote dmac for mac address {} and interface {}", macAddress,
+                            interfaceName);
+                        try (Acquired lock = ElanUtils.lockElanMacDPN(elanInfo.getElanTag(), macAddress,
+                            interfaceInfo.getDpId())) {
+                            LOG.info("Acquired lock for mac : {}, proceeding with remote dmac install operation",
+                                macAddress);
+                            elanUtils.setupDMacFlowOnRemoteDpn(elanInfo, interfaceInfo, dstDpId, macAddress, tx);
+                        }
+                    }
+                })));
         }
-        return Collections.emptyList();
+        return emptyList();
     }
 
-    private void createDropBucket(List<Bucket> listBucket) {
+    private static void createDropBucket(List<Bucket> listBucket) {
         List<Action> actionsInfos = new ArrayList<>();
         actionsInfos.add(new ActionDrop().buildAction());
         Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
@@ -1121,20 +1159,20 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         listBucket.add(dropBucket);
     }
 
-    public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
-            InterfaceInfo interfaceInfo) {
-        setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
-        setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
+    private void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
+            InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
+        setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
+        setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo, confTx);
     }
 
-    public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
-            InterfaceInfo interfaceInfo) {
+    private void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
+            InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
         List<Bucket> listBucket = new ArrayList<>();
         int bucketId = 0;
         long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
 
         List<String> interfaces = new ArrayList<>();
-        if (newDpnInterface != null) {
+        if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
             interfaces = newDpnInterface.getInterfaces();
         }
         for (String ifName : interfaces) {
@@ -1156,18 +1194,18 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
                 MDSALUtil.buildBucketLists(listBucket));
         LOG.trace("installing the localBroadCast Group:{}", group);
-        mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
+        mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
     }
 
     private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
-            InterfaceInfo interfaceInfo) {
+            InterfaceInfo interfaceInfo, TypedWriteTransaction<Configuration> confTx) {
         EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
         if (etreeInstance != null) {
             List<Bucket> listBucket = new ArrayList<>();
             int bucketId = 0;
 
             List<String> interfaces = new ArrayList<>();
-            if (newDpnInterface != null) {
+            if (newDpnInterface != null && newDpnInterface.getInterfaces() != null) {
                 interfaces = newDpnInterface.getInterfaces();
             }
             for (String ifName : interfaces) {
@@ -1195,7 +1233,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
                     MDSALUtil.buildBucketLists(listBucket));
             LOG.trace("installing the localBroadCast Group:{}", group);
-            mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group);
+            mdsalManager.addGroup(confTx, interfaceInfo.getDpId(), group);
         }
     }
 
@@ -1211,51 +1249,31 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
+            throws ExecutionException, InterruptedException {
         BigInteger dpnId = interfaceInfo.getDpId();
         long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
-        List<Bucket> listBuckets = new ArrayList<>();
-        int bucketId = 0;
-        listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
-        // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
-        // interfaceInfo));
-        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
-                MDSALUtil.buildBucketLists(listBuckets));
-        LOG.trace("deleted the localBroadCast Group:{}", group);
-        mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+        LOG.trace("deleted the localBroadCast Group:{}", groupId);
+        mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
     }
 
     public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
-            WriteTransaction deleteFlowGroupTx) {
-        int bucketId = 0;
-        int actionKey = 0;
-        Long elanTag = elanInfo.getElanTag();
-        List<Bucket> listBuckets = new ArrayList<>();
-        List<Action> listAction = new ArrayList<>();
-        listAction.add(new ActionGroup(++actionKey, ElanUtils.getElanLocalBCGId(elanTag)).buildAction());
-        listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
-                MDSALUtil.WATCH_GROUP));
-        bucketId++;
-        listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanTag));
+            TypedReadWriteTransaction<Configuration> deleteFlowGroupTx)
+            throws ExecutionException, InterruptedException {
         BigInteger dpnId = interfaceInfo.getDpId();
         long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
-        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
-                MDSALUtil.buildBucketLists(listBuckets));
-        LOG.trace("deleting the remoteBroadCast group:{}", group);
-        mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+        LOG.trace("deleting the remoteBroadCast group:{}", groupId);
+        mdsalManager.removeGroup(deleteFlowGroupTx, dpnId, groupId);
     }
 
     /**
      * Installs a flow in the External Tunnel table consisting in translating
      * the VNI retrieved from the packet that came over a tunnel with a TOR into
      * elanTag that will be used later in the ELANs pipeline.
-     *
-     * @param dpnId
-     *            the dpn id
-     * @param elanInfo
-     *            the elan info
+     * @param dpnId the dpn id
      */
-    public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
+    private void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
+            TypedWriteTransaction<Configuration> confTx) {
         long elanTag = elanInfo.getElanTag();
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
                 getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
@@ -1266,7 +1284,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 buildMatchesForVni(ElanUtils.getVxlanSegmentationId(elanInfo)),
                 getInstructionsIntOrExtTunnelTable(elanTag));
 
-        mdsalManager.installFlow(flowEntity);
+        mdsalManager.addFlow(confTx, flowEntity);
     }
 
     /**
@@ -1274,12 +1292,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      * elanTag. Important: ensure this method is only called whenever there is
      * no other ElanInterface in the specified DPN
      *
-     * @param dpnId
-     *            DPN whose Ext Tunnel table is going to be modified
-     * @param elanInfo
-     *            holds the elanTag needed for selecting the flow to be removed
+     * @param dpnId DPN whose Ext Tunnel table is going to be modified
      */
-    public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
+    private void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo,
+            TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
         // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
         // last ElanInstance plus
         // adding a new one does (almost at the same time) are executed in that
@@ -1291,16 +1307,17 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             .setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE)
             .setFlowId(flowId)
             .build();
-        mdsalManager.removeFlow(flowEntity);
+        mdsalManager.removeFlow(confTx, flowEntity);
     }
 
-    public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
+    public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
         setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
     }
 
     public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
-            WriteTransaction writeFlowGroupTx) {
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         List<? extends MatchInfoBase> listMatchInfoBase;
         List<InstructionInfo> instructionInfos;
         long serviceId;
@@ -1309,7 +1326,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             listMatchInfoBase = ElanUtils.getTunnelMatchesForServiceId((int) elanTag);
             instructionInfos = getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag));
         } else {
-            serviceId = elanUtils.getVxlanSegmentationId(elanInfo);
+            serviceId = ElanUtils.getVxlanSegmentationId(elanInfo);
             listMatchInfoBase = buildMatchesForVni(serviceId);
             instructionInfos = getInstructionsIntOrExtTunnelTable(elanTag);
         }
@@ -1317,18 +1334,19 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, serviceId), 5, String.format("%s:%d", "ITM Flow Entry ",
                 elanTag), 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), listMatchInfoBase,
                 instructionInfos);
-        mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
+        mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
     }
 
     private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
-            WriteTransaction writeFlowGroupTx) {
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
         if (etreeInstance != null) {
             setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
         }
     }
 
-    public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
+    public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId,
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         long elanTag = elanInfo.getElanTag();
         installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
         installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
@@ -1336,7 +1354,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
-            WriteTransaction writeFlowGroupTx) {
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
         if (etreeLeafTag != null) {
             long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
@@ -1346,7 +1364,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
-            WriteTransaction writeFlowGroupTx) {
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
                 getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,/* SH flag */false),
                 5, elanInfo.getElanInstanceName(), 0, 0,
@@ -1354,11 +1372,11 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 getMatchesForElanTag(elanTag, /* SH flag */false),
                 getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGId(elanTag)));
 
-        mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
+        mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
     }
 
     private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
-            WriteTransaction writeFlowGroupTx) {
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         // only if ELAN can connect to external network, perform the following
 
         if (isVxlanNetworkOrVxlanSegment(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
@@ -1368,22 +1386,23 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                     ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
                     getMatchesForElanTag(elanTag, /* SH flag */true),
                     getInstructionsForOutGroup(ElanUtils.getElanLocalBCGId(elanTag)));
-            mdsalManager.addFlowToTx(flowEntity, writeFlowGroupTx);
+            mdsalManager.addFlow(writeFlowGroupTx, flowEntity);
         }
     }
 
 
-    private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
-            long elanTag) {
+    private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
+            TypedReadWriteTransaction<Configuration> deleteFlowGroupTx, long elanTag)
+            throws ExecutionException, InterruptedException {
         Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
                 elanTag, SH_FLAG_UNSET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
-        mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
+        mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow);
 
         if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
             Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
                     elanTag, SH_FLAG_SET))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
                     .build();
-            mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
+            mdsalManager.removeFlow(deleteFlowGroupTx, dpId, flow2);
         }
     }
 
@@ -1391,7 +1410,8 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
     }
 
-    private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag, WriteTransaction tx) {
+    private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
+            TypedWriteTransaction<Configuration> tx) {
         if (isStandardElanService(elanInterface)) {
             bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(),
                     elanInterface.getName(), lportTag, tx);
@@ -1401,7 +1421,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, int lportTag,
-            WriteTransaction tx) {
+            TypedWriteTransaction<Configuration> tx) {
         int instructionKey = 0;
         List<Instruction> instructions = new ArrayList<>();
         instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanHelper.getElanMetadataLabel(elanTag),
@@ -1425,13 +1445,12 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         Optional<BoundServices> existingElanService = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
                 bindServiceId);
         if (!existingElanService.isPresent()) {
-            tx.put(LogicalDatastoreType.CONFIGURATION, bindServiceId, serviceInfo,
-                    WriteTransaction.CREATE_MISSING_PARENTS);
+            tx.put(bindServiceId, serviceInfo, CREATE_MISSING_PARENTS);
         }
     }
 
     private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, int lportTag,
-            WriteTransaction tx) {
+            TypedWriteTransaction<Configuration> tx) {
         if (elanInterface.augmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
             bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(),
                     lportTag, tx);
@@ -1447,32 +1466,33 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
     }
 
-    private boolean isStandardElanService(ElanInterface elanInterface) {
+    private static boolean isStandardElanService(ElanInterface elanInterface) {
         return elanInterface.augmentation(EtreeInterface.class) == null;
     }
 
-    protected void unbindService(String interfaceName, ReadWriteTransaction tx) throws ReadFailedException {
+    protected void unbindService(String interfaceName, TypedReadWriteTransaction<Configuration> tx)
+            throws ExecutionException, InterruptedException {
         short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
         InstanceIdentifier<BoundServices> bindServiceId = ElanUtils.buildServiceId(interfaceName, elanServiceIndex);
-        if (tx.read(LogicalDatastoreType.CONFIGURATION, bindServiceId).checkedGet().isPresent()) {
-            tx.delete(LogicalDatastoreType.CONFIGURATION, bindServiceId);
+        if (tx.read(bindServiceId).get().isPresent()) {
+            tx.delete(bindServiceId);
         }
     }
 
-    private String getFlowRef(long tableId, long elanTag) {
+    private static String getFlowRef(long tableId, long elanTag) {
         return String.valueOf(tableId) + elanTag;
     }
 
-    private String getFlowRef(long tableId, long elanTag, String flowName) {
-        return new StringBuffer().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
+    private static String getFlowRef(long tableId, long elanTag, String flowName) {
+        return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(elanTag)
                 .append(NwConstants.FLOWID_SEPARATOR).append(flowName).toString();
     }
 
-    private String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
+    private static String getUnknownDmacFlowRef(long tableId, long elanTag, boolean shFlag) {
         return String.valueOf(tableId) + elanTag + shFlag;
     }
 
-    private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
+    private static List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
         List<Action> listAction = new ArrayList<>();
         int actionKey = 0;
         listAction.add(
@@ -1482,13 +1502,12 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         return listAction;
     }
 
-    private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
-            List<String> interfaceNames, WriteTransaction tx) {
+    private static DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
+            List<String> interfaceNames, TypedWriteTransaction<Operational> tx) {
         DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
                 .withKey(new DpnInterfacesKey(dpId)).build();
-        tx.put(LogicalDatastoreType.OPERATIONAL,
-                ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
-                WriteTransaction.CREATE_MISSING_PARENTS);
+        tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
+                CREATE_MISSING_PARENTS);
         return dpnInterface;
     }
 
@@ -1500,48 +1519,46 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      * @param dpId
      *            the dp id
      */
-    private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
+    private static void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId,
+            TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
         InstanceIdentifier<DpnInterfaces> dpnInterfacesId = ElanUtils
                 .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
-        Optional<DpnInterfaces> dpnInterfaces = ElanUtils.read(broker,
-                LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
+        Optional<DpnInterfaces> dpnInterfaces = tx.read(dpnInterfacesId).get();
         if (dpnInterfaces.isPresent()) {
-            tx.delete(LogicalDatastoreType.OPERATIONAL, dpnInterfacesId);
+            tx.delete(dpnInterfacesId);
         }
     }
 
-    private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
-            WriteTransaction tx) {
+    private static DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName,
+            BigInteger dpId, TypedWriteTransaction<Operational> tx) {
         List<String> interfaceNames = new ArrayList<>();
         interfaceNames.add(interfaceName);
         DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
                 .withKey(new DpnInterfacesKey(dpId)).build();
-        tx.put(LogicalDatastoreType.OPERATIONAL,
-                ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
-                WriteTransaction.CREATE_MISSING_PARENTS);
+        tx.put(ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface,
+                CREATE_MISSING_PARENTS);
         return dpnInterface;
     }
 
-    private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
+    private static void createElanInterfaceTablesList(String interfaceName, TypedReadWriteTransaction<Operational> tx)
+            throws ExecutionException, InterruptedException {
         InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
                 .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
-        Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker,
-                LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
+        Optional<ElanInterfaceMac> interfaceMacTables = tx.read(elanInterfaceMacTables).get();
         // Adding new Elan Interface Port to the operational DataStore without
         // Static-Mac Entries..
         if (!interfaceMacTables.isPresent()) {
             ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
                     .withKey(new ElanInterfaceMacKey(interfaceName)).build();
-            tx.put(LogicalDatastoreType.OPERATIONAL,
-                    ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
-                    WriteTransaction.CREATE_MISSING_PARENTS);
+            tx.put(ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
+                    CREATE_MISSING_PARENTS);
         }
     }
 
-    private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
+    private static void createElanStateList(String elanInstanceName, String interfaceName,
+            TypedReadWriteTransaction<Operational> tx) throws ExecutionException, InterruptedException {
         InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
-        Optional<Elan> elanInterfaceLists = ElanUtils.read(broker,
-                LogicalDatastoreType.OPERATIONAL, elanInstance);
+        Optional<Elan> elanInterfaceLists = tx.read(elanInstance).get();
         // Adding new Elan Interface Port to the operational DataStore without
         // Static-Mac Entries..
         if (elanInterfaceLists.isPresent()) {
@@ -1552,16 +1569,12 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             interfaceLists.add(interfaceName);
             Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
                     .withKey(new ElanKey(elanInstanceName)).build();
-            tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
-                    elanState, WriteTransaction.CREATE_MISSING_PARENTS);
+            tx.put(ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, CREATE_MISSING_PARENTS);
         }
     }
 
-    private boolean isOperational(InterfaceInfo interfaceInfo) {
-        if (interfaceInfo == null) {
-            return false;
-        }
-        return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
+    private static boolean isOperational(InterfaceInfo interfaceInfo) {
+        return interfaceInfo != null && interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
     }
 
     @SuppressWarnings("checkstyle:IllegalCatch")
@@ -1572,7 +1585,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         if (dpnInterfaceLists == null) {
             return;
         }
-        List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
+        List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
         for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
             int cnt = 0;
             String elanName = elanDpns.getElanInstanceName();
@@ -1593,9 +1606,9 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             DpnInterfaces dstDpnIf = null;
             for (DpnInterfaces dpnIf : dpnInterfaces) {
                 BigInteger dpnIfDpId = dpnIf.getDpId();
-                if (dpnIfDpId.equals(srcDpId)) {
+                if (Objects.equals(dpnIfDpId, srcDpId)) {
                     cnt++;
-                } else if (dpnIfDpId.equals(dstDpId)) {
+                } else if (Objects.equals(dpnIfDpId, dstDpId)) {
                     cnt++;
                     dstDpnIf = dpnIf;
                 }
@@ -1607,7 +1620,9 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                     // update Remote BC Group
                     LOG.trace("procesing elan remote bc group for tunnel event {}", elanInfo);
                     try {
-                        elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId);
+                        txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                            confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, srcDpId,
+                                confTx)).get();
                     } catch (RuntimeException e) {
                         LOG.error("Error while adding remote bc group for {} on dpId {} ", elanName, srcDpId);
                     }
@@ -1620,10 +1635,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                             if (isOperational(interfaceInfo)) {
                                 return installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
                             }
-                            return Collections.emptyList();
+                            return emptyList();
                         }, ElanConstants.JOB_MAX_RETRIES);
                     }
-                    return Collections.emptyList();
+                    return emptyList();
                 }, ElanConstants.JOB_MAX_RETRIES);
             }
 
@@ -1637,9 +1652,8 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      *            the external tunnel
      * @param intrf
      *            the interface
-     * @throws ElanException in case of issues creating the flow objects
      */
-    public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
+    void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
         if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
             return;
         }
@@ -1663,7 +1677,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         if (dpnInterfaceLists == null) {
             return;
         }
-        List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
+        List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.nonnullElanDpnInterfacesList();
         for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
             String elanName = elanDpns.getElanInstanceName();
             ElanInstance elanInfo = elanInstanceCache.get(elanName).orNull();
@@ -1675,7 +1689,10 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             }
             LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
 
-            elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, dpId);
+            final BigInteger finalDpId = dpId;
+            LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                confTx -> elanL2GatewayMulticastUtils.setupElanBroadcastGroups(elanInfo, finalDpId, confTx)), LOG,
+                "Error setting up ELAN BGs");
             // install L2gwDevices local macs in dpn.
             elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
             // Install dpn macs on external device
@@ -1723,7 +1740,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
                 dpnTepIp);
         LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
-                phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
+                phyLocAlreadyExists, dpnTepIp.stringValue(), elanName, externalNodeId.getValue());
         List<PhysAddress> staticMacs = elanL2GatewayUtils.getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
 
         if (phyLocAlreadyExists) {
@@ -1765,7 +1782,7 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         return false;
     }
 
-    private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
+    private static List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
         List<MatchInfo> mkMatches = new ArrayList<>();
         // Matching metadata
         mkMatches.add(
@@ -1782,7 +1799,9 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     public void handleExternalInterfaceEvent(ElanInstance elanInstance, DpnInterfaces dpnInterfaces,
                                              BigInteger dpId) {
         LOG.debug("setting up remote BC group for elan {}", elanInstance.getPhysicalNetworkName());
-        elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId);
+        addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+            confTx -> elanL2GatewayMulticastUtils.setupStandardElanBroadcastGroups(elanInstance, dpnInterfaces, dpId,
+                confTx)), LOG, "Error setting up remote BC group for ELAN {}", elanInstance.getPhysicalNetworkName());
         try {
             Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
         } catch (InterruptedException e) {