cleanup elanmanager blueprint
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanInterfaceManager.java
index 54ce3fb316660c059295bae10616999c4b04dde4..64d729d1bc941f96bc34184817631d70f76ed916 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.netvirt.elan.internal;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -17,23 +21,15 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentMap;
-
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.netvirt.elan.utils.ElanConstants;
-import org.opendaylight.netvirt.elan.utils.ElanUtils;
-import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
-import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
-import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
-import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo.InterfaceType;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.itm.globals.ITMConstants;
-import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.ActionType;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
@@ -45,6 +41,13 @@ import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.utils.ServiceIndex;
+import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.netvirt.elan.utils.ElanConstants;
+import org.opendaylight.netvirt.elan.utils.ElanForwardingEntriesHandler;
+import org.opendaylight.netvirt.elan.utils.ElanUtils;
+import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
@@ -52,9 +55,16 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.Fl
 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.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
 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.Bucket;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeLeafTagName;
 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.ElanInterfaces;
@@ -76,273 +86,369 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntryKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
 /**
- * Class in charge of handling creations, modifications and removals of ElanInterfaces.
+ * Class in charge of handling creations, modifications and removals of
+ * ElanInterfaces.
  *
  * @see org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface
  *
  */
-public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterface> implements AutoCloseable {
-
-    private static ElanInterfaceManager elanInterfaceManager = new ElanInterfaceManager();
-    private ListenerRegistration<DataChangeListener> elanInterfaceListenerRegistration;
-    private ListenerRegistration<DataChangeListener> itmInterfaceListenerRegistration;
-    private OdlInterfaceRpcService interfaceManagerRpcService;
-    private DataBroker broker;
-    private IMdsalApiManager mdsalManager;
-    private IInterfaceManager interfaceManager;
-    private IdManagerService idManager;
-
-    private ElanForwardingEntriesHandler elanForwardingEntriesHandler;
-    private Map<String, ConcurrentLinkedQueue<ElanInterface>> unProcessedElanInterfaces =
-            new ConcurrentHashMap<>();
-
-    private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceManager.class);
+@SuppressWarnings("deprecation")
+public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
+        implements AutoCloseable {
 
-    public ElanInterfaceManager() {
-        super(ElanInterface.class);
-    }
+    private final DataBroker broker;
+    private final IMdsalApiManager mdsalManager;
+    private final IInterfaceManager interfaceManager;
+    private final IdManagerService idManager;
+    private final ElanForwardingEntriesHandler elanForwardingEntriesHandler;
+    private ElanL2GatewayUtils elanL2GatewayUtils;
+    private ElanUtils elanUtils;
 
-    public static ElanInterfaceManager getElanInterfaceManager() {
-        return elanInterfaceManager;
-    }
+    private static final long waitTimeForSyncInstall = Long.getLong("wait.time.sync.install", 300L);
 
-    public void setMdSalApiManager(IMdsalApiManager mdsalManager) {
-        this.mdsalManager = mdsalManager;
-    }
+    private Map<String, ConcurrentLinkedQueue<ElanInterface>> unProcessedElanInterfaces = new ConcurrentHashMap<>();
 
-    public void setInterfaceManagerRpcService(OdlInterfaceRpcService ifManager) {
-        this.interfaceManagerRpcService = ifManager;
-    }
+    private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceManager.class);
 
-    public void setElanForwardingEntriesHandler(ElanForwardingEntriesHandler elanForwardingEntriesHandler) {
+    public ElanInterfaceManager(final DataBroker dataBroker,
+                                final IdManagerService managerService,
+                                final IMdsalApiManager mdsalApiManager,
+                                IInterfaceManager interfaceManager,
+                                final ElanForwardingEntriesHandler elanForwardingEntriesHandler) {
+        super(ElanInterface.class, ElanInterfaceManager.class);
+        this.broker = dataBroker;
+        this.idManager = managerService;
+        this.mdsalManager = mdsalApiManager;
+        this.interfaceManager = interfaceManager;
         this.elanForwardingEntriesHandler = elanForwardingEntriesHandler;
     }
 
-    public void setInterfaceManager(IInterfaceManager interfaceManager) {
-        this.interfaceManager = interfaceManager;
+    public void setElanUtils(ElanUtils elanUtils) {
+        this.elanUtils = elanUtils;
+        this.elanL2GatewayUtils = elanUtils.getElanL2GatewayUtils();
+        this.elanForwardingEntriesHandler.setElanUtils(elanUtils);
     }
 
-    public void setDataBroker(DataBroker broker) {
-        this.broker = broker;
+    public void init() {
+        registerListener(LogicalDatastoreType.CONFIGURATION, broker);
     }
 
     @Override
-    public void close() throws Exception {
-        if (elanInterfaceListenerRegistration != null) {
-            try {
-                elanInterfaceListenerRegistration.close();
-            } catch (final Exception e) {
-                logger.error("Error when cleaning up DataChangeListener.", e);
-            }
-            elanInterfaceListenerRegistration = null;
-        }
-    }
-
-    public void registerListener() {
-        try {
-            elanInterfaceListenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                    getElanInterfaceWildcardPath(), ElanInterfaceManager.this, DataChangeScope.SUBTREE);
-        } catch (final Exception e) {
-            logger.error("ELAN Interface DataChange listener registration failed !", e);
-            throw new IllegalStateException("ELAN Interface registration Listener failed.", e);
-        }
-    }
-
-    private InstanceIdentifier<?> getElanInterfaceWildcardPath() {
+    protected InstanceIdentifier<ElanInterface> getWildCardPath() {
         return InstanceIdentifier.create(ElanInterfaces.class).child(ElanInterface.class);
     }
 
-    public void setIdManager(IdManagerService idManager) {
-        this.idManager = idManager;
-    }
-
     @Override
     protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
-        String interfaceName =  del.getName();
-        ElanInstance elanInfo = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
+        String interfaceName = del.getName();
+        ElanInstance elanInfo = elanUtils.getElanInstanceByName(del.getElanInstanceName());
+        /*
+         * Handling in case the elan instance is deleted.If the Elan instance is
+         * deleted, there is no need to explicitly delete the elan interfaces
+         */
+        if (elanInfo == null) {
+            return;
+        }
         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
         String elanInstanceName = elanInfo.getElanInstanceName();
         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
-        ElanInterfaceRemoveWorker configWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInfo, interfaceName, interfaceInfo, this);
+        InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo,
+                interfaceName, interfaceInfo, false, this);
         coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
-    public void removeElanInterface(ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo) {
+    public void removeElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo,
+            boolean isInterfaceStateRemoved) {
         String elanName = elanInfo.getElanInstanceName();
-        if (interfaceInfo == null) {
-            // Interface does not exist in ConfigDS, so lets remove everything about that interface related to Elan
-            ElanInterfaceMac elanInterfaceMac =  ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
-            if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
-               List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
-                for(MacEntry macEntry : macEntries) {
-                    ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
+        boolean isLastElanInterface = false;
+        long elanTag = elanInfo.getElanTag();
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
+        Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, tx);
+        if (elanState == null) {
+            return;
+        }
+        List<String> elanInterfaces = elanState.getElanInterfaces();
+        if (elanInterfaces.size() == 0) {
+            isLastElanInterface = true;
+        }
+        if (interfaceInfo != null) {
+            BigInteger dpId = interfaceInfo.getDpId();
+            DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName,
+                    elanTag, tx);
+            /*
+             * If there are not elan ports, remove the unknown dmac, terminating
+             * service table flows, remote/local bc group
+             */
+            if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
+                    || dpnInterfaces.getInterfaces().isEmpty()) {
+                // No more Elan Interfaces in this DPN
+                logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
+                removeDefaultTermFlow(dpId, elanInfo.getElanTag());
+                removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, elanInfo.getElanTag());
+                removeEtreeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx);
+                removeElanBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
+                removeLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
+                removeEtreeBroadcastGrups(elanInfo, interfaceInfo, deleteFlowGroupTx);
+                if (ElanUtils.isVxlan(elanInfo)) {
+                    unsetExternalTunnelTable(dpId, elanInfo);
                 }
-            }
-            ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName));
-            Elan elanState = ElanUtils.getElanByName(elanName);
-            List<String> elanInterfaces = elanState.getElanInterfaces();
-            elanInterfaces.remove(interfaceName);
-            if(elanInterfaces.isEmpty()) {
-                ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
-                ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
-                ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
             } else {
-                Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName).setKey(new ElanKey(elanName)).build();
-                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
+                setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
             }
+        }
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
+        futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(
+                interfaceName, elanInfo, interfaceInfo, isInterfaceStateRemoved, this, isLastElanInterface);
+        coordinator.enqueueJob(interfaceName, removeInterfaceWorker, ElanConstants.JOB_MAX_RETRIES);
+    }
+
+    private void removeEtreeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo,
+            WriteTransaction deleteFlowGroupTx) {
+        EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanInfo.getElanTag());
+        if (etreeLeafTag != null) {
+            long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
+            removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx, leafTag);
+        }
+    }
+
+    private void removeEtreeBroadcastGrups(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
+        removeLeavesEtreeBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
+        removeLeavesLocalBroadcastGroup(elanInfo, interfaceInfo, deleteFlowGroupTx);
+    }
+
+    private void removeLeavesLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
+        EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+        if (etreeInstance != null) {
+            BigInteger dpnId = interfaceInfo.getDpId();
+            long groupId = ElanUtils.getEtreeLeafLocalBCGID(etreeInstance.getEtreeLeafTagVal().getValue());
+            List<Bucket> listBuckets = new ArrayList<>();
+            int bucketId = 0;
+            listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
+            Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                    MDSALUtil.buildBucketLists(listBuckets));
+            logger.trace("deleted the localBroadCast Group:{}", group);
+            mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+        }
+    }
+
+    private void removeLeavesEtreeBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
+        EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+        if (etreeInstance != null) {
+            long etreeTag = etreeInstance.getEtreeLeafTagVal().getValue();
+            int bucketId = 0;
+            int actionKey = 0;
+            List<Bucket> listBuckets = new ArrayList<>();
+            List<Action> listAction = new ArrayList<Action>();
+            listAction.add((new ActionInfo(ActionType.group,
+                    new String[] { String.valueOf(ElanUtils.getEtreeLeafLocalBCGID(etreeTag)) }, ++actionKey))
+                            .buildAction());
+            listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
+                    MDSALUtil.WATCH_GROUP));
+            bucketId++;
+            listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, etreeTag));
+            BigInteger dpnId = interfaceInfo.getDpId();
+            long groupId = ElanUtils.getEtreeLeafRemoteBCGID(etreeTag);
+            Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                    MDSALUtil.buildBucketLists(listBuckets));
+            logger.trace("deleting the remoteBroadCast group:{}", group);
+            mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+        }
+    }
+
+    private Elan removeElanStateForInterface(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
+        String elanName = elanInfo.getElanInstanceName();
+        Elan elanState = elanUtils.getElanByName(elanName);
+        if (elanState == null) {
+            return elanState;
+        }
+        List<String> elanInterfaces = elanState.getElanInterfaces();
+        elanInterfaces.remove(interfaceName);
+        if (elanInterfaces.isEmpty()) {
+            tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
+            tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
+            tx.delete(LogicalDatastoreType.OPERATIONAL,
+                    ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
         } else {
-            removeElanInterface(elanInfo, interfaceInfo);
-            unbindService(elanInfo, interfaceName);
+            Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName)
+                    .setKey(new ElanKey(elanName)).build();
+            tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName),
+                    updateElanState);
         }
