Migrate ElanUtils to use NamedLocks
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / utils / ElanUtils.java
index 554f7ba60ac37356578e59c7cbbef281c4551331..a25c8a25eed3c7b10a2475eca48ccbe96fbee4e6 100755 (executable)
@@ -7,6 +7,10 @@
  */
 package org.opendaylight.netvirt.elan.utils;
 
  */
 package org.opendaylight.netvirt.elan.utils;
 
+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 com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
@@ -17,30 +21,37 @@ import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
+import edu.umd.cs.findbugs.annotations.CheckReturnValue;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.apache.commons.lang3.StringUtils;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.genius.infra.Datastore;
+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.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.TypedReadTransaction;
+import org.opendaylight.genius.infra.TypedReadWriteTransaction;
+import org.opendaylight.genius.infra.TypedWriteTransaction;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
-import org.opendaylight.genius.interfacemanager.globals.InterfaceServiceUtil;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.itm.api.IITMProvider;
 import org.opendaylight.genius.itm.globals.ITMConstants;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.itm.globals.ITMConstants;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
@@ -62,9 +73,9 @@ import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
 import org.opendaylight.genius.mdsalutil.packet.ARP;
 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
 import org.opendaylight.genius.mdsalutil.packet.IPv4;
 import org.opendaylight.genius.mdsalutil.packet.ARP;
 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
 import org.opendaylight.genius.mdsalutil.packet.IPv4;
-import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
-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.NamedLocks;
+import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
@@ -117,6 +128,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ext
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
@@ -132,7 +147,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev16061
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagNameBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagNameBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanDpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanForwardingTables;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaceForwardingEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaceForwardingEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanState;
@@ -165,6 +179,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.tag.name.map.ElanTagNameKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
@@ -174,8 +190,38 @@ import org.slf4j.LoggerFactory;
 
 @Singleton
 public class ElanUtils {
 
 @Singleton
 public class ElanUtils {
+    private static final class ElanLockName {
+        private final String macAddress;
+        private final BigInteger dpnId;
+        private final long elanTag;
+
+        ElanLockName(long elanTag, String macAddress, BigInteger dpnId) {
+            this.elanTag = elanTag;
+            this.macAddress = macAddress;
+            this.dpnId = dpnId;
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * Long.hashCode(elanTag) + Objects.hash(macAddress, dpnId);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof ElanLockName)) {
+                return false;
+            }
+            final ElanLockName other = (ElanLockName) obj;
+            return elanTag == other.elanTag && Objects.equals(macAddress, other.macAddress)
+                    && Objects.equals(dpnId, other.dpnId);
+        }
+    }
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class);
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanUtils.class);
+    private static final NamedLocks<ElanLockName> ELAN_LOCKS = new NamedLocks<>();
 
     private final DataBroker broker;
     private final ManagedNewTransactionRunner txRunner;
 
     private final DataBroker broker;
     private final ManagedNewTransactionRunner txRunner;
@@ -187,6 +233,7 @@ public class ElanUtils {
     private final ElanItmUtils elanItmUtils;
     private final ElanEtreeUtils elanEtreeUtils;
     private final ElanInterfaceCache elanInterfaceCache;
     private final ElanItmUtils elanItmUtils;
     private final ElanEtreeUtils elanEtreeUtils;
     private final ElanInterfaceCache elanInterfaceCache;
+    private final IITMProvider iitmProvider;
 
     public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
         @Override
 
     public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
         @Override
@@ -204,7 +251,7 @@ public class ElanUtils {
     public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager,
             OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService, ElanConfig elanConfig,
             IInterfaceManager interfaceManager, ElanEtreeUtils elanEtreeUtils, ElanItmUtils elanItmUtils,
     public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager,
             OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService, ElanConfig elanConfig,
             IInterfaceManager interfaceManager, ElanEtreeUtils elanEtreeUtils, ElanItmUtils elanItmUtils,
-            ElanInterfaceCache elanInterfaceCache) {
+            ElanInterfaceCache elanInterfaceCache, IITMProvider iitmProvider) {
         this.broker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
         this.broker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
@@ -215,6 +262,7 @@ public class ElanUtils {
         this.elanEtreeUtils = elanEtreeUtils;
         this.elanItmUtils = elanItmUtils;
         this.elanInterfaceCache = elanInterfaceCache;
         this.elanEtreeUtils = elanEtreeUtils;
         this.elanItmUtils = elanItmUtils;
         this.elanInterfaceCache = elanInterfaceCache;
+        this.iitmProvider = iitmProvider;
     }
 
     public final Boolean isOpenstackVniSemanticsEnforced() {
     }
 
     public final Boolean isOpenstackVniSemanticsEnforced() {
@@ -252,7 +300,7 @@ public class ElanUtils {
 
     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
 
     public static void releaseId(IdManagerService idManager, String poolName, String idKey) {
         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(poolName).setIdKey(idKey).build();
-        JdkFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id");
+        LoggingFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id");
     }
 
     /**
     }
 
     /**
@@ -268,7 +316,7 @@ public class ElanUtils {
      */
     @Deprecated
     @SuppressWarnings("checkstyle:IllegalCatch")
      */
     @Deprecated
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public static <T extends DataObject> Optional<T> read(@Nonnull DataBroker broker,
+    public static <T extends DataObject> Optional<T> read(@NonNull DataBroker broker,
             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
             return tx.read(datastoreType, path).get();
             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
             return tx.read(datastoreType, path).get();
@@ -285,6 +333,7 @@ public class ElanUtils {
         }
     }
 
         }
     }
 
+    @SuppressWarnings("checkstyle:ForbidCertainMethod")
     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
             InstanceIdentifier<T> path) {
         WriteTransaction tx = broker.newWriteOnlyTransaction();
     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
             InstanceIdentifier<T> path) {
         WriteTransaction tx = broker.newWriteOnlyTransaction();
@@ -292,32 +341,22 @@ public class ElanUtils {
         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor());
     }
 
         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor());
     }
 
-    public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-            InstanceIdentifier<T> path, FutureCallback<Void> callback) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.delete(datastoreType, path);
-        Futures.addCallback(tx.submit(), callback, MoreExecutors.directExecutor());
-    }
-
-    public static InstanceIdentifier<ElanInstance> getElanInstanceIdentifier() {
-        return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class).build();
-    }
-
     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
         return InstanceIdentifier.builder(ElanInterfaces.class)
                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
     }
 
     // elan-state Operational container
     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
         return InstanceIdentifier.builder(ElanInterfaces.class)
                 .child(ElanInterface.class, new ElanInterfaceKey(interfaceName)).build();
     }
 
     // elan-state Operational container
+    @Nullable
     public static Elan getElanByName(DataBroker broker, String elanInstanceName) {
         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
         return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).orNull();
     }
 
     @Nullable
     public static Elan getElanByName(DataBroker broker, String elanInstanceName) {
         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
         return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).orNull();
     }
 
     @Nullable
