MRI version bumpup for Aluminium
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / utils / ElanUtils.java
index c76535a65328409526b2a2de301b75fb7ef29c0f..975c12d8806cf10401f5469e8dfae825619c7794 100755 (executable)
@@ -7,40 +7,53 @@
  */
 package org.opendaylight.netvirt.elan.utils;
 
  */
 package org.opendaylight.netvirt.elan.utils;
 
-import com.google.common.base.Optional;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.primitives.Ints;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
 import com.google.common.primitives.Ints;
-import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FluentFuture;
 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.FutureCallback;
 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.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
-import javax.annotation.CheckReturnValue;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 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.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.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+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.itm.api.IITMProvider;
 import org.opendaylight.genius.itm.globals.ITMConstants;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.itm.api.IITMProvider;
 import org.opendaylight.genius.itm.globals.ITMConstants;
@@ -64,11 +77,18 @@ 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.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.ReadTransaction;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
+import org.opendaylight.netvirt.elan.internal.ElanGroupCache;
 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
@@ -86,6 +106,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.ta
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
@@ -120,6 +141,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.I
 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.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.BucketId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
+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;
@@ -135,7 +164,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;
@@ -155,6 +183,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegments;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegmentsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
@@ -174,13 +203,45 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
 public class ElanUtils {
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 @Singleton
 public class ElanUtils {
+    private static final class ElanLockName {
+        private final String macAddress;
+        private final Uint64 dpnId;
+        private final long elanTag;
+
+        ElanLockName(long elanTag, String macAddress, Uint64 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;
@@ -193,10 +254,20 @@ public class ElanUtils {
     private final ElanEtreeUtils elanEtreeUtils;
     private final ElanInterfaceCache elanInterfaceCache;
     private final IITMProvider iitmProvider;
     private final ElanEtreeUtils elanEtreeUtils;
     private final ElanInterfaceCache elanInterfaceCache;
     private final IITMProvider iitmProvider;
+    private final ElanGroupCache elanGroupCache;
+
+    private static final Function<Bucket, Bucket> TO_BUCKET_WITHOUT_ID = (bucket) -> new BucketBuilder(bucket)
+            .setBucketId(new BucketId(0L))
+            .build();
+
+    private static final BiFunction<Bucket, AtomicLong, Bucket> TO_BUCKET_WITH_ID = (bucket, id)
+        -> new BucketBuilder(bucket)
+            .setBucketId(new BucketId(id.incrementAndGet()))
+            .build();
 
 
-    public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
+    public static final FutureCallback<CommitInfo> DEFAULT_CALLBACK = new FutureCallback<CommitInfo>() {
         @Override
         @Override
-        public void onSuccess(Void result) {
+        public void onSuccess(CommitInfo result) {
             LOG.debug("Success in Datastore operation");
         }
 
             LOG.debug("Success in Datastore operation");
         }
 
@@ -210,7 +281,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, IITMProvider iitmProvider) {
+            ElanInterfaceCache elanInterfaceCache, IITMProvider iitmProvider, ElanGroupCache elanGroupCache) {
         this.broker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
         this.broker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
@@ -222,6 +293,7 @@ public class ElanUtils {
         this.elanItmUtils = elanItmUtils;
         this.elanInterfaceCache = elanInterfaceCache;
         this.iitmProvider = iitmProvider;
         this.elanItmUtils = elanItmUtils;
         this.elanInterfaceCache = elanInterfaceCache;
         this.iitmProvider = iitmProvider;
+        this.elanGroupCache = elanGroupCache;
     }
 
     public final Boolean isOpenstackVniSemanticsEnforced() {
     }
 
     public final Boolean isOpenstackVniSemanticsEnforced() {
@@ -238,7 +310,7 @@ public class ElanUtils {
      *            the id key
      * @return the integer
      */
      *            the id key
      * @return the integer
      */
-    public static Long retrieveNewElanTag(IdManagerService idManager, String idKey) {
+    public static Uint32 retrieveNewElanTag(IdManagerService idManager, String idKey) {
 
         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
                 .setIdKey(idKey).build();
 
         AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
                 .setIdKey(idKey).build();
@@ -254,12 +326,12 @@ public class ElanUtils {
         } catch (InterruptedException | ExecutionException e) {
             LOG.warn("Exception when Allocating Id", e);
         }
         } catch (InterruptedException | ExecutionException e) {
             LOG.warn("Exception when Allocating Id", e);
         }
-        return 0L;
+        return Uint32.valueOf(0L);
     }
 
     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");
     }
 
     /**
     }
 
     /**
@@ -275,41 +347,30 @@ 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) {
             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
-        try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
+        try (ReadTransaction tx = broker.newReadOnlyTransaction()) {
             return tx.read(datastoreType, path).get();
             return tx.read(datastoreType, path).get();
-        } catch (Exception e) {
+        } catch (ExecutionException | InterruptedException  e) {
             throw new RuntimeException(e);
         }
     }
 
     public <T extends DataObject> Optional<T> read2(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
             throw new RuntimeException(e);
         }
     }
 
     public <T extends DataObject> Optional<T> read2(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
-            throws ReadFailedException {
-        try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
-            CheckedFuture<Optional<T>, ReadFailedException> checkedFuture = tx.read(datastoreType, path);
-            return checkedFuture.checkedGet();
+            throws InterruptedException, ExecutionException {
+        try (ReadTransaction tx = broker.newReadOnlyTransaction()) {
+            FluentFuture<Optional<T>> checkedFuture = tx.read(datastoreType, path);
+            return checkedFuture.get();
         }
     }
 
     @SuppressWarnings("checkstyle:ForbidCertainMethod")
     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
         }
     }
 
     @SuppressWarnings("checkstyle:ForbidCertainMethod")
     public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-            InstanceIdentifier<T> path) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.delete(datastoreType, path);
-        Futures.addCallback(tx.submit(), DEFAULT_CALLBACK, MoreExecutors.directExecutor());
-    }
-
-    @SuppressWarnings("checkstyle:ForbidCertainMethod")
-    public static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-            InstanceIdentifier<T> path, FutureCallback<Void> callback) {
+                                                            InstanceIdentifier<T> path) {
         WriteTransaction tx = broker.newWriteOnlyTransaction();
         tx.delete(datastoreType, path);
         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();
+        FluentFuture<? extends @NonNull CommitInfo> future = tx.commit();
+        future.addCallback(DEFAULT_CALLBACK, MoreExecutors.directExecutor());
     }
 
     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
     }
 
     public static InstanceIdentifier<ElanInterface> getElanInterfaceConfigurationDataPathId(String interfaceName) {
@@ -318,15 +379,23 @@ public class ElanUtils {
     }
 
     // elan-state Operational container
     }
 
     // elan-state Operational container
+    @Nullable
     public static Elan getElanByName(DataBroker broker, String elanInstanceName) {
         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
     public static Elan getElanByName(DataBroker broker, String elanInstanceName) {
         InstanceIdentifier<Elan> elanIdentifier = getElanInstanceOperationalDataPath(elanInstanceName);
-        return MDSALUtil.read(broker, LogicalDatastoreType.OPERATIONAL, elanIdentifier).orNull();
+        try {
+            return SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.OPERATIONAL,
+                    elanIdentifier).orElse(null);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getElanByName: Exception while reading elan-instance DS for the elan instance {}",
+                    elanInstanceName, e);
+            return null;
+        }
     }
 
     @Nullable
     }
 
     @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().orElse(null);
     }
 
     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
     }
 
     public static InstanceIdentifier<Elan> getElanInstanceOperationalDataPath(String elanInstanceName) {
@@ -334,16 +403,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);
     public MacEntry getInterfaceMacEntriesOperationalDataPath(String interfaceName, PhysAddress physAddress) {
         InstanceIdentifier<MacEntry> existingMacEntryId = getInterfaceMacEntriesIdentifierOperationalDataPath(
                 interfaceName, physAddress);
-        return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orNull();
+        return read(broker, LogicalDatastoreType.OPERATIONAL, existingMacEntryId).orElse(null);
     }
 
     }
 
-    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().orElse(null);
     }
 
     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName,
     }
 
     public static InstanceIdentifier<MacEntry> getInterfaceMacEntriesIdentifierOperationalDataPath(String interfaceName,
@@ -360,16 +430,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().orElse(null);
     }
 
     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
     }
 
     public static InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName,
@@ -392,26 +462,7 @@ public class ElanUtils {
     public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(DataBroker dataBroker, String interfaceName) {
         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath(
                 interfaceName);
     public static ElanInterfaceMac getElanInterfaceMacByInterfaceName(DataBroker dataBroker, String interfaceName) {
         InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = getElanInterfaceMacEntriesOperationalDataPath(
                 interfaceName);
-        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;
+        return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId).orElse(null);
     }
 
     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(
     }
 
     public static InstanceIdentifier<ElanInterfaceMac> getElanInterfaceMacEntriesOperationalDataPath(
@@ -422,7 +473,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
@@ -430,10 +481,11 @@ 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
      */
-    public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, BigInteger dpId) {
+    @Nullable
+    public DpnInterfaces getElanInterfaceInfoByElanDpn(String elanInstanceName, Uint64 dpId) {
         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
                 dpId);
         InstanceIdentifier<DpnInterfaces> elanDpnInterfacesId = getElanDpnInterfaceOperationalDataPath(elanInstanceName,
                 dpId);
-        return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orNull();
+        return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfacesId).orElse(null);
     }
 
     /**
     }
 
     /**
@@ -448,34 +500,36 @@ public class ElanUtils {
      * @return the elan dpn interface
      */
     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
      * @return the elan dpn interface
      */
     public static InstanceIdentifier<DpnInterfaces> getElanDpnInterfaceOperationalDataPath(String elanInstanceName,
-            BigInteger dpId) {
+            Uint64 dpId) {
         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
     }
 
     // elan-tag-name-map Operational Container
         return InstanceIdentifier.builder(ElanDpnInterfaces.class)
                 .child(ElanDpnInterfacesList.class, new ElanDpnInterfacesListKey(elanInstanceName))
                 .child(DpnInterfaces.class, new DpnInterfacesKey(dpId)).build();
     }
 
     // elan-tag-name-map Operational Container
-    public ElanTagName getElanInfoByElanTag(long elanTag) {
+    @Nullable
+    public ElanTagName getElanInfoByElanTag(Uint32 elanTag) {
         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
         Optional<ElanTagName> existingElanInfo = read(broker,
                 LogicalDatastoreType.OPERATIONAL, elanId);
         InstanceIdentifier<ElanTagName> elanId = getElanInfoEntriesOperationalDataPath(elanTag);
         Optional<ElanTagName> existingElanInfo = read(broker,
                 LogicalDatastoreType.OPERATIONAL, elanId);
-        return existingElanInfo.orNull();
+        return existingElanInfo.orElse(null);
     }
 
     }
 
-    public static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(long elanTag) {
+    public static InstanceIdentifier<ElanTagName> getElanInfoEntriesOperationalDataPath(Uint32 elanTag) {
         return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class, new ElanTagNameKey(elanTag))
                 .build();
     }
 
     // interface-index-tag operational container
         return InstanceIdentifier.builder(ElanTagNameMap.class).child(ElanTagName.class, new ElanTagNameKey(elanTag))
                 .build();
     }
 
     // interface-index-tag operational container
-    public Optional<IfIndexInterface> getInterfaceInfoByInterfaceTag(long interfaceTag) {
+    public Optional<IfIndexInterface> getInterfaceInfoByInterfaceTag(Uint32 interfaceTag) {
         InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
         return read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
     }
 
         InstanceIdentifier<IfIndexInterface> interfaceId = getInterfaceInfoEntriesOperationalDataPath(interfaceTag);
         return read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
     }
 
-    public static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(long interfaceTag) {
+    public static InstanceIdentifier<IfIndexInterface> getInterfaceInfoEntriesOperationalDataPath(Uint32 interfaceTag) {
         return InstanceIdentifier.builder(IfIndexesInterfaceMap.class)
         return InstanceIdentifier.builder(IfIndexesInterfaceMap.class)
-                .child(IfIndexInterface.class, new IfIndexInterfaceKey((int) interfaceTag)).build();
+                .child(IfIndexInterface.class,
+                        new IfIndexInterfaceKey(Integer.valueOf(interfaceTag.intValue()))).build();
     }
 
     public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
     }
 
     public static InstanceIdentifier<ElanDpnInterfacesList> getElanDpnOperationDataPath(String elanInstanceName) {
@@ -483,15 +537,17 @@ 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);
     public ElanDpnInterfacesList getElanDpnInterfacesList(String elanName) {
         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanName);
-        return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
+        return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orElse(null);
     }
 
     }
 
+    @Nullable
     public ElanDpnInterfaces getElanDpnInterfacesList() {
         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class)
                 .build();
     public ElanDpnInterfaces getElanDpnInterfacesList() {
         InstanceIdentifier<ElanDpnInterfaces> elanDpnInterfaceId = InstanceIdentifier.builder(ElanDpnInterfaces.class)
                 .build();
-        return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orNull();
+        return read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId).orElse(null);
     }
 
     /**
     }
 
     /**
@@ -503,55 +559,22 @@ public class ElanUtils {
      *            the elan instance name
      * @return list of dpIds
      */
      *            the elan instance name
      * @return list of dpIds
      */