+        return elanState;
     }
 
-    private void removeElanInterface(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+    private void deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
+        // removing the ElanInterface from the config data_store if interface is
+        // not present in Interface config DS
+        if (interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName) == null) {
+            tx.delete(LogicalDatastoreType.CONFIGURATION,
+                    ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
+        }
+    }
 
-        BigInteger dpId = interfaceInfo.getDpId();
+    void removeEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo, InterfaceInfo interfaceInfo, String interfaceName,
+            boolean isInterfaceStateRemoved, boolean isLastElanInterface) {
         String elanName = elanInfo.getElanInstanceName();
-        long elanTag = elanInfo.getElanTag();
-        String interfaceName = interfaceInfo.getInterfaceName();
-        Elan elanState = ElanUtils.getElanByName(elanName);
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
+        InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
+                .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
         logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
-        InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
-        Optional<ElanInterfaceMac> existingElanInterface = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
-        if(existingElanInterface.isPresent()) {
-            List<PhysAddress> macAddresses = new ArrayList<>();
-            List<MacEntry> existingMacEntries = existingElanInterface.get().getMacEntry();
-            List<MacEntry> macEntries = new ArrayList<>();
-            if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
-                macEntries.addAll(existingMacEntries);
-            }
-            if(!macEntries.isEmpty()) {
-                for (MacEntry macEntry : macEntries) {
-                    logger.debug("removing the  mac-entry:{} present on elanInterface:{}", macEntry.getMacAddress().getValue(), interfaceName);
-                    elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(elanInfo, interfaceInfo, macEntry);
-                    macAddresses.add(macEntry.getMacAddress());
+        if (interfaceInfo != null) {
+            Optional<ElanInterfaceMac> existingElanInterfaceMac = elanUtils.read(broker,
+                    LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
+            if (existingElanInterfaceMac.isPresent()) {
+                List<PhysAddress> macAddresses = new ArrayList<PhysAddress>();
+                List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
+                List<MacEntry> macEntries = new ArrayList<>();
+                if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
+                    macEntries.addAll(existingMacEntries);
                 }
+                if (!macEntries.isEmpty()) {
+                    for (MacEntry macEntry : macEntries) {
+                        logger.debug("removing the  mac-entry:{} present on elanInterface:{}",
+                                macEntry.getMacAddress().getValue(), interfaceName);
+                        if (!isLastElanInterface) {
+                            tx.delete(LogicalDatastoreType.OPERATIONAL,
+                                    ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
+                        }
+                        elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, deleteFlowGroupTx);
+                        macAddresses.add(macEntry.getMacAddress());
+                    }
 
-                // Removing all those MACs from External Devices belonging to this ELAN
-                if ( elanInfo.getVni() != null && elanInfo.getVni() != 0 ) {
-                    ElanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
-                }
-            }
-        }
-        /*
-         *This condition check is mainly to get DPN-ID in pre-provision deletion scenario after stopping CSS
-         */
-        if(dpId.equals(ElanConstants.INVALID_DPN)) {
-            ElanDpnInterfacesList elanDpnInterfacesList = ElanUtils.getElanDpnInterfacesList(elanName);
-            if(elanDpnInterfacesList != null && !elanDpnInterfacesList.getDpnInterfaces().isEmpty()) {
-                List<DpnInterfaces> dpnIfList = elanDpnInterfacesList.getDpnInterfaces();
-                for (DpnInterfaces dpnInterface : dpnIfList) {
-                    DpnInterfaces dpnIfLists = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpnInterface.getDpId());
-                    if (dpnIfLists.getInterfaces().contains(interfaceName)) {
-                        logger.debug("deleting the elanInterface from the ElanDpnInterface cache in pre-provision scenario of elan:{} dpn:{} interfaceName:{}", elanName, dpId, interfaceName);
-                        removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
-                        break;
+                    // Removing all those MACs from External Devices belonging
+                    // to this ELAN
+                    if (ElanUtils.isVxlan(elanInfo)) {
+                        elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
                     }
                 }
             }
+            removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
+            removeFilterEqualsTable(elanInfo, interfaceInfo, deleteFlowGroupTx);
         } else {
-            removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
+            // Interface does not exist in ConfigDS, so lets remove everything
+            // about that interface related to Elan
+            ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
+            if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
+                List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
+                for (MacEntry macEntry : macEntries) {
+                    tx.delete(LogicalDatastoreType.OPERATIONAL,
+                            ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
+                }
+            }
         }
-
-        removeStaticELanFlows(elanInfo, interfaceInfo);
-        ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
-        List<String> elanInterfaces = elanState.getElanInterfaces();
-        elanInterfaces.remove(interfaceName);
-
-        if(elanInterfaces.isEmpty()) {
-            ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
-            ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnOperationDataPath(elanName));
-            ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
-            ElanUtils.delete(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
-            //ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInstanceConfigurationDataPath(elanName));
-        } else {
-            Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName).setKey(new ElanKey(elanName)).build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
+        tx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
+        if (!isInterfaceStateRemoved) {
+            unbindService(elanInfo, interfaceName, tx);
         }
+        deleteElanInterfaceFromConfigDS(interfaceName, tx);
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
+        futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
     }
 
-    private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName, long elanTag) {
-        DpnInterfaces dpnInterfaces =  ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
-        if(dpnInterfaces != null) {
+    private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId,
+            String interfaceName, long elanTag, WriteTransaction tx) {
+        DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+        if (dpnInterfaces != null) {
             List<String> interfaceLists = dpnInterfaces.getInterfaces();
             interfaceLists.remove(interfaceName);
 
             if (interfaceLists == null || interfaceLists.isEmpty()) {
                 deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
-                deleteElanDpnInterface(elanName, dpId);
+                deleteElanDpnInterface(elanName, dpId, tx);
             } else {
-                updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
+                dpnInterfaces = updateElanDpnInterfacesList(elanName, dpId, interfaceLists, tx);
             }
         }
+        return dpnInterfaces;
     }
 
     private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
-        List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
+        List<DpnInterfaces> dpnInterfaces = elanUtils.getInvolvedDpnsInElan(elanName);
         for (DpnInterfaces dpnInterface : dpnInterfaces) {
             BigInteger currentDpId = dpnInterface.getDpId();
             if (!currentDpId.equals(dpId)) {
                 for (String elanInterface : dpnInterface.getInterfaces()) {
-                    ElanInterfaceMac macs = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
-                    if (macs == null) {
+                    ElanInterfaceMac macs = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+                    if (macs == null || macs.getMacEntry() == null) {
                         continue;
                     }
-                    for (MacEntry mac : macs.getMacEntry())
-                        mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
-                            ElanUtils.getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, currentDpId, mac.getMacAddress().getValue(), elanTag)));
+                    for (MacEntry mac : macs.getMacEntry()) {
+                        removeTheMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
+                        removeEtreeMacFlowInTheDPN(dpId, elanTag, currentDpId, mac);
+                    }
                 }
             }
         }
     }
 
+    private void removeEtreeMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
+        EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanTag);
+        if (etreeLeafTag != null) {
+            removeTheMacFlowInTheDPN(dpId, etreeLeafTag.getEtreeLeafTag().getValue(), currentDpId, mac);
+        }
+    }
+
+    private void removeTheMacFlowInTheDPN(BigInteger dpId, long elanTag, BigInteger currentDpId, MacEntry mac) {
+        mdsalManager
+                .removeFlow(dpId,
+                        MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
+                                ElanUtils.getKnownDynamicmacFlowRef(NwConstants.ELAN_DMAC_TABLE, dpId, currentDpId,
+                                        mac.getMacAddress().getValue(), elanTag)));
+    }
+
     @Override
     protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
         // updating the static-Mac Entries for the existing elanInterface
         String elanName = update.getElanInstanceName();
         String interfaceName = update.getName();
-        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
         List<PhysAddress> existingPhysAddress = original.getStaticMacEntries();
         List<PhysAddress> updatedPhysAddress = update.getStaticMacEntries();
-        if(updatedPhysAddress != null && !updatedPhysAddress.isEmpty()) {
+        if (updatedPhysAddress != null && !updatedPhysAddress.isEmpty()) {
             List<PhysAddress> existingClonedPhyAddress = new ArrayList<>();
-            if(existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
+            if (existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
                 existingClonedPhyAddress.addAll(0, existingPhysAddress);
                 existingPhysAddress.removeAll(updatedPhysAddress);
                 updatedPhysAddress.removeAll(existingClonedPhyAddress);
-                // removing the PhyAddress which are not presented in the updated List
-                for(PhysAddress physAddress: existingPhysAddress) {
+                // removing the PhyAddress which are not presented in the
+                // updated List
+                for (PhysAddress physAddress : existingPhysAddress) {
                     removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
                 }
             }
-            // Adding the new PhysAddress which are presented in the updated List
-            if(updatedPhysAddress.size() > 0) {
-                for(PhysAddress physAddress: updatedPhysAddress) {
-                    InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanName, physAddress);
-                    Optional<MacEntry> existingMacEntry = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, macId);
-                    if(existingMacEntry.isPresent()) {
-                        elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get());
+            // Adding the new PhysAddress which are presented in the updated
+            // List
+            if (updatedPhysAddress.size() > 0) {
+                for (PhysAddress physAddress : updatedPhysAddress) {
+                    InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanName, physAddress);
+                    Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
+                            LogicalDatastoreType.OPERATIONAL, macId);
+                    WriteTransaction tx = broker.newWriteOnlyTransaction();
+                    if (existingMacEntry.isPresent()) {
+                        elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
+                                elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(),
+                                tx);
                     } else {
-                        elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(ElanUtils.getElanInstanceByName(elanName), interfaceName, physAddress);
+                        elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
+                                elanUtils.getElanInstanceByName(elanName), interfaceName, physAddress, tx);
                     }
+                    ElanUtils.waitForTransactionToComplete(tx);
                 }
             }
-        } else if(existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
-            forPhysAddress physAddress : existingPhysAddress) {
+        } else if (existingPhysAddress != null && !existingPhysAddress.isEmpty()) {
+            for (PhysAddress physAddress : existingPhysAddress) {
                 removeInterfaceStaticMacEntires(elanName, interfaceName, physAddress);
             }
         }
@@ -357,318 +463,438 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             logger.warn("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
             return;
         }
-        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+        ElanInstance elanInstance = elanUtils.getElanInstanceByName(elanInstanceName);
 
         if (elanInstance == null) {
-            elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(elanInterfaceAdded.getDescription()).build();
-            //Add the ElanInstance in the Configuration data-store
-            ElanUtils.updateOperationalDataStore(broker, idManager, elanInstance);
-            elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+            elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
+                    .setDescription(elanInterfaceAdded.getDescription()).build();
+            // Add the ElanInstance in the Configuration data-store
+            WriteTransaction tx = broker.newWriteOnlyTransaction();
+            List<String> elanInterfaces = new ArrayList<String>();
+            elanInterfaces.add(interfaceName);
+            ElanUtils.updateOperationalDataStore(broker, idManager,
+                    elanInstance, elanInterfaces, tx);
+            ElanUtils.waitForTransactionToComplete(tx);
+            elanInstance = elanUtils.getElanInstanceByName(elanInstanceName);
         }
 