-    public static Elan getElanByName(ReadTransaction tx, String elanInstanceName) throws ReadFailedException {
-        return tx.read(LogicalDatastoreType.OPERATIONAL,
-                getElanInstanceOperationalDataPath(elanInstanceName)).checkedGet().orNull();
+    public static Elan getElanByName(TypedReadTransaction<Operational> tx, String elanInstanceName)
+            throws ExecutionException, InterruptedException {
+        return tx.read(getElanInstanceOperationalDataPath(elanInstanceName)).get().orNull();
     }
 
     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
     }
 
     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
@@ -325,16 +364,17 @@ public class ElanUtils {
     }
 
     // grouping of forwarding-entries
     }
 
     // grouping of forwarding-entries
+    @Nullable
     public MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
         InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(
                 interfaceName, physAddress);
         return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orNull();
     }
 
     public MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
         InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(
                 interfaceName, physAddress);
         return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orNull();
     }
 
-    public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(InstanceIdentifier identifier) {
-        Optional<MacEntry> existingInterfaceMacEntry = read(broker,
-                LogicalDatastoreType.OPERATIONAL, identifier);
-        return existingInterfaceMacEntry.orNull();
+    @Nullable
+    public MacEntry getInterfaceMacEntriesOperationalDataPathFromId(TypedReadTransaction<Operational> tx,
+            InstanceIdentifier<MacEntry> identifier) throws ExecutionException, InterruptedException {
+        return tx.read(identifier).get().orNull();
     }
 
     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName,
     }
 
     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName,
@@ -351,16 +391,16 @@ public class ElanUtils {
         return read(broker, LogicalDatastoreType.OPERATIONAL, macId);
     }
 
         return read(broker, LogicalDatastoreType.OPERATIONAL, macId);
     }
 
-    public Optional<MacEntry> getMacEntryForElanInstance(ReadTransaction tx, String elanName, PhysAddress physAddress)
-            throws ReadFailedException {
+    public Optional<MacEntry> getMacEntryForElanInstance(TypedReadTransaction<Operational> tx, String elanName,
+            PhysAddress physAddress) throws ExecutionException, InterruptedException {
         InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
         InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
-        return tx.read(LogicalDatastoreType.OPERATIONAL, macId).checkedGet();
+        return tx.read(macId).get();
     }
 
     }
 
-    public MacEntry getMacEntryFromElanMacId(InstanceIdentifier identifier) {
-        Optional<MacEntry> existingInterfaceMacEntry = read(broker,
-                LogicalDatastoreType.OPERATIONAL, identifier);
-        return existingInterfaceMacEntry.orNull();
+    @Nullable
+    public MacEntry getMacEntryFromElanMacId(TypedReadTransaction<Operational> tx,
+            InstanceIdentifier<MacEntry> identifier) throws ExecutionException, InterruptedException {
+        return tx.read(identifier).get().orNull();
     }
 
     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
     }
 
     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
@@ -386,25 +426,6 @@ public class ElanUtils {
         return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull();
     }
 
         return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orNull();
     }
 
-    /**
-     * Gets the elan interface mac addresses.
-     *
-     * @param interfaceName
-     *            the interface name
-     * @return the elan interface mac addresses
-     */
-    public List<PhysAddress> getElanInterfaceMacAddresses(String interfaceName) {
-        List<PhysAddress> macAddresses = new ArrayList<>();
-        ElanInterfaceMac elanInterfaceMac = getElanInterfaceMacByInterfaceName(interfaceName);
-        if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
-            List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
-            for (MacEntry macEntry : macEntries) {
-                macAddresses.add(macEntry.getMacAddress());
-            }
-        }
-        return macAddresses;
-    }
-
     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(
             String interfaceName) {
         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(
             String interfaceName) {
         return InstanceIdentifier.builder(ElanInterfaceForwardingEntries.class)
@@ -413,7 +434,7 @@ public class ElanUtils {
 
     /**
      * Returns the list of Interfaces that belong to an Elan on an specific DPN.
 
     /**
      * Returns the list of Interfaces that belong to an Elan on an specific DPN.
-     * Data retrieved from Elan's operational DS: elan-dpn-interfaces container
+     * Data retrieved from Elan's operational DS: elan-dpn-interfaces container.
      *
      * @param elanInstanceName
      *            name of the Elan to which the interfaces must belong to
      *
      * @param elanInstanceName
      *            name of the Elan to which the interfaces must belong to
@@ -421,6 +442,7 @@ public class ElanUtils {
      *            Id of the DPN where the interfaces are located
      * @return the elan interface Info
      */
      *            Id of the DPN where the interfaces are located
      * @return the elan interface Info
      */
+    @Nullable
     public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
                 dpId);
     public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
                 dpId);
@@ -446,6 +468,7 @@ public class ElanUtils {
     }
 
     // elan-tag-name-map Operational Container
     }
 
     // elan-tag-name-map Operational Container
+    @Nullable
     public ElanTagName getElanInfoByElanTag(long elanTag) {
         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
         Optional<ElanTagName> existingElanInfo = read(broker,
     public ElanTagName getElanInfoByElanTag(long elanTag) {
         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
         Optional<ElanTagName> existingElanInfo = read(broker,
@@ -474,11 +497,13 @@ public class ElanUtils {
                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
     }
 
                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName)).build();
     }
 
+    @Nullable
     public ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
     }
 
     public ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
         return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
     }
 
+    @Nullable
     public ElanDpnInterfaces getElanDpnInterfacesList() {
         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class)
                 .build();
     public ElanDpnInterfaces getElanDpnInterfacesList() {
         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class)
                 .build();
