Fix DMAC flows for Vlan E/W provider
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanInterfaceManager.java
index b713f0ba14c84c211ee7ccb50fcb996e76424e79..d445694c9963533dd5d0763f69e8a63563c6590e 100644 (file)
@@ -7,6 +7,9 @@
  */
 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;
@@ -18,17 +21,14 @@ 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.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
-import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
-import org.opendaylight.netvirt.elan.utils.ElanConstants;
-import org.opendaylight.netvirt.elan.utils.ElanUtils;
 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.itm.globals.ITMConstants;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.ActionType;
@@ -40,7 +40,14 @@ import org.opendaylight.genius.mdsalutil.MatchFieldType;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
-//import org.opendaylight.genius.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.utils.ServiceIndex;
+import org.opendaylight.netvirt.elan.ElanException;
+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;
@@ -49,11 +56,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.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.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;
@@ -75,52 +87,56 @@ 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.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.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
- *
  */
-@SuppressWarnings( "deprecation" )
-public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface,ElanInterfaceManager> implements AutoCloseable {
+@SuppressWarnings("deprecation")
+public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanInterface, ElanInterfaceManager>
+        implements AutoCloseable {
 
-    private ElanServiceProvider elanServiceProvider = null;
-    private static volatile ElanInterfaceManager elanInterfaceManager = null;
-    private static long waitTimeForSyncInstall;
+    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;
 
-    private Map<String, ConcurrentLinkedQueue<ElanInterface>> unProcessedElanInterfaces =
-        new ConcurrentHashMap<String, ConcurrentLinkedQueue<ElanInterface>> ();
+    private static final long WAIT_TIME_FOR_SYNC_INSTALL = Long.getLong("wait.time.sync.install", 300L);
 
-    private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceManager.class);
+    private Map<String, ConcurrentLinkedQueue<ElanInterface>> unProcessedElanInterfaces = new ConcurrentHashMap<>();
 
-    public ElanInterfaceManager(ElanServiceProvider elanServiceProvider) {
-        super(ElanInterface.class,ElanInterfaceManager.class);
-        this.elanServiceProvider = elanServiceProvider;
+    private static final Logger LOG = LoggerFactory.getLogger(ElanInterfaceManager.class);
+
+    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 static ElanInterfaceManager getElanInterfaceManager(ElanServiceProvider elanServiceProvider) {
-        if (elanInterfaceManager == null) {
-            synchronized (ElanInterfaceManager.class) {
-                if (elanInterfaceManager == null) {
-                    elanInterfaceManager = new ElanInterfaceManager(elanServiceProvider);
-                    Long waitTime = Long.getLong("wait.time.sync.install");
-                    if (waitTime == null) {
-                        waitTime = 300L;
-                    }
-                    waitTimeForSyncInstall = waitTime;
-                }
-            }
-        }
-        return elanInterfaceManager;
+    public void setElanUtils(ElanUtils elanUtils) {
+        this.elanUtils = elanUtils;
+        this.elanL2GatewayUtils = elanUtils.getElanL2GatewayUtils();
+        this.elanForwardingEntriesHandler.setElanUtils(elanUtils);
+    }
+
+    public void init() {
+        registerListener(LogicalDatastoreType.CONFIGURATION, broker);
     }
 
     @Override
@@ -130,27 +146,30 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
 
     @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(broker, 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
+         * 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 = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
+        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
         String elanInstanceName = elanInfo.getElanInstanceName();
         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
-        InterfaceRemoveWorkerOnElan configWorker = new InterfaceRemoveWorkerOnElan(elanInstanceName, elanInfo, interfaceName, interfaceInfo, false, 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, boolean isInterfaceStateRemoved) {
+    public void removeElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo, String interfaceName,
+            InterfaceInfo interfaceInfo, boolean isInterfaceStateRemoved) {
         String elanName = elanInfo.getElanInstanceName();
         boolean isLastElanInterface = false;
         long elanTag = elanInfo.getElanTag();
-        WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
-        WriteTransaction deleteFlowGroupTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
         Elan elanState = removeElanStateForInterface(elanInfo, interfaceName, tx);
         if (elanState == null) {
             return;
@@ -161,18 +180,22 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
         if (interfaceInfo != null) {
             BigInteger dpId = interfaceInfo.getDpId();
-            DpnInterfaces dpnInterfaces = removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag, tx);
+            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 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()) {
+            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);
+                LOG.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
                 removeDefaultTermFlow(dpId, elanInfo.getElanTag());
-                removeUnknownDmacFlow(dpId, elanInfo, deleteFlowGroupTx);
+                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);
                 }
@@ -180,96 +203,166 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 setupLocalBroadcastGroups(elanInfo, dpnInterfaces, interfaceInfo);
             }
         }
-        ElanUtils.waitForTransactionToComplete(tx);
-        ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx);
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
+        futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
-        InterfaceRemoveWorkerOnElanInterface removeInterfaceWorker = new InterfaceRemoveWorkerOnElanInterface(interfaceName, elanInfo,
-            interfaceInfo, isInterfaceStateRemoved, this, isLastElanInterface);
+        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));
+            LOG.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<>();
+            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));
+            LOG.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) {
+        Elan elanState = ElanUtils.getElanByName(broker, elanName);
+        if (elanState == null) {
             return elanState;
         }
         List<String> elanInterfaces = elanState.getElanInterfaces();
         elanInterfaces.remove(interfaceName);
-        if(elanInterfaces.isEmpty()) {
+        if (elanInterfaces.isEmpty()) {
             tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName));
             tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanMacTableOperationalDataPath(elanName));
-            tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
+            tx.delete(LogicalDatastoreType.OPERATIONAL,
+                    ElanUtils.getElanInfoEntriesOperationalDataPath(elanInfo.getElanTag()));
         } else {
-            Elan updateElanState = new ElanBuilder().setElanInterfaces(elanInterfaces).setName(elanName).setKey(new ElanKey(elanName)).build();
-            tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanName), updateElanState);
+            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 deleteElanInterfaceFromConfigDS(String interfaceName, WriteTransaction tx) {
-        //removing the ElanInterface from the config data_store if interface is not present in Interface config DS
-        if (elanServiceProvider.getInterfaceManager().getInterfaceInfoFromConfigDataStore(interfaceName) == null) {
-            tx.delete(LogicalDatastoreType.CONFIGURATION, ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
+        // 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));
         }
     }
 
-    void removeEntriesForElanInterface(ElanInstance elanInfo, InterfaceInfo interfaceInfo, String interfaceName, boolean isInterfaceStateRemoved, boolean isLastElanInterface) {
+    void removeEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInfo,
+            InterfaceInfo interfaceInfo, String interfaceName, boolean isInterfaceStateRemoved,
+            boolean isLastElanInterface) {
         String elanName = elanInfo.getElanInstanceName();
-        WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
-        WriteTransaction deleteFlowGroupTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
-        InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils.getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
-        logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        WriteTransaction deleteFlowGroupTx = broker.newWriteOnlyTransaction();
+        InstanceIdentifier<ElanInterfaceMac> elanInterfaceId = ElanUtils
+                .getElanInterfaceMacEntriesOperationalDataPath(interfaceName);
+        LOG.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
         if (interfaceInfo != null) {
-            Optional<ElanInterfaceMac> existingElanInterfaceMac = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
-            if(existingElanInterfaceMac.isPresent()) {
-                List<PhysAddress> macAddresses = new ArrayList<PhysAddress>();
+            Optional<ElanInterfaceMac> existingElanInterfaceMac = elanUtils.read(broker,
+                    LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
+            if (existingElanInterfaceMac.isPresent()) {
+                List<PhysAddress> macAddresses = new ArrayList<>();
                 List<MacEntry> existingMacEntries = existingElanInterfaceMac.get().getMacEntry();
                 List<MacEntry> macEntries = new ArrayList<>();
                 if (existingMacEntries != null && !existingMacEntries.isEmpty()) {
                     macEntries.addAll(existingMacEntries);
                 }
-                if(!macEntries.isEmpty()) {
+                if (!macEntries.isEmpty()) {
                     for (MacEntry macEntry : macEntries) {
-                        logger.debug("removing the  mac-entry:{} present on elanInterface:{}", macEntry.getMacAddress().getValue(), interfaceName);
+                        LOG.debug("removing the  mac-entry:{} present on elanInterface:{}",
+                                macEntry.getMacAddress().getValue(), interfaceName);
                         if (!isLastElanInterface) {
-                            tx.delete(LogicalDatastoreType.OPERATIONAL, ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
+                            tx.delete(LogicalDatastoreType.OPERATIONAL,
+                                    ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
                         }
-                        ElanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, deleteFlowGroupTx);
+                        elanUtils.deleteMacFlows(elanInfo, interfaceInfo, macEntry, deleteFlowGroupTx);
                         macAddresses.add(macEntry.getMacAddress());
                     }
 
-                    // Removing all those MACs from External Devices belonging to this ELAN
+                    // Removing all those MACs from External Devices belonging
+                    // to this ELAN
                     if (ElanUtils.isVxlan(elanInfo)) {
-                        ElanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
+                        elanL2GatewayUtils.removeMacsFromElanExternalDevices(elanInfo, macAddresses);
                     }
                 }
             }
             removeDefaultTermFlow(interfaceInfo.getDpId(), interfaceInfo.getInterfaceTag());
             removeFilterEqualsTable(elanInfo, interfaceInfo, deleteFlowGroupTx);
         } else {
-            // 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) {
+            // 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()));
+                for (MacEntry macEntry : macEntries) {
+                    tx.delete(LogicalDatastoreType.OPERATIONAL,
+                            ElanUtils.getMacEntryOperationalDataPath(elanName, macEntry.getMacAddress()));
                 }
             }
         }
         tx.delete(LogicalDatastoreType.OPERATIONAL, elanInterfaceId);
-        if(!isInterfaceStateRemoved) {
+        if (!isInterfaceStateRemoved) {
             unbindService(elanInfo, interfaceName, tx);
         }
         deleteElanInterfaceFromConfigDS(interfaceName, tx);
-        ElanUtils.waitForTransactionToComplete(tx);
-        ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx);
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
+        futures.add(ElanUtils.waitForTransactionToComplete(deleteFlowGroupTx));
     }
 
-    private DpnInterfaces removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName,
-                                                                         long elanTag, WriteTransaction tx) {
-        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);
 
@@ -284,58 +377,79 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     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())
-                        elanServiceProvider.getMdsalManager().removeFlow(dpId, MDSALUtil.buildFlow(NwConstants.ELAN_DMAC_TABLE,
-                            ElanUtils.getKnownDynamicmacFlowRef(NwConstants.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 = elanServiceProvider.getInterfaceManager().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(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, macId);
-                    WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
-                    if(existingMacEntry.isPresent()) {
-                        elanServiceProvider.getElanForwardingEntriesHandler().updateElanInterfaceForwardingTablesList(elanName, interfaceName, existingMacEntry.get().getInterface(), existingMacEntry.get(), tx);
+            // 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 {
-                        elanServiceProvider.getElanForwardingEntriesHandler().addElanInterfaceForwardingTableList(ElanUtils.getElanInstanceByName(elanName), interfaceName, physAddress, tx);
+                        elanForwardingEntriesHandler.addElanInterfaceForwardingTableList(
+                                ElanUtils.getElanInstanceByName(broker, 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);
             }
         }
@@ -345,32 +459,34 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     protected void add(InstanceIdentifier<ElanInterface> identifier, ElanInterface elanInterfaceAdded) {
         String elanInstanceName = elanInterfaceAdded.getElanInstanceName();
         String interfaceName = elanInterfaceAdded.getName();
-        InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
+        InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
         if (interfaceInfo == null) {
-            logger.warn("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
+            LOG.warn("Interface {} is removed from Interface Oper DS due to port down ", interfaceName);
             return;
         }
-        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
 
         if (elanInstance == null) {
-            elanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName).setDescription(elanInterfaceAdded.getDescription()).build();
-            //Add the ElanInstance in the Configuration data-store
-            WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
-            List<String> elanInterfaces = new ArrayList<String>();
+            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<>();
             elanInterfaces.add(interfaceName);
-            ElanUtils.updateOperationalDataStore(elanServiceProvider.getBroker(), elanServiceProvider.getIdManager(), elanInstance, elanInterfaces, tx);
+            ElanUtils.updateOperationalDataStore(broker, idManager,
+                    elanInstance, elanInterfaces, tx);
             ElanUtils.waitForTransactionToComplete(tx);
-            elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+            elanInstance = ElanUtils.getElanInstanceByName(broker, 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<ElanInterface>();
+                elanInterfaces = new ConcurrentLinkedQueue<>();
             }
             elanInterfaces.add(elanInterfaceAdded);
             unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
@@ -378,58 +494,60 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
         InterfaceAddWorkerOnElan addWorker = new InterfaceAddWorkerOnElan(elanInstanceName, elanInterfaceAdded,
-            interfaceInfo, elanInstance, this);
+                interfaceInfo, elanInstance, this);
         coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
-    void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
+    void handleunprocessedElanInterfaces(ElanInstance elanInstance) throws ElanException {
+        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 = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
-            addElanInterface(elanInterface, interfaceInfo, elanInstance);
+            InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+            addElanInterface(futures, elanInterface, interfaceInfo, elanInstance);
         }
     }
 
-    void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo, WriteTransaction writeFlowGroupTx){
-        ElanDpnInterfacesList elanDpnInterfacesList =  ElanUtils.getElanDpnInterfacesList(elanInstance.getElanInstanceName());
-        List<DpnInterfaces> dpnInterfaceLists =  null;
+    void programRemoteDmacFlow(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
+            WriteTransaction writeFlowGroupTx) throws ElanException {
+        ElanDpnInterfacesList elanDpnInterfacesList = elanUtils
+                .getElanDpnInterfacesList(elanInstance.getElanInstanceName());
+        List<DpnInterfaces> dpnInterfaceLists = null;
         if (elanDpnInterfacesList != null) {
             dpnInterfaceLists = elanDpnInterfacesList.getDpnInterfaces();
         }
         if (dpnInterfaceLists == null) {
-            dpnInterfaceLists = new ArrayList<DpnInterfaces>();
+            dpnInterfaceLists = new ArrayList<>();
         }
-        for(DpnInterfaces dpnInterfaces : dpnInterfaceLists){
-            if(dpnInterfaces.getDpId().equals(interfaceInfo.getDpId())) {
+        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 = elanServiceProvider.getInterfaceManager().getInterfaceInfo(remoteIf);
-                if(elanIfMac == null) {
+            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) {
+                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(), writeFlowGroupTx);
+                        elanUtils.setupRemoteDmacFlow(interfaceInfo.getDpId(), remoteInterface.getDpId(),
+                                remoteInterface.getInterfaceTag(), elanInstance.getElanTag(), physAddress.getValue(),
+                                elanInstance.getElanInstanceName(), writeFlowGroupTx, remoteIf, elanInstance);
                     }
                 }
             }
         }
     }
 
-    void addElanInterface(ElanInterface elanInterface, InterfaceInfo interfaceInfo, ElanInstance elanInstance) {
+    void addElanInterface(List<ListenableFuture<Void>> futures, ElanInterface elanInterface,
+            InterfaceInfo interfaceInfo, ElanInstance elanInstance) throws ElanException {
         Preconditions.checkNotNull(elanInstance, "elanInstance cannot be null");
         Preconditions.checkNotNull(interfaceInfo, "interfaceInfo cannot be null");
         Preconditions.checkNotNull(elanInterface, "elanInterface cannot be null");
@@ -437,217 +555,253 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         String interfaceName = elanInterface.getName();
         String elanInstanceName = elanInterface.getElanInstanceName();
 
-        Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
-        WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
+        Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
         if (elanInfo == null) {
-            List<String> elanInterfaces = new ArrayList<String>();
+            List<String> elanInterfaces = new ArrayList<>();
             elanInterfaces.add(interfaceName);
-            ElanUtils.updateOperationalDataStore(elanServiceProvider.getBroker(), elanServiceProvider.getIdManager(), elanInstance, elanInterfaces, tx);
+            ElanUtils.updateOperationalDataStore(broker, idManager,
+                    elanInstance, elanInterfaces, tx);
         } else {
             createElanStateList(elanInstanceName, interfaceName, tx);
         }
         boolean isFirstInterfaceInDpn = false;
-        // Specific actions to the DPN where the ElanInterface has been added, for example, programming the
-        // External tunnel table if needed or adding the ElanInterface to the DpnInterfaces in the operational DS.
-        BigInteger dpId = ( interfaceInfo != null ) ? dpId = interfaceInfo.getDpId() : null;
+        // 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(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanDpnInterfaces);
+            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
                 dpnInterfaces = createElanInterfacesList(elanInstanceName, interfaceName, dpId, tx);
-                // The 1st ElanInterface in a DPN must program the Ext Tunnel table, but only if Elan has VNI
+                // 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);
                 }
                 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
+        // 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) {
             installEntriesForFirstInterfaceonDpn(elanInstance, interfaceInfo, dpnInterfaces, isFirstInterfaceInDpn, tx);
         }
-        ElanUtils.waitForTransactionToComplete(tx);
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
 
         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
-        InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(interfaceName, elanInterface,
-            interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
+        InterfaceAddWorkerOnElanInterface addWorker = new InterfaceAddWorkerOnElanInterface(interfaceName,
+                elanInterface, interfaceInfo, elanInstance, isFirstInterfaceInDpn, this);
         coordinator.enqueueJob(interfaceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
     }
 
-    void setupEntriesForElanInterface(ElanInstance elanInstance, ElanInterface elanInterface,
-                                      InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn) {
+    void setupEntriesForElanInterface(List<ListenableFuture<Void>> futures, ElanInstance elanInstance,
+            ElanInterface elanInterface, InterfaceInfo interfaceInfo, boolean isFirstInterfaceInDpn)
+            throws ElanException {
         String elanInstanceName = elanInstance.getElanInstanceName();
         String interfaceName = elanInterface.getName();
-        WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
         BigInteger dpId = interfaceInfo.getDpId();
-        WriteTransaction writeFlowGroupTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
+        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(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, macId);
+                Optional<MacEntry> existingMacEntry = elanUtils.read(broker,
+                        LogicalDatastoreType.OPERATIONAL, macId);
                 if (existingMacEntry.isPresent()) {
-                    elanServiceProvider.getElanForwardingEntriesHandler().updateElanInterfaceForwardingTablesList(elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
-                        existingMacEntry.get(), tx);
+                    elanForwardingEntriesHandler.updateElanInterfaceForwardingTablesList(
+                            elanInstanceName, interfaceName, existingMacEntry.get().getInterface(),
+                            existingMacEntry.get(), tx);
                 } else {
-                    elanServiceProvider.getElanForwardingEntriesHandler().addElanInterfaceForwardingTableList(elanInstance, interfaceName, physAddress, tx);
+                    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(), writeFlowGroupTx);
+                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);
             }
         }
-        ElanUtils.waitForTransactionToComplete(tx);
-        ElanUtils.waitForTransactionToComplete(writeFlowGroupTx);
+        futures.add(ElanUtils.waitForTransactionToComplete(tx));
+        futures.add(ElanUtils.waitForTransactionToComplete(writeFlowGroupTx));
     }
 
-    protected void removeInterfaceStaticMacEntires(String elanInstanceName, String interfaceName, PhysAddress physAddress) {
-        InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(interfaceName);
-        InstanceIdentifier<MacEntry> macId =  getMacEntryOperationalDataPath(elanInstanceName, physAddress);
-        Optional<MacEntry> existingMacEntry = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, macId);
+    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);
 
         if (!existingMacEntry.isPresent()) {
             return;
         }
 
-        MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName).setKey(new MacEntryKey(physAddress)).build();
-        WriteTransaction tx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
-        elanServiceProvider.getElanForwardingEntriesHandler().deleteElanInterfaceForwardingEntries(ElanUtils.getElanInstanceByName(elanInstanceName), interfaceInfo, macEntry, tx);
-        elanServiceProvider.getElanForwardingEntriesHandler().deleteElanInterfaceMacForwardingEntries(interfaceName, physAddress, tx);
+        MacEntry macEntry = new MacEntryBuilder().setMacAddress(physAddress).setInterface(interfaceName)
+                .setKey(new MacEntryKey(physAddress)).build();
+        WriteTransaction tx = broker.newWriteOnlyTransaction();
+        elanForwardingEntriesHandler.deleteElanInterfaceForwardingEntries(
+                ElanUtils.getElanInstanceByName(broker, 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();
     }
 
     private void installEntriesForElanInterface(ElanInstance elanInstance, InterfaceInfo interfaceInfo,
-                                                boolean isFirstInterfaceInDpn, WriteTransaction tx, WriteTransaction writeFlowGroupTx) {
+            boolean isFirstInterfaceInDpn, WriteTransaction tx, WriteTransaction writeFlowGroupTx)
+            throws ElanException {
         if (!isOperational(interfaceInfo)) {
             return;
         }
         BigInteger dpId = interfaceInfo.getDpId();
-        ElanUtils.setupTermDmacFlows(interfaceInfo, elanServiceProvider.getMdsalManager(), writeFlowGroupTx);
+        elanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager, writeFlowGroupTx);
         setupFilterEqualsTable(elanInstance, interfaceInfo, writeFlowGroupTx);
         if (isFirstInterfaceInDpn) {
-            //Terminating Service , UnknownDMAC Table.
+            // Terminating Service , UnknownDMAC Table.
             setupTerminateServiceTable(elanInstance, dpId, writeFlowGroupTx);
             setupUnknownDMacTable(elanInstance, dpId, writeFlowGroupTx);
-            //update the remote-DPNs remoteBC group entry with Tunnels
-            setElanBCGrouponOtherDpns(elanInstance, dpId, writeFlowGroupTx);
+            // update the remote-DPNs remoteBC group entry with Tunnels
+            if (ElanUtils.isVxlan(elanInstance)) {
+                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.
+             * 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, interfaceInfo.getInterfaceName(), tx);
+        bindService(elanInstance,
+                ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceInfo.getInterfaceName()), tx);
     }
 