-    @Nonnull
-    public List<BigInteger> getParticipatingDpnsInElanInstance(String elanInstanceName) {
-        List<BigInteger> dpIds = new ArrayList<>();
+    @NonNull
+    public List<Uint64> getParticipatingDpnsInElanInstance(String elanInstanceName) {
+        List<Uint64> dpIds = new ArrayList<>();
         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = read(broker,
                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
         if (!existingElanDpnInterfaces.isPresent()) {
             return dpIds;
         }
         InstanceIdentifier<ElanDpnInterfacesList> elanDpnInterfaceId = getElanDpnOperationDataPath(elanInstanceName);
         Optional<ElanDpnInterfacesList> existingElanDpnInterfaces = read(broker,
                 LogicalDatastoreType.OPERATIONAL, elanDpnInterfaceId);
         if (!existingElanDpnInterfaces.isPresent()) {
             return dpIds;
         }
-        List<DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().getDpnInterfaces();
-        for (DpnInterfaces dpnInterface : dpnInterfaces) {
+        Map<DpnInterfacesKey, DpnInterfaces> dpnInterfaces = existingElanDpnInterfaces.get().nonnullDpnInterfaces();
+        for (DpnInterfaces dpnInterface : dpnInterfaces.values()) {
             dpIds.add(dpnInterface.getDpId());
         }
         return dpIds;
     }
 
             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;
     }
@@ -563,6 +586,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);
     }