@@ -494,7 +519,7 @@ public class ElanUtils {
      *            the elan instance name
      * @return list of dpIds
      */
      *            the elan instance name
      * @return list of dpIds
      */
-    @Nonnull
+    @NonNull
     public List<BigInteger> getParticipatingDpnsInElanInstance(String elanInstanceName) {
         List<BigInteger> dpIds = new ArrayList<>();
         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
     public List<BigInteger> getParticipatingDpnsInElanInstance(String elanInstanceName) {
         List<BigInteger> dpIds = new ArrayList<>();
         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
@@ -503,46 +528,13 @@ public class ElanUtils {
         if (!existingElanDpnInterfaces.isPresent()) {
             return dpIds;
         }
         if (!existingElanDpnInterfaces.isPresent()) {
             return dpIds;
         }
-        List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
+        List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().nonnullDpnInterfaces();
         for (DpnInterfaces dpnInterface : dpnInterfaces) {
             dpIds.add(dpnInterface.getDpId());
         }
         return dpIds;
     }
 
         for (DpnInterfaces dpnInterface : dpnInterfaces) {
             dpIds.add(dpnInterface.getDpId());
         }
         return dpIds;
     }
 
-    /**
-     * To check given dpId is already present in Elan instance. This can be used
-     * to program flow entry in external tunnel table when a new access port
-     * added for first time into the ELAN instance
-     *
-     * @param dpId
-     *            the dp id
-     * @param elanInstanceName
-     *            the elan instance name
-     * @return true if dpId is already present, otherwise return false
-     */
-    public boolean isDpnAlreadyPresentInElanInstance(BigInteger dpId, String elanInstanceName) {
-        InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
-        Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = read(broker,
-                LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
-        if (!existingElanDpnInterfaces.isPresent()) {
-            return false;
-        }
-        List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
-        for (DpnInterfaces dpnInterface : dpnInterfaces) {
-            if (dpnInterface.getDpId().equals(dpId)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public ElanForwardingTables getElanForwardingList() {
-        InstanceIdentifier<ElanForwardingTables> elanForwardingTableId = InstanceIdentifier
-                .builder(ElanForwardingTables.class).build();
-        return read(broker, LogicalDatastoreType.OPERATIONAL, elanForwardingTableId).orNull();
-    }
-
     public static long getElanRemoteBroadCastGroupID(long elanTag) {
         return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2;
     }
     public static long getElanRemoteBroadCastGroupID(long elanTag) {
         return ElanConstants.ELAN_GID_MIN + elanTag % ElanConstants.ELAN_GID_MIN * 2;
     }
@@ -554,6 +546,7 @@ public class ElanUtils {
      *            the elan name
      * @return the elan mac table
      */
      *            the elan name
      * @return the elan mac table
      */
+    @Nullable
     public MacTable getElanMacTable(String elanName) {
         return getElanMacTable(broker, elanName);
     }
     public MacTable getElanMacTable(String elanName) {
         return getElanMacTable(broker, elanName);
     }
@@ -600,12 +593,11 @@ public class ElanUtils {
      *            true if remote dmac flows should be configured as well
      * @param writeFlowGroupTx
      *            the flow group tx
      *            true if remote dmac flows should be configured as well
      * @param writeFlowGroupTx
      *            the flow group tx
-     * @throws ElanException in case of issues creating the flow objects
      */
     public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
                               long macTimeout, String macAddress, boolean configureRemoteFlows,
      */
     public void setupMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
                               long macTimeout, String macAddress, boolean configureRemoteFlows,
-                              WriteTransaction writeFlowGroupTx) throws ElanException {
-        synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
+                              TypedWriteTransaction<Configuration> writeFlowGroupTx) {
+        try (Acquired lock = lockElanMacDPN(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalManager,
                 writeFlowGroupTx);
             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, configureRemoteFlows, mdsalManager,
             setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalManager,
                 writeFlowGroupTx);
             setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, configureRemoteFlows, mdsalManager,
@@ -614,7 +606,7 @@ public class ElanUtils {
     }
 
     public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
     }
 
     public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
-                                         String macAddress, WriteTransaction writeFlowTx) throws ElanException {
+                                         String macAddress, TypedWriteTransaction<Configuration> writeFlowTx) {
         String elanInstanceName = elanInfo.getElanInstanceName();
         setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(),
                 macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo);
         String elanInstanceName = elanInfo.getElanInstanceName();
         setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(),
                 macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo);
@@ -628,9 +620,10 @@ public class ElanUtils {
      * learnt.
      */
     private void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
      * learnt.
      */
     private void setupKnownSmacFlow(ElanInstance elanInfo, InterfaceInfo interfaceInfo, long macTimeout,
-            String macAddress, IMdsalApiManager mdsalApiManager, WriteTransaction writeFlowGroupTx) {
+            String macAddress, IMdsalApiManager mdsalApiManager,
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress);
         FlowEntity flowEntity = buildKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress);
-        mdsalApiManager.addFlowToTx(flowEntity, writeFlowGroupTx);
+        mdsalApiManager.addFlow(writeFlowGroupTx, flowEntity);
         LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}",
                 elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
     }
         LOG.debug("Known Smac flow entry created for elan Name:{}, logical Interface port:{} and mac address:{}",
                 elanInfo.getElanInstanceName(), elanInfo.getDescription(), macAddress);
     }
@@ -669,7 +662,7 @@ public class ElanUtils {
         if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
             return elanInfo.getElanTag();
         } else { // Leaf
         if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
             return elanInfo.getElanTag();
         } else { // Leaf
-            EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+            EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
             if (etreeInstance == null) {
                 LOG.warn("EtreeInterface {} is connected to a non-Etree network: {}",
                          interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
             if (etreeInstance == null) {
                 LOG.warn("EtreeInterface {} is connected to a non-Etree network: {}",
                          interfaceInfo.getInterfaceName(), elanInfo.getElanInstanceName());
@@ -693,7 +686,7 @@ public class ElanUtils {
      *            the writeFLowGroup tx
      */
     public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager,
      *            the writeFLowGroup tx
      */
     public void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager,
-                                   WriteTransaction writeFlowGroupTx) {
+                                   TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         BigInteger dpId = interfaceInfo.getDpId();
         int lportTag = interfaceInfo.getInterfaceTag();
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
         BigInteger dpId = interfaceInfo.getDpId();
         int lportTag = interfaceInfo.getInterfaceTag();
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
@@ -702,7 +695,7 @@ public class ElanUtils {
                 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
                 getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
                 ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
                 getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
-        mdsalApiManager.addFlowToTx(dpId, flow, writeFlowGroupTx);
+        mdsalApiManager.addFlow(writeFlowGroupTx, dpId, flow);
         LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId,
                 interfaceInfo.getPortName());
     }
         LOG.debug("Terminating service table flow entry created on dpn:{} for logical Interface port:{}", dpId,
                 interfaceInfo.getPortName());
     }
@@ -718,7 +711,7 @@ public class ElanUtils {
      * @return the Internal tunnel
      */
     public static String getIntTunnelTableFlowRef(short tableId, int elanTag) {
      * @return the Internal tunnel
      */
     public static String getIntTunnelTableFlowRef(short tableId, int elanTag) {
-        return new StringBuffer().append(tableId).append(elanTag).toString();
+        return new StringBuilder().append(tableId).append(elanTag).toString();
     }
 
     /**
     }
 
     /**
@@ -768,7 +761,8 @@ public class ElanUtils {
      * @return the egress actions for interface
      */
     @SuppressWarnings("checkstyle:IllegalCatch")
      * @return the egress actions for interface
      */
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public List<Action> getEgressActionsForInterface(String ifName, Long tunnelKey) {
+    @NonNull
+    public List<Action> getEgressActionsForInterface(String ifName, @Nullable Long tunnelKey) {
         List<Action> listAction = new ArrayList<>();
         try {
             GetEgressActionsForInterfaceInput getEgressActionInput = new GetEgressActionsForInterfaceInputBuilder()
         List<Action> listAction = new ArrayList<>();
         try {
             GetEgressActionsForInterfaceInput getEgressActionInput = new GetEgressActionsForInterfaceInputBuilder()
@@ -780,8 +774,7 @@ public class ElanUtils {
                 LOG.debug("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName,
                         rpcResult.getErrors());
             } else {
                 LOG.debug("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName,
                         rpcResult.getErrors());
             } else {
-                List<Action> actions = rpcResult.getResult().getAction();
-                listAction = actions;
+                listAction = rpcResult.getResult().nonnullAction();
             }
         } catch (Exception e) {
             LOG.warn("Exception when egress actions for interface {}", ifName, e);
             }
         } catch (Exception e) {
             LOG.warn("Exception when egress actions for interface {}", ifName, e);
@@ -791,8 +784,7 @@ public class ElanUtils {
 
     private void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
                                     boolean configureRemoteFlows, IMdsalApiManager mdsalApiManager,
 
     private void setupOrigDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
                                     boolean configureRemoteFlows, IMdsalApiManager mdsalApiManager,
-                                    WriteTransaction writeFlowGroupTx)
-                                    throws ElanException {
+                                    TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         BigInteger dpId = interfaceInfo.getDpId();
         String ifName = interfaceInfo.getInterfaceName();
         long ifTag = interfaceInfo.getInterfaceTag();
         BigInteger dpId = interfaceInfo.getDpId();
         String ifName = interfaceInfo.getInterfaceName();
         long ifTag = interfaceInfo.getInterfaceTag();
@@ -812,7 +804,7 @@ public class ElanUtils {
         List<DpnInterfaces> elanDpns = getInvolvedDpnsInElan(elanInstanceName);
         for (DpnInterfaces elanDpn : elanDpns) {
 
         List<DpnInterfaces> elanDpns = getInvolvedDpnsInElan(elanInstanceName);
         for (DpnInterfaces elanDpn : elanDpns) {
 
-            if (elanDpn.getDpId().equals(dpId)) {
+            if (Objects.equals(elanDpn.getDpId(), dpId)) {
                 continue;
             }
 
                 continue;
             }
 
@@ -837,28 +829,28 @@ public class ElanUtils {
         // TODO: Make sure that the same is performed against the ElanDevices.
     }
 
         // TODO: Make sure that the same is performed against the ElanDevices.
     }
 
-    @Nonnull
+    @NonNull
     public List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
         return getElanDPNByName(elanName);
     }
 
     public List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
         return getElanDPNByName(elanName);
     }
 
-    @Nonnull
+    @NonNull
     public List<DpnInterfaces> getElanDPNByName(String elanInstanceName) {
         InstanceIdentifier<ElanDpnInterfacesList> elanIdentifier = getElanDpnOperationDataPath(elanInstanceName);
         return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).toJavaUtil().map(
     public List<DpnInterfaces> getElanDPNByName(String elanInstanceName) {
         InstanceIdentifier<ElanDpnInterfacesList> elanIdentifier = getElanDpnOperationDataPath(elanInstanceName);
         return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).toJavaUtil().map(
-                ElanDpnInterfacesList::getDpnInterfaces).orElse(Collections.emptyList());
+                ElanDpnInterfacesList::getDpnInterfaces).orElse(emptyList());
     }
 
     private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
     }
 
     private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
-            ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
+            ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag,
+            TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, elanInfo, ifTag);
         Flow flowEntity = buildLocalDmacFlowEntry(elanTag, dpId, ifName, macAddress, elanInfo, ifTag);
-        mdsalApiManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
-        installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo,
-                ifTag, writeFlowGroupTx);
+        mdsalApiManager.addFlow(writeFlowGroupTx, dpId, flowEntity);
+        installEtreeLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, ifTag, writeFlowGroupTx);
     }
 
     private void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
     }
 
     private void installEtreeLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
-            ElanInstance elanInfo, long ifTag, WriteTransaction writeFlowGroupTx) {
+            ElanInstance elanInfo, long ifTag, TypedWriteTransaction<Configuration> writeFlowGroupTx) {
         EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(ifName).orNull();
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
             EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
         EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(ifName).orNull();
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
             EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
@@ -868,7 +860,7 @@ public class ElanUtils {
             } else {
                 Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName,
                         macAddress, elanInfo, ifTag);
             } else {
                 Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName,
                         macAddress, elanInfo, ifTag);
-                mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
+                mdsalManager.addFlow(writeFlowGroupTx, dpId, flowEntity);
             }
         }
     }
             }
         }
     }