-    public void installEntriesForFirstInterfaceonDpn(ElanInstance elanInfo, InterfaceInfo interfaceInfo, DpnInterfaces dpnInterfaces,
-                                                     boolean isFirstInterfaceInDpn, WriteTransaction tx) {
+    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);
+            LOG.trace("waitTimeForSyncInstall is {}", WAIT_TIME_FOR_SYNC_INSTALL);
             BigInteger dpId = interfaceInfo.getDpId();
             // RemoteBroadcast Group creation
             try {
-                Thread.sleep(waitTimeForSyncInstall);
+                Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
             } catch (InterruptedException e1) {
-                logger.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
+                LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
             }
             setupElanBroadcastGroups(elanInfo, dpnInterfaces, dpId);
             try {
-                Thread.sleep(waitTimeForSyncInstall);
+                Thread.sleep(WAIT_TIME_FOR_SYNC_INSTALL);
             } catch (InterruptedException e1) {
-                logger.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
+                LOG.warn("Error while waiting for local BC group for ELAN {} to install", elanInfo);
             }
         }
     }
 
-    public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo, WriteTransaction writeFlowGroupTx) {
+    public void setupFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction writeFlowGroupTx) {
         int ifTag = interfaceInfo.getInterfaceTag();
-        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()));
+        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()));
 