@@ -570,7 +594,7 @@ public class ElanUtils {
     @Nullable
     public static MacTable getElanMacTable(DataBroker dataBroker, String elanName) {
         InstanceIdentifier<MacTable> elanMacTableId = getElanMacTableOperationalDataPath(elanName);
     @Nullable
     public static MacTable getElanMacTable(DataBroker dataBroker, String elanName) {
         InstanceIdentifier<MacTable> elanMacTableId = getElanMacTableOperationalDataPath(elanName);
-        return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orNull();
+        return read(dataBroker, LogicalDatastoreType.OPERATIONAL, elanMacTableId).orElse(null);
     }
 
     public static long getElanLocalBCGId(long elanTag) {
     }
 
     public static long getElanLocalBCGId(long elanTag) {
@@ -589,9 +613,9 @@ public class ElanUtils {
         return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2;
     }
 
         return ElanConstants.ELAN_GID_MIN + etreeLeafTag % ElanConstants.ELAN_GID_MIN * 2;
     }
 
-    public static BigInteger getElanMetadataLabel(long elanTag, boolean isSHFlagSet) {
+    public static Uint64 getElanMetadataLabel(long elanTag, boolean isSHFlagSet) {
         int shBit = isSHFlagSet ? 1 : 0;
         int shBit = isSHFlagSet ? 1 : 0;
-        return BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit));
+        return Uint64.valueOf(BigInteger.valueOf(elanTag).shiftLeft(24).or(BigInteger.valueOf(shBit)));
     }
 
     /**
     }
 
     /**
@@ -609,12 +633,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().toJava(), 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,
@@ -622,11 +645,12 @@ public class ElanUtils {
         }
     }
 
         }
     }
 
-    public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId,
-                                         String macAddress, WriteTransaction writeFlowTx) throws ElanException {
+    public void setupDMacFlowOnRemoteDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, Uint64 dstDpId,
+                                         String macAddress, TypedWriteTransaction<Configuration> writeFlowTx) {
         String elanInstanceName = elanInfo.getElanInstanceName();
         String elanInstanceName = elanInfo.getElanInstanceName();
-        setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(), elanInfo.getElanTag(),
-                macAddress, elanInstanceName, writeFlowTx, interfaceInfo.getInterfaceName(), elanInfo);
+        setupRemoteDmacFlow(dstDpId, interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag(),
+                elanInfo.getElanTag(), macAddress, elanInstanceName, writeFlowTx,
+                interfaceInfo.getInterfaceName(), elanInfo);
         LOG.info("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and"
                 + " mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(),
                 macAddress, dstDpId);
         LOG.info("Remote Dmac flow entry created for elan Name:{}, logical port Name:{} and"
                 + " mac address {} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(),
                 macAddress, dstDpId);
@@ -637,9 +661,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);
     }
@@ -649,22 +674,22 @@ public class ElanUtils {
         int lportTag = interfaceInfo.getInterfaceTag();
         // Matching metadata and eth_src fields
         List<MatchInfo> mkMatches = new ArrayList<>();
         int lportTag = interfaceInfo.getInterfaceTag();
         // Matching metadata and eth_src fields
         List<MatchInfo> mkMatches = new ArrayList<>();
-        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag(), lportTag),
+        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanInfo.getElanTag().toJava(), lportTag),
                 ElanHelper.getElanMetadataMask()));
         mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress)));
         List<InstructionInfo> mkInstructions = new ArrayList<>();
         mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
                 ElanHelper.getElanMetadataMask()));
         mkMatches.add(new MatchEthernetSource(new MacAddress(macAddress)));
         List<InstructionInfo> mkInstructions = new ArrayList<>();
         mkInstructions.add(new InstructionGotoTable(NwConstants.ELAN_DMAC_TABLE));
-        BigInteger dpId = interfaceInfo.getDpId();
-        long elanTag = getElanTag(elanInfo, interfaceInfo);
+        Uint64 dpId = interfaceInfo.getDpId();
+        Uint32 elanTag = getElanTag(elanInfo, interfaceInfo);
         return new FlowEntityBuilder()
             .setDpnId(dpId)
             .setTableId(NwConstants.ELAN_SMAC_TABLE)
         return new FlowEntityBuilder()
             .setDpnId(dpId)
             .setTableId(NwConstants.ELAN_SMAC_TABLE)
-            .setFlowId(getKnownDynamicmacFlowRef(NwConstants.ELAN_SMAC_TABLE, dpId, lportTag, macAddress, elanTag))
+            .setFlowId(getKnownDynamicmacFlowRef(elanTag, macAddress))
             .setPriority(20)
             .setFlowName(elanInfo.getDescription())
             .setIdleTimeOut((int) macTimeout)
             .setHardTimeOut(0)
             .setPriority(20)
             .setFlowName(elanInfo.getDescription())
             .setIdleTimeOut((int) macTimeout)
             .setHardTimeOut(0)
-            .setCookie(ElanConstants.COOKIE_ELAN_KNOWN_SMAC.add(BigInteger.valueOf(elanTag)))
+            .setCookie(Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_SMAC.longValue() + elanTag.longValue()))
             .setMatchInfoList(mkMatches)
             .setInstructionInfoList(mkInstructions)
             .setStrictFlag(true)
             .setMatchInfoList(mkMatches)
             .setInstructionInfoList(mkInstructions)
             .setStrictFlag(true)
@@ -673,8 +698,9 @@ public class ElanUtils {
             .build();
     }
 
             .build();
     }
 
-    private Long getElanTag(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
-        EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceInfo.getInterfaceName()).orNull();
+    private Uint32 getElanTag(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+        EtreeInterface etreeInterface = elanInterfaceCache
+            .getEtreeInterface(interfaceInfo.getInterfaceName()).orElse(null);
         if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
             return elanInfo.getElanTag();
         } else { // Leaf
         if (etreeInterface == null || etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
             return elanInfo.getElanTag();
         } else { // Leaf
@@ -702,16 +728,16 @@ 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) {
-        BigInteger dpId = interfaceInfo.getDpId();
+                                   TypedWriteTransaction<Configuration> writeFlowGroupTx) {
+        Uint64 dpId = interfaceInfo.getDpId();
         int lportTag = interfaceInfo.getInterfaceTag();
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
                 getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5,
                 String.format("%s:%d", "ITM Flow Entry ", lportTag), 0, 0,
         int lportTag = interfaceInfo.getInterfaceTag();
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
                 getIntTunnelTableFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, lportTag), 5,
                 String.format("%s:%d", "ITM Flow Entry ", lportTag), 0, 0,
-                ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(lportTag)),
+                Uint64.valueOf(ITMConstants.COOKIE_ITM.longValue() + lportTag),
                 getTunnelIdMatchForFilterEqualsLPortTag(lportTag),
                 getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
                 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());
     }
@@ -727,7 +753,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();
     }
 
     /**
     }
 
     /**
@@ -741,7 +767,7 @@ public class ElanUtils {
     public static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
         List<MatchInfo> mkMatches = new ArrayList<>();
         // Matching metadata
     public static List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
         List<MatchInfo> mkMatches = new ArrayList<>();
         // Matching metadata
-        mkMatches.add(new MatchTunnelId(BigInteger.valueOf(lportTag)));
+        mkMatches.add(new MatchTunnelId(Uint64.valueOf(lportTag)));
         return mkMatches;
     }
 
         return mkMatches;
     }
 
@@ -754,11 +780,12 @@ public class ElanUtils {
      *            external)
      * @return the Instruction
      */
      *            external)
      * @return the Instruction
      */
-    public List<Instruction> getInstructionsInPortForOutGroup(String ifName) {
-        List<Instruction> mkInstructions = new ArrayList<>();
+    public Map<InstructionKey, Instruction> getInstructionsInPortForOutGroup(String ifName) {
+        int instructionsKey = 0;
+        Map<InstructionKey, Instruction> mkInstructions = new HashMap<>();
         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
 
         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
 
-        mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
+        mkInstructions.put(new InstructionKey(++instructionsKey), MDSALUtil.buildApplyActionsInstruction(actions));
         return mkInstructions;
     }
 
         return mkInstructions;
     }
 
@@ -777,7 +804,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()
@@ -789,8 +817,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 = new ArrayList<Action>(rpcResult.getResult().nonnullAction().values());
             }
         } 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);
@@ -800,14 +827,13 @@ 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 {
-        BigInteger dpId = interfaceInfo.getDpId();
+                                    TypedWriteTransaction<Configuration> writeFlowGroupTx) {
+        Uint64 dpId = interfaceInfo.getDpId();
         String ifName = interfaceInfo.getInterfaceName();
         long ifTag = interfaceInfo.getInterfaceTag();
         String elanInstanceName = elanInfo.getElanInstanceName();
 
         String ifName = interfaceInfo.getInterfaceName();
         long ifTag = interfaceInfo.getInterfaceTag();
         String elanInstanceName = elanInfo.getElanInstanceName();
 
-        Long elanTag = elanInfo.getElanTag();
+        Uint32 elanTag = elanInfo.getElanTag();
 
         setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, mdsalApiManager, ifTag,
                 writeFlowGroupTx);
 
         setupLocalDmacFlow(elanTag, dpId, ifName, macAddress, elanInfo, mdsalApiManager, ifTag,
                 writeFlowGroupTx);