@@ -932,9 +924,9 @@ public class ElanUtils {
         return flow;
     }
 
         return flow;
     }
 
-    public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag, String
-            macAddress, String displayName, WriteTransaction writeFlowGroupTx, String interfaceName, ElanInstance
-            elanInstance) throws ElanException {
+    public void setupRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, int lportTag, long elanTag,
+            String macAddress, String displayName, TypedWriteTransaction<Configuration> writeFlowGroupTx,
+            String interfaceName, ElanInstance elanInstance) {
         if (interfaceManager.isExternalInterface(interfaceName)) {
             LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}",
                     macAddress, interfaceName, elanInstance.getElanInstanceName());
         if (interfaceManager.isExternalInterface(interfaceName)) {
             LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}",
                     macAddress, interfaceName, elanInstance.getElanInstanceName());
@@ -947,14 +939,15 @@ public class ElanUtils {
                 ? getVxlanSegmentationId(elanInstance) : 0;
         flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName,
                 elanInstance);
                 ? getVxlanSegmentationId(elanInstance) : 0;
         flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName,
                 elanInstance);
-        mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
+        mdsalManager.addFlow(writeFlowGroupTx, srcDpId, flowEntity);
         setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName,
                 writeFlowGroupTx, elanInstance);
     }
 
     private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
                                           String macAddress, String displayName, String interfaceName,
         setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName,
                 writeFlowGroupTx, elanInstance);
     }
 
     private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
                                           String macAddress, String displayName, String interfaceName,
-                                          WriteTransaction writeFlowGroupTx, ElanInstance elanInstance) {
+                                          TypedWriteTransaction<Configuration> writeFlowGroupTx,
+                                          ElanInstance elanInstance) {
         Flow flowEntity;
         EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName).orNull();
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
         Flow flowEntity;
         EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName).orNull();
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
@@ -965,7 +958,7 @@ public class ElanUtils {
             } else {
                 flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni,
                         etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance);
             } else {
                 flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni,
                         etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance);
-                mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
+                mdsalManager.addFlow(writeFlowGroupTx, srcDpId, flowEntity);
             }
         }
     }
             }
         }
     }