-        elanServiceProvider.getMdsalManager().addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
+        mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flow, writeFlowGroupTx);
 
-        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());
+        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());
 
-        elanServiceProvider.getMdsalManager().addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
+        mdsalManager.addFlowToTx(interfaceInfo.getDpId(), flowEntry, writeFlowGroupTx);
     }
 
-    public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo, WriteTransaction deleteFlowGroupTx) {
+    public void removeFilterEqualsTable(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
         int ifTag = interfaceInfo.getInterfaceTag();
-        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()));
+        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()));
 
-        elanServiceProvider.getMdsalManager().removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
+        mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flow, deleteFlowGroupTx);
 
-        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());
+        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());
 
-        elanServiceProvider.getMdsalManager().removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
+        mdsalManager.removeFlowToTx(interfaceInfo.getDpId(), flowEntity, deleteFlowGroupTx);
     }
 
-    private List<Bucket> getRemoteBCGroupBucketInfos(ElanInstance elanInfo,
-                                                     int bucketKeyStart, InterfaceInfo interfaceInfo) {
-        return getRemoteBCGroupBuckets(elanInfo, null, interfaceInfo.getDpId(), bucketKeyStart);
+    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, DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
-        int elanTag = elanInfo.getElanTag().intValue();
-        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
-        ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
+    private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
+            int bucketId, long elanTag) {
+        List<Bucket> listBucketInfo = new ArrayList<>();
+        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;
     }
 
