Bug 8860 : Populate elantag at time of elanInstance creation
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / internal / ElanServiceProvider.java
index 6bd3fdf242afe7eb2980ee3e758ffaeddb406ede..d789ada54150efd72445395eb659246ef11d6cbb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright (c) 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -20,29 +20,29 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Future;
 import java.util.function.BiFunction;
+import javax.inject.Inject;
+import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.interfacemanager.exceptions.InterfaceAlreadyExistsException;
 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
-import org.opendaylight.genius.itm.api.IITMProvider;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.netvirt.elan.l2gw.internal.ElanL2GatewayProvider;
-import org.opendaylight.netvirt.elan.statisitcs.ElanStatisticsImpl;
+import org.opendaylight.genius.mdsalutil.MatchInfoBase;
+import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchRegister;
+import org.opendaylight.genius.utils.ServiceIndex;
+import org.opendaylight.genius.utils.clustering.EntityOwnerUtils;
+import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
+import org.opendaylight.infrautils.inject.AbstractLifecycle;
+import org.opendaylight.netvirt.elan.arp.responder.ArpResponderInput;
 import org.opendaylight.netvirt.elan.statusanddiag.ElanStatusMonitor;
-import org.opendaylight.netvirt.elan.utils.CacheElanInstanceListener;
-import org.opendaylight.netvirt.elan.utils.CacheElanInterfaceListener;
-import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
 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.api.ElanHelper;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.elanmanager.exceptions.MacNotFoundException;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