-
         Long elanTag = elanInstance.getElanTag();
-        // If elan tag is not updated, then put the elan interface into unprocessed entry map and entry. Let entries
+        // If elan tag is not updated, then put the elan interface into
+        // unprocessed entry map and entry. Let entries
         // in this map get processed during ELAN update DCN.
         if (elanTag == null) {
             ConcurrentLinkedQueue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstanceName);
             if (elanInterfaces == null) {
-                elanInterfaces = new ConcurrentLinkedQueue<>();
+                elanInterfaces = new ConcurrentLinkedQueue<ElanInterface>();
             }
             elanInterfaces.add(elanInterfaceAdded);
             unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
             return;
         }
         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
-        ElanInterfaceAddWorker addWorker = new ElanInterfaceAddWorker(elanInstanceName, elanInterfaceAdded,
+        InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
                 interfaceInfo, elanInstance, this);
         coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
     void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
+        List<ListenableFuture<Void>> futures = new ArrayList<>();
         Queue<ElanInterface> elanInterfaces = unProcessedElanInterfaces.get(elanInstance.getElanInstanceName());
         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
             return;
         }
-        for (ElanInterface elanInterface: elanInterfaces) {
+        for (ElanInterface elanInterface : elanInterfaces) {
             String interfaceName = elanInterface.getName();
             InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
-            addElanInterface(elanInterface, interfaceInfo, elanInstance);
+            addElanInterface(futures, elanInterface, interfaceInfo, elanInstance);
         }
     }
 
-    void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo){
-        ElanDpnInterfacesList elanDpnInterfacesList =  ElanUtils.getElanDpnInterfacesList(elanInstance.getElanInstanceName());
-        List<DpnInterfaces> dpnInterfaceLists =  elanDpnInterfacesList.getDpnInterfaces();
-        for(DpnInterfaces dpnInterfaces : dpnInterfaceLists){
-            if(dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
+    void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
+            WriteTransaction writeFlowGroupTx) {
+        ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
+                .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
+        List<DpnInterfaces> dpnInterfaceLists = null;
+        if (elanDpnInterfacesList != null) {
+            dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
+        }
+        if (dpnInterfaceLists == null) {
+            dpnInterfaceLists = new ArrayList<DpnInterfaces>();
+        }
+        for (DpnInterfaces dpnInterfaces : dpnInterfaceLists) {
+            if (dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
                 continue;
             }
             List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
-            for(String remoteIf : remoteElanInterfaces) {
-                ElanInterfaceMac elanIfMac = ElanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
+            for (String remoteIf : remoteElanInterfaces) {
+                ElanInterfaceMac elanIfMac = elanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
                 InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
-                if(elanIfMac == null) {
+                if (elanIfMac == null) {
                     continue;
                 }
                 List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
-                if(remoteMacEntries != null) {
+                if (remoteMacEntries != null) {
                     for (MacEntry macEntry : remoteMacEntries) {
                         PhysAddress physAddress = macEntry.getMacAddress();
-                        ElanUtils.setupRemoteDmacFlow(interfaceInfo.getDpId(), remoteInterface.getDpId(),
-                                remoteInterface.getInterfaceTag(),
-                                elanInstance.getElanTag(),
-                                physAddress.getValue(),
-                                elanInstance.getElanInstanceName());
+                        elanUtils.setupRemoteDmacFlow(interfaceInfo.getDpId(), remoteInterface.getDpId(),
+                                remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), physAddress.getValue(),
+                                elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf);
                     }
                 }
             }
         }
     }
 
-    void addElanInterface(ElanInterface elanInterface, InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
+    void addElanInterface(List<ListenableFuture<Void>> futures, ElanInterface elanInterface, InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
         Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
         Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
         Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
 
         String interfaceName = elanInterface.getName();
         String elanInstanceName = elanInterface.getElanInstanceName();
-        List<PhysAddress> staticMacAddresses = elanInterface.getStaticMacEntries();
 
-        Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
-        if(elanInfo == null) {
-            ElanUtils.updateOperationalDataStore(broker, idManager, elanInstance);
+        Elan elanInfo = elanUtils.getElanByName(elanInstanceName);
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        if (elanInfo == null) {
+            List<String> elanInterfaces = new ArrayList<String>();
+            elanInterfaces.add(interfaceName);
+            ElanUtils.updateOperationalDataStore(broker, idManager,
+                    elanInstance, elanInterfaces, tx);
+        } else {
+            createElanStateList(elanInstanceName, interfaceName, tx);
         }
-
-        // Specific actions to the DPN where the ElanInterface has been added, for example, programming the
-        // External tunnel table if needed or adding the ElanInterface to the DpnInterfaces in the operational DS.
-        BigInteger dpId = ( interfaceInfo != null ) ? dpId = interfaceInfo.getDpId() : null;
-        if(dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
-            InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
-            Optional<DpnInterfaces> existingElanDpnInterfaces = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
+        boolean isFirstInterfaceInDpn = false;
+        // Specific actions to the DPN where the ElanInterface has been added,
+        // for example, programming the
+        // External tunnel table if needed or adding the ElanInterface to the
+        // DpnInterfaces in the operational DS.
+        BigInteger dpId = (interfaceInfo != null) ? dpId = interfaceInfo.getDpId() : null;
+        DpnInterfaces dpnInterfaces = null;
+        if (dpId != null && !dpId.equals(ElanConstants.INVALID_DPN)) {
+            InstanceIdentifier<DpnInterfaces> elanDpnInterfaces = ElanUtils
+                    .getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId);
+            Optional<DpnInterfaces> existingElanDpnInterfaces = elanUtils.read(broker,
+                    LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
             if (!existingElanDpnInterfaces.isPresent()) {
+                isFirstInterfaceInDpn = true;
                 // ELAN's 1st ElanInterface added to this DPN
-                createElanInterfacesList(elanInstanceName, interfaceName, dpId);
-                /*
-                 * Install remote DMAC flow.
-                 * This is required since this DPN is added later to the elan instance
-                 * and remote DMACs of other interfaces in this elan instance are not present in the current dpn.
-                 */
-                programRemoteDmacFlow(elanInstance, interfaceInfo);
-                // The 1st ElanInterface in a DPN must program the Ext Tunnel table, but only if Elan has VNI
-                if ( elanInstance.getVni() != null && elanInstance.getVni().longValue() != 0 ) {
+                dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
+                // The 1st ElanInterface in a DPN must program the Ext Tunnel
+                // table, but only if Elan has VNI
+                if (ElanUtils.isVxlan(elanInstance)) {
                     setExternalTunnelTable(dpId, elanInstance);
                 }
-                ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
+                elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
             } else {
                 List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
                 elanInterfaces.add(interfaceName);
-                if (elanInterfaces.size() == 1) {//1st dpn interface
-                    ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
+                if (elanInterfaces.size() == 1) {// 1st dpn interface
+                    elanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance, interfaceName);
                 }
-                updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces);
+                dpnInterfaces = updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces, tx);
             }
         }
 
-        // add code to install Local/Remote BC group, unknow DMAC entry, terminating service table flow entry
-        // call bindservice of interfacemanager to create ingress table flow enty.
-        //Add interface to the ElanInterfaceForwardingEntires Container
-        createElanInterfaceTablesList(interfaceName);
-        createElanStateList(elanInstanceName, interfaceName);
+        // add code to install Local/Remote BC group, unknow DMAC entry,
+        // terminating service table flow entry
+        // call bindservice of interfacemanager to create ingress table flow
+        // enty.
+        // Add interface to the ElanInterfaceForwardingEntires Container
+        createElanInterfaceTablesList(interfaceName, tx);
         if (interfaceInfo != null) {
-            installFlowsAndGroups(elanInstance, interfaceInfo);
+            installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn, tx);
         }
-        // add the static mac addresses
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
+
+        DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+        InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(interfaceName,
+                elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
+        coordinator.enqueueJob(interfaceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
+    }
+
+    void setupEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInstance, ElanInterface elanInterface,
+            InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
+        String elanInstanceName = elanInstance.getElanInstanceName();
+        String interfaceName = elanInterface.getName();
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        BigInteger dpId = interfaceInfo.getDpId();
+        WriteTransaction writeFlowGroupTx = broker.newWriteOnlyTransaction();
+        installEntriesForElanInterface(elanInstance, interfaceInfo, isFirstInterfaceInDpn, tx, writeFlowGroupTx);
+        List<PhysAddress> staticMacAddresses = elanInterface.getStaticMacEntries();
         if (staticMacAddresses != null) {
             boolean isInterfaceOperational = isOperational(interfaceInfo);
             for (PhysAddress physAddress : staticMacAddresses) {
                 InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
-                Optional<MacEntry> existingMacEntry = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, macId);
+                Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
+                        LogicalDatastoreType.OPERATIONAL, macId);
                 if (existingMacEntry.isPresent()) {
-                    elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(elanInstanceName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get());
+                    elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
+                            elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
+                            existingMacEntry.get(), tx);
                 } else {
-                    elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(elanInstance, interfaceName, physAddress);
+                    elanForwardingEntriesHandler
+                            .addElanInterfaceForwardingTableList(elanInstance, interfaceName, physAddress, tx);
                 }
 
-                if ( isInterfaceOperational ) {
-                    // Setting SMAC, DMAC, UDMAC in this DPN and also in other DPNs
-                    ElanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, physAddress.getValue());
+                if (isInterfaceOperational) {
+                    // Setting SMAC, DMAC, UDMAC in this DPN and also in other
+                    // DPNs
+                    elanUtils.setupMacFlows(elanInstance, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT,
+                            physAddress.getValue(), writeFlowGroupTx);
                 }
             }
 
-            if( isInterfaceOperational ) {
-                // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop on purpose.
-                ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, staticMacAddresses);
+            if (isInterfaceOperational) {
+                // Add MAC in TOR's remote MACs via OVSDB. Outside of the loop
+                // on purpose.
+                elanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
+                        staticMacAddresses);
             }
         }
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
+        futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
     }
 
-    protected void removeInterfaceStaticMacEntires(String elanInstanceName, String interfaceName, PhysAddress physAddress) {
+    protected void removeInterfaceStaticMacEntires(String elanInstanceName, String interfaceName,
+            PhysAddress physAddress) {
         InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
-        InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanInstanceName, physAddress);
-        Optional<MacEntry> existingMacEntry = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, macId);
+        InstanceIdentifier<MacEntry> macId = getMacEntryOperationalDataPath(elanInstanceName, physAddress);
+        Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
+                LogicalDatastoreType.OPERATIONAL, macId);
 
-        if(!existingMacEntry.isPresent()) {
+        if (!existingMacEntry.isPresent()) {
             return;
         }
 
-        MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName).setKey(new MacEntryKey(physAddress)).build();
-        elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(ElanUtils.getElanInstanceByName(elanInstanceName), interfaceInfo, macEntry);
-        elanForwardingEntriesHandler.deleteElanInterfaceMacForwardingEntries(interfaceName, physAddress);
+        MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
+                .setKey(new MacEntryKey(physAddress)).build();
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
+                elanUtils.getElanInstanceByName(elanInstanceName), interfaceInfo, macEntry, tx);
+        elanForwardingEntriesHandler.deleteElanInterfaceMacForwardingEntries(interfaceName,
+                physAddress, tx);
+        ElanUtils.waitForTransactionToComplete(tx);
     }
 
