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 e8f7d19f344316f4766ed96194330b1eec85d53f..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,
@@ -9,6 +9,7 @@
 package org.opendaylight.netvirt.elan.internal;
 
 import com.google.common.base.Optional;
+
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -19,6 +20,8 @@ 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.common.api.clustering.CandidateAlreadyRegisteredException;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
@@ -27,11 +30,19 @@ import org.opendaylight.genius.interfacemanager.exceptions.InterfaceAlreadyExist
 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
+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.ElanConstants;
 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;
@@ -57,6 +68,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.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.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
@@ -65,7 +78,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ElanServiceProvider implements IElanService {
+@Singleton
+public class ElanServiceProvider extends AbstractLifecycle implements IElanService {
 
     private static final Logger LOG = LoggerFactory.getLogger(ElanServiceProvider.class);
 
@@ -75,10 +89,12 @@ public class ElanServiceProvider implements IElanService {
     private final ElanBridgeManager bridgeMgr;
     private final DataBroker broker;
     private final ElanStatusMonitor elanStatusMonitor;
-    private static ElanUtils elanUtils;
+    private final ElanUtils elanUtils;
 
     private boolean generateIntBridgeMac = true;
+    private boolean isL2BeforeL3;
 
+    @Inject
     public ElanServiceProvider(IdManagerService idManager, IInterfaceManager interfaceManager,
                                ElanInstanceManager elanInstanceManager, ElanBridgeManager bridgeMgr,
                                DataBroker dataBroker,
@@ -102,10 +118,12 @@ public class ElanServiceProvider implements IElanService {
         }
     }
 
+    @Override
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public void init() throws Exception {
+    protected void start() throws Exception {
         LOG.info("Starting ElnaServiceProvider");
         elanStatusMonitor.reportStatus("STARTING");
+        setIsL2BeforeL3();
         try {
             createIdPool();
             elanStatusMonitor.reportStatus("OPERATIONAL");
@@ -115,6 +133,15 @@ public class ElanServiceProvider implements IElanService {
         }
     }
 
+    @Override
+    protected void stop() throws Exception {
+    }
+
+    @Override
+    public Boolean isOpenStackVniSemanticsEnforced() {
+        return elanUtils.isOpenStackVniSemanticsEnforced();
+    }
+
     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();
@@ -137,7 +164,7 @@ public class ElanServiceProvider implements IElanService {
                         .setDescription(description).setMacTimeout(macTimeout)
                         .setKey(new ElanInstanceKey(elanInstanceName)).build();
                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                        ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
+                        ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
                 LOG.debug("Updating the Elan Instance {} with MAC TIME-OUT %l and Description %s ",
                         updateElanInstance, macTimeout, description);
             }
@@ -146,7 +173,7 @@ public class ElanServiceProvider implements IElanService {
                     .setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName))
                     .build();
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
+                    ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
             LOG.debug("Creating the new Elan Instance {}", elanInstance);
         }
         return isSuccess;
@@ -167,7 +194,7 @@ public class ElanServiceProvider implements IElanService {
                         .setKey(new ElanInstanceKey(elanInstanceName))
                         .addAugmentation(EtreeInstance.class, etreeInstance).build();
                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                        ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
+                        ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), updateElanInstance);
                 LOG.debug("Updating the Etree Instance {} with MAC TIME-OUT %l and Description %s ",
                         updateElanInstance, macTimeout, description);
             }
@@ -177,7 +204,7 @@ public class ElanServiceProvider implements IElanService {
                     .setMacTimeout(macTimeout).setDescription(description).setKey(new ElanInstanceKey(elanInstanceName))
                     .addAugmentation(EtreeInstance.class, etreeInstance).build();
             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION,
-                    ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
+                    ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName), elanInstance);
             LOG.debug("Creating the new Etree Instance {}", elanInstance);
         }
         return isSuccess;
@@ -218,7 +245,7 @@ public class ElanServiceProvider implements IElanService {
         }
         LOG.debug("Deletion of the existing Elan Instance {}", existingElanInstance);
         ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION,