+    @SuppressWarnings("checkstyle:IllegalCatch")
     private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
-            int elanTag) {
-        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+            long elanTag) {
+        List<Bucket> listBucketInfo = new ArrayList<>();
         if (elanDpns != null) {
             for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
-                if (ElanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId
+                if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && dpnInterface.getDpId() != dpnId
                         && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
                     try {
-                        List<Action> listActionInfo = ElanUtils.getInternalTunnelItmEgressAction(dpnId,
+                        List<Action> listActionInfo = elanUtils.getInternalTunnelItmEgressAction(dpnId,
                                 dpnInterface.getDpId(), elanTag);
                         if (listActionInfo.isEmpty()) {
                             continue;
@@ -656,8 +810,8 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                                 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());
+                        LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
+                                dpnId, dpnInterface.getDpId(), ex);
                     }
                 }
             }
@@ -665,18 +819,18 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         return listBucketInfo;
     }
 
-    private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns, DpnInterfaces dpnInterfaces, BigInteger dpnId,
-            int bucketId) {
+    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())
+        if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
                 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
             return Collections.emptyList();
         }
 
-        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+        List<Bucket> listBucketInfo = new ArrayList<>();
         for (String interfaceName : currDpnInterfaces.getInterfaces()) {
-            if (ElanUtils.isExternal(interfaceName)) {
-                List<Action> listActionInfo = ElanUtils.getExternalPortItmEgressAction(interfaceName);
+            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));
@@ -698,49 +852,58 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         return null;
     }
 
-    private void setElanBCGrouponOtherDpns(ElanInstance elanInfo,
-                                           BigInteger dpId, WriteTransaction tx) {
-        int elanTag = elanInfo.getElanTag().intValue();
-        long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
-        List<Bucket> listBucket = new ArrayList<Bucket>();
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    private void setElanBCGrouponOtherDpns(ElanInstance elanInfo, long elanTag, BigInteger dpId, WriteTransaction tx) {
+        long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
+        List<Bucket> listBucket = new ArrayList<>();
         int bucketId = 0;
-        ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
+        ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
         if (elanDpns != null) {
             List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
-            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>();
+            for (DpnInterfaces dpnInterface : dpnInterfaceses) {
+                List<Bucket> remoteListBucketInfo = new ArrayList<>();
+                if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !dpnInterface.getDpId().equals(dpId)
+                        && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
+                    List<Action> listAction = new ArrayList<>();
                     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));
+                    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.getInternalTunnelItmEgressAction(dpnInterface.getDpId(), otherFes.getDpId(), elanTag);
+                                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));
+                                    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() );
+                                LOG.error("setElanBCGrouponOtherDpns failed due to Exception caught; "
+                                        + "Logical Group Interface not found between source Dpn - {}, "
+                                        + "destination Dpn - {} ", dpnInterface.getDpId(), otherFes.getDpId(), ex);
                                 return;
                             }
                         }
                     }
                     List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpId,
-                        bucketId);
+                            bucketId);
                     remoteListBucketInfo.addAll(elanL2GwDevicesBuckets);
 
                     if (remoteListBucketInfo.size() == 0) {
-                        logger.debug( "No ITM is present on Dpn - {} " ,dpnInterface.getDpId());
+                        LOG.debug("No ITM is present on Dpn - {} ", dpnInterface.getDpId());
                         continue;
                     }
-                    Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(remoteListBucketInfo));
-                    elanServiceProvider.getMdsalManager().addGroupToTx(dpnInterface.getDpId(), group, tx);
+                    Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                            MDSALUtil.buildBucketLists(remoteListBucketInfo));
+                    mdsalManager.addGroupToTx(dpnInterface.getDpId(), group, tx);
                 }
             }
         }
@@ -750,77 +913,66 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      * Returns the bucket info with the given interface as the only bucket.
      */
     private Bucket getLocalBCGroupBucketInfo(InterfaceInfo interfaceInfo, int bucketIdStart) {
-        return MDSALUtil.buildBucket(getInterfacePortActions(interfaceInfo), MDSALUtil.GROUP_WEIGHT, bucketIdStart, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP);
-    }
-
-    private List<MatchInfo> getMatchesForElanTag(Long elanTag) {
-        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
-        // 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>();
-        MatchInfo match = new MatchInfo(MatchFieldType.tunnel_id,
-            new BigInteger[]{BigInteger.valueOf(vni)} );
+        List<MatchInfo> mkMatches = new ArrayList<>();
+        MatchInfo match = new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] { BigInteger.valueOf(vni) });
         mkMatches.add(match);
         return mkMatches;
     }
 
-    private List<Instruction> getInstructionsForOutGroup(
-        long groupId) {
-        List<Instruction> mkInstructions = new ArrayList<Instruction>();
-        List <Action> actions = new ArrayList <Action> ();
-        actions.add(new ActionInfo(ActionType.group, new String[]{Long.toString(groupId)}).buildAction());
+    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());
         mkInstructions.add(MDSALUtil.getWriteActionsInstruction(actions, 0));
         return mkInstructions;
     }
 
     private List<MatchInfo> getMatchesForElanTag(long elanTag, boolean isSHFlagSet) {
-        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+        List<MatchInfo> mkMatches = new ArrayList<>();
         // 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<InstructionInfo>();
+        List<InstructionInfo> mkInstructions = new ArrayList<>();
         mkInstructions.add(new InstructionInfo(InstructionType.write_metadata,
-            new BigInteger[] {
-                ElanUtils.getElanMetadataLabel(elanTag),
-                ElanUtils.getElanMetadataMask()
-            } ) );
-        // TODO: 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[] { NwConstants.ELAN_DMAC_TABLE }));
+        mkInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.ELAN_DMAC_TABLE }));
 
         return mkInstructions;
     }
 
     // Install DMAC entry on dst DPN