-
     private InstanceIdentifier<MacEntry> getMacEntryOperationalDataPath(String elanName, PhysAddress physAddress) {
-        return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class,
-                new MacTableKey(elanName)).child(MacEntry.class, new MacEntryKey(physAddress)).build();
+        return InstanceIdentifier.builder(ElanForwardingTables.class).child(MacTable.class, new MacTableKey(elanName))
+                .child(MacEntry.class, new MacEntryKey(physAddress)).build();
     }
 
-    public void installFlowsAndGroups(final ElanInstance elanInfo, final InterfaceInfo interfaceInfo) {
-        if (isOperational(interfaceInfo)) {
-
-            // LocalBroadcast Group creation with elan-Interfaces
-            setupElanBroadcastGroups(elanInfo, interfaceInfo.getDpId());
-
-            setupLocalBroadcastGroups(elanInfo, interfaceInfo);
-            //Terminating Service , UnknownDMAC Table.
-            setupTerminateServiceTable(elanInfo, interfaceInfo);
-            ElanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager);
-            setupUnknownDMacTable(elanInfo, interfaceInfo);
-            setupFilterEqualsTable(elanInfo, interfaceInfo);
-            // bind the Elan service to the Interface
-            bindService(elanInfo, interfaceInfo.getInterfaceName());
+    private void installEntriesForElanInterface(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
+            boolean isFirstInterfaceInDpn, WriteTransaction tx, WriteTransaction writeFlowGroupTx) {
+        if (!isOperational(interfaceInfo)) {
+            return;
+        }
+        BigInteger dpId = interfaceInfo.getDpId();
+        elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
+        setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
+        if (isFirstInterfaceInDpn) {
+            // Terminating Service , UnknownDMAC Table.
+            setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
+            setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
+            // update the remote-DPNs remoteBC group entry with Tunnels
+            setElanBCGrouponOtherDpns(elanInstance, elanInstance.getElanTag().longValue(), dpId, writeFlowGroupTx);
+            /*
+             * Install remote DMAC flow. This is required since this DPN is
+             * added later to the elan instance and remote DMACs of other
+             * interfaces in this elan instance are not present in the current
+             * dpn.
+             */
+            programRemoteDmacFlow(elanInstance, interfaceInfo, writeFlowGroupTx);
+        }
+        // bind the Elan service to the Interface
+        bindService(elanInstance, elanUtils.getElanInterfaceByElanInterfaceName(interfaceInfo.getInterfaceName()), tx);
+    }
 
-            //update the remote-DPNs remoteBC group entry with Tunnels
-            setElanBCGrouponOtherDpns(elanInfo, interfaceInfo);
+    public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            DpnInterfaces dpnInterfaces, boolean isFirstInterfaceInDpn, WriteTransaction tx) {
+        if (!isOperational(interfaceInfo)) {
+            return;
+        }
+        // LocalBroadcast Group creation with elan-Interfaces
+        setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
+        if (isFirstInterfaceInDpn) {
+            logger.trace("waitTimeForSyncInstall is {}", waitTimeForSyncInstall);
+            BigInteger dpId = interfaceInfo.getDpId();
+            // RemoteBroadcast Group creation
+            try {
+                Thread.sleep(waitTimeForSyncInstall);
+            } catch (InterruptedException e1) {
+                logger.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
+            }
+            setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
+            try {
+                Thread.sleep(waitTimeForSyncInstall);
+            } catch (InterruptedException e1) {
+                logger.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
+            }
         }
     }
 
-    public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+    public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction writeFlowGroupTx) {
         int ifTag = interfaceInfo.getInterfaceTag();
-        Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, ifTag),
-                9, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getTunnelIdMatchForFilterEqualsLPortTag(ifTag), ElanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
+        Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
+                getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag), 9, elanInfo.getElanInstanceName(), 0, 0,
+                ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
+                getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
+                elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
 
-        mdsalManager.installFlow(interfaceInfo.getDpId(), flow);
+        mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
 
-        Flow flowEntry = MDSALUtil.buildFlowNew(ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, 1000+ifTag),
-                10, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getMatchesForFilterEqualsLPortTag(ifTag),
-                MDSALUtil.buildInstructionsDrop());
+        Flow flowEntry = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
+                getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000 + ifTag), 10, elanInfo.getElanInstanceName(), 0,
+                0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
+                getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
 
-        mdsalManager.installFlow(interfaceInfo.getDpId(), flowEntry);
+        mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
     }
 
-    public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+    public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
         int ifTag = interfaceInfo.getInterfaceTag();
-        Flow flow = MDSALUtil.buildFlowNew(ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, ifTag),
-                9, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getTunnelIdMatchForFilterEqualsLPortTag(ifTag), ElanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
+        Flow flow = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
+                getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, ifTag), 9, elanInfo.getElanInstanceName(), 0, 0,
+                ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
+                getTunnelIdMatchForFilterEqualsLPortTag(ifTag),
+                elanUtils.getInstructionsInPortForOutGroup(interfaceInfo.getInterfaceName()));
 
-        mdsalManager.removeFlow(interfaceInfo.getDpId(), flow);
+        mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
 
-        Flow flowEntity = MDSALUtil.buildFlowNew(ElanConstants.ELAN_FILTER_EQUALS_TABLE, getFlowRef(ElanConstants.ELAN_FILTER_EQUALS_TABLE, 1000+ifTag),
-                10, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)), getMatchesForFilterEqualsLPortTag(ifTag),
-                MDSALUtil.buildInstructionsDrop());
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_FILTER_EQUALS_TABLE,
+                getFlowRef(NwConstants.ELAN_FILTER_EQUALS_TABLE, 1000 + ifTag), 10, elanInfo.getElanInstanceName(), 0,
+                0, ElanConstants.COOKIE_ELAN_FILTER_EQUALS.add(BigInteger.valueOf(ifTag)),
+                getMatchesForFilterEqualsLPortTag(ifTag), MDSALUtil.buildInstructionsDrop());
 
-        mdsalManager.removeFlow(interfaceInfo.getDpId(), flowEntity);
+        mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
     }
 
-    private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo,
-                                                     int bucketKeyStart, InterfaceInfo interfaceInfo) {
-        BigInteger dpnId = interfaceInfo.getDpId();
-        int elanTag = elanInfo.getElanTag().intValue();
-        int bucketId = bucketKeyStart;
-        List<Bucket> listBuckets = new ArrayList<>();
-        ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
-        if(elanDpns != null) {
-            List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            for(DpnInterfaces dpnInterface : dpnInterfaceses) {
-               if(ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
-                   try {
-                       List<Action> listAction = ElanUtils.getInternalItmEgressAction(dpnId, dpnInterface.getDpId(), elanTag);
-                       listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-                       bucketId++;
-                   } catch (Exception ex) {
-                       logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnId, dpnInterface.getDpId() );
-                   }
-               }
-            }
-            List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
-            listBuckets.addAll(elanL2GwDevicesBuckets);
-        }
-        return listBuckets;
+    private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo, int bucketKeyStart,
+            InterfaceInfo interfaceInfo, long elanTag) {
+        return getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), bucketKeyStart, elanTag);
     }
 
-    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, BigInteger dpnId, int bucketId) {
-        int elanTag = elanInfo.getElanTag().intValue();
-        List<Bucket> listBucketInfo = new ArrayList<>();
-        ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
-        if(elanDpns != null) {
-            List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            for(DpnInterfaces dpnInterface : dpnInterfaceses) {
-                if(ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
+    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
+            int bucketId, long elanTag) {
+        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+        ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
+        listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId, elanTag));
+        listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId, bucketId));
+        listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId));
+        return listBucketInfo;
+    }
+
+    private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
+            long elanTag) {
+        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+        if (elanDpns != null) {
+            for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
+                if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId
+                        && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
                     try {
-                        List<Action> listActionInfo = ElanUtils.getInternalItmEgressAction(dpnId, dpnInterface.getDpId(), elanTag);
-                        listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, 0, bucketId, 0xffffffffL, 0xffffffffL));
+                        List<Action> listActionInfo = elanUtils.getInternalTunnelItmEgressAction(dpnId,
+                                dpnInterface.getDpId(), elanTag);
+                        if (listActionInfo.isEmpty()) {
+                            continue;
+                        }
+                        listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
+                                MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
                         bucketId++;
                     } catch (Exception ex) {
-                        logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnId, dpnInterface.getDpId() );
+                        logger.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
+                                dpnId, dpnInterface.getDpId());
                     }
                 }
             }
+        }
+        return listBucketInfo;
+    }
 
-            List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
-            listBucketInfo.addAll(elanL2GwDevicesBuckets);
+    private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
+            DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
+        DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
+        if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
+                || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+        for (String interfaceName : currDpnInterfaces.getInterfaces()) {
+            if (elanUtils.isExternal(interfaceName)) {
+                List<Action> listActionInfo = elanUtils.getExternalPortItmEgressAction(interfaceName);
+                if (!listActionInfo.isEmpty()) {
+                    listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
+                            MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+                    bucketId++;
+                }
+            }
         }
         return listBucketInfo;
     }
 