-                ElanUtils.getElanInstanceConfigurationDataPath(elanInstanceName));
+                ElanHelper.getElanInstanceConfigurationDataPath(elanInstanceName));
         isSuccess = true;
         return isSuccess;
     }
@@ -235,9 +262,10 @@ public class ElanServiceProvider implements 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();
             }
@@ -252,20 +280,18 @@ public class ElanServiceProvider implements 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);
-            LOG.debug("Creating the new ELan Interface {}", elanInterface);
+            LOG.debug("Created the new ELan Interface {}", elanInterface);
         }
     }
 
@@ -276,17 +302,14 @@ public class ElanServiceProvider implements IElanService {
         if (existingElanInterface == null) {
             return;
         }
-        List<PhysAddress> existingMacAddress = existingElanInterface.getStaticMacEntries();
-        List<PhysAddress> updatedMacAddresses = getPhysAddress(updatedStaticMacAddresses);
-        List<PhysAddress> updatedPhysAddress = getUpdatedPhyAddress(existingMacAddress, updatedMacAddresses);
-        if (updatedPhysAddress.size() > 0) {
-            LOG.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
@@ -310,39 +333,27 @@ public class ElanServiceProvider implements IElanService {
         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(broker, 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("deleteStaticMacAddress did not find MAC: " + macAddress);
+        if (existingElanInterface != null) {
+            InstanceIdentifier<StaticMacEntries> staticMacEntriesIdentifier =
+                    ElanUtils.getStaticMacEntriesCfgDataPathIdentifier(interfaceName,
+                    macAddress);
+            MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, staticMacEntriesIdentifier);
         }
     }
 
@@ -392,27 +403,6 @@ public class ElanServiceProvider implements IElanService {
 
     }
 
-    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(broker, elanName);
@@ -420,15 +410,10 @@ public class ElanServiceProvider implements IElanService {
 
     @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
@@ -460,7 +445,7 @@ public class ElanServiceProvider implements IElanService {
 
     @Override
     public void createExternalElanNetworks(Node node) {
-        handleExternalElanNetworks(node, (elanInstance, interfaceName) -> {
+        handleExternalElanNetworks(node, true, (elanInstance, interfaceName) -> {
             createExternalElanNetwork(elanInstance, interfaceName);
             return null;
         });
@@ -468,15 +453,26 @@ public class ElanServiceProvider implements IElanService {
 
     @Override
     public void createExternalElanNetwork(ElanInstance elanInstance) {
-        handleExternalElanNetwork(elanInstance, (elanInstance1, interfaceName) -> {
+        handleExternalElanNetwork(elanInstance, false, (elanInstance1, interfaceName) -> {
             createExternalElanNetwork(elanInstance1, 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 physial interface is attached to {}", elanInstance.getPhysicalNetworkName());
+            LOG.trace("No physical interface is attached to {}", elanInstance.getPhysicalNetworkName());
             return;
         }
 
@@ -484,9 +480,17 @@ public class ElanServiceProvider implements IElanService {
         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, (elanInstance, interfaceName) -> {
+        handleExternalElanNetworks(node, false, (elanInstance, interfaceName) -> {
             deleteExternalElanNetwork(elanInstance, interfaceName);
             return null;
         });
@@ -494,12 +498,26 @@ public class ElanServiceProvider implements IElanService {
 
     @Override
     public void deleteExternalElanNetwork(ElanInstance elanInstance) {
-        handleExternalElanNetwork(elanInstance, (elanInstance1, interfaceName) -> {
+        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());
@@ -509,12 +527,30 @@ public class ElanServiceProvider implements IElanService {
         String elanInstanceName = elanInstance.getElanInstanceName();
         for (String elanInterface : getExternalElanInterfaces(elanInstanceName)) {
             if (elanInterface.startsWith(interfaceName)) {
-                deleteIetfInterface(elanInterface);
+                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
     public void updateExternalElanNetworks(Node origNode, Node updatedNode) {
         if (!bridgeMgr.isIntegrationBridge(updatedNode)) {
@@ -527,44 +563,64 @@ public class ElanServiceProvider implements IElanService {
             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 (hasPortNameRemoved(origPortName, updatedPortName)) {
+                    deleteExternalElanNetwork(elanInstance,
+                            bridgeMgr.getProviderInterfaceName(origNode, physicalNetworkName));
                 }
-                if (updatedPortName != null && !updatedPortName.equals(origPortName)) {
-                    createExternalElanNetwork(elanInstance, getExtInterfaceName(updatedNode, updatedPortName));
+
+                if (createExternalElanNw && (hasPortNameUpdated(origPortName, updatedPortName)
+                        || hasDatapathIdAdded(hasDatapathIdOnOrigNode, hasDatapathIdOnUpdatedNode))) {
+                    createExternalElanNetwork(elanInstance,
+                            bridgeMgr.getProviderInterfaceName(updatedNode, physicalNetworkName));
                 }
             }
         }
     }
 
-    @Override
-    public String getExternalElanInterface(String elanInstanceName, BigInteger dpnId) {
-        DpnInterfaces dpnInterfaces = elanUtils.getElanInterfaceInfoByElanDpn(elanInstanceName, dpnId);
-        if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null) {
-            LOG.trace("Elan {} does not have interfaces in DPN {}", elanInstanceName, dpnId);
-            return null;
-        }
+    private boolean hasDatapathIdAdded(boolean hasDatapathIdOnOrigNode, boolean hasDatapathIdOnUpdatedNode) {
+        return !hasDatapathIdOnOrigNode && hasDatapathIdOnUpdatedNode;
+    }
 
-        for (String dpnInterface : dpnInterfaces.getInterfaces()) {
-            if (elanUtils.isExternal(dpnInterface)) {
-                return dpnInterface;
-            }
-        }
+    private boolean hasPortNameUpdated(String origPortName, String updatedPortName) {
+        return updatedPortName != null && !updatedPortName.equals(origPortName);
+    }
+
+    private boolean hasPortNameRemoved(String origPortName, String updatedPortName) {
+        return origPortName != null && !origPortName.equals(updatedPortName);
+    }
 
-        LOG.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
@@ -577,7 +633,7 @@ public class ElanServiceProvider implements IElanService {
 
         Set<String> externalElanInterfaces = new HashSet<>();
         for (String elanInterface : elanInterfaces) {
-            if (elanUtils.isExternal(elanInterface)) {
+            if (interfaceManager.isExternalInterface(elanInterface)) {
                 externalElanInterfaces.add(elanInterface);
             }
         }
@@ -585,9 +641,14 @@ public class ElanServiceProvider implements 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
@@ -595,6 +656,45 @@ public class ElanServiceProvider implements IElanService {
         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()));
+    }
+
     /**
      * Create ietf-interfaces based on the ELAN segment type.<br>
      * For segment type flat - create transparent interface pointing to the
@@ -615,20 +715,18 @@ public class ElanServiceProvider implements 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";
-                // trunk interface may have been created by other vlan network
-                Interface trunkInterface = ElanUtils.getInterfaceFromConfigDS(trunkName, broker);
-                if (trunkInterface == null) {
-                    interfaceManager.createVLANInterface(trunkName, parentRef, null, null, null,
-                            IfL2vlan.L2vlanMode.Trunk, true);
-                }
                 interfaceManager.createVLANInterface(interfaceName, trunkName, null, segmentationId.intValue(), null,
                         IfL2vlan.L2vlanMode.TrunkMember, true);
             }
@@ -647,23 +745,8 @@ public class ElanServiceProvider implements IElanService {
         LOG.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) {
-            LOG.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);
-    }
-
-    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;
         }
@@ -675,14 +758,18 @@ public class ElanServiceProvider implements IElanService {
         }
 
         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) {
             LOG.trace("No physical network attached to {}", elanInstanceName);
@@ -698,10 +785,60 @@ public class ElanServiceProvider implements IElanService {
 
         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);
+    }
+
 }