-    public void installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId) {
+    public void installDMacAddressTables(ElanInstance elanInfo, InterfaceInfo interfaceInfo, BigInteger dstDpId)
+            throws ElanException {
         String interfaceName = interfaceInfo.getInterfaceName();
-        ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
+        ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
         if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
-            WriteTransaction writeFlowTx = elanServiceProvider.getBroker().newWriteOnlyTransaction();
-            List<MacEntry> macEntries =  elanInterfaceMac.getMacEntry();
-            for(MacEntry macEntry : macEntries) {
+            WriteTransaction writeFlowTx = broker.newWriteOnlyTransaction();
+            List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
+            for (MacEntry macEntry : macEntries) {
                 PhysAddress physAddress = macEntry.getMacAddress();
-                ElanUtils.setupDMacFlowonRemoteDpn(elanInfo, interfaceInfo, dstDpId, physAddress.getValue(), writeFlowTx);
+                elanUtils.setupDMacFlowonRemoteDpn(elanInfo, interfaceInfo, dstDpId, physAddress.getValue(),
+                        writeFlowTx);
             }
             writeFlowTx.submit();
         }
@@ -831,79 +983,190 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
-        List<Bucket> listBucket = new ArrayList<Bucket>();
+        setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
+        setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
+    }
+
+    public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
+        List<Bucket> listBucket = new ArrayList<>();
         int bucketId = 0;
         int actionKey = 0;
         Long elanTag = elanInfo.getElanTag();
-        long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
-        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));
+        List<Action> listAction = new ArrayList<>();
+        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);
+        List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
+                elanInfo.getElanTag());
         listBucket.addAll(listBucketInfoRemote);
-        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
-        logger.trace("Installing the remote BroadCast Group:{}", group);
-        elanServiceProvider.getMdsalManager().syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
+        long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBucket));
+        LOG.trace("Installing the remote BroadCast Group:{}", group);
+        mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
+    }
+
+    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<>();
+            int bucketId = 0;
+            int actionKey = 0;
+            List<Action> listAction = new ArrayList<>();
+            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));
+            LOG.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<>();
+        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, DpnInterfaces newDpnInterface, InterfaceInfo interfaceInfo) {
-        List<Bucket> listBucket = new ArrayList<Bucket>();
+    public void setupStandardLocalBroadcastGroups(ElanInstance elanInfo, DpnInterfaces newDpnInterface,
+            InterfaceInfo interfaceInfo) {
+        List<Bucket> listBucket = new ArrayList<>();
         int bucketId = 0;
-        BigInteger dpnId = interfaceInfo.getDpId();
-        long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
+        long groupId = ElanUtils.getElanLocalBCGId(elanInfo.getElanTag());
 
-        List<String> interfaces = new ArrayList<String>();
+        List<String> interfaces = new ArrayList<>();
         if (newDpnInterface != null) {
             interfaces = newDpnInterface.getInterfaces();
         }
-        for(String ifName : interfaces) {
+        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 = elanServiceProvider.getInterfaceManager().getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
+            InterfaceInfo ifInfo = interfaceManager
+                    .getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
             if (!isOperational(ifInfo)) {
                 continue;
             }
 
-            if (!ElanUtils.isExternal(ifName)) {
+            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));
-        logger.trace("installing the localBroadCast Group:{}", group);
-        elanServiceProvider.getMdsalManager().syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBucket));
+        LOG.trace("installing the localBroadCast Group:{}", group);
+        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) {
+            List<Bucket> listBucket = new ArrayList<>();
+            int bucketId = 0;
+
+            List<String> interfaces = new ArrayList<>();
+            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);
+            }
+
+            long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
+            long groupId = ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag);
+            Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                    MDSALUtil.buildBucketLists(listBucket));
+            LOG.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(broker, 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, WriteTransaction deleteFlowGroupTx) {
+    public void removeLocalBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
         BigInteger dpnId = interfaceInfo.getDpId();
-        long groupId = ElanUtils.getElanLocalBCGID(elanInfo.getElanTag());
+        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));
-        logger.trace("deleted the localBroadCast Group:{}", group);
-        elanServiceProvider.getMdsalManager().removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+        // listBuckets.addAll(getRemoteBCGroupBucketInfos(elanInfo, 1,
+        // interfaceInfo));
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBuckets));
+        LOG.trace("deleted the localBroadCast Group:{}", group);
+        mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
     }
 
-    public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo, WriteTransaction deleteFlowGroupTx) {
+    public void removeElanBroadcastGroup(ElanInstance elanInfo, InterfaceInfo interfaceInfo,
+            WriteTransaction deleteFlowGroupTx) {
         int bucketId = 0;
         int actionKey = 0;
         Long elanTag = elanInfo.getElanTag();
         List<Bucket> listBuckets = new ArrayList<>();
-        List<Action> listAction = new ArrayList<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));
+        List<Action> listAction = new ArrayList<>();
+        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));
-        logger.trace("deleting the remoteBroadCast group:{}", group);
-        elanServiceProvider.getMdsalManager().removeGroupToTx(dpnId, group, deleteFlowGroupTx);
+        long groupId = ElanUtils.getElanRemoteBCGId(elanInfo.getElanTag());
+        Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
+                MDSALUtil.buildBucketLists(listBuckets));
+        LOG.trace("deleting the remoteBroadCast group:{}", group);
+        mdsalManager.removeGroupToTx(dpnId, group, deleteFlowGroupTx);
     }
 
     /**
@@ -918,108 +1181,178 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      */
     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.getSegmentationId()),
-            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));
 
-        elanServiceProvider.getMdsalManager().installFlow(flowEntity);
+        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: 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);
         flowEntity.setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE);
         flowEntity.setFlowId(flowId);