-    private void setElanBCGrouponOtherDpns(ElanInstance elanInfo,
-                                           InterfaceInfo interfaceInfo) {
-        BigInteger dpnId = interfaceInfo.getDpId();
-        int elanTag = elanInfo.getElanTag().intValue();
+    private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
+        if (elanDpns != null) {
+            for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
+                if (dpnInterface.getDpId() == dpnId) {
+                    return dpnInterface;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void setElanBCGrouponOtherDpns(ElanInstance elanInfo, long elanTag, BigInteger dpId, WriteTransaction tx) {
         long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
-        List<Bucket> listBucket = new ArrayList<>();
+        List<Bucket> listBucket = new ArrayList<Bucket>();
         int bucketId = 0;
-        ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
-        if(elanDpns != null) {
+        ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
+        if (elanDpns != null) {
             List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            for(DpnInterfaces dpnInterface : dpnInterfaceses) {
-              List<Bucket> remoteListBucketInfo = new ArrayList<>();
-                if(ElanUtils.isDpnPresent(dpnInterface.getDpId()) && !dpnInterface.getDpId().equals(dpnId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
-                    for(String ifName : dpnInterface.getInterfaces()) {
-                        // In case if there is a InterfacePort in the cache which is not in
-                        // operational state, skip processing it
-                        InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
-                        if (!isOperational(ifInfo)) {
-                            continue;
-                        }
-
-                        listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-                        bucketId++;
-                    }
+            for (DpnInterfaces dpnInterface : dpnInterfaceses) {
+                List<Bucket> remoteListBucketInfo = new ArrayList<Bucket>();
+                if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !dpnInterface.getDpId().equals(dpId)
+                        && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
+                    List<Action> listAction = new ArrayList<Action>();
+                    int actionKey = 0;
+                    listAction.add((new ActionInfo(ActionType.group,
+                            new String[] { String.valueOf(ElanUtils.getElanLocalBCGID(elanTag)) }, ++actionKey))
+                                    .buildAction());
+                    listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId,
+                            MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+                    bucketId++;
                     remoteListBucketInfo.addAll(listBucket);
-                    for(DpnInterfaces otherFes : dpnInterfaceses) {
-                        if (ElanUtils.isDpnPresent(otherFes.getDpId()) && otherFes.getDpId() != dpnInterface.getDpId()
-                                && otherFes.getInterfaces() != null && ! otherFes.getInterfaces().isEmpty()) {
+                    for (DpnInterfaces otherFes : dpnInterfaceses) {
+                        if (elanUtils.isDpnPresent(otherFes.getDpId()) && otherFes.getDpId() != dpnInterface.getDpId()
+                                && otherFes.getInterfaces() != null && !otherFes.getInterfaces().isEmpty()) {
                             try {
-                                List<Action> remoteListActionInfo = ElanUtils.getInternalItmEgressAction(dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
-                                remoteListBucketInfo.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,MDSALUtil.WATCH_GROUP));
-                                bucketId++;
+                                List<Action> remoteListActionInfo = elanUtils.getInternalTunnelItmEgressAction(
+                                        dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
+                                if (!remoteListActionInfo.isEmpty()) {
+                                    remoteListBucketInfo
+                                            .add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT,
+                                                    bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+                                    bucketId++;
+                                }
                             } catch (Exception ex) {
-                                logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), otherFes.getDpId() );
+                                logger.error(
+                                        "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
+                                        dpnInterface.getDpId(), otherFes.getDpId());
                                 return;
                             }
                         }
                     }
-                    List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId,
+                    List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpId,
                             bucketId);
                     remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
 
                     if (remoteListBucketInfo.size() == 0) {
-                        logger.debug( "No ITM is present on Dpn - {} " ,dpnInterface.getDpId());
+                        logger.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
                         continue;
                     }
-                    Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(remoteListBucketInfo));
-                    mdsalManager.syncInstallGroup(dpnInterface.getDpId(), group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
+                    Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                            MDSALUtil.buildBucketLists(remoteListBucketInfo));
+                    mdsalManager.addGroupToTx(dpnInterface.getDpId(), group, tx);
                 }
             }
         }
@@ -678,218 +904,259 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
      * Returns the bucket info with the given interface as the only bucket.
      */
     private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
-        return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
-    }
-
-    private List<MatchInfo> getMatchesForElanTag(Long elanTag) {
-        List<MatchInfo> mkMatches = new ArrayList<>();
-        // Matching metadata
-        mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-                ElanUtils.getElanMetadataLabel(elanTag),
-                MetaDataUtil.METADATA_MASK_SERVICE }));
-        return mkMatches;
+        return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart,
+                MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
     }
 
-
     private List<MatchInfo> buildMatchesForVni(Long vni) {
         List<MatchInfo> mkMatches = new ArrayList<>();
-        MatchInfo match = new MatchInfo(MatchFieldType.tunnel_id,
-                                        new BigInteger[]{BigInteger.valueOf(vni)} );
+        MatchInfo match = new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(vni) });
         mkMatches.add(match);
         return mkMatches;
     }
 
-    private List<Instruction> getInstructionsForOutGroup(
-            long groupId) {
+    private List<Instruction> getInstructionsForOutGroup(long groupId) {
         List<Instruction> mkInstructions = new ArrayList<>();
-        List <Action> actions = new ArrayList<>();
-        actions.add(new ActionInfo(ActionType.group, new String[]{Long.toString(groupId)}).buildAction());
+        List<Action> actions = new ArrayList<>();
+        actions.add(new ActionInfo(ActionType.group, new String[] { Long.toString(groupId) }).buildAction());
         mkInstructions.add(MDSALUtil.getWriteActionsInstruction(actions, 0));
         return mkInstructions;
     }
 
     private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
-        List<MatchInfo> mkMatches = new ArrayList<>();
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
         // Matching metadata
         mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-                ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet),
-                MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG}));
+                ElanUtils.getElanMetadataLabel(elanTag, isSHFlagSet), MetaDataUtil.METADATA_MASK_SERVICE_SH_FLAG }));
         return mkMatches;
     }
 
-
-
-
     /**
-     * Builds the list of instructions to be installed in the External Tunnel table (38), which so far
-     * consists in writing the elanTag in metadata and send packet to the new DHCP table
+     * Builds the list of instructions to be installed in the External Tunnel
+     * table (38), which so far consists in writing the elanTag in metadata and
+     * send packet to the new DHCP table
      *
-     * @param elanTag elanTag to be written in metadata when flow is selected
+     * @param elanTag
+     *            elanTag to be written in metadata when flow is selected
      * @return the instructions ready to be installed in a flow
      */
     private List<InstructionInfo> getInstructionsExtTunnelTable(Long elanTag) {
-        List<InstructionInfo> mkInstructions = new ArrayList<>();
+        List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
         mkInstructions.add(new InstructionInfo(InstructionType.write_metadata,
-                                               new BigInteger[] {
-                                                       ElanUtils.getElanMetadataLabel(elanTag),
-                                                       ElanUtils.getElanMetadataMask()
-                                               } ) );
-        // TODO (eperefr) We should point to SMAC or DMAC depending on a configuration property to enable
+                new BigInteger[] { ElanUtils.getElanMetadataLabel(elanTag), ElanUtils.getElanMetadataMask() }));
+        // TODO: We should point to SMAC or DMAC depending on a configuration
+        // property to enable
         // mac learning
-        mkInstructions.add(new InstructionInfo(InstructionType.goto_table,
-                                               new long[] { ElanConstants.ELAN_DMAC_TABLE }));
+        mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.ELAN_DMAC_TABLE }));
 
         return mkInstructions;
     }
 
-    public void removeFlowsAndGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
-        removeStaticELanFlows(elanInfo, interfaceInfo);
-        unbindService(elanInfo, interfaceInfo.getInterfaceName());
-    }
-
-    public void installMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
-
-        String interfaceName = interfaceInfo.getInterfaceName();
-        BigInteger currentDpn = interfaceInfo.getDpId();
-        ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
-        if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
-            List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
-            for(MacEntry macEntry : macEntries) {
-                PhysAddress physAddress = macEntry.getMacAddress();
-                ElanUtils.setupMacFlows(elanInfo,
-                                        interfaceInfo,
-                                        macEntry.isIsStaticAddress()
-                                          ? ElanConstants.STATIC_MAC_TIMEOUT
-                                          : elanInfo.getMacTimeout(), physAddress.getValue());
-            }
-            //Programming the remoteDMACFlows
-            ElanDpnInterfacesList elanDpnInterfacesList =  ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
-            List<DpnInterfaces> dpnInterfaceLists =  elanDpnInterfacesList.getDpnInterfaces();
-            for(DpnInterfaces dpnInterfaces : dpnInterfaceLists){
-                if(dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
-                    continue;
-                }
-                List<String> remoteElanInterfaces = dpnInterfaces.getInterfaces();
-                for(String remoteIf : remoteElanInterfaces) {
-                    ElanInterfaceMac elanIfMac = ElanUtils.getElanInterfaceMacByInterfaceName(remoteIf);
-                    InterfaceInfo remoteInterface = interfaceManager.getInterfaceInfo(remoteIf);
-                    if(elanIfMac == null) {
-                        continue;
-                    }
-                    List<MacEntry> remoteMacEntries = elanIfMac.getMacEntry();
-                    if(remoteMacEntries != null) {
-                        for (MacEntry macEntry : remoteMacEntries) {
-                            PhysAddress physAddress = macEntry.getMacAddress();
-                            ElanUtils.installDmacFlowsToInternalRemoteMac(currentDpn, remoteInterface.getDpId(),
-                                    remoteInterface.getInterfaceTag(),
-                                    elanInfo.getElanTag(),
-                                    physAddress.getValue(),
-                                    elanInfo.getElanInstanceName());
-                        }
-                    }
-                }
-            }
-        }
-    }
-
     // Install DMAC entry on dst DPN
     public void installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId) {
         String interfaceName = interfaceInfo.getInterfaceName();
-        ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
-        if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
-            List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
-            for(MacEntry macEntry : macEntries) {
+        ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
+        if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
+            WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
+            List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
+            for (MacEntry macEntry : macEntries) {
                 PhysAddress physAddress = macEntry.getMacAddress();
-                ElanUtils.setupDMacFlowonRemoteDpn(elanInfo, interfaceInfo, dstDpId, physAddress.getValue());
+                elanUtils.setupDMacFlowonRemoteDpn(elanInfo, interfaceInfo, dstDpId, physAddress.getValue(),
+                        writeFlowTx);
             }
+            writeFlowTx.submit();
         }
     }
 
-    public void removeMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
-        ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceInfo.getInterfaceName());
-        if(elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
-            List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
-            for(MacEntry macEntry : macEntries) {
-                ElanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry);
-            }
-        }
+    public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
+        setupElanBroadcastGroups(elanInfo, null, dpnId);
     }
 
-    public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
-        List<Bucket> listBucket = new ArrayList<>();
-        int bucketId = 0;
-        long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
+    public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
+        setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
+        setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
+    }
 
-        DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpnId);
-        for(String ifName : dpnInterfaces.getInterfaces()) {
-            // In case if there is a InterfacePort in the cache which is not in
-            // operational state, skip processing it
-            // FIXME: interfaceType to be obtained dynamically. It doesn't
-            // affect the functionality here as it is nowhere used.
-            InterfaceType interfaceType = InterfaceInfo.InterfaceType.VLAN_INTERFACE;
-            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceType);
-            if (!isOperational(ifInfo)) {
-                continue;
-            }
+    public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
+        List<Bucket> listBucket = new ArrayList<Bucket>();
+        int bucketId = 0;
+        int actionKey = 0;
+        Long elanTag = elanInfo.getElanTag();
+        List<Action> listAction = new ArrayList<Action>();
+        listAction.add((new ActionInfo(ActionType.group,
+                new String[] { String.valueOf(ElanUtils.getElanLocalBCGID(elanTag)) }, ++actionKey)).buildAction());
+        listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
+                MDSALUtil.WATCH_GROUP));
+        bucketId++;
+        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
+                elanInfo.getElanTag());
+        listBucket.addAll(listBucketInfoRemote);
+        long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBucket));
+        logger.trace("Installing the remote BroadCast Group:{}", group);
+        mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
+    }
 
-            listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+    public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
+        EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+        if (etreeInstance != null) {
+            long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
+            List<Bucket> listBucket = new ArrayList<Bucket>();
+            int bucketId = 0;
+            int actionKey = 0;
+            List<Action> listAction = new ArrayList<Action>();
+            listAction.add((new ActionInfo(ActionType.group,
+                    new String[] { String.valueOf(ElanUtils.getEtreeLeafLocalBCGID(etreeLeafTag)) }, ++actionKey))
+                            .buildAction());
+            listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
+                    MDSALUtil.WATCH_GROUP));
             bucketId++;