@@ -53,8 +53,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 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.EtreeInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface;
@@ -70,248 +68,86 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntriesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.state.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.statistics.rev150824.ElanStatisticsService;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ElanServiceProvider implements BindingAwareProvider, IElanService, AutoCloseable {
+@Singleton
+public class ElanServiceProvider extends AbstractLifecycle implements IElanService {
 
-    private IdManagerService idManager;
-    private IMdsalApiManager mdsalManager;
-    private IInterfaceManager interfaceManager;
-    private OdlInterfaceRpcService interfaceManagerRpcService;
-    private ElanInstanceManager elanInstanceManager;
-    private ElanForwardingEntriesHandler elanForwardingEntriesHandler;
-    private ElanBridgeManager bridgeMgr;
+    private static final Logger LOG = LoggerFactory.getLogger(ElanServiceProvider.class);
 
-    public IdManagerService getIdManager() {
-        return idManager;
-    }
-
-    public ElanForwardingEntriesHandler getElanForwardingEntriesHandler() {
-        return elanForwardingEntriesHandler;
-    }
-
-    public ElanPacketInHandler getElanPacketInHandler() {
-        return elanPacketInHandler;
-    }
-
-    public ElanSmacFlowEventListener getElanSmacFlowEventListener() {
-        return elanSmacFlowEventListener;
-    }
-
-    public ElanInterfaceStateChangeListener getElanInterfaceStateChangeListener() {
-        return elanInterfaceStateChangeListener;
-    }
-
-    public ElanInterfaceStateClusteredListener getInfStateChangeClusteredListener() {
-        return infStateChangeClusteredListener;
-    }
-
-    public ElanDpnInterfaceClusteredListener getElanDpnInterfaceClusteredListener() {
-        return elanDpnInterfaceClusteredListener;
-    }
-
-    public ElanNodeListener getElanNodeListener() {
-        return elanNodeListener;
-    }
-
-    public NotificationService getNotificationService() {
-        return notificationService;
-    }
-
-    public RpcProviderRegistry getRpcProviderRegistry() {
-        return rpcProviderRegistry;
-    }
-
-    public ElanL2GatewayProvider getElanL2GatewayProvider() {
-        return elanL2GatewayProvider;
-    }
-
-    public static ElanStatusMonitor getElanstatusmonitor() {
-        return elanStatusMonitor;
-    }
-
-    public ElanItmEventListener getElanItmEventListener() {
-        return elanItmEventListener;
-    }
-
-    public static Logger getLogger() {
-        return logger;
-    }
-
-    private ElanInterfaceManager elanInterfaceManager;
-    private ElanPacketInHandler elanPacketInHandler;
-    private ElanSmacFlowEventListener elanSmacFlowEventListener;
-    private ElanInterfaceStateChangeListener elanInterfaceStateChangeListener;
-    private ElanInterfaceStateClusteredListener infStateChangeClusteredListener;
-    private ElanDpnInterfaceClusteredListener elanDpnInterfaceClusteredListener;
-    private ElanNodeListener elanNodeListener;
-    private NotificationService notificationService;
-    private RpcProviderRegistry rpcProviderRegistry;
-    private IITMProvider itmManager;
-    private ItmRpcService itmRpcService;
-    private DataBroker broker;
-    private ElanL2GatewayProvider elanL2GatewayProvider;
-    private ElanStatisticsService interfaceStatsService;
-    private EntityOwnershipService entityOwnershipService;
-    private CacheElanInstanceListener cacheElanInstanceListener;
-    private CacheElanInterfaceListener cacheElanInterfaceListener;
-    private static final ElanStatusMonitor elanStatusMonitor = ElanStatusMonitor.getInstance();
-    static DataStoreJobCoordinator dataStoreJobCoordinator;
-    private ElanOvsdbNodeListener elanOvsdbNodeListener;
+    private final IdManagerService idManager;
+    private final IInterfaceManager interfaceManager;
+    private final ElanInstanceManager elanInstanceManager;
+    private final ElanBridgeManager bridgeMgr;
+    private final DataBroker broker;
+    private final ElanStatusMonitor elanStatusMonitor;
+    private final ElanUtils elanUtils;
 
     private boolean generateIntBridgeMac = true;
-
-    public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
-        dataStoreJobCoordinator = ds;
-    }
-
-    public void setBroker(DataBroker broker) {
-        this.broker = broker;
-    }
-
-    public static DataStoreJobCoordinator getDataStoreJobCoordinator() {
-        if (dataStoreJobCoordinator == null) {
-            dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+    private boolean isL2BeforeL3;
+
+    @Inject
+    public ElanServiceProvider(IdManagerService idManager, IInterfaceManager interfaceManager,
+                               ElanInstanceManager elanInstanceManager, ElanBridgeManager bridgeMgr,
+                               DataBroker dataBroker,
+                               ElanInterfaceManager elanInterfaceManager,
+                               ElanStatusMonitor elanStatusMonitor, ElanUtils elanUtils,
+                               EntityOwnershipService entityOwnershipService) {
+        this.idManager = idManager;
+        this.interfaceManager = interfaceManager;
+        this.elanInstanceManager = elanInstanceManager;
+        this.bridgeMgr = bridgeMgr;
+        this.broker = dataBroker;
+        this.elanStatusMonitor = elanStatusMonitor;
+        this.elanUtils = elanUtils;
+        elanInterfaceManager.setElanUtils(elanUtils);
+        try {
+            EntityOwnerUtils.registerEntityCandidateForOwnerShip(entityOwnershipService,
+                    HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+                    null/*listener*/);
+        } catch (CandidateAlreadyRegisteredException e) {
+            LOG.error("failed to register the entity");
         }
-        return dataStoreJobCoordinator;
     }
 
-    public ElanServiceProvider(RpcProviderRegistry rpcRegistry) {
-        rpcProviderRegistry = rpcRegistry;
-        elanStatusMonitor.registerMbean();
-    }
-
-    // private ElanInterfaceStateChangeListener elanInterfaceEventListener;
-    private ElanItmEventListener elanItmEventListener;
-
-    private static final Logger logger = LoggerFactory.getLogger(ElanServiceProvider.class);
-
     @Override
-    public void onSessionInitiated(ProviderContext session) {
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    protected void start() throws Exception {
+        LOG.info("Starting ElnaServiceProvider");
         elanStatusMonitor.reportStatus("STARTING");
+        setIsL2BeforeL3();
         try {
             createIdPool();
-            getDataStoreJobCoordinator();
-            broker = session.getSALService(DataBroker.class);
-
-            bridgeMgr = new ElanBridgeManager(broker);
-            elanOvsdbNodeListener = new ElanOvsdbNodeListener(broker, generateIntBridgeMac, bridgeMgr, this);
-            ElanUtils.setElanServiceProvider(this);
-            elanForwardingEntriesHandler = ElanForwardingEntriesHandler.getElanForwardingEntriesHandler(this);
-            elanInterfaceManager = ElanInterfaceManager.getElanInterfaceManager(this);
-            elanInstanceManager = ElanInstanceManager.getElanInstanceManager(this);
-            elanNodeListener = ElanNodeListener.getElanNodeListener(this);
-            elanPacketInHandler = ElanPacketInHandler.getElanPacketInHandler(this);
-            elanSmacFlowEventListener = ElanSmacFlowEventListener.getElanSmacFlowEventListener(this);
-            // Initialize statistics rpc provider for elan
-            interfaceStatsService = ElanStatisticsImpl.getElanStatisticsService(this);
-            rpcProviderRegistry.addRpcImplementation(ElanStatisticsService.class, interfaceStatsService);
-            elanInterfaceStateChangeListener = ElanInterfaceStateChangeListener
-                    .getElanInterfaceStateChangeListener(this);
-            infStateChangeClusteredListener = ElanInterfaceStateClusteredListener
-                    .getElanInterfaceStateClusteredListener(this);
-            elanDpnInterfaceClusteredListener = ElanDpnInterfaceClusteredListener
-                    .getElanDpnInterfaceClusteredListener(this);
-            ElanClusterUtils.setElanServiceProvider(this);
-            this.elanL2GatewayProvider = new ElanL2GatewayProvider(this);
-            cacheElanInstanceListener = new CacheElanInstanceListener(this);
-            cacheElanInterfaceListener = new CacheElanInterfaceListener(this);
-            elanInterfaceManager.registerListener(LogicalDatastoreType.CONFIGURATION, broker);
-            elanInstanceManager.registerListener(LogicalDatastoreType.CONFIGURATION, broker);
-            notificationService.registerNotificationListener(elanSmacFlowEventListener);
-            notificationService.registerNotificationListener(elanPacketInHandler);
             elanStatusMonitor.reportStatus("OPERATIONAL");
         } catch (Exception e) {
-            logger.error("Error initializing services", e);
             elanStatusMonitor.reportStatus("ERROR");
+            throw e;
         }
     }
 
-    public void setIdManager(IdManagerService idManager) {
-        this.idManager = idManager;
-    }
-
-    public void setMdsalManager(IMdsalApiManager mdsalManager) {
-        this.mdsalManager = mdsalManager;
-    }
-
-    public void setInterfaceManager(IInterfaceManager interfaceManager) {
-        this.interfaceManager = interfaceManager;
-    }
-
-    public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
-        this.entityOwnershipService = entityOwnershipService;
-    }
-
-    public IInterfaceManager getInterfaceManager() {
-        return this.interfaceManager;
-    }
-
-    public IMdsalApiManager getMdsalManager() {
-        return mdsalManager;
-    }
-
-    public IITMProvider getItmManager() {
-        return itmManager;
-    }
-
-    public DataBroker getBroker() {
-        return broker;
-    }
-
-    public void setNotificationService(NotificationService notificationService) {
-        this.notificationService = notificationService;
-    }
-
-    public void setInterfaceManagerRpcService(OdlInterfaceRpcService interfaceManager) {
-        this.interfaceManagerRpcService = interfaceManager;
-    }
-
-    public OdlInterfaceRpcService getInterfaceManagerRpcService() {
-        return interfaceManagerRpcService;
-    }
-
-    public void setItmManager(IITMProvider itmManager) {
-        this.itmManager = itmManager;
-    }
-
-    public void setItmRpcService(ItmRpcService itmRpcService) {
-        this.itmRpcService = itmRpcService;
-    }
-
-    public ItmRpcService getItmRpcService() {
-        return itmRpcService;
-    }
-
-    public ElanInstanceManager getElanInstanceManager() {
-        return elanInstanceManager;
-    }
-
-    public ElanInterfaceManager getElanInterfaceManager() {
-        return elanInterfaceManager;
+    @Override
+    protected void stop() throws Exception {
     }
 
-    public EntityOwnershipService getEntityOwnershipService() {
-        return entityOwnershipService;
+    @Override
+    public Boolean isOpenStackVniSemanticsEnforced() {
+        return elanUtils.isOpenStackVniSemanticsEnforced();
     }
 
-    private void createIdPool() {
+    private void createIdPool() throws Exception {
         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
                 .setLow(ElanConstants.ELAN_ID_LOW_VALUE).setHigh(ElanConstants.ELAN_ID_HIGH_VALUE).build();
-        try {
-            Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
-            if ((result != null) && (result.get().isSuccessful())) {
-                logger.debug("ELAN Id Pool is created successfully");
-            }
-        } catch (Exception e) {
-            logger.error("Failed to create ELAN Id pool {}", e);
+        Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
+        if (result != null && result.get().isSuccessful()) {
+            LOG.debug("ELAN Id Pool is created successfully");
         }
     }
 
@@ -321,15 +157,15 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         boolean isSuccess = true;
         if (existingElanInstance != null) {
             if (compareWithExistingElanInstance(existingElanInstance, macTimeout, description)) {
-                logger.debug("Elan Instance is already present in the Operational DS {}", existingElanInstance);
+                LOG.debug("Elan Instance is already present in the Operational DS {}", existingElanInstance);
                 return true;
             } else {
                 ElanInstance updateElanInstance = new ElanInstanceBuilder().setElanInstanceName(elanInstanceName)
                         .setDescription(description).setMacTimeout(macTimeout)
                         .setKey(new ElanInstanceKey(elanInstanceName)).build();
                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                        ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
-                logger.debug("Updating the Elan Instance {} with MAC TIME-OUT %l and Description %s ",
+                        ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
+                LOG.debug("Updating the Elan Instance {} with MAC TIME-OUT %l and Description %s ",
                         updateElanInstance, macTimeout, description);
             }
         } else {
@@ -337,8 +173,8 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
                     .setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName))
                     .build();
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
-            logger.debug("Creating the new Elan Instance {}", elanInstance);
+                    ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
+            LOG.debug("Creating the new Elan Instance {}", elanInstance);
         }
         return isSuccess;
     }
@@ -349,7 +185,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         boolean isSuccess = true;
         if (existingElanInstance != null) {
             if (compareWithExistingElanInstance(existingElanInstance, macTimeout, description)) {
-                logger.warn("Etree Instance is already present in the Operational DS {}", existingElanInstance);
+                LOG.warn("Etree Instance is already present in the Operational DS {}", existingElanInstance);
                 return true;
             } else {
                 EtreeInstance etreeInstance = new EtreeInstanceBuilder().build();
@@ -358,8 +194,8 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
                         .setKey(new ElanInstanceKey(elanInstanceName))
                         .addAugmentation(EtreeInstance.class, etreeInstance).build();
                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                        ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
-                logger.debug("Updating the Etree Instance {} with MAC TIME-OUT %l and Description %s ",
+                        ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
+                LOG.debug("Updating the Etree Instance {} with MAC TIME-OUT %l and Description %s ",
                         updateElanInstance, macTimeout, description);
             }
         } else {
@@ -368,12 +204,17 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
                     .setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName))
                     .addAugmentation(EtreeInstance.class, etreeInstance).build();
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
-            logger.debug("Creating the new Etree Instance {}", elanInstance);
+                    ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
+            LOG.debug("Creating the new Etree Instance {}", elanInstance);
         }
         return isSuccess;
     }
 
+    @Override
+    public EtreeInterface getEtreeInterfaceByElanInterfaceName(String elanInterface) {
+        return ElanUtils.getEtreeInterfaceByElanInterfaceName(broker, elanInterface);
+    }
+
     public static boolean compareWithExistingElanInstance(ElanInstance existingElanInstance, long macTimeOut,
             String description) {
         boolean isEqual = false;
@@ -399,12 +240,12 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         boolean isSuccess = false;
         ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
         if (existingElanInstance == null) {
-            logger.debug("Elan Instance is not present {}", existingElanInstance);
+            LOG.debug("Elan Instance is not present {}", existingElanInstance);
             return isSuccess;
         }
-        logger.debug("Deletion of the existing Elan Instance {}", existingElanInstance);
+        LOG.debug("Deletion of the existing Elan Instance {}", existingElanInstance);
         ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
-                ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName));
+                ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName));
         isSuccess = true;
         return isSuccess;
     }