@@ -821,7 +847,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;
             }
 
@@ -846,57 +872,54 @@ 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);
     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());
+        try {
+            return new ArrayList<DpnInterfaces>((SingleTransactionDataBroker.syncReadOptional(broker,
+                    LogicalDatastoreType.OPERATIONAL, elanIdentifier).map(ElanDpnInterfacesList::getDpnInterfaces)
+                    .orElse(emptyMap())).values());
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getElanDPNByName: Exception while reading elanDpnInterfaceList DS for the elan "
+                    + "instance {}", elanInstanceName, e);
+            return emptyList();
+        }
     }
 
     }
 
-    private void setupLocalDmacFlow(long elanTag, BigInteger dpId, String ifName, String macAddress,
-            ElanInstance elanInfo, IMdsalApiManager mdsalApiManager, long ifTag, WriteTransaction writeFlowGroupTx) {
+    private void setupLocalDmacFlow(Uint32 elanTag, Uint64 dpId, String ifName, String macAddress,
+            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,
-            ElanInstance elanInfo, long ifTag, WriteTransaction writeFlowGroupTx) {
-        EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(ifName).orNull();
+    private void installEtreeLocalDmacFlow(Uint32 elanTag, Uint64 dpId, String ifName, String macAddress,
+            ElanInstance elanInfo, long ifTag, TypedWriteTransaction<Configuration> writeFlowGroupTx) {
+        EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(ifName).orElse(null);
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
-            EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
+            EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue());
             if (etreeTagName == null) {
                 LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null",
                         ifName, elanTag);
             } else {
             if (etreeTagName == null) {
                 LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null",
                         ifName, elanTag);
             } else {
-                Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId, ifName,
-                        macAddress, elanInfo, ifTag);
-                mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
+                Flow flowEntity = buildLocalDmacFlowEntry(etreeTagName.getEtreeLeafTag().getValue(), dpId,
+                        ifName, macAddress, elanInfo, ifTag);
+                mdsalManager.addFlow(writeFlowGroupTx, dpId, flowEntity);
             }
         }
     }
 
             }
         }
     }
 
-    public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, long lporTag, String macAddress,
-            long elanTag) {
-        return String.valueOf(tableId) + elanTag + dpId + lporTag + macAddress;
+    public static String getKnownDynamicmacFlowRef(Uint32 elanTag, String macAddress) {
+        return new StringBuffer().append(elanTag).append(macAddress.toLowerCase(Locale.getDefault())).toString();
     }
 
     }
 
-    public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, BigInteger remoteDpId,
-            String macAddress, long elanTag) {
-        return String.valueOf(tableId) + elanTag + dpId + remoteDpId + macAddress;
-    }
-
-    public static String getKnownDynamicmacFlowRef(short tableId, BigInteger dpId, String macAddress, long elanTag) {
-        return String.valueOf(tableId) + elanTag + dpId + macAddress;
-    }
-
-    public static String getKnownDynamicmacFlowRef(short elanDmacTable, BigInteger dpId, String extDeviceNodeId,
+    public static String getKnownDynamicmacFlowRef(short elanDmacTable, Uint64 dpId, String extDeviceNodeId,
             String dstMacAddress, long elanTag, boolean shFlag) {
         return String.valueOf(elanDmacTable) + elanTag + dpId + extDeviceNodeId + dstMacAddress + shFlag;
     }
             String dstMacAddress, long elanTag, boolean shFlag) {
         return String.valueOf(elanDmacTable) + elanTag + dpId + extDeviceNodeId + dstMacAddress + shFlag;
     }
@@ -923,58 +946,60 @@ public class ElanUtils {
      *            the if tag
      * @return the flow
      */
      *            the if tag
      * @return the flow
      */
-    public Flow buildLocalDmacFlowEntry(long elanTag, BigInteger dpId, String ifName, String macAddress,
+    public Flow buildLocalDmacFlowEntry(Uint32 elanTag, Uint64 dpId, String ifName, String macAddress,
             ElanInstance elanInfo, long ifTag) {
 
         List<MatchInfo> mkMatches = new ArrayList<>();
             ElanInstance elanInfo, long ifTag) {
 
         List<MatchInfo> mkMatches = new ArrayList<>();
-        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()),
+            MetaDataUtil.METADATA_MASK_SERVICE));
         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
 
         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
 
-        List<Instruction> mkInstructions = new ArrayList<>();
+        Map<InstructionKey, Instruction> mkInstructions = new HashMap<>();
         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
         List<Action> actions = getEgressActionsForInterface(ifName, /* tunnelKey */ null);
-        mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
+        mkInstructions.put(new InstructionKey(0), MDSALUtil.buildApplyActionsInstruction(actions));
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
-                getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, ifTag, macAddress, elanTag), 20,
-                elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(
-                        BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
+                getKnownDynamicmacFlowRef(elanTag, macAddress), 20,
+                elanInfo.getElanInstanceName(), 0, 0,
+                Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.longValue() + elanTag.longValue()),
+                mkMatches, mkInstructions);
 
         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(Uint64 srcDpId, Uint64 destDpId, int lportTag, Uint32 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());
             return;
         }
         if (interfaceManager.isExternalInterface(interfaceName)) {
             LOG.debug("Ignoring install remote DMAC {} flow on provider interface {} elan {}",
                     macAddress, interfaceName, elanInstance.getElanInstanceName());
             return;
         }
-        Flow flowEntity;
         // if openstack-vni-semantics are enforced, segmentation ID is passed as network VNI for VxLAN based provider
         // networks, 0 otherwise
         long lportTagOrVni = !isOpenstackVniSemanticsEnforced() ? lportTag : isVxlanNetworkOrVxlanSegment(elanInstance)
         // if openstack-vni-semantics are enforced, segmentation ID is passed as network VNI for VxLAN based provider
         // networks, 0 otherwise
         long lportTagOrVni = !isOpenstackVniSemanticsEnforced() ? lportTag : isVxlanNetworkOrVxlanSegment(elanInstance)
-                ? getVxlanSegmentationId(elanInstance) : 0;
-        flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName,
+                ? getVxlanSegmentationId(elanInstance).longValue() : 0;
+        Flow flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName,
                 elanInstance);
                 elanInstance);
-        mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
+        mdsalManager.addFlow(writeFlowGroupTx, srcDpId, flowEntity);
         setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName,
                 writeFlowGroupTx, elanInstance);
     }
 
         setupEtreeRemoteDmacFlow(srcDpId, destDpId, lportTagOrVni, elanTag, macAddress, displayName, interfaceName,
                 writeFlowGroupTx, elanInstance);
     }
 
-    private void setupEtreeRemoteDmacFlow(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
+    private void setupEtreeRemoteDmacFlow(Uint64 srcDpId, Uint64 destDpId, long lportTagOrVni, Uint32 elanTag,
                                           String macAddress, String displayName, String interfaceName,
                                           String macAddress, String displayName, String interfaceName,
-                                          WriteTransaction writeFlowGroupTx, ElanInstance elanInstance) {
+                                          TypedWriteTransaction<Configuration> writeFlowGroupTx,
+                                          ElanInstance elanInstance) {
         Flow flowEntity;
         Flow flowEntity;
-        EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName).orNull();
+        EtreeInterface etreeInterface = elanInterfaceCache.getEtreeInterface(interfaceName).orElse(null);
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
         if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
-            EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
+            EtreeLeafTagName etreeTagName = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue());
             if (etreeTagName == null) {
                 LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null.",
                         interfaceName, elanTag);
             } else {
                 flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni,
                         etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance);
             if (etreeTagName == null) {
                 LOG.warn("Interface {} seems like it belongs to Etree but etreeTagName from elanTag {} is null.",
                         interfaceName, elanTag);
             } else {
                 flowEntity = buildRemoteDmacFlowEntry(srcDpId, destDpId, lportTagOrVni,
                         etreeTagName.getEtreeLeafTag().getValue(), macAddress, displayName, elanInstance);
-                mdsalManager.addFlowToTx(srcDpId, flowEntity, writeFlowGroupTx);
+                mdsalManager.addFlow(writeFlowGroupTx, srcDpId, flowEntity);
             }
         }
     }
             }
         }
     }