+            List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
+                    etreeLeafTag);
+            listBucket.addAll(listBucketInfoRemote);
+            long groupId = ElanUtils.getEtreeLeafRemoteBCGID(etreeLeafTag);
+            Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                    MDSALUtil.buildBucketLists(listBucket));
+            logger.trace("Installing the remote BroadCast Group:{}", group);
+            mdsalManager.syncInstallGroup(dpnId, group,
+                    ElanConstants.DELAY_TIME_IN_MILLISECOND);
         }
-        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnId, bucketId);
-        listBucket.addAll(listBucketInfoRemote);
+    }
 
-        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
-        logger.trace("installing the remote BroadCast Group:{}", group);
-        mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
+    private void createDropBucket(List<Bucket> listBucket) {
+        List<Action> actionsInfos = new ArrayList<Action>();
+        actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}).buildAction());
+        Bucket dropBucket = MDSALUtil.buildBucket(actionsInfos, MDSALUtil.GROUP_WEIGHT, 0, MDSALUtil.WATCH_PORT,
+                MDSALUtil.WATCH_GROUP);
+        listBucket.add(dropBucket);
+    }
+
+    public void setupLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
+            InterfaceInfo interfaceInfo) {
+        setupStandardLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
+        setupLeavesLocalBroadcastGroups(elanInfo, newDpnInterface, interfaceInfo);
     }
 
-    public void setupLocalBroadcastGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
-        List<Bucket> listBucket = new ArrayList<>();
+    public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
+            InterfaceInfo interfaceInfo) {
+        List<Bucket> listBucket = new ArrayList<Bucket>();
         int bucketId = 0;
-        BigInteger dpnId = interfaceInfo.getDpId();
         long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
 
-        DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpnId);
-        for(String ifName : dpnInterfaces.getInterfaces()) {
+        List<String> interfaces = new ArrayList<String>();
+        if (newDpnInterface != null) {
+            interfaces = newDpnInterface.getInterfaces();
+        }
+        for (String ifName : interfaces) {
             // In case if there is a InterfacePort in the cache which is not in
             // operational state, skip processing it
-            InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
+            InterfaceInfo ifInfo = interfaceManager
+                    .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
             if (!isOperational(ifInfo)) {
                 continue;
             }
 
-            listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-            bucketId++;
+            if (!elanUtils.isExternal(ifName)) {
+                listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
+                        MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+                bucketId++;
+            }
         }
 
-        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBucket));
         logger.trace("installing the localBroadCast Group:{}", group);
-        mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
+        mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group,
+                ElanConstants.DELAY_TIME_IN_MILLISECOND);
+    }
+
+    private void setupLeavesLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
+            InterfaceInfo interfaceInfo) {
+        EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+        if (etreeInstance != null) {
+            long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
+            List<Bucket> listBucket = new ArrayList<Bucket>();
+            int bucketId = 0;
+            long groupId = ElanUtils.getEtreeLeafLocalBCGID(etreeLeafTag);
+
+            List<String> interfaces = new ArrayList<String>();
+            if (newDpnInterface != null) {
+                interfaces = newDpnInterface.getInterfaces();
+            }
+            for (String ifName : interfaces) {
+                // In case if there is a InterfacePort in the cache which is not
+                // in
+                // operational state, skip processing it
+                InterfaceInfo ifInfo = interfaceManager
+                        .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
+                if (!isOperational(ifInfo)) {
+                    continue;
+                }
+
+                if (!elanUtils.isExternal(ifName)) {
+                    // only add root interfaces
+                    bucketId = addInterfaceIfRootInterface(bucketId, ifName, listBucket, ifInfo);
+                }
+            }
+
+            if (listBucket.size() == 0) { // No Buckets
+                createDropBucket(listBucket);
+            }
+
+            Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                    MDSALUtil.buildBucketLists(listBucket));
+            logger.trace("installing the localBroadCast Group:{}", group);
+            mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group,
+                    ElanConstants.DELAY_TIME_IN_MILLISECOND);
+        }
+    }
+
+    private int addInterfaceIfRootInterface(int bucketId, String ifName, List<Bucket> listBucket,
+            InterfaceInfo ifInfo) {
+        EtreeInterface etreeInterface = elanUtils.getEtreeInterfaceByElanInterfaceName(ifName);
+        if (etreeInterface != null && etreeInterface.getEtreeInterfaceType() == EtreeInterfaceType.Root) {
+            listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId,
+                    MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+            bucketId++;
+        }
+        return bucketId;
     }
 
-    public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+    public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
         BigInteger dpnId = interfaceInfo.getDpId();
         long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
         List<Bucket> listBuckets = new ArrayList<>();
         int bucketId = 0;
         listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
-        //listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1, interfaceInfo));
-        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBuckets));
+        // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
+        // interfaceInfo));
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBuckets));
         logger.trace("deleted the localBroadCast Group:{}", group);
-        mdsalManager.syncRemoveGroup(dpnId, group);
+        mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
     }
 
-    public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+    public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
         int bucketId = 0;
+        int actionKey = 0;
+        Long elanTag = elanInfo.getElanTag();
         List<Bucket> listBuckets = new ArrayList<>();
-        listBuckets.add(getLocalBCGroupBucketInfo(interfaceInfo, bucketId));
+        List<Action> listAction = new ArrayList<Action>();
+        listAction.add((new ActionInfo(ActionType.group,
+                new String[] { String.valueOf(ElanUtils.getElanLocalBCGID(elanTag)) }, ++actionKey)).buildAction());
+        listBuckets.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
+                MDSALUtil.WATCH_GROUP));
         bucketId++;
-        listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo));
+        listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, bucketId, interfaceInfo, elanInfo.getElanTag()));
         BigInteger dpnId = interfaceInfo.getDpId();
         long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
-        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBuckets));
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBuckets));
         logger.trace("deleting the remoteBroadCast group:{}", group);
-        mdsalManager.syncRemoveGroup(dpnId, group);
+        mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
     }
 
     /**
@@ -904,30 +1171,32 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
      */
     public void setExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
         long elanTag = elanInfo.getElanTag();
-        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId,
-                                                          NwConstants.EXTERNAL_TUNNEL_TABLE,
-                                                          getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag),
-                                                          5,  // prio
-                                                          elanInfo.getElanInstanceName(),  // flowName
-                                                          0,  // idleTimeout
-                                                          0,  // hardTimeout
-                                                          ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
-                                                          buildMatchesForVni(elanInfo.getVni()),
-                                                          getInstructionsExtTunnelTable(elanTag) );
+        FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.EXTERNAL_TUNNEL_TABLE,
+                getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanTag), 5, // prio
+                elanInfo.getElanInstanceName(), // flowName
+                0, // idleTimeout
+                0, // hardTimeout
+                ITMConstants.COOKIE_ITM_EXTERNAL.add(BigInteger.valueOf(elanTag)),
+                buildMatchesForVni(elanInfo.getSegmentationId()), getInstructionsExtTunnelTable(elanTag));
 
         mdsalManager.installFlow(flowEntity);
     }
 
     /**
-     * Removes, from External Tunnel table, the flow that translates from VNI to elanTag.
-     * Important: ensure this method is only called whenever there is no other ElanInterface in the specified DPN
+     * Removes, from External Tunnel table, the flow that translates from VNI to
+     * elanTag. Important: ensure this method is only called whenever there is
+     * no other ElanInterface in the specified DPN
      *
-     * @param dpnId DPN whose Ext Tunnel table is going to be modified
-     * @param elanInfo holds the elanTag needed for selecting the flow to be removed
+     * @param dpnId
+     *            DPN whose Ext Tunnel table is going to be modified
+     * @param elanInfo
+     *            holds the elanTag needed for selecting the flow to be removed
      */
     public void unsetExternalTunnelTable(BigInteger dpnId, ElanInstance elanInfo) {
-        // TODO (eperefr): Use DataStoreJobCoordinator in order to avoid that removing the last ElanInstance plus
-        // adding a new one does (almost at the same time) are executed in that exact order
+        // TODO: Use DataStoreJobCoordinator in order to avoid that removing the
+        // last ElanInstance plus
+        // adding a new one does (almost at the same time) are executed in that
+        // exact order
 
         String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
         FlowEntity flowEntity = new FlowEntity(dpnId);
@@ -936,111 +1205,144 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         mdsalManager.removeFlow(flowEntity);
     }
 
-    public void setupTerminateServiceTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
-        long elanTag = elanInfo.getElanTag();
-        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE, getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, elanTag),
-                5, String.format("%s:%d","ITM Flow Entry ",elanTag), 0,  0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)), ElanUtils.getTunnelMatchesForServiceId((int)elanTag),
-                getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
-
-        mdsalManager.installFlow(interfaceInfo.getDpId(), flowEntity);
+    public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
+        setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
+        setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
     }
 
-    public void setupUnknownDMacTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
-        long elanTag = elanInfo.getElanTag();
-        Flow flowEntity = MDSALUtil.buildFlowNew(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, /*SH flag*/false),
-                5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag, /*SH flag*/false),
-                getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGID(elanTag)));
-
-        mdsalManager.installFlow(interfaceInfo.getDpId(), flowEntity);
+    private void setupEtreeTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId,
+            WriteTransaction writeFlowGroupTx) {
+        EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+        if (etreeInstance != null) {
+            setupTerminateServiceTable(elanInfo, dpId, etreeInstance.getEtreeLeafTagVal().getValue(), writeFlowGroupTx);
+        }
+    }
 
-        // only if vni is present in elanInfo, perform the following
-        if (elanInfo.getVni() != null && elanInfo.getVni() != 0) {
-           Flow flowEntity2 = MDSALUtil.buildFlowNew(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag, /*SH flag*/true),
-                5, elanInfo.getElanInstanceName(), 0, 0, ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)), getMatchesForElanTag(elanTag, /*SH flag*/true),
+    public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
+            WriteTransaction writeFlowGroupTx) {
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
+                getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE, elanTag), 5,
+                String.format("%s:%d", "ITM Flow Entry ", elanTag), 0, 0,
+                ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(elanTag)),
+                ElanUtils.getTunnelMatchesForServiceId((int) elanTag),
                 getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
-           mdsalManager.installFlow(interfaceInfo.getDpId(), flowEntity2);
-        }
 
+        mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
     }
 