@@ -1004,15 +997,15 @@ public class ElanUtils {
         // List of Action for the provided Source and Destination DPIDs
         try {
             List<Action> actions = null;
         // List of Action for the provided Source and Destination DPIDs
         try {
             List<Action> actions = null;
-            if (isVlan(elanInstance) || isFlat(elanInstance)) {
+            if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
+                actions = elanItmUtils.getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni);
+            } else if (isVlan(elanInstance) || isFlat(elanInstance)) {
                 String interfaceName = getExternalElanInterface(elanInstance.getElanInstanceName(), srcDpId);
                 if (null == interfaceName) {
                     LOG.info("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId,
                 String interfaceName = getExternalElanInterface(elanInstance.getElanInstanceName(), srcDpId);
                 if (null == interfaceName) {
                     LOG.info("buildRemoteDmacFlowEntry: Could not find interfaceName for {} {}", srcDpId,
-                        elanInstance);
+                            elanInstance);
                 }
                 actions = getEgressActionsForInterface(interfaceName, null);
                 }
                 actions = getEgressActionsForInterface(interfaceName, null);
-            } else if (isVxlanNetworkOrVxlanSegment(elanInstance)) {
-                actions = elanItmUtils.getInternalTunnelItmEgressAction(srcDpId, destDpId, lportTagOrVni);
             }
             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
         } catch (Exception e) {
             }
             mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
         } catch (Exception e) {
@@ -1032,18 +1025,20 @@ public class ElanUtils {
     }
 
     public void deleteMacFlows(@Nullable ElanInstance elanInfo, @Nullable InterfaceInfo interfaceInfo,
     }
 
     public void deleteMacFlows(@Nullable ElanInstance elanInfo, @Nullable InterfaceInfo interfaceInfo,
-            MacEntry macEntry, WriteTransaction deleteFlowGroupTx) {
+            MacEntry macEntry, TypedReadWriteTransaction<Configuration> flowTx)
+            throws ExecutionException, InterruptedException {
         if (elanInfo == null || interfaceInfo == null) {
             return;
         }
         String macAddress = macEntry.getMacAddress().getValue();
         if (elanInfo == null || interfaceInfo == null) {
             return;
         }
         String macAddress = macEntry.getMacAddress().getValue();
-        synchronized (getElanMacDPNKey(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
-            deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, deleteFlowGroupTx);
+        try (Acquired lock = lockElanMacDPN(elanInfo.getElanTag(), macAddress, interfaceInfo.getDpId())) {
+            deleteMacFlows(elanInfo, interfaceInfo, macAddress, /* alsoDeleteSMAC */ true, flowTx);
         }
     }
 
     public void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
         }
     }
 
     public void deleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
-            boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
+            boolean deleteSmac, TypedReadWriteTransaction<Configuration> flowTx)
+            throws ExecutionException, InterruptedException {
         String elanInstanceName = elanInfo.getElanInstanceName();
         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
         BigInteger srcdpId = interfaceInfo.getDpId();
         String elanInstanceName = elanInfo.getElanInstanceName();
         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
         BigInteger srcdpId = interfaceInfo.getDpId();
@@ -1052,40 +1047,39 @@ public class ElanUtils {
             Long elanTag = elanInfo.getElanTag();
             BigInteger dstDpId = dpnInterface.getDpId();
             if (executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
             Long elanTag = elanInfo.getElanTag();
             BigInteger dstDpId = dpnInterface.getDpId();
             if (executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
-                    elanTag, dstDpId, deleteFlowGroupTx)) {
+                    elanTag, dstDpId, flowTx)) {
                 isFlowsRemovedInSrcDpn = true;
             }
             executeEtreeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
                 isFlowsRemovedInSrcDpn = true;
             }
             executeEtreeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
-                    elanTag, dstDpId, deleteFlowGroupTx);
+                    elanTag, dstDpId, flowTx);
         }
         if (!isFlowsRemovedInSrcDpn) {
         }
         if (!isFlowsRemovedInSrcDpn) {
-            deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
+            deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, flowTx);
         }
     }
 
     private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
         }
     }
 
     private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
         if (etreeLeafTag != null) {
             executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
         EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
         if (etreeLeafTag != null) {
             executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
-                    etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, deleteFlowGroupTx);
+                    etreeLeafTag.getEtreeLeafTag().getValue(), dstDpId, flowTx);
         }
     }
 
     private boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
         }
     }
 
     private boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
             boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
-            WriteTransaction deleteFlowGroupTx) {
+            TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
         boolean isFlowsRemovedInSrcDpn = false;
         if (dstDpId.equals(srcdpId)) {
             isFlowsRemovedInSrcDpn = true;
         boolean isFlowsRemovedInSrcDpn = false;
         if (dstDpId.equals(srcdpId)) {
             isFlowsRemovedInSrcDpn = true;
-            deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, deleteFlowGroupTx);
+            deleteSmacAndDmacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, flowTx);
         } else if (isDpnPresent(dstDpId)) {
             mdsalManager
         } else if (isDpnPresent(dstDpId)) {
             mdsalManager
-                    .removeFlowToTx(dstDpId,
-                            MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(
-                                    NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)),
-                            deleteFlowGroupTx);
+                .removeFlow(flowTx, dstDpId,
+                    MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, getKnownDynamicmacFlowRef(
+                        NwConstants.ELAN_DMAC_TABLE, dstDpId, srcdpId, macAddress, elanTag)));
             LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}",
                     elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
         }
             LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}",
                     elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
         }
@@ -1093,22 +1087,21 @@ public class ElanUtils {
     }
 
     private void deleteSmacAndDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
     }
 
     private void deleteSmacAndDmacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