@@ -421,15 +262,16 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
                         .setDescription(description).setName(interfaceName).setKey(new ElanInterfaceKey(interfaceName))
                         .addAugmentation(EtreeInterface.class, etreeInterface).build();
             } else {
+                List<StaticMacEntries> staticMacEntries = ElanUtils.getStaticMacEntries(staticMacAddresses);
                 elanInterface = new ElanInterfaceBuilder().setElanInstanceName(etreeInstanceName)
                         .setDescription(description).setName(interfaceName)
-                        .setStaticMacEntries(getPhysAddress(staticMacAddresses))
+                        .setStaticMacEntries(staticMacEntries)
                         .setKey(new ElanInterfaceKey(interfaceName))
                         .addAugmentation(EtreeInterface.class, etreeInterface).build();
             }
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
                     ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
-            logger.debug("Creating the new Etree Interface {}", elanInterface);
+            LOG.debug("Creating the new Etree Interface {}", elanInterface);
         }
     }
 
@@ -438,103 +280,86 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             String description) {
         ElanInstance existingElanInstance = elanInstanceManager.getElanInstanceByName(elanInstanceName);
         if (existingElanInstance != null) {
-            ElanInterface elanInterface;
-            if (staticMacAddresses == null) {
-                elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
-                        .setDescription(description).setName(interfaceName).setKey(new ElanInterfaceKey(interfaceName))
-                        .build();
-            } else {
-                elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
-                        .setDescription(description).setName(interfaceName)
-                        .setStaticMacEntries(getPhysAddress(staticMacAddresses))
-                        .setKey(new ElanInterfaceKey(interfaceName)).build();
+            ElanInterfaceBuilder elanInterfaceBuilder = new ElanInterfaceBuilder()
+                    .setElanInstanceName(elanInstanceName)
+                    .setDescription(description).setName(interfaceName)
+                    .setKey(new ElanInterfaceKey(interfaceName));
+            if (staticMacAddresses != null) {
+                List<StaticMacEntries> staticMacEntries = ElanUtils.getStaticMacEntries(staticMacAddresses);
+                elanInterfaceBuilder.setStaticMacEntries(staticMacEntries);
             }
+            ElanInterface elanInterface = elanInterfaceBuilder.build();
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
                     ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
-            logger.debug("Creating the new ELan Interface {}", elanInterface);
+            LOG.debug("Created the new ELan Interface {}", elanInterface);
         }
     }
 
     @Override
     public void updateElanInterface(String elanInstanceName, String interfaceName,
             List<String> updatedStaticMacAddresses, String newDescription) {
-        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
+        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
         if (existingElanInterface == null) {
             return;
         }
-        List<PhysAddress> existingMacAddress = existingElanInterface.getStaticMacEntries();
-        List<PhysAddress> updatedMacAddresses = getPhysAddress(updatedStaticMacAddresses);
-        List<PhysAddress> updatedPhysAddress = getUpdatedPhyAddress(existingMacAddress, updatedMacAddresses);
-        if (updatedPhysAddress.size() > 0) {
-            logger.debug("updating the ElanInterface with new Mac Entries {}", updatedStaticMacAddresses);
-            ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
-                    .setName(interfaceName).setDescription(newDescription).setStaticMacEntries(updatedPhysAddress)
-                    .setKey(new ElanInterfaceKey(interfaceName)).build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
-        }
+
+        List<StaticMacEntries> updatedStaticMacEntries = ElanUtils.getStaticMacEntries(updatedStaticMacAddresses);
+        LOG.debug("updating the ElanInterface with new Mac Entries {}", updatedStaticMacAddresses);
+        ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
+                .setName(interfaceName).setDescription(newDescription).setStaticMacEntries(updatedStaticMacEntries)
+                .setKey(new ElanInterfaceKey(interfaceName)).build();
+        MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
+                ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
     }
 
     @Override
     public void deleteEtreeInterface(String elanInstanceName, String interfaceName) {
         deleteElanInterface(elanInstanceName, interfaceName);
-        logger.debug("deleting the Etree Interface {}", interfaceName);
+        LOG.debug("deleting the Etree Interface {}", interfaceName);
     }
 
     @Override
     public void deleteElanInterface(String elanInstanceName, String interfaceName) {
-        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
+        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
         if (existingElanInterface != null) {
             ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
                     ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName));
-            logger.debug("deleting the Elan Interface {}", existingElanInterface);
+            LOG.debug("deleting the Elan Interface {}", existingElanInterface);
         }
     }
 
     @Override
     public void addStaticMacAddress(String elanInstanceName, String interfaceName, String macAddress) {
-        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
+        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
         PhysAddress updateStaticMacAddress = new PhysAddress(macAddress);
         if (existingElanInterface != null) {
-            List<PhysAddress> existingMacAddress = existingElanInterface.getStaticMacEntries();
-            if (existingMacAddress.contains(updateStaticMacAddress)) {
-                return;
-            }
-            existingMacAddress.add(updateStaticMacAddress);
-            ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
-                    .setName(interfaceName).setStaticMacEntries(existingMacAddress)
-                    .setDescription(existingElanInterface.getDescription()).setKey(new ElanInterfaceKey(interfaceName))
-                    .build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
+            StaticMacEntriesBuilder staticMacEntriesBuilder = new StaticMacEntriesBuilder();
+            StaticMacEntries staticMacEntry = staticMacEntriesBuilder.setMacAddress(updateStaticMacAddress).build();
+            InstanceIdentifier<StaticMacEntries> staticMacEntriesIdentifier =
+                    ElanUtils.getStaticMacEntriesCfgDataPathIdentifier(interfaceName,
+                    macAddress);
+            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, staticMacEntriesIdentifier, staticMacEntry);
+            return;
         }