@@ -1002,13 +1027,14 @@ public class ElanUtils {
      * @return the flow remote Dmac
      */
     @SuppressWarnings("checkstyle:IllegalCatch")
      * @return the flow remote Dmac
      */
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public Flow buildRemoteDmacFlowEntry(BigInteger srcDpId, BigInteger destDpId, long lportTagOrVni, long elanTag,
+    public Flow buildRemoteDmacFlowEntry(Uint64 srcDpId, Uint64 destDpId, long lportTagOrVni, Uint32 elanTag,
             String macAddress, String displayName, ElanInstance elanInstance) {
         List<MatchInfo> mkMatches = new ArrayList<>();
             String macAddress, String displayName, ElanInstance elanInstance) {
         List<MatchInfo> mkMatches = new ArrayList<>();
-        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+        mkMatches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()),
+            MetaDataUtil.METADATA_MASK_SERVICE));
         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
 
         mkMatches.add(new MatchEthernetDestination(new MacAddress(macAddress)));
 
-        List<Instruction> mkInstructions = new ArrayList<>();
+        Map<InstructionKey, Instruction> mkInstructions = new HashMap<>();
 
         // List of Action for the provided Source and Destination DPIDs
         try {
 
         // List of Action for the provided Source and Destination DPIDs
         try {
@@ -1023,101 +1049,112 @@ public class ElanUtils {
                 }
                 actions = getEgressActionsForInterface(interfaceName, null);
             }
                 }
                 actions = getEgressActionsForInterface(interfaceName, null);
             }
-            mkInstructions.add(MDSALUtil.buildApplyActionsInstruction(actions));
+            mkInstructions.put(new InstructionKey(0), MDSALUtil.buildApplyActionsInstruction(actions));
         } catch (Exception e) {
             LOG.error("Could not get egress actions to add to flow for srcDpId {}, destDpId {}, lportTag/VNI {}",
                     srcDpId,  destDpId, lportTagOrVni, e);
         }
 
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
         } catch (Exception e) {
             LOG.error("Could not get egress actions to add to flow for srcDpId {}, destDpId {}, lportTag/VNI {}",
                     srcDpId,  destDpId, lportTagOrVni, e);
         }
 
         Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_DMAC_TABLE,
-                getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, srcDpId, destDpId, macAddress, elanTag),
+                getKnownDynamicmacFlowRef(elanTag, macAddress),
                 20, /* prio */
                 displayName, 0, /* idleTimeout */
                 0, /* hardTimeout */
                 20, /* prio */
                 displayName, 0, /* idleTimeout */
                 0, /* hardTimeout */
-                ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)), mkMatches, mkInstructions);
+                Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.longValue() + elanTag.longValue()),
+                mkMatches, mkInstructions);
 
         return flow;
 
     }
 
     public void deleteMacFlows(@Nullable ElanInstance elanInfo, @Nullable InterfaceInfo interfaceInfo,
 
         return flow;
 
     }
 
     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().toJava(),
+                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);
         String elanInstanceName = elanInfo.getElanInstanceName();
         List<DpnInterfaces> remoteFEs = getInvolvedDpnsInElan(elanInstanceName);
-        BigInteger srcdpId = interfaceInfo.getDpId();
+        Uint64 srcdpId = interfaceInfo.getDpId();
         boolean isFlowsRemovedInSrcDpn = false;
         for (DpnInterfaces dpnInterface : remoteFEs) {
         boolean isFlowsRemovedInSrcDpn = false;
         for (DpnInterfaces dpnInterface : remoteFEs) {
-            Long elanTag = elanInfo.getElanTag();
-            BigInteger dstDpId = dpnInterface.getDpId();
+            Uint32 elanTag = elanInfo.getElanTag();
+            Uint64 dstDpId = dpnInterface.getDpId();
             if (executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
             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,
         }
     }
 
     private void executeEtreeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
-            boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
-            WriteTransaction deleteFlowGroupTx) {
-        EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag);
+            boolean deleteSmac, String elanInstanceName, Uint64 srcdpId, Uint32 elanTag, Uint64 dstDpId,
+            TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException, InterruptedException {
+        EtreeLeafTagName etreeLeafTag = elanEtreeUtils.getEtreeLeafTagByElanTag(elanTag.longValue());
         if (etreeLeafTag != null) {
             executeDeleteMacFlows(elanInfo, interfaceInfo, macAddress, deleteSmac, elanInstanceName, srcdpId,
         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,
         }
     }
 
     private boolean executeDeleteMacFlows(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
-            boolean deleteSmac, String elanInstanceName, BigInteger srcdpId, Long elanTag, BigInteger dstDpId,
-            WriteTransaction deleteFlowGroupTx) {
+            boolean deleteSmac, String elanInstanceName, Uint64 srcdpId, Uint32 elanTag, Uint64 dstDpId,
+            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(elanTag, macAddress)));
             LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}",
                     elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
         }
         return isFlowsRemovedInSrcDpn;
     }
 
             LOG.debug("Dmac flow entry deleted for elan:{}, logical interface port:{} and mac address:{} on dpn:{}",
                     elanInstanceName, interfaceInfo.getPortName(), macAddress, dstDpId);
         }
         return isFlowsRemovedInSrcDpn;
     }
 
+    public void deleteSmacFlowOnly(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String macAddress,
+                                   TypedReadWriteTransaction<Configuration> flowTx) throws ExecutionException,
+            InterruptedException {
+        Uint64 srcdpId = interfaceInfo.getDpId();
+        Uint32 elanTag = elanInfo.getElanTag();
+        LOG.debug("Deleting SMAC flow with id {}", getKnownDynamicmacFlowRef(elanTag, macAddress));
+        mdsalManager.removeFlow(flowTx, srcdpId,
+                MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(elanTag, macAddress)));
+    }
+
     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();
         String elanInstanceName = elanInfo.getElanInstanceName();
-        long ifTag = interfaceInfo.getInterfaceTag();
-        BigInteger srcdpId = interfaceInfo.getDpId();
-        Long elanTag = elanInfo.getElanTag();
+        Uint64 srcdpId = interfaceInfo.getDpId();
+        Uint32 elanTag = elanInfo.getElanTag();
         if (deleteSmac) {
         if (deleteSmac) {
+            LOG.debug("Deleting SMAC flow with id {}", getKnownDynamicmacFlowRef(elanTag, macAddress));
             mdsalManager
             mdsalManager
-                    .removeFlowToTx(srcdpId,
-                            MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE, getKnownDynamicmacFlowRef(
-                                    NwConstants.ELAN_SMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)),
-                            deleteFlowGroupTx);
+                    .removeFlow(flowTx, srcdpId,
+                            MDSALUtil.buildFlow(NwConstants.ELAN_SMAC_TABLE,
+                                    getKnownDynamicmacFlowRef(elanTag, macAddress)));
         }
         }
-        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(elanTag, macAddress)));
         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);
     }
@@ -1132,54 +1169,58 @@ 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();
         String elanInstanceName = elanInstanceAdded.getElanInstanceName();
-        Long elanTag = elanInstanceAdded.getElanTag();
-        if (elanTag == null || elanTag == 0L) {
+        Uint32 elanTag = elanInstanceAdded.getElanTag();
+        if (elanTag == null || elanTag.longValue() == 0L) {
             elanTag = retrieveNewElanTag(idManager, elanInstanceName);
         }
             elanTag = retrieveNewElanTag(idManager, elanInstanceName);
         }