-
-    private void removeStaticELanFlows(final ElanInstance elanInfo, final InterfaceInfo interfaceInfo) {
-        BigInteger dpId = interfaceInfo.getDpId();
-        /*
-         * If there are not elan ports, remove the unknown smac and default dmac
-         * flows
-         */
-        DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpId);
-        if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null || dpnInterfaces.getInterfaces().isEmpty()) {
-            // No more Elan Interfaces in this DPN
-            logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
-            removeDefaultTermFlow(dpId, elanInfo.getElanTag());
-            removeDefaultTermFlow(dpId, interfaceInfo.getInterfaceTag());
-            removeUnknownDmacFlow(dpId, elanInfo);
-            removeElanBroadcastGroup(elanInfo, interfaceInfo);
-            removeLocalBroadcastGroup(elanInfo, interfaceInfo);
-            if ( elanInfo.getVni() != null && elanInfo.getVni().longValue() != 0 ) {
-                unsetExternalTunnelTable(dpId, elanInfo);
-            }
-            removeFilterEqualsTable(elanInfo, interfaceInfo);
-        } else {
-            setupElanBroadcastGroups(elanInfo, dpId);
-            setupLocalBroadcastGroups(elanInfo, interfaceInfo);
-            removeFilterEqualsTable(elanInfo, interfaceInfo);
+    public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
+        long elanTag = elanInfo.getElanTag();
+        installLocalUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
+        installRemoteUnknownFlow(elanInfo, dpId, elanTag, writeFlowGroupTx);
+        setupEtreeUnknownDMacTable(elanInfo, dpId, elanTag, writeFlowGroupTx);
+    }
+
+    private void setupEtreeUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, long elanTag,
+            WriteTransaction writeFlowGroupTx) {
+        EtreeLeafTagName etreeLeafTag = elanUtils.getEtreeLeafTagByElanTag(elanTag);
+        if (etreeLeafTag != null) {
+            long leafTag = etreeLeafTag.getEtreeLeafTag().getValue();
+            installRemoteUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
+            installLocalUnknownFlow(elanInfo, dpId, leafTag, writeFlowGroupTx);
         }
     }
 
-    private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo) {
-//        Flow flow = getUnknownDmacFlowEntity(dpId, elanInfo);
-//        mdsalManager.removeFlow(dpId, flow);
-        Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE,
-                                                                             elanInfo.getElanTag(), /*SH flag*/ false)))
-                                     .setTableId(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE)
-                                     .build();
-        mdsalManager.removeFlow(dpId, flow);
+    private void installLocalUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
+            WriteTransaction writeFlowGroupTx) {
+        Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
+                getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,
+                        /* SH flag */false),
+                5, elanInfo.getElanInstanceName(), 0, 0,
+                ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
+                getMatchesForElanTag(elanTag, /* SH flag */false),
+                getInstructionsForOutGroup(ElanUtils.getElanRemoteBCGID(elanTag)));
 
-        if ( elanInfo.getVni() != null && elanInfo.getVni() > 0 ) {
-           Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE,
-                                                                                elanInfo.getElanTag(), /*SH flag*/ true)))
-                                        .setTableId(ElanConstants.ELAN_UNKNOWN_DMAC_TABLE)
-                                        .build();
-           mdsalManager.removeFlow(dpId, flow2);
+        mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
+    }
+
+    private void installRemoteUnknownFlow(ElanInstance elanInfo, BigInteger dpId, long elanTag,
+            WriteTransaction writeFlowGroupTx) {
+        // only if ELAN can connect to external network, perform the following
+        if (ElanUtils.isVxlan(elanInfo) || ElanUtils.isVlan(elanInfo) || ElanUtils.isFlat(elanInfo)) {
+            Flow flowEntity2 = MDSALUtil.buildFlowNew(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
+                    getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE, elanTag,
+                            /* SH flag */true),
+                    5, elanInfo.getElanInstanceName(), 0, 0,
+                    ElanConstants.COOKIE_ELAN_UNKNOWN_DMAC.add(BigInteger.valueOf(elanTag)),
+                    getMatchesForElanTag(elanTag, /* SH flag */true),
+                    getInstructionsForOutGroup(ElanUtils.getElanLocalBCGID(elanTag)));
+            mdsalManager.addFlowToTx(dpId, flowEntity2, writeFlowGroupTx);
         }
+    }
+
 
+    private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
+            long elanTag) {
+        Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
+                elanTag, /* SH flag */ false))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE).build();
+        mdsalManager.removeFlowToTx(dpId, flow, deleteFlowGroupTx);
 
+        if (ElanUtils.isVxlan(elanInfo)) {
+            Flow flow2 = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
+                    elanTag, /* SH flag */ true))).setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
+                    .build();
+            mdsalManager.removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
+        }
     }
 
     private void removeDefaultTermFlow(BigInteger dpId, long elanTag) {
-        ElanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
+        elanUtils.removeTerminatingServiceAction(dpId, (int) elanTag);
     }
 
-    private void bindService(ElanInstance elanInfo, String interfaceName) {
-       // interfaceManager.bindService(interfaceName, ElanUtils.getServiceInfo(elanInfo.getElanInstanceName(), elanInfo.getElanTag(), interfaceName));
+    private void bindService(ElanInstance elanInfo, ElanInterface elanInterface, WriteTransaction tx) {
+        if (isStandardElanService(elanInterface)) {
+            bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(), tx);
+        } else { // Etree service
+            bindEtreeService(elanInfo, elanInterface, tx);
+        }
+    }
 
+    private void bindElanService(long elanTag, String elanInstanceName, String interfaceName, WriteTransaction tx) {
         int priority = ElanConstants.ELAN_SERVICE_PRIORITY;
         int instructionKey = 0;
-        List<Instruction> instructions = new ArrayList<>();
-        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanInfo.getElanTag()), MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
-        instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(ElanConstants.ELAN_SMAC_TABLE, ++instructionKey));
-        BoundServices
-                serviceInfo =
-                ElanUtils.getBoundServices(String.format("%s.%s.%s", "vpn",elanInfo.getElanInstanceName(), interfaceName),
-                        ElanConstants.ELAN_SERVICE_INDEX, priority,
-                        ElanConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
-        ElanUtils.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                ElanUtils.buildServiceId(interfaceName, ElanConstants.ELAN_SERVICE_INDEX), serviceInfo);
+        List<Instruction> instructions = new ArrayList<Instruction>();
+        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag),
+                MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
+        instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey));
+        short elan_service_index = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
+        BoundServices serviceInfo = ElanUtils.getBoundServices(
+                String.format("%s.%s.%s", "vpn", elanInstanceName, interfaceName), elan_service_index,
+                priority, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
+        tx.put(LogicalDatastoreType.CONFIGURATION,
+                ElanUtils.buildServiceId(interfaceName, elan_service_index), serviceInfo, true);
+    }
+
+    private void bindEtreeService(ElanInstance elanInfo, ElanInterface elanInterface, WriteTransaction tx) {
+        if (elanInterface.getAugmentation(EtreeInterface.class).getEtreeInterfaceType() == EtreeInterfaceType.Root) {
+            bindElanService(elanInfo.getElanTag(), elanInfo.getElanInstanceName(), elanInterface.getName(), tx);
+        } else {
+            EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+            if (etreeInstance == null) {
+                logger.error("EtreeInterface " + elanInterface.getName() + " is associated with a non EtreeInstance: "
+                        + elanInfo.getElanInstanceName());
+            } else {
+                bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
+                        elanInterface.getName(), tx);
+            }
+        }
     }
 
-    private void unbindService(ElanInstance elanInfo, String interfaceName) {
-        ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
-                ElanUtils.buildServiceId(interfaceName,ElanConstants.ELAN_SERVICE_INDEX),
-                ElanUtils.DEFAULT_CALLBACK);
+    private boolean isStandardElanService(ElanInterface elanInterface) {
+        return elanInterface.getAugmentation(EtreeInterface.class) == null;
     }
 
-    private void unbindService(ElanInstance elanInfo, String interfaceName, int vlanId) {
-        ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
-                ElanUtils.buildServiceId(interfaceName,ElanConstants.ELAN_SERVICE_INDEX),
-                ElanUtils.DEFAULT_CALLBACK);
+    private boolean isStandardElanService(ElanInstance elanInstance) {
+        return elanInstance.getAugmentation(EtreeInstance.class) == null;
+    }
+
+    private void unbindService(ElanInstance elanInfo, String interfaceName, WriteTransaction tx) {
+        tx.delete(LogicalDatastoreType.CONFIGURATION,
+                ElanUtils.buildServiceId(interfaceName, ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX)));
     }
 
     private String getFlowRef(long tableId, long elanTag) {
@@ -1052,20 +1354,23 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
     }
 
     private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
-        List<Action> listAction = new ArrayList<>();
+        List<Action> listAction = new ArrayList<Action>();
         int actionKey = 0;
-        listAction.add((new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {BigInteger.valueOf(interfaceInfo.getInterfaceTag())}, actionKey)).buildAction());
+        listAction.add((new ActionInfo(ActionType.set_field_tunnel_id,
+                new BigInteger[] { BigInteger.valueOf(interfaceInfo.getInterfaceTag()) }, actionKey)).buildAction());
         actionKey++;
         listAction.add((new ActionInfo(ActionType.nx_resubmit,
-                new String[] {String.valueOf(ElanConstants.ELAN_FILTER_EQUALS_TABLE)}, actionKey)).buildAction());
+                new String[] { String.valueOf(NwConstants.ELAN_FILTER_EQUALS_TABLE) }, actionKey)).buildAction());
         return listAction;
     }
 
-    private void updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId, List<String> interfaceNames) {
-        DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
-                .setInterfaces(interfaceNames).setKey(new DpnInterfacesKey(dpId)).build();
-        MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId),
-                dpnInterface);
+    private DpnInterfaces updateElanDpnInterfacesList(String elanInstanceName, BigInteger dpId,
+            List<String> interfaceNames, WriteTransaction tx) {
+        DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
+                .setKey(new DpnInterfacesKey(dpId)).build();
+        tx.put(LogicalDatastoreType.OPERATIONAL,
+                ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface, true);
+        return dpnInterface;
     }
 
     /**
@@ -1076,44 +1381,54 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
      * @param dpId
      *            the dp id
      */
-    private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId) {
-        MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,
+    private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
+        tx.delete(LogicalDatastoreType.OPERATIONAL,
                 ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId));
     }
 
-    private List<String> createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId) {
-        List<String> interfaceNames = new ArrayList<>();
+    private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
+            WriteTransaction tx) {
+        List<String> interfaceNames = new ArrayList<String>();
         interfaceNames.add(interfaceName);
-        DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
-                .setInterfaces(interfaceNames).setKey(new DpnInterfacesKey(dpId)).build();
-        MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId),
-                dpnInterface);
-        return interfaceNames;
-    }
-
-    private void createElanInterfaceTablesList(String interfaceName) {
-        InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
-        Optional<ElanInterfaceMac> interfaceMacTables = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
-        // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
-        if(!interfaceMacTables.isPresent()) {
-            ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName).setKey(new ElanInterfaceMacKey(interfaceName)).build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName),
-                    elanInterfaceMacTable);
+        DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId).setInterfaces(interfaceNames)
+                .setKey(new DpnInterfacesKey(dpId)).build();
+        tx.put(LogicalDatastoreType.OPERATIONAL,
+                ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId), dpnInterface, true);
+        return dpnInterface;
+    }
+
+    private void createElanInterfaceTablesList(String interfaceName, WriteTransaction tx) {
+        InstanceIdentifier<ElanInterfaceMac> elanInterfaceMacTables = ElanUtils
+                .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
+        Optional<ElanInterfaceMac> interfaceMacTables = elanUtils.read(broker,
+                LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
+        // Adding new Elan Interface Port to the operational DataStore without
+        // Static-Mac Entries..
+        if (!interfaceMacTables.isPresent()) {
+            ElanInterfaceMac elanInterfaceMacTable = new ElanInterfaceMacBuilder().setElanInterface(interfaceName)
+                    .setKey(new ElanInterfaceMacKey(interfaceName)).build();
+            tx.put(LogicalDatastoreType.OPERATIONAL,
+                    ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName), elanInterfaceMacTable,
+                    true);
         }
     }
 