-        elanServiceProvider.getMdsalManager().removeFlow(flowEntity);
+        mdsalManager.removeFlow(flowEntity);
     }
 
     public void setupTerminateServiceTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
-        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)));
+        setupTerminateServiceTable(elanInfo, dpId, elanInfo.getElanTag(), writeFlowGroupTx);
+        setupEtreeTerminateServiceTable(elanInfo, dpId, writeFlowGroupTx);
+    }
+
+    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)));
 
-        elanServiceProvider.getMdsalManager().addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
+        mdsalManager.addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
+    }
+
+    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);
+        }
     }
 
     public void setupUnknownDMacTable(ElanInstance elanInfo, BigInteger dpId, WriteTransaction writeFlowGroupTx) {
         long elanTag = elanInfo.getElanTag();
-        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)));
+        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 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)));
 
-        elanServiceProvider.getMdsalManager().addFlowToTx(dpId, flowEntity, writeFlowGroupTx);
+        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)));
-            elanServiceProvider.getMdsalManager().addFlowToTx(dpId, flowEntity2, writeFlowGroupTx);
+            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) {
-        //        Flow flow = getUnknownDmacFlowEntity(dpId, elanInfo);
-        //        mdsalManager.removeFlow(dpId, flow);
+
+    private void removeUnknownDmacFlow(BigInteger dpId, ElanInstance elanInfo, WriteTransaction deleteFlowGroupTx,
+            long elanTag) {
         Flow flow = new FlowBuilder().setId(new FlowId(getUnknownDmacFlowRef(NwConstants.ELAN_UNKNOWN_DMAC_TABLE,
-            elanInfo.getElanTag(), /*SH flag*/ false)))
-            .setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
-            .build();
-        elanServiceProvider.getMdsalManager().removeFlowToTx(dpId, flow, deleteFlowGroupTx);
+                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,
-                elanInfo.getElanTag(), /*SH flag*/ true)))
-                .setTableId(NwConstants.ELAN_UNKNOWN_DMAC_TABLE)
-                .build();
-            elanServiceProvider.getMdsalManager().removeFlowToTx(dpId, flow2, deleteFlowGroupTx);
+                    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, WriteTransaction tx) {
-        // 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<Instruction>();
-        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanInfo.getElanTag()), MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
+        List<Instruction> instructions = new ArrayList<>();
+        instructions.add(MDSALUtil.buildAndGetWriteMetadaInstruction(ElanUtils.getElanMetadataLabel(elanTag),
+                MetaDataUtil.METADATA_MASK_SERVICE, ++instructionKey));
         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.ELAN_SMAC_TABLE, ++instructionKey));
-        BoundServices
-            serviceInfo =
-            ElanUtils.getBoundServices(String.format("%s.%s.%s", "vpn",elanInfo.getElanInstanceName(), interfaceName),
-                NwConstants.ELAN_SERVICE_INDEX, priority,
-                NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
+        short elanServiceIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX);
+        BoundServices serviceInfo = ElanUtils.getBoundServices(
+                String.format("%s.%s.%s", "vpn", elanInstanceName, interfaceName), elanServiceIndex,
+                priority, NwConstants.COOKIE_ELAN_INGRESS_TABLE, instructions);
         tx.put(LogicalDatastoreType.CONFIGURATION,
-            ElanUtils.buildServiceId(interfaceName, NwConstants.ELAN_SERVICE_INDEX), serviceInfo, true);
+                ElanUtils.buildServiceId(interfaceName, elanServiceIndex), 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) {
+                LOG.error("EtreeInterface " + elanInterface.getName() + " is associated with a non EtreeInstance: "
+                        + elanInfo.getElanInstanceName());
+            } else {
+                bindElanService(etreeInstance.getEtreeLeafTagVal().getValue(), elanInfo.getElanInstanceName(),
+                        elanInterface.getName(), tx);
+            }
+        }
+    }
+
+    private boolean isStandardElanService(ElanInterface elanInterface) {
+        return elanInterface.getAugmentation(EtreeInterface.class) == null;
+    }
+
+    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,NwConstants.ELAN_SERVICE_INDEX));
+        tx.delete(LogicalDatastoreType.CONFIGURATION, ElanUtils.buildServiceId(interfaceName,
+                ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME, NwConstants.ELAN_SERVICE_INDEX)));
     }
 
     private String getFlowRef(long tableId, long elanTag) {
@@ -1031,20 +1364,22 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
     }
 
     private List<Action> getInterfacePortActions(InterfaceInfo interfaceInfo) {
-        List<Action> listAction = new ArrayList<Action>();
+        List<Action> listAction = new ArrayList<>();
         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(NwConstants.ELAN_FILTER_EQUALS_TABLE)}, actionKey)).buildAction());
+        listAction.add(new ActionInfo(ActionType.nx_resubmit,
+                new String[] { String.valueOf(NwConstants.ELAN_FILTER_EQUALS_TABLE) }, actionKey).buildAction());
         return listAction;
     }
 
-    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);
+    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;
     }
 
@@ -1058,42 +1393,52 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      */
     private void deleteElanDpnInterface(String elanInstanceName, BigInteger dpId, WriteTransaction tx) {
         tx.delete(LogicalDatastoreType.OPERATIONAL,
-            ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId));
+                ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId));
     }
 
-    private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId, WriteTransaction tx) {
-        List<String> interfaceNames = new ArrayList<String>();
+    private DpnInterfaces createElanInterfacesList(String elanInstanceName, String interfaceName, BigInteger dpId,
+            WriteTransaction tx) {
+        List<String> interfaceNames = new ArrayList<>();
         interfaceNames.add(interfaceName);
-        DpnInterfaces dpnInterface = new DpnInterfacesBuilder().setDpId(dpId)
-            .setInterfaces(interfaceNames).setKey(new DpnInterfacesKey(dpId)).build();
-        tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanDpnInterfaceOperationalDataPath(elanInstanceName, dpId),
-            dpnInterface, true);
+        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(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanInterfaceMacTables);
-        // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
+        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);
+            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, WriteTransaction tx) {
         InstanceIdentifier<Elan> elanInstance = ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName);