+        if (elanTag.longValue() == 0L) {
+            LOG.error("ELAN tag creation failed for elan instance {}. Not updating the ELAN DS. "
+                    + "Recreate network for recovery", elanInstanceName);
+            return null;
+        }
         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces)
                 .withKey(new ElanKey(elanInstanceName)).build();
 
         // Add the ElanState in the elan-state operational data-store
         Elan elanInfo = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(elanInterfaces)
                 .withKey(new ElanKey(elanInstanceName)).build();
 
         // Add the ElanState in the elan-state operational data-store
-        tx.put(LogicalDatastoreType.OPERATIONAL, getElanInstanceOperationalDataPath(elanInstanceName),
-                elanInfo, WriteTransaction.CREATE_MISSING_PARENTS);
+        operTx.mergeParentStructurePut(getElanInstanceOperationalDataPath(elanInstanceName), elanInfo);
 
         // Add the ElanMacTable in the elan-mac-table operational data-store
         MacTable elanMacTable = new MacTableBuilder().withKey(new MacTableKey(elanInstanceName)).build();
 
         // Add the ElanMacTable in the elan-mac-table operational data-store
         MacTable elanMacTable = new MacTableBuilder().withKey(new MacTableKey(elanInstanceName)).build();
-        tx.put(LogicalDatastoreType.OPERATIONAL, getElanMacTableOperationalDataPath(elanInstanceName),
-                elanMacTable, WriteTransaction.CREATE_MISSING_PARENTS);
+        operTx.mergeParentStructurePut(getElanMacTableOperationalDataPath(elanInstanceName), elanMacTable);
 
         ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag)
                 .withKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName);
 
         ElanTagNameBuilder elanTagNameBuilder = new ElanTagNameBuilder().setElanTag(elanTag)
                 .withKey(new ElanTagNameKey(elanTag)).setName(elanInstanceName);
-        long etreeLeafTag = -1;
+        Uint32 etreeLeafTag = Uint32.valueOf(0L);
         if (isEtreeInstance(elanInstanceAdded)) {
             etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants
                     .LEAVES_POSTFIX);
             EtreeLeafTagName etreeLeafTagName = new EtreeLeafTagNameBuilder()
                     .setEtreeLeafTag(new EtreeLeafTag(etreeLeafTag)).build();
             elanTagNameBuilder.addAugmentation(EtreeLeafTagName.class, etreeLeafTagName);
         if (isEtreeInstance(elanInstanceAdded)) {
             etreeLeafTag = retrieveNewElanTag(idManager,elanInstanceName + ElanConstants
                     .LEAVES_POSTFIX);
             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
-        ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
+        ElanInstanceBuilder elanInstanceBuilder = new ElanInstanceBuilder(elanInstanceAdded)
+                .setElanInstanceName(elanInstanceName)
                 .setDescription(elanInstanceAdded.getDescription())
                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null
                 .setDescription(elanInstanceAdded.getDescription())
                 .setMacTimeout(elanInstanceAdded.getMacTimeout() == null
-                        ? Long.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout())
+                        ? Uint32.valueOf(ElanConstants.DEFAULT_MAC_TIME_OUT) : elanInstanceAdded.getMacTimeout())
                 .withKey(elanInstanceAdded.key()).setElanTag(elanTag);
         if (isEtreeInstance(elanInstanceAdded)) {
             EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag))
                 .withKey(elanInstanceAdded.key()).setElanTag(elanTag);
         if (isEtreeInstance(elanInstanceAdded)) {
             EtreeInstance etreeInstance = new EtreeInstanceBuilder().setEtreeLeafTagVal(new EtreeLeafTag(etreeLeafTag))
@@ -1187,23 +1228,25 @@ public class ElanUtils {
             elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance);
         }
         ElanInstance elanInstanceWithTag = elanInstanceBuilder.build();
             elanInstanceBuilder.addAugmentation(EtreeInstance.class, etreeInstance);
         }
         ElanInstance elanInstanceWithTag = elanInstanceBuilder.build();
-        tx.merge(LogicalDatastoreType.CONFIGURATION, ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName),
-                elanInstanceWithTag, WriteTransaction.CREATE_MISSING_PARENTS);
+        LOG.trace("Updated elan Operational DS for elan: {} with elanTag: {} and interfaces: {}", elanInstanceName,
+                elanTag, elanInterfaces);
+        confTx.mergeParentStructureMerge(ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName),
+                elanInstanceWithTag);
         return elanInstanceWithTag;
     }
 
         return elanInstanceWithTag;
     }
 
-    private static void addTheLeafTagAsElanTag(String elanInstanceName, long etreeLeafTag, WriteTransaction tx) {
+    private static void addTheLeafTagAsElanTag(String elanInstanceName,Uint32 etreeLeafTag,
+            TypedWriteTransaction<Operational> tx) {
         ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag)
                 .withKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build();
         ElanTagName etreeTagAsElanTag = new ElanTagNameBuilder().setElanTag(etreeLeafTag)
                 .withKey(new ElanTagNameKey(etreeLeafTag)).setName(elanInstanceName).build();
-        tx.put(LogicalDatastoreType.OPERATIONAL,
-                getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag);
+        tx.put(getElanInfoEntriesOperationalDataPath(etreeLeafTag), etreeTagAsElanTag);
     }
 
     private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) {
         return elanInstanceAdded.augmentation(EtreeInstance.class) != null;
     }
 
     }
 
     private static boolean isEtreeInstance(ElanInstance elanInstanceAdded) {
         return elanInstanceAdded.augmentation(EtreeInstance.class) != null;
     }
 