-            boolean deleteSmac, WriteTransaction deleteFlowGroupTx) {
+            boolean deleteSmac, TypedReadWriteTransaction<Configuration> flowTx)
+            throws ExecutionException, InterruptedException {
         String elanInstanceName = elanInfo.getElanInstanceName();
         long ifTag = interfaceInfo.getInterfaceTag();
         BigInteger srcdpId = interfaceInfo.getDpId();
         Long elanTag = elanInfo.getElanTag();
         if (deleteSmac) {
             mdsalManager
         String elanInstanceName = elanInfo.getElanInstanceName();
         long ifTag = interfaceInfo.getInterfaceTag();
         BigInteger srcdpId = interfaceInfo.getDpId();
         Long elanTag = elanInfo.getElanTag();
         if (deleteSmac) {
             mdsalManager
-                    .removeFlowToTx(srcdpId,
+                    .removeFlow(flowTx, srcdpId,
                             MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(
                             MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(
-                                    NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
-                            deleteFlowGroupTx);
+                                    NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
         }
         }
-        mdsalManager.removeFlowToTx(srcdpId,
-                MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
-                        getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
-                deleteFlowGroupTx);
+        mdsalManager.removeFlow(flowTx, srcdpId,
+            MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
+                getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
         LOG.debug("All the required flows deleted for elan:{}, logical Interface port:{} and MAC address:{} on dpn:{}",
                 elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
     }
         LOG.debug("All the required flows deleted for elan:{}, logical Interface port:{} and MAC address:{} on dpn:{}",
                 elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
     }
@@ -1123,32 +1116,31 @@ public class ElanUtils {
      *            the elan instance added
      * @param elanInterfaces
      *            the elan interfaces
      *            the elan instance added
      * @param elanInterfaces
      *            the elan interfaces
-     * @param tx
+     * @param operTx
      *            transaction
      *
      * @return the updated ELAN instance.
      */
     public static ElanInstance updateOperationalDataStore(IdManagerService idManager,
      *            transaction
      *
      * @return the updated ELAN instance.
      */
     public static ElanInstance updateOperationalDataStore(IdManagerService idManager,
-            ElanInstance elanInstanceAdded, List<String> elanInterfaces, WriteTransaction tx) {
+            ElanInstance elanInstanceAdded, List<String> elanInterfaces, TypedWriteTransaction<Configuration> confTx,
+            TypedWriteTransaction<Operational> operTx) {
         String elanInstanceName = elanInstanceAdded.getElanInstanceName();
         Long elanTag = elanInstanceAdded.getElanTag();
         if (elanTag == null || elanTag == 0L) {
             elanTag = retrieveNewElanTag(idManager, elanInstanceName);
         }
         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces)
         String elanInstanceName = elanInstanceAdded.getElanInstanceName();
         Long elanTag = elanInstanceAdded.getElanTag();
         if (elanTag == null || elanTag == 0L) {
             elanTag = retrieveNewElanTag(idManager, elanInstanceName);
         }
         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces)
-                .setKey(new ElanKey(elanInstanceName)).build();
+                .withKey(new ElanKey(elanInstanceName)).build();
 
         // Add the ElanState in the elan-state operational data-store
 
         // Add the ElanState in the elan-state operational data-store
-        tx.put(LogicalDatastoreType.OPERATIONAL, getElanInstanceOperationalDataPath(elanInstanceName),
-                elanInfo, WriteTransaction.CREATE_MISSING_PARENTS);
+        operTx.put(getElanInstanceOperationalDataPath(elanInstanceName), elanInfo, CREATE_MISSING_PARENTS);
 
         // Add the ElanMacTable in the elan-mac-table operational data-store
 
         // Add the ElanMacTable in the elan-mac-table operational data-store
-        MacTable elanMacTable = new MacTableBuilder().setKey(new MacTableKey(elanInstanceName)).build();
-        tx.put(LogicalDatastoreType.OPERATIONAL, getElanMacTableOperationalDataPath(elanInstanceName),
-                elanMacTable, WriteTransaction.CREATE_MISSING_PARENTS);
+        MacTable elanMacTable = new MacTableBuilder().withKey(new MacTableKey(elanInstanceName)).build();
+        operTx.put(getElanMacTableOperationalDataPath(elanInstanceName), elanMacTable, CREATE_MISSING_PARENTS);
 
         ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag)
 
         ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag)
-                .setKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName);
+                .withKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName);
         long etreeLeafTag = -1;
         if (isEtreeInstance(elanInstanceAdded)) {
             etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants
         long etreeLeafTag = -1;
         if (isEtreeInstance(elanInstanceAdded)) {
             etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants
@@ -1156,14 +1148,13 @@ public class ElanUtils {
             EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder()
                     .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build();
             elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName);
             EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder()
                     .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build();
             elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName);
-            addTheLeafTagAsElanTag(elanInstanceName, etreeLeafTag, tx);
+            addTheLeafTagAsElanTag(elanInstanceName, etreeLeafTag, operTx);
         }
         ElanTagName elanTagName = elanTagNameBuilder.build();
 
         // Add the ElanTag to ElanName in the elan-tag-name Operational
         // data-store
         }
         ElanTagName elanTagName = elanTagNameBuilder.build();
 
         // Add the ElanTag to ElanName in the elan-tag-name Operational
         // data-store
-        tx.put(LogicalDatastoreType.OPERATIONAL,
-                getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
+        operTx.put(getElanInfoEntriesOperationalDataPath(elanTag), elanTagName);
 
         // Updates the ElanInstance Config DS by setting the just acquired
         // elanTag
 
         // Updates the ElanInstance Config DS by setting the just acquired
         // elanTag
@@ -1171,27 +1162,27 @@ public class ElanUtils {
                 .setDescription(elanInstanceAdded.getDescription())
                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null
                         ? Long.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout())
                 .setDescription(elanInstanceAdded.getDescription())
                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null
                         ? Long.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout())
-                .setKey(elanInstanceAdded.getKey()).setElanTag(elanTag);
+                .withKey(elanInstanceAdded.key()).setElanTag(elanTag);
         if (isEtreeInstance(elanInstanceAdded)) {
             EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag))
                     .build();
             elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance);
         }
         ElanInstance elanInstanceWithTag = elanInstanceBuilder.build();
         if (isEtreeInstance(elanInstanceAdded)) {
             EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag))
                     .build();
             elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance);
         }
         ElanInstance elanInstanceWithTag = elanInstanceBuilder.build();
-        tx.merge(LogicalDatastoreType.CONFIGURATION, ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName),
-                elanInstanceWithTag, WriteTransaction.CREATE_MISSING_PARENTS);
+        confTx.merge(ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstanceWithTag,
+            CREATE_MISSING_PARENTS);
         return elanInstanceWithTag;
     }
 
         return elanInstanceWithTag;
     }
 
-    private static void addTheLeafTagAsElanTag(String elanInstanceName, long etreeLeafTag, WriteTransaction tx) {
+    private static void addTheLeafTagAsElanTag(String elanInstanceName, long etreeLeafTag,
+            TypedWriteTransaction<Operational> tx) {
         ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag)
         ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag)
-                .setKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build();
-        tx.put(LogicalDatastoreType.OPERATIONAL,
-                getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag);
+                .withKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build();
+        tx.put(getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag);
     }
 
     private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) {
     }
 
     private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) {
-        return elanInstanceAdded.getAugmentation(EtreeInstance.class) != null;
+        return elanInstanceAdded.augmentation(EtreeInstance.class) != null;
     }
 
     public boolean isDpnPresent(BigInteger dpnId) {
     }
 
     public boolean isDpnPresent(BigInteger dpnId) {
@@ -1203,11 +1194,6 @@ public class ElanUtils {
         return read(broker, LogicalDatastoreType.CONFIGURATION, node).isPresent();
     }
 
         return read(broker, LogicalDatastoreType.CONFIGURATION, node).isPresent();
     }
 
-    public static ServicesInfo getServiceInfo(String elanInstanceName, String interfaceName) {
-        return InterfaceServiceUtil.buildServiceInfo(elanInstanceName + "." + interfaceName,
-                ElanConstants.ELAN_SERVICE_PRIORITY);
-    }
-
     public static String getElanServiceName(String elanName, String interfaceName) {
         return "elan." + elanName + interfaceName;
     }
     public static String getElanServiceName(String elanName, String interfaceName) {
         return "elan." + elanName + interfaceName;
     }
@@ -1216,7 +1202,7 @@ public class ElanUtils {
             BigInteger cookie, List<Instruction> instructions) {
         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
                 .setInstruction(instructions);
             BigInteger cookie, List<Instruction> instructions) {
         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
                 .setInstruction(instructions);
-        return new BoundServicesBuilder().setKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
+        return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
     }
                 .setServicePriority(servicePriority).setServiceType(ServiceTypeFlowBased.class)
                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
     }