-    private void createElanStateList(String elanInstanceName, String interfaceName) {
+    private void createElanStateList(String elanInstanceName, String interfaceName, WriteTransaction tx) {
         InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
-        Optional<Elan> elanInterfaceLists = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInstance);
-        // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
-        if(elanInterfaceLists.isPresent()) {
+        Optional<Elan> elanInterfaceLists = elanUtils.read(broker,
+                LogicalDatastoreType.OPERATIONAL, elanInstance);
+        // Adding new Elan Interface Port to the operational DataStore without
+        // Static-Mac Entries..
+        if (elanInterfaceLists.isPresent()) {
             List<String> interfaceLists = elanInterfaceLists.get().getElanInterfaces();
-            if(interfaceLists == null) {
+            if (interfaceLists == null) {
                 interfaceLists = new ArrayList<>();
             }
             interfaceLists.add(interfaceName);
-            Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists).setKey(new ElanKey(elanInstanceName)).build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState);
+            Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
+                    .setKey(new ElanKey(elanInstanceName)).build();
+            tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
+                    elanState, true);
         }
     }
 
@@ -1124,81 +1439,37 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
     }
 
-    protected void updatedIfPrimaryAttributeChanged(ElanInterface elanInterface, boolean isUpdated) {
-        String interfaceName = elanInterface.getName();
-        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
-        BigInteger dpId = interfaceInfo.getDpId();
-        InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
-        Optional<ElanInterfaceMac> existingElanInterface = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
-        ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanInterface.getElanInstanceName());
-
-        if(!existingElanInterface.isPresent()) {
-            return;
-        }
-
-        List<MacEntry> macEntries = existingElanInterface.get().getMacEntry();
-        if(macEntries != null && !macEntries.isEmpty()) {
-            for (MacEntry macEntry : macEntries) {
-                if(isUpdated) {
-                    ElanUtils.setupMacFlows(elanInfo, interfaceInfo, ElanConstants.STATIC_MAC_TIMEOUT, macEntry.getMacAddress().getValue());
-                } else {
-                    ElanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry);
-                }
-            }
-        }
-
-        InstanceIdentifier<DpnInterfaces> dpnInterfaceId = ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInterface.getElanInstanceName(), interfaceInfo.getDpId());
-        Optional<DpnInterfaces> dpnInterfaces =  ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, dpnInterfaceId);
-        List<String> interfaceLists = dpnInterfaces.get().getInterfaces();
-
-        if(isUpdated) {
-            interfaceLists.add(elanInterface.getName());
-        } else {
-            interfaceLists.remove(elanInterface.getName());
-        }
-
-        DpnInterfaces  updateDpnInterfaces = new DpnInterfacesBuilder().setInterfaces(interfaceLists).setDpId(dpId).setKey(new DpnInterfacesKey(dpId)).build();
-        MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, dpnInterfaceId, updateDpnInterfaces);
-
-        if(isUpdated) {
-            installFlowsAndGroups(elanInfo, interfaceInfo);
-        } else {
-            removeStaticELanFlows(elanInfo, interfaceInfo);
-            unbindService(elanInfo, interfaceName);
-        }
-    }
-
     public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
-        ElanDpnInterfaces dpnInterfaceLists =  ElanUtils.getElanDpnInterfacesList();
-        if(dpnInterfaceLists == null) {
+        ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
+        if (dpnInterfaceLists == null) {
             return;
         }
         List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
-        for(ElanDpnInterfacesList elanDpns: elanDpnIf) {
+        for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
             int cnt = 0;
             String elanName = elanDpns.getElanInstanceName();
             List<DpnInterfaces> dpnInterfaces = elanDpns.getDpnInterfaces();
-            if(dpnInterfaces == null) {
-               continue;
+            if (dpnInterfaces == null) {
+                continue;
             }
             for (DpnInterfaces dpnIf : dpnInterfaces) {
-               if(dpnIf.getDpId().equals(srcDpId) || dpnIf.getDpId().equals(dstDpId)) {
-                   cnt++;
+                if (dpnIf.getDpId().equals(srcDpId) || dpnIf.getDpId().equals(dstDpId)) {
+                    cnt++;
                 }
             }
-            if(cnt == 2) {
+            if (cnt == 2) {
                 logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
-                ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+                ElanInstance elanInfo = elanUtils.getElanInstanceByName(elanName);
                 // update Remote BC Group
                 setupElanBroadcastGroups(elanInfo, srcDpId);
 
-                DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, srcDpId);
+                DpnInterfaces dpnInterface = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dstDpId);
                 Set<String> interfaceLists = new HashSet<>();
                 interfaceLists.addAll(dpnInterface.getInterfaces());
-                for(String ifName : interfaceLists) {
+                for (String ifName : interfaceLists) {
                     InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
                     if (isOperational(interfaceInfo)) {
-                        elanInterfaceManager.installDMacAddressTables(elanInfo, interfaceInfo, dstDpId);
+                        installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
                     }
                 }
             }
@@ -1234,16 +1505,16 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
             return;
         }
 
-        ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
+        ElanDpnInterfaces dpnInterfaceLists = elanUtils.getElanDpnInterfacesList();
         if (dpnInterfaceLists == null) {
             return;
         }
         List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
         for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
             String elanName = elanDpns.getElanInstanceName();
-            ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+            ElanInstance elanInfo = elanUtils.getElanInstanceByName(elanName);
 
-            DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+            DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
             if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
                     || dpnInterfaces.getInterfaces().isEmpty()) {
                 continue;
@@ -1252,9 +1523,9 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
 
             setupElanBroadcastGroups(elanInfo, dpId);
             // install L2gwDevices local macs in dpn.
-            ElanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo);
+            elanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo, intrf.getName());
             // Install dpn macs on external device
-            ElanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
+            elanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
                     externalNodeId);
         }
         logger.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
@@ -1273,15 +1544,15 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         if (intrf.getOperStatus() == Interface.OperStatus.Up) {
             String srcDevice = externalTunnel.getDestinationDevice();
             String destDevice = externalTunnel.getSourceDevice();
-            ExternalTunnel otherEndPointExtTunnel = ElanUtils.getExternalTunnel(srcDevice, destDevice,
+            ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
                     LogicalDatastoreType.CONFIGURATION);
             if (logger.isTraceEnabled()) {
                 logger.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
                         otherEndPointExtTunnel);
             }
             if (otherEndPointExtTunnel != null) {
-                boolean otherEndPointInterfaceOperational = ElanUtils
-                        .isInterfaceOperational(otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
+                boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
+                        otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
                 if (otherEndPointInterfaceOperational) {
                     return true;
                 } else {
@@ -1293,82 +1564,24 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         return false;
     }
 
-    public void handleInterfaceUpdated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
-        BigInteger dpId = interfaceInfo.getDpId();
-        String elanName = elanInstance.getElanInstanceName();
-        String ifName = interfaceInfo.getInterfaceName();
-        logger.trace("Handling interface update event for interface with info {} , state {}", interfaceInfo, isStateUp);
-        if(isStateUp) {
-
-            DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
-            if(dpnInterfaces == null) {
-                createElanInterfacesList(elanName, interfaceInfo.getInterfaceName(), dpId);
-            } else {
-              List<String> dpnElanInterfaces = dpnInterfaces.getInterfaces();
-                dpnElanInterfaces.add(interfaceInfo.getInterfaceName());
-                DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
-                        .setInterfaces(dpnElanInterfaces).setKey(new DpnInterfacesKey(dpId)).build();
-                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanName, interfaceInfo.getDpId()), dpnInterface);
-            }
-
-            logger.trace("ElanInterface Service is installed for interface:{}", ifName);
-            elanInterfaceManager.installFlowsAndGroups(elanInstance, interfaceInfo);
-            elanInterfaceManager.installMacAddressTables(elanInstance, interfaceInfo);
-
-            if (elanInstance.getVni() != null && elanInstance.getVni() != 0) {
-                List<PhysAddress> macAddresses = ElanUtils
-                        .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName());
-                if (macAddresses != null && !macAddresses.isEmpty()) {
-                    ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(),
-                            dpId, macAddresses);
-                }
-            }
-        } else {
-
-            DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
-            if(dpnInterfaces != null) {
-                List<String> dpnElanInterfaces = dpnInterfaces.getInterfaces();
-                dpnElanInterfaces.remove(interfaceInfo.getInterfaceName());
-                DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
-                        .setInterfaces(dpnElanInterfaces).setKey(new DpnInterfacesKey(dpId)).build();
-                MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanName, interfaceInfo.getDpId()), dpnInterface);
-            }
-            logger.trace("ElanInterface Service is removed for the interface:{}", ifName);
-            elanInterfaceManager.removeMacAddressTables(elanInstance, interfaceInfo);
-            elanInterfaceManager.removeFlowsAndGroups(elanInstance, interfaceInfo);
-
-            // Removing MACs from External Devices belonging to this ELAN
-            if (elanInstance.getVni() != null && elanInstance.getVni() != 0) {
-                List<PhysAddress> macAddresses = ElanUtils
-                        .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName());
-                if (macAddresses != null && !macAddresses.isEmpty()) {
-                    ElanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInstance, macAddresses);
-                }
-            }
-        }
-    }
-
     private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int LportTag) {
-        List<MatchInfo> mkMatches = new ArrayList<>();
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
         // Matching metadata
-        mkMatches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
-                MetaDataUtil.getLportTagMetaData(LportTag),
-                MetaDataUtil.METADATA_MASK_LPORT_TAG }));
-        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(LportTag)}));
+        mkMatches.add(new MatchInfo(MatchFieldType.metadata,
+                new BigInteger[] { MetaDataUtil.getLportTagMetaData(LportTag), MetaDataUtil.METADATA_MASK_LPORT_TAG }));
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(LportTag) }));
         return mkMatches;
     }
 
-
     private List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int LportTag) {
-        List<MatchInfo> mkMatches = new ArrayList<>();
+        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
         // Matching metadata
-        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
-                BigInteger.valueOf(LportTag)}));
+        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(LportTag) }));
         return mkMatches;
     }
 
     public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
-        List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
+        List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
         if (dpns == null) {
             return;
         }
@@ -1377,18 +1590,19 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         }
     }
 
-    public static List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
+    public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
             int bucketId) {
-        List<Bucket> listBucketInfo = new ArrayList<>();
+        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
         ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
                 .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
         for (L2GatewayDevice device : map.values()) {
-            String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
+            String interfaceName = elanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
                     device.getHwvtepNodeId());
             if (interfaceName == null) {
                 continue;
             }
-            List<Action> listActionInfo = ElanUtils.buildItmEgressActions(interfaceName, elanInfo.getVni());
+            List<Action> listActionInfo = elanUtils.buildTunnelItmEgressActions(interfaceName,
+                    elanInfo.getSegmentationId());
             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
                     MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
             bucketId++;
@@ -1396,6 +1610,8 @@ public class ElanInterfaceManager extends AbstractDataChangeListener<ElanInterfa
         return listBucketInfo;
     }
 
+    @Override
+    protected ElanInterfaceManager getDataTreeChangeListener() {
+        return this;
+    }
 }
-
-