-        Optional<Elan> elanInterfaceLists = ElanUtils.read(elanServiceProvider.getBroker(), LogicalDatastoreType.OPERATIONAL, elanInstance);
-        // Adding new Elan Interface Port to the operational DataStore without Static-Mac Entries..
+        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) {
                 interfaceLists = new ArrayList<>();
             }
             interfaceLists.add(interfaceName);
-            Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists).setKey(new ElanKey(elanInstanceName)).build();
-            tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName), elanState, true);
+            Elan elanState = new ElanBuilder().setName(elanInstanceName).setElanInterfaces(interfaceLists)
+                    .setKey(new ElanKey(elanInstanceName)).build();
+            tx.put(LogicalDatastoreType.OPERATIONAL, ElanUtils.getElanInstanceOperationalDataPath(elanInstanceName),
+                    elanState, true);
         }
     }
 
@@ -1104,13 +1449,13 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
     }
 
-    public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
-        ElanDpnInterfaces dpnInterfaceLists =  ElanUtils.getElanDpnInterfacesList();
+    public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) throws ElanException {
+        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();
@@ -1123,16 +1468,16 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
                 }
             }
             if (cnt == 2) {
-                logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
-                ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+                LOG.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
+                ElanInstance elanInfo = ElanUtils.getElanInstanceByName(broker, elanName);
                 // update Remote BC Group
                 setupElanBroadcastGroups(elanInfo, srcDpId);
 
-                DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dstDpId);
+                DpnInterfaces dpnInterface = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dstDpId);
                 Set<String> interfaceLists = new HashSet<>();
                 interfaceLists.addAll(dpnInterface.getInterfaces());
-                for(String ifName : interfaceLists) {
-                    InterfaceInfo interfaceInfo = elanServiceProvider.getInterfaceManager().getInterfaceInfo(ifName);
+                for (String ifName : interfaceLists) {
+                    InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
                     if (isOperational(interfaceInfo)) {
                         installDMacAddressTables(elanInfo, interfaceInfo, srcDpId);
                     }
@@ -1149,8 +1494,9 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
      *            the external tunnel
      * @param intrf
      *            the interface
+     * @throws ElanException in case of issues creating the flow objects
      */
-    public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+    public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) throws ElanException {
         if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
             return;
         }
@@ -1166,34 +1512,34 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
             externalNodeId = new NodeId(externalTunnel.getSourceDevice());
         }
         if (dpId == null || externalNodeId == null) {
-            logger.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
+            LOG.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
             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(broker, elanName);
 
-            DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+            DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
             if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
-                || dpnInterfaces.getInterfaces().isEmpty()) {
+                    || dpnInterfaces.getInterfaces().isEmpty()) {
                 continue;
             }
-            logger.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
+            LOG.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
 
             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,
-                externalNodeId);
+            elanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
+                    externalNodeId);
         }
-        logger.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
+        LOG.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
     }
 
     /**
@@ -1209,47 +1555,44 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         if (intrf.getOperStatus() == Interface.OperStatus.Up) {
             String srcDevice = externalTunnel.getDestinationDevice();
             String destDevice = externalTunnel.getSourceDevice();
-            ExternalTunnel otherEndPointExtTunnel = ElanUtils.getExternalTunnel(srcDevice, destDevice,
-                LogicalDatastoreType.CONFIGURATION);
-            if (logger.isTraceEnabled()) {
-                logger.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
-                    otherEndPointExtTunnel);
+            ExternalTunnel otherEndPointExtTunnel = elanUtils.getExternalTunnel(srcDevice, destDevice,
+                    LogicalDatastoreType.CONFIGURATION);
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
+                        otherEndPointExtTunnel);
             }
             if (otherEndPointExtTunnel != null) {
-                boolean otherEndPointInterfaceOperational = ElanUtils
-                    .isInterfaceOperational(otherEndPointExtTunnel.getTunnelInterfaceName(), elanServiceProvider.getBroker());
+                boolean otherEndPointInterfaceOperational = ElanUtils.isInterfaceOperational(
+                        otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
                 if (otherEndPointInterfaceOperational) {
                     return true;
                 } else {
-                    logger.debug("Other end [{}] of the external tunnel is not yet UP for {}",
-                        otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
+                    LOG.debug("Other end [{}] of the external tunnel is not yet UP for {}",
+                            otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
                 }
             }
         }
         return false;
     }
 
-    private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int LportTag) {
-        List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
+    private List<MatchInfo> getMatchesForFilterEqualsLPortTag(int lportTag) {
+        List<MatchInfo> mkMatches = new ArrayList<>();
         // 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<MatchInfo>();
+    private List<MatchInfo> getTunnelIdMatchForFilterEqualsLPortTag(int lportTag) {
+        List<MatchInfo> mkMatches = new ArrayList<>();
         // 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;
         }
@@ -1258,39 +1601,28 @@ public class ElanInterfaceManager extends AsyncDataTreeChangeListenerBase<ElanIn
         }
     }
 
-    public static List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
-                                                                        int bucketId) {
-        List<Bucket> listBucketInfo = new ArrayList<Bucket>();
+    public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
+            int bucketId) {
+        List<Bucket> listBucketInfo = new ArrayList<>();
         ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
-            .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
+                .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
         for (L2GatewayDevice device : map.values()) {
-            String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
-                device.getHwvtepNodeId());
+            String interfaceName = elanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
+                    device.getHwvtepNodeId());
             if (interfaceName == null) {
                 continue;
             }
-            List<Action> listActionInfo = ElanUtils.buildTunnelItmEgressActions(interfaceName, elanInfo.getSegmentationId());
+            List<Action> listActionInfo = elanUtils.buildTunnelItmEgressActions(interfaceName,
+                    elanInfo.getSegmentationId());
             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
-                MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
+                    MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
             bucketId++;
         }
         return listBucketInfo;
     }
 
-    public ElanServiceProvider getElanServiceProvider() {
-        return elanServiceProvider;
-    }
-
-    public void setElanServiceProvider(ElanServiceProvider elanServiceProvider) {
-        this.elanServiceProvider = elanServiceProvider;
-    }
-
-
     @Override
     protected ElanInterfaceManager getDataTreeChangeListener() {
         return this;
     }
-
 }
-
-