@@ -1238,9 +1224,10 @@ public class ElanUtils {
     public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder()
                 .setDpnId(destDpId).setServiceId(serviceId).build();
     public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder()
                 .setDpnId(destDpId).setServiceId(serviceId).build();
-        Future<RpcResult<Void>> futureObject = itmRpcService.removeTerminatingServiceActions(input);
+        Future<RpcResult<RemoveTerminatingServiceActionsOutput>> futureObject =
+                itmRpcService.removeTerminatingServiceActions(input);
         try {
         try {
-            RpcResult<Void> result = futureObject.get();
+            RpcResult<RemoveTerminatingServiceActionsOutput> result = futureObject.get();
             if (result.isSuccessful()) {
                 LOG.debug("Successfully completed removeTerminatingServiceActions for ELAN with serviceId {} on "
                                 + "dpn {}", serviceId, destDpId);
             if (result.isSuccessful()) {
                 LOG.debug("Successfully completed removeTerminatingServiceActions for ELAN with serviceId {} on "
                                 + "dpn {}", serviceId, destDpId);
@@ -1265,6 +1252,7 @@ public class ElanUtils {
      *            the datastore type
      * @return the external tunnel
      */
      *            the datastore type
      * @return the external tunnel
      */
+    @Nullable
     public ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
             LogicalDatastoreType datastoreType) {
         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
     public ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
             LogicalDatastoreType datastoreType) {
         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
@@ -1282,6 +1270,7 @@ public class ElanUtils {
      *            the datastore type
      * @return the external tunnel
      */
      *            the datastore type
      * @return the external tunnel
      */
+    @Nullable
     public ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
         ExternalTunnel externalTunnel = null;
         List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
     public ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
         ExternalTunnel externalTunnel = null;
         List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
@@ -1304,7 +1293,7 @@ public class ElanUtils {
     public List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
         InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
         return read(broker, datastoreType, iid).toJavaUtil().map(ExternalTunnelList::getExternalTunnel).orElse(
     public List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
         InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
         return read(broker, datastoreType, iid).toJavaUtil().map(ExternalTunnelList::getExternalTunnel).orElse(
-                Collections.emptyList());
+                emptyList());
     }
 
     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
     }
 
     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
@@ -1344,13 +1333,10 @@ public class ElanUtils {
      *            the data broker
      * @return the interface state from oper ds
      */
      *            the data broker
      * @return the interface state from oper ds
      */
-    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
-        .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
-            String interfaceName, DataBroker dataBroker) {
-        InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
-            .ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
-                interfaceName);
-        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId).orNull();
+    public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
+            .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName, DataBroker dataBroker) {
+        return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
+            createInterfaceStateInstanceIdentifier(interfaceName)).orNull();
     }
 
     /**
     }
 
     /**
@@ -1374,15 +1360,15 @@ public class ElanUtils {
         return idBuilder.build();
     }
 
         return idBuilder.build();
     }
 
-    public static CheckedFuture<Void, TransactionCommitFailedException> waitForTransactionToComplete(
-            WriteTransaction tx) {
-        CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
+    @CheckReturnValue
+    public static ListenableFuture<Void> waitForTransactionToComplete(ListenableFuture<Void> future) {
         try {
         try {
-            futures.get();
+            future.get();
         } catch (InterruptedException | ExecutionException e) {
         } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Error writing to datastore {}", e);
+            // NETVIRT-1215: Do not log.error() here, only debug(); but callers *MUST* @CheckReturnValue
+            LOG.debug("Error writing to datastore", e);
         }
         }
-        return futures;
+        return future;
     }
 
     public static boolean isVxlan(@Nullable ElanInstance elanInstance) {
     }
 
     public static boolean isVxlan(@Nullable ElanInstance elanInstance) {
@@ -1391,7 +1377,7 @@ public class ElanUtils {
                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
     }
 
                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
     }
 
-    private static boolean isVxlanSegment(ElanInstance elanInstance) {
+    private static boolean isVxlanSegment(@Nullable ElanInstance elanInstance) {
         if (elanInstance != null) {
             List<ElanSegments> elanSegments = elanInstance.getElanSegments();
             if (elanSegments != null) {
         if (elanInstance != null) {
             List<ElanSegments> elanSegments = elanInstance.getElanSegments();
             if (elanSegments != null) {
@@ -1407,7 +1393,7 @@ public class ElanUtils {
         return false;
     }
 
         return false;
     }
 
-    public static boolean isVxlanNetworkOrVxlanSegment(ElanInstance elanInstance) {
+    public static boolean isVxlanNetworkOrVxlanSegment(@Nullable ElanInstance elanInstance) {
         return isVxlan(elanInstance) || isVxlanSegment(elanInstance);
     }
 
         return isVxlan(elanInstance) || isVxlanSegment(elanInstance);
     }
 
@@ -1447,18 +1433,21 @@ public class ElanUtils {
     public void addDmacRedirectToDispatcherFlows(Long elanTag, String displayName,
             String macAddress, List<BigInteger> dpnIds) {
         for (BigInteger dpId : dpnIds) {
     public void addDmacRedirectToDispatcherFlows(Long elanTag, String displayName,
             String macAddress, List<BigInteger> dpnIds) {
         for (BigInteger dpId : dpnIds) {
-            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
-                tx -> mdsalManager.addFlowToTx(
-                        buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName, elanTag), tx)), LOG,
+            LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                tx -> mdsalManager.addFlow(tx, buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName,
+                        elanTag))), LOG,
                 "Error adding DMAC redirect to dispatcher flows");
         }
     }
 
     public void removeDmacRedirectToDispatcherFlows(Long elanTag, String macAddress, List<BigInteger> dpnIds) {
                 "Error adding DMAC redirect to dispatcher flows");
         }
     }
 
     public void removeDmacRedirectToDispatcherFlows(Long elanTag, String macAddress, List<BigInteger> dpnIds) {
-        for (BigInteger dpId : dpnIds) {
-            String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag);
-            mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId));
-        }
+        LoggingFutures.addErrorLogging(
+            txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+                for (BigInteger dpId : dpnIds) {
+                    String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, macAddress, elanTag);
+                    mdsalManager.removeFlow(tx, dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE, flowId));
+                }
+            }), LOG, "Error removing DMAC redirect to dispatcher flows");
     }
 
     public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress,
     }
 
     public static FlowEntity buildDmacRedirectToDispatcherFlow(BigInteger dpId, String dstMacAddress,
@@ -1477,6 +1466,7 @@ public class ElanUtils {
                 matches, instructions);
     }
 
                 matches, instructions);
     }
 
+    @Nullable
     public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
         DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
         if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
     public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
         DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
         if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
@@ -1494,22 +1484,18 @@ public class ElanUtils {
         return null;
     }
 
         return null;
     }
 
-    public static String getElanMacDPNKey(long elanTag, String macAddress, BigInteger dpnId) {
-        String elanMacDmacDpnKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag + "DPN_ID-" + dpnId;
-        return elanMacDmacDpnKey.intern();
+    public static Acquired lockElanMacDPN(long elanTag, String macAddress, BigInteger dpnId) {
+        return ELAN_LOCKS.acquire(new ElanLockName(elanTag, macAddress, dpnId));
     }
 
     }
 
-    public static String getElanMacKey(long elanTag, String macAddress) {
-        String elanMacKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag;
-        return elanMacKey.intern();
-    }
+    public static List<ListenableFuture<Void>>
+        returnFailedListenableFutureIfTransactionCommitFailedExceptionCauseOrElseThrow(RuntimeException exception) {
 
 
-    // TODO This should return a collection of futures
-    public static void addToListenableFutureIfTxException(RuntimeException exception,
-            List<ListenableFuture<Void>> futures) {
         Throwable cause = exception.getCause();
         if (cause != null && cause instanceof TransactionCommitFailedException) {
         Throwable cause = exception.getCause();
         if (cause != null && cause instanceof TransactionCommitFailedException) {
-            futures.add(Futures.immediateFailedCheckedFuture((TransactionCommitFailedException) cause));
+            return Collections.singletonList(Futures.immediateFailedFuture(cause));
+        } else {
+            throw exception;
         }
     }
 
         }
     }
 
@@ -1542,18 +1528,6 @@ public class ElanUtils {
                         new StaticMacEntriesKey(new PhysAddress(macAddress))).build();
     }
 
                         new StaticMacEntriesKey(new PhysAddress(macAddress))).build();
     }
 
-    public static List<StaticMacEntries> getDeletedEntries(List<StaticMacEntries> originalStaticMacEntries,
-                                                           List<StaticMacEntries> updatedStaticMacEntries) {
-        if (isEmpty(originalStaticMacEntries)) {
-            return Collections.EMPTY_LIST;
-        }
-        List<StaticMacEntries> deleted = Lists.newArrayList(originalStaticMacEntries);
-        if (isNotEmpty(updatedStaticMacEntries)) {
-            deleted.removeAll(updatedStaticMacEntries);
-        }
-        return deleted;
-    }
-
     public static <T> List<T> diffOf(List<T> orig, List<T> updated) {
         if (isEmpty(orig)) {
             return Collections.EMPTY_LIST;
     public static <T> List<T> diffOf(List<T> orig, List<T> updated) {
         if (isEmpty(orig)) {
             return Collections.EMPTY_LIST;
@@ -1565,18 +1539,6 @@ public class ElanUtils {
         return diff;
     }
 
         return diff;
     }
 
-    public static void segregateToBeDeletedAndAddEntries(List<StaticMacEntries> originalStaticMacEntries,
-                                                             List<StaticMacEntries> updatedStaticMacEntries) {
-        if (isNotEmpty(updatedStaticMacEntries)) {
-            List<StaticMacEntries> existingClonedStaticMacEntries = new ArrayList<>();
-            if (isNotEmpty(originalStaticMacEntries)) {
-                existingClonedStaticMacEntries.addAll(0, originalStaticMacEntries);
-                originalStaticMacEntries.removeAll(updatedStaticMacEntries);
-                updatedStaticMacEntries.removeAll(existingClonedStaticMacEntries);
-            }
-        }
-    }
-
     public static boolean isEmpty(Collection collection) {
         return collection == null || collection.isEmpty();
     }
     public static boolean isEmpty(Collection collection) {
         return collection == null || collection.isEmpty();
     }
@@ -1607,7 +1569,7 @@ public class ElanUtils {
     public List<MacEntry> getElanMacEntries(String elanName) {
         MacTable macTable = getElanMacTable(elanName);
         if (macTable == null) {
     public List<MacEntry> getElanMacEntries(String elanName) {
         MacTable macTable = getElanMacTable(elanName);
         if (macTable == null) {
-            return Collections.emptyList();
+            return emptyList();
         }
         return macTable.getMacEntry();
     }
         }
         return macTable.getMacEntry();
     }
@@ -1616,12 +1578,16 @@ public class ElanUtils {
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
             .ietf.interfaces.rev140508.interfaces.Interface configIface =
             interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
             .ietf.interfaces.rev140508.interfaces.Interface configIface =
             interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
-        IfTunnel ifTunnel = configIface.getAugmentation(IfTunnel.class);
+        if (configIface == null) {
+            configIface = iitmProvider.getInterface(interfaceName);
+        }
+        if (configIface == null) {
+            return  false;
+        }
+        IfTunnel ifTunnel = configIface.augmentation(IfTunnel.class);
         if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
         if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
-            ParentRefs refs = configIface.getAugmentation(ParentRefs.class);
-            if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
-                return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
-            }
+            ParentRefs refs = configIface.augmentation(ParentRefs.class);
+            return refs != null && !Strings.isNullOrEmpty(refs.getParentInterface());
         }
         return false;
     }
         }
         return false;
     }
@@ -1631,10 +1597,10 @@ public class ElanUtils {
         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
                 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId);
         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node nodeDpn =
         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
                 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId);
         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node nodeDpn =
-                new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
+                new NodeBuilder().setId(nodeId).withKey(new NodeKey(nodeId)).build();
         return InstanceIdentifier.builder(Nodes.class)
                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
         return InstanceIdentifier.builder(Nodes.class)
                 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
-                        nodeDpn.getKey()).augmentation(FlowCapableNode.class)
+                        nodeDpn.key()).augmentation(FlowCapableNode.class)
                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
     }
 
                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
     }
 
@@ -1646,8 +1612,36 @@ public class ElanUtils {
             int lportTag) {
         LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName,
                 ipAddress);
             int lportTag) {
         LOG.info("Removing the ARP responder flow on DPN {} of Interface {} with IP {}", dpnId, ingressInterfaceName,
                 ipAddress);
-        ArpResponderUtil.removeFlow(mdsalManager, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress));
+        LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION,
+            tx -> mdsalManager.removeFlow(tx, dpnId, ArpResponderUtil.getFlowId(lportTag, ipAddress),
+                NwConstants.ARP_RESPONDER_TABLE)), LOG, "Error removing ARP responder flow");
+    }
+
+    @Nullable
+    public static String getRouterPordIdFromElanInstance(DataBroker dataBroker, String elanInstanceName) {
+        Optional<Subnetmaps> subnetMapsData =
+                read(dataBroker, LogicalDatastoreType.CONFIGURATION, buildSubnetMapsWildCardPath());
+        if (subnetMapsData.isPresent()) {
+            List<Subnetmap> subnetMapList = subnetMapsData.get().getSubnetmap();
+            if (subnetMapList != null && !subnetMapList.isEmpty()) {
+                for (Subnetmap subnet : subnetMapList) {
+                    if (subnet.getNetworkId().getValue().equals(elanInstanceName)) {
+                        if (subnet.getRouterInterfacePortId() != null) {
+                            return subnet.getRouterInterfacePortId().getValue();
+                        }
+                    }
+                }
+            }
+        }
+        return null;
     }
     }
-}
 
 
+    static InstanceIdentifier<Subnetmaps> buildSubnetMapsWildCardPath() {
+        return InstanceIdentifier.create(Subnetmaps.class);
+    }
 
 
+    public static InstanceIdentifier<Group> getGroupInstanceid(BigInteger dpnId, long groupId) {
+        return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow:" + dpnId)))
+                .augmentation(FlowCapableNode.class).child(Group.class, new GroupKey(new GroupId(groupId))).build();
+    }
+}