-    public boolean isDpnPresent(BigInteger dpnId) {
+    public boolean isDpnPresent(Uint64 dpnId) {
         String dpn = String.format("%s:%s", "openflow", dpnId);
         NodeId nodeId = new NodeId(dpn);
 
         String dpn = String.format("%s:%s", "openflow", dpnId);
         NodeId nodeId = new NodeId(dpn);
 
@@ -1212,17 +1255,12 @@ 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 BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
     public static String getElanServiceName(String elanName, String interfaceName) {
         return "elan." + elanName + interfaceName;
     }
 
     public static BoundServices getBoundServices(String serviceName, short servicePriority, int flowPriority,
-            BigInteger cookie, List<Instruction> instructions) {
+            Uint64 cookie, List<Instruction> instructions) {
         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
                 .setInstruction(instructions);
         return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookie).setFlowPriority(flowPriority)
                 .setInstruction(instructions);
         return new BoundServicesBuilder().withKey(new BoundServicesKey(servicePriority)).setServiceName(serviceName)
@@ -1236,15 +1274,16 @@ public class ElanUtils {
                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
     }
 
                 .child(BoundServices.class, new BoundServicesKey(serviceIndex)).build();
     }
 
-    public static List<MatchInfo> getTunnelMatchesForServiceId(int elanTag) {
+    public static List<MatchInfo> getTunnelMatchesForServiceId(Uint32 elanTag) {
         List<MatchInfo> mkMatches = new ArrayList<>();
         List<MatchInfo> mkMatches = new ArrayList<>();
-        // Matching metadata
-        mkMatches.add(new MatchTunnelId(BigInteger.valueOf(elanTag)));
+
+        // Adding 270000 to avoid collision between LPort and elan tag for broadcast
+        mkMatches.add(new MatchTunnelId(Uint64.valueOf(elanTag.longValue() + ElanConstants.ELAN_TAG_ADDEND)));
 
         return mkMatches;
     }
 
 
         return mkMatches;
     }
 
-    public void removeTerminatingServiceAction(BigInteger destDpId, int serviceId) {
+    public void removeTerminatingServiceAction(Uint64 destDpId, int serviceId) {
         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder()
                 .setDpnId(destDpId).setServiceId(serviceId).build();
         Future<RpcResult<RemoveTerminatingServiceActionsOutput>> futureObject =
         RemoveTerminatingServiceActionsInput input = new RemoveTerminatingServiceActionsInputBuilder()
                 .setDpnId(destDpId).setServiceId(serviceId).build();
         Future<RpcResult<RemoveTerminatingServiceActionsOutput>> futureObject =
@@ -1275,12 +1314,13 @@ 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;
         InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
                 .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
     public ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
             LogicalDatastoreType datastoreType) {
         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
         InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
                 .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
-        return read(broker, datastoreType, iid).orNull();
+        return read(broker, datastoreType, iid).orElse(null);
     }
 
     /**
     }
 
     /**
@@ -1292,6 +1332,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);
@@ -1313,8 +1354,8 @@ public class ElanUtils {
      */
     public List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
         InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
      */
     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());
+        return new ArrayList<ExternalTunnel>(read(broker, datastoreType, iid).map(ExternalTunnelList
+                ::getExternalTunnel).orElse(Collections.emptyMap()).values());
     }
 
     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
     }
 
     public static List<MatchInfo> buildMatchesForElanTagShFlagAndDstMac(long elanTag, boolean shFlag, String macAddr) {
@@ -1354,13 +1395,16 @@ 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) {
+        try {
+            return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    createInterfaceStateInstanceIdentifier(interfaceName)).orElse(null);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getInterfaceStateFromOperDS: Exception while reading interface DS for the interface {}",
+                    interfaceName, e);
+            return null;
+        }
     }
 
     /**
     }
 
     /**
@@ -1385,29 +1429,27 @@ public class ElanUtils {
     }
 
     @CheckReturnValue
     }
 
     @CheckReturnValue
-    public static CheckedFuture<Void, TransactionCommitFailedException> waitForTransactionToComplete(
-            WriteTransaction tx) {
-        CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
+    public static ListenableFuture<Void> waitForTransactionToComplete(ListenableFuture<Void> future) {
         try {
         try {
-            futures.get();
+            future.get();
         } catch (InterruptedException | ExecutionException e) {
             // NETVIRT-1215: Do not log.error() here, only debug(); but callers *MUST* @CheckReturnValue
             LOG.debug("Error writing to datastore", e);
         }
         } catch (InterruptedException | ExecutionException 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) {
         return elanInstance != null && elanInstance.getSegmentType() != null
                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
     }
 
     public static boolean isVxlan(@Nullable ElanInstance elanInstance) {
         return elanInstance != null && elanInstance.getSegmentType() != null
                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
-                && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
+                && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().toJava() != 0;
     }
 
     }
 
-    private static boolean isVxlanSegment(ElanInstance elanInstance) {
+    private static boolean isVxlanSegment(@Nullable ElanInstance elanInstance) {
         if (elanInstance != null) {
         if (elanInstance != null) {
-            List<ElanSegments> elanSegments = elanInstance.getElanSegments();
+            Map<ElanSegmentsKey, ElanSegments> elanSegments = elanInstance.getElanSegments();
             if (elanSegments != null) {
             if (elanSegments != null) {
-                for (ElanSegments segment : elanSegments) {
+                for (ElanSegments segment : elanSegments.values()) {
                     if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
                             && segment.getSegmentationId() != null
                             && segment.getSegmentationId().longValue() != 0) {
                     if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
                             && segment.getSegmentationId() != null
                             && segment.getSegmentationId().longValue() != 0) {
@@ -1419,12 +1461,12 @@ 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);
     }
 
-    public static Long getVxlanSegmentationId(ElanInstance elanInstance) {
-        Long segmentationId = 0L;
+    public static Uint32 getVxlanSegmentationId(ElanInstance elanInstance) {
+        Uint32 segmentationId = Uint32.ZERO;
         if (elanInstance == null) {
             return segmentationId;
         }
         if (elanInstance == null) {
             return segmentationId;
         }
@@ -1434,7 +1476,7 @@ public class ElanUtils {
                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0) {
             segmentationId = elanInstance.getSegmentationId();
         } else {
                 && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().longValue() != 0) {
             segmentationId = elanInstance.getSegmentationId();
         } else {
-            for (ElanSegments segment: elanInstance.getElanSegments()) {
+            for (ElanSegments segment: elanInstance.getElanSegments().values()) {
                 if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
                     && segment.getSegmentationId() != null
                     && segment.getSegmentationId().longValue() != 0) {
                 if (segment != null && segment.getSegmentType().isAssignableFrom(SegmentTypeVxlan.class)
                     && segment.getSegmentationId() != null
                     && segment.getSegmentationId().longValue() != 0) {
@@ -1448,7 +1490,7 @@ public class ElanUtils {
     public static boolean isVlan(ElanInstance elanInstance) {
         return elanInstance != null && elanInstance.getSegmentType() != null
                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class)
     public static boolean isVlan(ElanInstance elanInstance) {
         return elanInstance != null && elanInstance.getSegmentType() != null
                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeVlan.class)
-                && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId() != 0;
+                && elanInstance.getSegmentationId() != null && elanInstance.getSegmentationId().toJava() != 0;
     }
 
     public static boolean isFlat(ElanInstance elanInstance) {
     }
 
     public static boolean isFlat(ElanInstance elanInstance) {
@@ -1456,40 +1498,45 @@ public class ElanUtils {
                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class);
     }
 
                 && elanInstance.getSegmentType().isAssignableFrom(SegmentTypeFlat.class);
     }
 
-    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,
+    public void addDmacRedirectToDispatcherFlows(Uint32 elanTag, String displayName,
+            String macAddress, List<Uint64> dpnIds) {
+        for (Uint64 dpId : dpnIds) {
+            LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                tx -> mdsalManager.addFlow(tx, buildDmacRedirectToDispatcherFlow(dpId, macAddress, displayName,
+                        elanTag))), LOG,
                 "Error adding DMAC redirect to dispatcher flows");
         }
     }
 
                 "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));
-        }
+    public void removeDmacRedirectToDispatcherFlows(Uint32 elanTag, String macAddress, List<Uint64> dpnIds) {
+        LoggingFutures.addErrorLogging(
+            txRunner.callWithNewReadWriteTransactionAndSubmit(Datastore.CONFIGURATION, tx -> {
+                for (Uint64 dpId : dpnIds) {
+                    String flowId = getKnownDynamicmacFlowRef(elanTag, macAddress);
+                    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,
-            String displayName, long elanTag) {
+    public static FlowEntity buildDmacRedirectToDispatcherFlow(Uint64 dpId, String dstMacAddress,
+            String displayName, Uint32 elanTag) {
         List<MatchInfo> matches = new ArrayList<>();
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag), MetaDataUtil.METADATA_MASK_SERVICE));
+        matches.add(new MatchMetadata(ElanHelper.getElanMetadataLabel(elanTag.longValue()),
+                MetaDataUtil.METADATA_MASK_SERVICE));
         matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress)));
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actions = new ArrayList<>();
         actions.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
 
         instructions.add(new InstructionApplyActions(actions));
         matches.add(new MatchEthernetDestination(new MacAddress(dstMacAddress)));
         List<InstructionInfo> instructions = new ArrayList<>();
         List<ActionInfo> actions = new ArrayList<>();
         actions.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
 
         instructions.add(new InstructionApplyActions(actions));
-        String flowId = getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, dstMacAddress, elanTag);
+        String flowId = getKnownDynamicmacFlowRef(elanTag, dstMacAddress);
         return MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_DMAC_TABLE, flowId, 20, displayName, 0, 0,
         return MDSALUtil.buildFlowEntity(dpId, NwConstants.ELAN_DMAC_TABLE, flowId, 20, displayName, 0, 0,
-                ElanConstants.COOKIE_ELAN_KNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
+                Uint64.valueOf(ElanConstants.COOKIE_ELAN_KNOWN_DMAC.longValue() + elanTag.longValue()),
                 matches, instructions);
     }
 
                 matches, instructions);
     }
 
-    public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
+    @Nullable
+    public String getExternalElanInterface(String elanInstanceName, Uint64 dpnId) {
         DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
         if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
             LOG.trace("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId);
         DpnInterfaces dpnInterfaces = getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
         if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
             LOG.trace("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId);
@@ -1506,14 +1553,8 @@ 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 String getElanMacKey(long elanTag, String macAddress) {
-        String elanMacKey = "MAC-" + macAddress + " ELAN_TAG-" + elanTag;
-        return elanMacKey.intern();
+    public static Acquired lockElanMacDPN(long elanTag, String macAddress, Uint64 dpnId) {
+        return ELAN_LOCKS.acquire(new ElanLockName(elanTag, macAddress, dpnId));
     }
 
     public static List<ListenableFuture<Void>>
     }
 
     public static List<ListenableFuture<Void>>
@@ -1556,18 +1597,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;
@@ -1579,18 +1608,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();
     }
@@ -1600,7 +1617,7 @@ public class ElanUtils {
     }
 
     public Optional<IpAddress> getSourceIpAddress(Ethernet ethernet) {
     }
 
     public Optional<IpAddress> getSourceIpAddress(Ethernet ethernet) {
-        Optional<IpAddress> srcIpAddress = Optional.absent();
+        Optional<IpAddress> srcIpAddress = Optional.empty();
         if (ethernet.getPayload() == null) {
             return srcIpAddress;
         }
         if (ethernet.getPayload() == null) {
             return srcIpAddress;
         }
@@ -1621,9 +1638,9 @@ 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 new ArrayList<MacEntry>(macTable.getMacEntry().values());
     }
 
     public boolean isTunnelInLogicalGroup(String interfaceName) {
     }
 
     public boolean isTunnelInLogicalGroup(String interfaceName) {
@@ -1639,14 +1656,12 @@ public class ElanUtils {
         IfTunnel ifTunnel = configIface.augmentation(IfTunnel.class);
         if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
             ParentRefs refs = configIface.augmentation(ParentRefs.class);
         IfTunnel ifTunnel = configIface.augmentation(IfTunnel.class);
         if (ifTunnel != null && ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
             ParentRefs refs = configIface.augmentation(ParentRefs.class);
-            if (refs != null && !Strings.isNullOrEmpty(refs.getParentInterface())) {
-                return true; //multiple VxLAN tunnels enabled, i.e. only logical tunnel should be treated
-            }
+            return refs != null && !Strings.isNullOrEmpty(refs.getParentInterface());
         }
         return false;
     }
 
         }
         return false;
     }
 
-    public static InstanceIdentifier<Flow> getFlowIid(Flow flow, BigInteger dpnId) {
+    public static InstanceIdentifier<Flow> getFlowIid(Flow flow, Uint64 dpnId) {
         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
                 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId);
         FlowKey flowKey = new FlowKey(new FlowId(flow.getId()));
         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
                 new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId("openflow:" + dpnId);
@@ -1662,18 +1677,21 @@ public class ElanUtils {
         return "elaninterface-" + interfaceName;
     }
 
         return "elaninterface-" + interfaceName;
     }
 
-    public void removeArpResponderFlow(BigInteger dpnId, String ingressInterfaceName, String ipAddress,
+    public void removeArpResponderFlow(Uint64 dpnId, String ingressInterfaceName, String ipAddress,
             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()) {
     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();
+            List<Subnetmap> subnetMapList = new ArrayList<>(subnetMapsData.get().getSubnetmap().values());
             if (subnetMapList != null && !subnetMapList.isEmpty()) {
                 for (Subnetmap subnet : subnetMapList) {
                     if (subnet.getNetworkId().getValue().equals(elanInstanceName)) {
             if (subnetMapList != null && !subnetMapList.isEmpty()) {
                 for (Subnetmap subnet : subnetMapList) {
                     if (subnet.getNetworkId().getValue().equals(elanInstanceName)) {
@@ -1687,9 +1705,81 @@ public class ElanUtils {
         return null;
     }
 
         return null;
     }
 
+    protected  Node buildDpnNode(Uint64 dpnId) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819
+                        .NodeId("openflow:" + dpnId);
+        Node nodeDpn = new NodeBuilder().setId(nodeId).withKey(new NodeKey(nodeId)).build();
+        return nodeDpn;
+    }
+
+    public void syncUpdateGroup(Uint64 dpnId, Group newGroup, long delayTime,
+                                TypedWriteTransaction<Datastore.Configuration> confTx) {
+        Node nodeDpn = buildDpnNode(dpnId);
+        long groupIdInfo = newGroup.getGroupId().getValue().toJava();
+        GroupKey groupKey = new GroupKey(new GroupId(groupIdInfo));
+        InstanceIdentifier<Group> groupInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
+                .child(Group.class, groupKey).build();
+        LOG.trace("Performing merge operation for remote BC group for node {} with group {}", nodeDpn, newGroup);
+        Optional<Group> existingGroupOpt = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, groupInstanceId);
+        if (!existingGroupOpt.isPresent()) {
+            LOG.debug("Group {} doesn't exist. Performing syncInstall", groupIdInfo);
+            mdsalManager.addGroup(confTx, dpnId, newGroup);
+            return;
+        }
+        Buckets existingGroup = existingGroupOpt.get().getBuckets();
+        if (existingGroup == null) {
+            LOG.debug("Bucket doesn't exist for group {}. Performing syncInstall", groupIdInfo);
+            mdsalManager.addGroup(confTx, dpnId, newGroup);
+            return;
+        }
+        if (newGroup.getBuckets() == null) {
+            LOG.debug("Buckets are not sent for group {}. Skipping merge operation", groupIdInfo);
+            return;
+        }
+        List<Bucket> newBuckets = new ArrayList<Bucket>(newGroup.getBuckets().getBucket().values());
+        List<Bucket> existingBuckets = new ArrayList<Bucket>(existingGroup.getBucket().values());
+        Set<Bucket> toMergeBucketsWithoutId = new LinkedHashSet<>();
+
+        existingBuckets.stream()
+                .map(TO_BUCKET_WITHOUT_ID)
+                .forEach(bucketWithoutId -> toMergeBucketsWithoutId.add(bucketWithoutId));
+
+        newBuckets.stream()
+                .map(TO_BUCKET_WITHOUT_ID)
+                .forEach(bucketWithoutId -> toMergeBucketsWithoutId.add(bucketWithoutId));
+
+        if (toMergeBucketsWithoutId.size() == existingBuckets.size()) {
+            //no new buckets got added
+            //size matched and no extra buckets in existing buckets , rewrite the group
+            LOG.debug("Buckets did not change group {}. Skipping merge operation", groupIdInfo);
+            return;
+        }
+        LOG.debug("Old group buckets size {} New group buckets size {} Dpn id {} Group id {} ",
+                existingBuckets.size(), toMergeBucketsWithoutId.size(), dpnId, groupIdInfo);
+        AtomicLong bucketIdValue = new AtomicLong(-1);
+        //Change the bucket id of existing buckets
+        List<Bucket> bucketsToBeAdded = toMergeBucketsWithoutId.stream()
+                .map(bucketWithoutId -> TO_BUCKET_WITH_ID.apply(bucketWithoutId, bucketIdValue))
+                .collect(Collectors.toList());
+
+        Group group = MDSALUtil.buildGroup(newGroup.getGroupId().getValue().toJava(), newGroup.getGroupName(),
+                GroupTypes.GroupAll, MDSALUtil.buildBucketLists(bucketsToBeAdded));
+        mdsalManager.addGroup(confTx, dpnId, group);
+        LOG.trace("Installed remote BC group for node {} with group {}", nodeDpn, group);
+    }
+
     static InstanceIdentifier<Subnetmaps> buildSubnetMapsWildCardPath() {
         return InstanceIdentifier.create(Subnetmaps.class);
     }
     static InstanceIdentifier<Subnetmaps> buildSubnetMapsWildCardPath() {
         return InstanceIdentifier.create(Subnetmaps.class);
     }
-}
 
 
+    public static InstanceIdentifier<Group> getGroupInstanceid(Uint64 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();
+    }
 
 
+    public static String getBcGroupUpdateKey(String elanName) {
+        return "bc.group.update." + elanName;
+    }
+}