+
+        return;
     }
 
     @Override
     public void deleteStaticMacAddress(String elanInstanceName, String interfaceName, String macAddress)
             throws MacNotFoundException {
-        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
-        PhysAddress physAddress = new PhysAddress(macAddress);
-        if (existingElanInterface == null) {
-            return;
-        }
-        List<PhysAddress> existingMacAddress = existingElanInterface.getStaticMacEntries();
-        if (existingMacAddress.contains(physAddress)) {
-            existingMacAddress.remove(physAddress);
-            ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
-                    .setName(interfaceName).setStaticMacEntries(existingMacAddress)
-                    .setDescription(existingElanInterface.getDescription()).setKey(new ElanInterfaceKey(interfaceName))
-                    .build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInterfaceConfigurationDataPathId(interfaceName), elanInterface);
-        } else {
-            throw new MacNotFoundException("Mac Not Found Exception");
+        ElanInterface existingElanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
+        if (existingElanInterface != null) {
+            InstanceIdentifier<StaticMacEntries> staticMacEntriesIdentifier =
+                    ElanUtils.getStaticMacEntriesCfgDataPathIdentifier(interfaceName,
+                    macAddress);
+            MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, staticMacEntriesIdentifier);
         }
     }
 
     @Override
     public Collection<MacEntry> getElanMacTable(String elanInstanceName) {
-        Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
+        Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
         List<MacEntry> macAddress = new ArrayList<>();
         if (elanInfo == null) {
             return macAddress;
@@ -542,7 +367,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         List<String> elanInterfaces = elanInfo.getElanInterfaces();
         if (elanInterfaces != null && elanInterfaces.size() > 0) {
             for (String elanInterface : elanInterfaces) {
-                ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+                ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
                 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null
                         && elanInterfaceMac.getMacEntry().size() > 0) {
                     macAddress.addAll(elanInterfaceMac.getMacEntry());
@@ -554,7 +379,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
 
     @Override
     public void flushMACTable(String elanInstanceName) {
-        Elan elanInfo = ElanUtils.getElanByName(elanInstanceName);
+        Elan elanInfo = ElanUtils.getElanByName(broker, elanInstanceName);
         if (elanInfo == null) {
             return;
         }
@@ -563,15 +388,14 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
             return;
         }
         for (String elanInterface : elanInterfaces) {
-            ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+            ElanInterfaceMac elanInterfaceMac = elanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
             if (elanInterfaceMac.getMacEntry() != null && elanInterfaceMac.getMacEntry().size() > 0) {
                 List<MacEntry> macEntries = elanInterfaceMac.getMacEntry();
                 for (MacEntry macEntry : macEntries) {
                     try {
                         deleteStaticMacAddress(elanInstanceName, elanInterface, macEntry.getMacAddress().getValue());
                     } catch (MacNotFoundException e) {
-                        logger.error("Mac Not Found Exception {}", e);
-                        e.printStackTrace();
+                        LOG.error("Mac Not Found Exception {}", e);
                     }
                 }
             }
@@ -579,51 +403,17 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
 
     }
 
-    @Override
-    public void close() throws Exception {
-        this.elanInstanceManager.close();
-        this.elanL2GatewayProvider.close();
-        this.cacheElanInstanceListener.close();
-        this.cacheElanInterfaceListener.close();
-    }
-
-    public static List<PhysAddress> getPhysAddress(List<String> macAddress) {
-        List<PhysAddress> physAddresses = new ArrayList<>();
-        for (String mac : macAddress) {
-            physAddresses.add(new PhysAddress(mac));
-        }
-        return physAddresses;
-    }
-
-    public List<PhysAddress> getUpdatedPhyAddress(List<PhysAddress> originalAddresses,
-            List<PhysAddress> updatePhyAddresses) {
-        if (updatePhyAddresses != null && !updatePhyAddresses.isEmpty()) {
-            List<PhysAddress> existingClonedPhyAddress = new ArrayList<>();
-            if (originalAddresses != null && !originalAddresses.isEmpty()) {
-                existingClonedPhyAddress.addAll(0, originalAddresses);
-                originalAddresses.removeAll(updatePhyAddresses);
-                updatePhyAddresses.removeAll(existingClonedPhyAddress);
-            }
-        }
-        return updatePhyAddresses;
-    }
-
     @Override
     public ElanInstance getElanInstance(String elanName) {
-        return ElanUtils.getElanInstanceByName(elanName);
+        return ElanUtils.getElanInstanceByName(broker, elanName);
     }
 
     @Override
     public List<ElanInstance> getElanInstances() {
-        List<ElanInstance> elanList = new ArrayList<>();
         InstanceIdentifier<ElanInstances> elanInstancesIdentifier = InstanceIdentifier.builder(ElanInstances.class)
                 .build();
-        Optional<ElanInstances> elansOptional = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
-                elanInstancesIdentifier);
-        if (elansOptional.isPresent()) {
-            elanList.addAll(elansOptional.get().getElanInstance());
-        }
-        return elanList;
+        return elanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, elanInstancesIdentifier).toJavaUtil().map(
+                ElanInstances::getElanInstance).orElse(Collections.emptyList());
     }
 
     @Override
@@ -631,7 +421,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         List<String> elanInterfaces = new ArrayList<>();
         InstanceIdentifier<ElanInterfaces> elanInterfacesIdentifier = InstanceIdentifier.builder(ElanInterfaces.class)
                 .build();
-        Optional<ElanInterfaces> elanInterfacesOptional = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
+        Optional<ElanInterfaces> elanInterfacesOptional = elanUtils.read(broker, LogicalDatastoreType.CONFIGURATION,
                 elanInterfacesIdentifier);
         if (!elanInterfacesOptional.isPresent()) {
             return elanInterfaces;
@@ -655,52 +445,110 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
 
     @Override
     public void createExternalElanNetworks(Node node) {
-        handleExternalElanNetworks(node, new BiFunction<ElanInstance, String, Void>() {
-
-            @Override
-            public Void apply(ElanInstance elanInstance, String interfaceName) {
-                createExternalElanNetwork(elanInstance, interfaceName);
-                return null;
-            }
+        handleExternalElanNetworks(node, true, (elanInstance, interfaceName) -> {
+            createExternalElanNetwork(elanInstance, interfaceName);
+            return null;
         });
     }
 
     @Override
     public void createExternalElanNetwork(ElanInstance elanInstance) {
-        handleExternalElanNetwork(elanInstance, new BiFunction<ElanInstance, String, Void>() {
+        handleExternalElanNetwork(elanInstance, false, (elanInstance1, interfaceName) -> {
+            createExternalElanNetwork(elanInstance1, interfaceName);
+            return null;
+        });
+    }
 
-            @Override
-            public Void apply(ElanInstance elanInstance, String interfaceName) {
-                createExternalElanNetwork(elanInstance, interfaceName);
-                return null;
-            }
+    protected void createExternalElanNetwork(ElanInstance elanInstance, BigInteger dpId) {
+        String providerIntfName = bridgeMgr.getProviderInterfaceName(dpId, elanInstance.getPhysicalNetworkName());
+        String intfName = providerIntfName + IfmConstants.OF_URI_SEPARATOR + elanInstance.getSegmentationId();
+        Interface memberIntf = interfaceManager.getInterfaceInfoFromConfigDataStore(intfName);
+        if (memberIntf == null) {
+            LOG.debug("creating vlan prv intf in elan {}, dpn {}", elanInstance.getElanInstanceName(),
+                    dpId);
+            createExternalElanNetwork(elanInstance, providerIntfName);
+        }
+    }
+
+    private void createExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
+        if (interfaceName == null) {
+            LOG.trace("No physical interface is attached to {}", elanInstance.getPhysicalNetworkName());
+            return;
+        }
+
+        String elanInterfaceName = createIetfInterfaces(elanInstance, interfaceName);
+        addElanInterface(elanInstance.getElanInstanceName(), elanInterfaceName, null, null);
+    }
 
+    @Override
+    public void updateExternalElanNetwork(ElanInstance elanInstance) {
+        handleExternalElanNetwork(elanInstance, true, (elanInstance1, interfaceName) -> {
+            createExternalElanNetwork(elanInstance1, interfaceName);
+            return null;
         });
     }
 
     @Override
     public void deleteExternalElanNetworks(Node node) {
-        handleExternalElanNetworks(node, new BiFunction<ElanInstance, String, Void>() {
-
-            @Override
-            public Void apply(ElanInstance elanInstance, String interfaceName) {
-                deleteExternalElanNetwork(elanInstance, interfaceName);
-                return null;
-            }
+        handleExternalElanNetworks(node, false, (elanInstance, interfaceName) -> {
+            deleteExternalElanNetwork(elanInstance, interfaceName);
+            return null;
         });
     }
 
     @Override
     public void deleteExternalElanNetwork(ElanInstance elanInstance) {
-        handleExternalElanNetwork(elanInstance, new BiFunction<ElanInstance, String, Void>() {
+        handleExternalElanNetwork(elanInstance, false, (elanInstance1, interfaceName) -> {
+            deleteExternalElanNetwork(elanInstance1, interfaceName);
+            return null;
+        });
+    }
+
+    protected void deleteExternalElanNetwork(ElanInstance elanInstance, BigInteger dpnId) {
+        String providerIntfName = bridgeMgr.getProviderInterfaceName(dpnId, elanInstance.getPhysicalNetworkName());
+        String intfName = providerIntfName + IfmConstants.OF_URI_SEPARATOR + elanInstance.getSegmentationId();
+        Interface memberIntf = interfaceManager.getInterfaceInfoFromConfigDataStore(intfName);
+        if (memberIntf != null) {
+            deleteElanInterface(elanInstance.getElanInstanceName(), intfName);
+            deleteIetfInterface(intfName);
+            LOG.debug("delete vlan prv intf {} in elan {}, dpID {}", intfName,
+                    elanInstance.getElanInstanceName(), dpnId);
+        } else {
+            LOG.debug("vlan prv intf {} not found in interfacemgr config DS", intfName);
+        }
+    }
+
+    private void deleteExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
+        if (interfaceName == null) {
+            LOG.trace("No physial interface is attached to {}", elanInstance.getPhysicalNetworkName());
+            return;
+        }
 
-            @Override
-            public Void apply(ElanInstance elanInstance, String interfaceName) {
-                deleteExternalElanNetwork(elanInstance, interfaceName);
-                return null;
+        String elanInstanceName = elanInstance.getElanInstanceName();
+        for (String elanInterface : getExternalElanInterfaces(elanInstanceName)) {
+            if (elanInterface.startsWith(interfaceName)) {
+                if (ElanUtils.isVlan(elanInstance)) {
+                    deleteIetfInterface(elanInterface);
+                }
+                String trunkInterfaceName = getTrunkInterfaceName(interfaceName);
+                if (shouldDeleteTrunk(trunkInterfaceName, elanInterface)) {
+                    deleteIetfInterface(trunkInterfaceName);
+                }
+                deleteElanInterface(elanInstanceName, elanInterface);
             }
+        }
+    }
 
-        });
+    private boolean shouldDeleteTrunk(String trunkInterfaceName, String elanInterfaceName) {
+        List<Interface> childInterfaces = interfaceManager.getChildInterfaces(trunkInterfaceName);
+        if (childInterfaces == null || childInterfaces.isEmpty()
+                || childInterfaces.size() == 1 && elanInterfaceName.equals(childInterfaces.get(0).getName())) {
+            LOG.debug("No more VLAN member interfaces left for trunk {}", trunkInterfaceName);
+            return true;
+        }
+
+        LOG.debug("Trunk interface {} has {} VLAN member interfaces left", trunkInterfaceName, childInterfaces.size());
+        return false;
     }
 
     @Override
@@ -711,86 +559,81 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
 
         List<ElanInstance> elanInstances = getElanInstances();
         if (elanInstances == null || elanInstances.isEmpty()) {
-            logger.trace("No ELAN instances found");
+            LOG.trace("No ELAN instances found");
             return;
         }
 
-        Optional<Map<String, String>> origProviderMapOpt = bridgeMgr.getOpenvswitchOtherConfigMap(origNode,
+        LOG.debug("updateExternalElanNetworks, orig bridge {} . updated bridge {}", origNode, updatedNode);
+
+        Map<String, String> origProviderMappping = getMapFromOtherConfig(origNode,
                 ElanBridgeManager.PROVIDER_MAPPINGS_KEY);
-        Optional<Map<String, String>> updatedProviderMapOpt = bridgeMgr.getOpenvswitchOtherConfigMap(updatedNode,
+        Map<String, String> updatedProviderMappping = getMapFromOtherConfig(updatedNode,
                 ElanBridgeManager.PROVIDER_MAPPINGS_KEY);
-        Map<String, String> origProviderMappping = origProviderMapOpt.or(Collections.emptyMap());
-        Map<String, String> updatedProviderMappping = updatedProviderMapOpt.or(Collections.emptyMap());
+
+        boolean hasDatapathIdOnOrigNode = bridgeMgr.hasDatapathID(origNode);
+        boolean hasDatapathIdOnUpdatedNode = bridgeMgr.hasDatapathID(updatedNode);
+        BigInteger origDpnID = bridgeMgr.getDatapathId(origNode);
 
         for (ElanInstance elanInstance : elanInstances) {
             String physicalNetworkName = elanInstance.getPhysicalNetworkName();
+            boolean createExternalElanNw = true;
             if (physicalNetworkName != null) {
                 String origPortName = origProviderMappping.get(physicalNetworkName);
                 String updatedPortName = updatedProviderMappping.get(physicalNetworkName);
-                if (origPortName != null && !origPortName.equals(updatedPortName)) {
-                    deleteExternalElanNetwork(elanInstance, getExtInterfaceName(origNode, physicalNetworkName));
+                /**
+                 * for internal vlan network, vlan provider interface creation should be
+                 * triggered only if there is existing vlan provider intf indicating presence
+                 * of VM ports on the DPN
+                 */
+                if (hasDatapathIdOnOrigNode && !elanInstance.isExternal()
+                        && ElanUtils.isVlan(elanInstance)) {
+                    String externalIntf = getExternalElanInterface(elanInstance.getElanInstanceName(),
+                            origDpnID);
+                    if (externalIntf == null) {
+                        createExternalElanNw = false;
+                    }
                 }
-                if (updatedPortName != null && !updatedPortName.equals(origPortName)) {
-                    createExternalElanNetwork(elanInstance, getExtInterfaceName(updatedNode, updatedPortName));
+                if (hasPortNameRemoved(origPortName, updatedPortName)) {
+                    deleteExternalElanNetwork(elanInstance,
+                            bridgeMgr.getProviderInterfaceName(origNode, physicalNetworkName));
+                }
+
+                if (createExternalElanNw && (hasPortNameUpdated(origPortName, updatedPortName)
+                        || hasDatapathIdAdded(hasDatapathIdOnOrigNode, hasDatapathIdOnUpdatedNode))) {
+                    createExternalElanNetwork(elanInstance,
+                            bridgeMgr.getProviderInterfaceName(updatedNode, physicalNetworkName));
                 }
             }
         }
     }
 
-    private void createExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
-        if (interfaceName == null) {
-            logger.trace("No physial interface is attached to {}", elanInstance.getPhysicalNetworkName());
-            return;
-        }
-
-        String elanInterfaceName = createIetfInterfaces(elanInstance, interfaceName);
-        addElanInterface(elanInstance.getElanInstanceName(), elanInterfaceName, null, null);
+    private boolean hasDatapathIdAdded(boolean hasDatapathIdOnOrigNode, boolean hasDatapathIdOnUpdatedNode) {
+        return !hasDatapathIdOnOrigNode && hasDatapathIdOnUpdatedNode;
     }
 
-    private void deleteExternalElanNetwork(ElanInstance elanInstance, String interfaceName) {
-        if (interfaceName == null) {
-            logger.trace("No physial interface is attached to {}", elanInstance.getPhysicalNetworkName());
-            return;
-        }
-
-        String elanInstanceName = elanInstance.getElanInstanceName();
-        for (String elanInterface : getExternalElanInterfaces(elanInstanceName)) {
-            if (elanInterface.startsWith(interfaceName)) {
-                deleteIetfInterface(elanInterface);
-                deleteElanInterface(elanInstanceName, elanInterface);
-            }
-        }
+    private boolean hasPortNameUpdated(String origPortName, String updatedPortName) {
+        return updatedPortName != null && !updatedPortName.equals(origPortName);
     }
 
-    @Override
-    public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
-        DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
-        if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
-            logger.trace("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId);
-            return null;
-        }
-
-        for (String dpnInterface : dpnInterfaces.getInterfaces()) {
-            if (ElanUtils.isExternal(dpnInterface)) {
-                return dpnInterface;
-            }
-        }
+    private boolean hasPortNameRemoved(String origPortName, String updatedPortName) {
+        return origPortName != null && !origPortName.equals(updatedPortName);
+    }
 
-        logger.trace("Elan {} does not have any external interace attached to DPN {}", elanInstanceName, dpnId);
-        return null;
+    private Map<String, String> getMapFromOtherConfig(Node node, String otherConfigColumn) {
+        return bridgeMgr.getOpenvswitchOtherConfigMap(node, otherConfigColumn);
     }
 
     @Override
     public Collection<String> getExternalElanInterfaces(String elanInstanceName) {
         List<String> elanInterfaces = getElanInterfaces(elanInstanceName);
         if (elanInterfaces == null || elanInterfaces.isEmpty()) {
-            logger.trace("No ELAN interfaces defined for {}", elanInstanceName);
+            LOG.trace("No ELAN interfaces defined for {}", elanInstanceName);
             return Collections.emptySet();
         }
 
         Set<String> externalElanInterfaces = new HashSet<>();
         for (String elanInterface : elanInterfaces) {
-            if (ElanUtils.isExternal(elanInterface)) {
+            if (interfaceManager.isExternalInterface(elanInterface)) {
                 externalElanInterfaces.add(elanInterface);
             }
         }
@@ -798,9 +641,58 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         return externalElanInterfaces;
     }
 
+    @Override
+    public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
+        return elanUtils.getExternalElanInterface(elanInstanceName, dpnId);
+    }
+
     @Override
     public boolean isExternalInterface(String interfaceName) {
-        return ElanUtils.isExternal(interfaceName);
+        return interfaceManager.isExternalInterface(interfaceName);
+    }
+
+    @Override
+    public ElanInterface getElanInterfaceByElanInterfaceName(String interfaceName) {
+        return ElanUtils.getElanInterfaceByElanInterfaceName(broker, interfaceName);
+    }
+
+    @Override
+    public void handleKnownL3DmacAddress(String macAddress, String elanInstanceName, int addOrRemove) {
+        if (!isL2BeforeL3) {
+            LOG.trace("ELAN service is after L3VPN in the Netvirt pipeline skip known L3DMAC flows installation");
+            return;
+        }
+        ElanInstance elanInstance = ElanUtils.getElanInstanceByName(broker, elanInstanceName);
+        if (elanInstance == null) {
+            LOG.warn("Null elan instance {}", elanInstanceName);
+            return;
+        }
+
+        List<BigInteger> dpnsIdsForElanInstance = elanUtils.getParticipatingDpnsInElanInstance(elanInstanceName);
+        if (dpnsIdsForElanInstance == null || dpnsIdsForElanInstance.isEmpty()) {
+            LOG.warn("No DPNs for elan instance {}", elanInstance);
+            return;
+        }
+
+        elanUtils.handleDmacRedirectToDispatcherFlows(elanInstance.getElanTag(), elanInstanceName, macAddress,
+                addOrRemove, dpnsIdsForElanInstance);
+    }
+
+    @Override
+    public List<MatchInfoBase> getEgressMatchesForElanInstance(String elanInstanceName) {
+        ElanInstance elanInstance = getElanInstance(elanInstanceName);
+        if (elanInstance == null) {
+            LOG.debug("No ELAN instance found for {}", elanInstanceName);
+            return Collections.emptyList();
+        }
+
+        Long elanTag = elanInstance.getElanTag();
+        if (elanTag == null) {
+            LOG.debug("No ELAN tag found for {}", elanInstanceName);
+            return Collections.emptyList();
+        }
+        return Collections.singletonList(
+                new NxMatchRegister(ElanConstants.ELAN_REG_ID, elanTag, MetaDataUtil.getElanMaskForReg()));
     }
 
     /**
@@ -823,22 +715,23 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         String interfaceName = null;
 
         try {
+            String trunkName = getTrunkInterfaceName(parentRef);
+            // trunk interface may have been created by other vlan network
+            Interface trunkInterface = interfaceManager.getInterfaceInfoFromConfigDataStore(trunkName);
+            if (trunkInterface == null) {
+                interfaceManager.createVLANInterface(trunkName, parentRef, null, null, null,
+                        IfL2vlan.L2vlanMode.Trunk, true);
+            }
             if (ElanUtils.isFlat(elanInstance)) {
-                interfaceName = parentRef + IfmConstants.OF_URI_SEPARATOR + "flat";
-                interfaceManager.createVLANInterface(interfaceName, parentRef, null, null, null,
-                        IfL2vlan.L2vlanMode.Transparent, true);
+                interfaceName = trunkName;
             } else if (ElanUtils.isVlan(elanInstance)) {
                 Long segmentationId = elanInstance.getSegmentationId();
                 interfaceName = parentRef + IfmConstants.OF_URI_SEPARATOR + segmentationId;
-                String trunkName = parentRef + IfmConstants.OF_URI_SEPARATOR + "trunk";
-                interfaceManager.createVLANInterface(trunkName, parentRef, null, null, null,
-                        IfL2vlan.L2vlanMode.Trunk, true);
-
                 interfaceManager.createVLANInterface(interfaceName, trunkName, null, segmentationId.intValue(), null,
                         IfL2vlan.L2vlanMode.TrunkMember, true);
             }
         } catch (InterfaceAlreadyExistsException e) {
-            logger.trace("Interface {} was already created", interfaceName);
+            LOG.trace("Interface {} was already created", interfaceName);
         }
 
         return interfaceName;
@@ -849,64 +742,103 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService,
         InstanceIdentifier<Interface> interfaceInstanceIdentifier = InstanceIdentifier.builder(Interfaces.class)
                 .child(Interface.class, interfaceKey).build();
         MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, interfaceInstanceIdentifier);
-        logger.debug("Deleting IETF interface {}", interfaceName);
-    }
-
-    private String getExtInterfaceName(Node node, String physicalNetworkName) {
-        if (physicalNetworkName == null) {
-            return null;
-        }
-
-        String providerMappingValue = bridgeMgr.getProviderMappingValue(node, physicalNetworkName);
-        if (providerMappingValue == null) {
-            logger.trace("No provider mapping found for physicalNetworkName {} node {}", physicalNetworkName,
-                    node.getNodeId().getValue());
-            return null;
-        }
-
-        return bridgeMgr.southboundUtils.getDataPathId(node) + IfmConstants.OF_URI_SEPARATOR
-                + bridgeMgr.getIntBridgePortNameFor(node, providerMappingValue);
+        LOG.debug("Deleting IETF interface {}", interfaceName);
     }
 
-    private void handleExternalElanNetworks(Node node, BiFunction<ElanInstance, String, Void> function) {
+    private void handleExternalElanNetworks(Node node, boolean skipIntVlanNw,
+                                            BiFunction<ElanInstance, String, Void> function) {
         if (!bridgeMgr.isIntegrationBridge(node)) {
             return;
         }
 
         List<ElanInstance> elanInstances = getElanInstances();
         if (elanInstances == null || elanInstances.isEmpty()) {
-            logger.trace("No ELAN instances found");
+            LOG.trace("No ELAN instances found");
             return;
         }
 
         for (ElanInstance elanInstance : elanInstances) {
-            String interfaceName = getExtInterfaceName(node, elanInstance.getPhysicalNetworkName());
+            if (skipIntVlanNw && !elanInstance.isExternal() && ElanUtils.isVlan(elanInstance)) {
+                continue;
+            }
+            String interfaceName = bridgeMgr.getProviderInterfaceName(node, elanInstance.getPhysicalNetworkName());
             if (interfaceName != null) {
                 function.apply(elanInstance, interfaceName);
             }
         }
     }
 
-    private void handleExternalElanNetwork(ElanInstance elanInstance, BiFunction<ElanInstance, String, Void> function) {
+    private void handleExternalElanNetwork(ElanInstance elanInstance, boolean update,
+                                           BiFunction<ElanInstance, String, Void> function) {
         String elanInstanceName = elanInstance.getElanInstanceName();
         if (elanInstance.getPhysicalNetworkName() == null) {
-            logger.trace("No physical network attached to {}", elanInstanceName);
+            LOG.trace("No physical network attached to {}", elanInstanceName);
             return;
         }
 
         List<Node> nodes = bridgeMgr.southboundUtils.getOvsdbNodes();
         if (nodes == null || nodes.isEmpty()) {
-            logger.trace("No OVS nodes found while creating external network for ELAN {}",
+            LOG.trace("No OVS nodes found while creating external network for ELAN {}",
                     elanInstance.getElanInstanceName());
             return;
         }
 
         for (Node node : nodes) {
             if (bridgeMgr.isIntegrationBridge(node)) {
-                String interfaceName = getExtInterfaceName(node, elanInstance.getPhysicalNetworkName());
+                if (update && !elanInstance.isExternal()) {
+                    DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanInstanceName,
+                            bridgeMgr.getDatapathId(node));
+                    if (dpnInterfaces == null || dpnInterfaces.getInterfaces().isEmpty()) {
+                        continue;
+                    }
+                }
+                String interfaceName = bridgeMgr.getProviderInterfaceName(node, elanInstance.getPhysicalNetworkName());
                 function.apply(elanInstance, interfaceName);
             }
         }
     }
 
+    private String getTrunkInterfaceName(String parentRef) {
+        return parentRef + IfmConstants.OF_URI_SEPARATOR + "trunk";
+    }
+
+    private void setIsL2BeforeL3() {
+        short elanServiceRealIndex = ServiceIndex.getIndex(NwConstants.ELAN_SERVICE_NAME,
+                NwConstants.ELAN_SERVICE_INDEX);
+        short l3vpnServiceRealIndex = ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
+                NwConstants.L3VPN_SERVICE_INDEX);
+        if (elanServiceRealIndex < l3vpnServiceRealIndex) {
+            LOG.info("ELAN service is set before L3VPN service in the Netvirt pipeline");
+            isL2BeforeL3 = true;
+        } else {
+            LOG.info("ELAN service is set after L3VPN service in the Netvirt pipeline");
+            isL2BeforeL3 = false;
+        }
+    }
+
+    @Override
+    public void addArpResponderFlow(ArpResponderInput arpResponderInput) {
+        elanUtils.addArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
+                arpResponderInput.getSpa(), arpResponderInput.getSha(), arpResponderInput.getLportTag(),
+                arpResponderInput.getInstructions());
+    }
+
+    @Override
+    public void removeArpResponderFlow(ArpResponderInput arpResponderInput) {
+        elanUtils.removeArpResponderFlow(arpResponderInput.getDpId(), arpResponderInput.getInterfaceName(),
+                arpResponderInput.getSpa(), arpResponderInput.getLportTag());
+    }
+
+    /**
+     * Uses the IdManager to retrieve a brand new ElanTag.
+     *
+     * @param idKey
+     *            the id key
+     * @return the integer
+     */
+    @Override
+    public Long retrieveNewElanTag(String idKey) {
+        return elanUtils.retrieveNewElanTag(idManager, idKey);
+    }
+
 }