Use IetfYangUtils to canonize addresses
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / utils / ElanL2GatewayUtils.java
index ae3874d949c5b2559f6f3ec0dc580afbb3ad7e94..c1f83b99a673f46ddb856f5cce28a987372aab97 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.netvirt.elan.l2gw.utils;
 
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+
 import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.FutureCallback;
@@ -19,7 +21,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Locale;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -34,21 +35,25 @@ import javax.annotation.Nonnull;
 import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Singleton;
-
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
+import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.utils.SystemPropertyReader;
 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
+import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
 import org.opendaylight.netvirt.elan.ElanException;
+import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
+import org.opendaylight.netvirt.elan.cache.ElanInstanceDpnsCache;
+import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteLogicalSwitchJob;
 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
@@ -63,18 +68,24 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.IetfYangUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVteps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
@@ -112,12 +123,15 @@ public class ElanL2GatewayUtils {
     private static final int DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS = 20;
 
     private final DataBroker broker;
+    private final ManagedNewTransactionRunner txRunner;
     private final ElanDmacUtils elanDmacUtils;
     private final ElanItmUtils elanItmUtils;
     private final ElanClusterUtils elanClusterUtils;
     private final OdlInterfaceRpcService interfaceManagerRpcService;
     private final JobCoordinator jobCoordinator;
     private final ElanUtils elanUtils;
+    private final ElanInstanceCache elanInstanceCache;
+    private final ElanInstanceDpnsCache elanInstanceDpnsCache;
 
     private final ConcurrentMap<Pair<NodeId, String>, ScheduledFuture> logicalSwitchDeletedTasks
             = new ConcurrentHashMap<>();
@@ -129,8 +143,10 @@ public class ElanL2GatewayUtils {
     public ElanL2GatewayUtils(DataBroker broker, ElanDmacUtils elanDmacUtils, ElanItmUtils elanItmUtils,
             ElanClusterUtils elanClusterUtils, OdlInterfaceRpcService interfaceManagerRpcService,
             JobCoordinator jobCoordinator, ElanUtils elanUtils,
-            Scheduler scheduler, ElanConfig elanConfig) {
+            Scheduler scheduler, ElanConfig elanConfig, ElanInstanceCache elanInstanceCache,
+            ElanInstanceDpnsCache elanInstanceDpnsCache) {
         this.broker = broker;
+        this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
         this.elanDmacUtils = elanDmacUtils;
         this.elanItmUtils = elanItmUtils;
         this.elanClusterUtils = elanClusterUtils;
@@ -139,6 +155,8 @@ public class ElanL2GatewayUtils {
         this.elanUtils = elanUtils;
         this.scheduler = scheduler;
         this.elanConfig = elanConfig;
+        this.elanInstanceCache = elanInstanceCache;
+        this.elanInstanceDpnsCache = elanInstanceDpnsCache;
     }
 
     @PreDestroy
@@ -185,7 +203,7 @@ public class ElanL2GatewayUtils {
             RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
         if (remoteMcastMac != null) {
             HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
-                    .createHwvtepPhysicalLocatorAugmentation(String.valueOf(expectedPhyLocatorIp.getValue()));
+                    .createHwvtepPhysicalLocatorAugmentation(expectedPhyLocatorIp);
             HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
                     HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
             if (remoteMcastMac.getLocatorSet() != null) {
@@ -217,9 +235,7 @@ public class ElanL2GatewayUtils {
                 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
         RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
                 new MacAddress(ElanConstants.UNKNOWN_DMAC));
-        RemoteMcastMacs remoteMcastMac = HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId,
-                remoteMcastMacsKey);
-        return remoteMcastMac;
+        return HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId, remoteMcastMacsKey);
     }
 
     /**
@@ -264,14 +280,9 @@ public class ElanL2GatewayUtils {
                 (InstanceIdentifier<LogicalSwitches>) localUcastMac.getLogicalSwitchRef().getValue());
         if (lsOpc.isPresent()) {
             LogicalSwitches ls = lsOpc.get();
-            if (ls != null) {
-                // Logical switch name is Elan name
-                String elanName = getElanFromLogicalSwitch(ls.getHwvtepNodeName().getValue());
-                return ElanUtils.getElanInstanceByName(broker, elanName);
-            } else {
-                String macAddress = localUcastMac.getMacEntryKey().getValue();
-                LOG.error("Could not find logical_switch for {} being added/deleted", macAddress);
-            }
+            // Logical switch name is Elan name
+            String elanName = getElanFromLogicalSwitch(ls.getHwvtepNodeName().getValue());
+            return elanInstanceCache.get(elanName).orNull();
         }
         return null;
     }
@@ -358,7 +369,7 @@ public class ElanL2GatewayUtils {
             final String macToBeAdded, final LocalUcastMacs localUcastMacs, String interfaceName) {
         final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
         final String elanInstanceName = elan.getElanInstanceName();
-        final List<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
+        final Collection<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
                 .getInvolvedL2GwDevices(elanInstanceName);
 
@@ -450,7 +461,7 @@ public class ElanL2GatewayUtils {
             return;
         }
 
-        final List<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
+        final Collection<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
 
         // Retrieve all participating DPNs in this Elan. Populate this MAC in
         // DMAC table. Looping through all DPNs in order to add/remove mac flows
@@ -462,7 +473,8 @@ public class ElanL2GatewayUtils {
                     for (DpnInterfaces elanDpn : elanDpns) {
                         BigInteger dpnId = elanDpn.getDpId();
                         result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
-                                l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase(Locale.getDefault())));
+                                l2GwDevice.getHwvtepNodeId(),
+                                IetfYangUtil.INSTANCE.canonizeMacAddress(mac).getValue()));
                     }
                     return result;
                 });
@@ -476,16 +488,14 @@ public class ElanL2GatewayUtils {
      *            the elan name
      * @param dpnId
      *            the dpn id
-     * @throws ReadFailedException if a read fails throws ReadFailedException
      */
-    public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId)
-            throws ReadFailedException {
+    public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId) {
         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
         if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
             LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
             return;
         }
-        final ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
+        final ElanInstance elan = elanInstanceCache.get(elanName).orNull();
         if (elan == null) {
             LOG.error("Could not find Elan by name: {}", elanName);
             return;
@@ -526,12 +536,12 @@ public class ElanL2GatewayUtils {
                     @Override
                     public void onSuccess(Optional<Node> configNode) {
                         if (configNode != null && configNode.isPresent()) {
-                            HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(
+                            HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(
                                     HwvtepGlobalAugmentation.class);
                             if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
                                 macs.addAll(augmentation.getLocalUcastMacs().stream()
                                         .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
-                                        .map(mac -> mac.getMacEntryKey())
+                                        .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
                                         .collect(Collectors.toSet()));
                             }
                             function.apply(macs);
@@ -540,7 +550,7 @@ public class ElanL2GatewayUtils {
 
                     @Override
                     public void onFailure(Throwable throwable) {
-                        LOG.error("Failed to read config topology node ", nodeIid);
+                        LOG.error("Failed to read config topology node {}", nodeIid);
                     }
                 }, MoreExecutors.directExecutor());
     }
@@ -578,8 +588,8 @@ public class ElanL2GatewayUtils {
 
             @Override
             public void onFailure(Throwable error) {
-                LOG.warn(String.format("Failed during batch delete of elan [%s] macs from l2gw device [%s]. "
-                        + "Retrying with sequential deletes.", elanName, hwvtepNodeId), error);
+                LOG.warn("Failed during batch delete of elan {} macs from l2gw device {}. "
+                        + "Retrying with sequential deletes.", elanName, hwvtepNodeId, error);
                 if (lstElanMacs != null && !lstElanMacs.isEmpty()) {
                     for (MacAddress mac : lstElanMacs) {
                         HwvtepUtils.deleteRemoteUcastMac(broker, new NodeId(hwvtepNodeId), logicalSwitch, mac);
@@ -612,7 +622,7 @@ public class ElanL2GatewayUtils {
         List<MacAddress> lstMacs = Collections.emptyList();
         Node hwvtepNode = HwvtepUtils.getHwVtepNode(broker, datastoreType, hwvtepNodeId);
         if (hwvtepNode != null) {
-            List<RemoteUcastMacs> remoteUcastMacs = hwvtepNode.getAugmentation(HwvtepGlobalAugmentation.class)
+            List<RemoteUcastMacs> remoteUcastMacs = hwvtepNode.augmentation(HwvtepGlobalAugmentation.class)
                     .getRemoteUcastMacs();
             if (remoteUcastMacs != null && !remoteUcastMacs.isEmpty()) {
                 // Filtering remoteUcastMacs based on the logical switch and
@@ -644,7 +654,7 @@ public class ElanL2GatewayUtils {
 
         List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName, l2GatewayDevice, hwVtepNodeId,
                 logicalSwitchName);
-        List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName, l2GatewayDevice,
+        List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
                 hwVtepNodeId, logicalSwitchName);
 
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
@@ -684,11 +694,10 @@ public class ElanL2GatewayUtils {
                 if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
                     for (LocalUcastMacs localUcastMac : otherDevice.getUcastLocalMacs()) {
                         HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
-                                .createHwvtepPhysicalLocatorAugmentation(
-                                        String.valueOf(otherDevice.getTunnelIp().getValue()));
+                                .createHwvtepPhysicalLocatorAugmentation(otherDevice.getTunnelIp());
                         RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
-                                localUcastMac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault()),
-                                localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
+                            IetfYangUtil.INSTANCE.canonizeMacAddress(localUcastMac.getMacEntryKey()).getValue(),
+                            localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
                         lstRemoteUcastMacs.add(remoteUcastMac);
                     }
                 }
@@ -719,8 +728,6 @@ public class ElanL2GatewayUtils {
      *
      * @param elanName
      *            the elan name
-     * @param l2GatewayDeviceToBeConfigured
-     *            the l2 gateway device to be configured
      * @param hwVtepNodeId
      *            the hw vtep node id
      * @param logicalSwitchName
@@ -728,7 +735,7 @@ public class ElanL2GatewayUtils {
      * @return the elan mac table entries as remote ucast macs
      */
     public List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
-            L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+            NodeId hwVtepNodeId, String logicalSwitchName) {
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
 
         MacTable macTable = ElanUtils.getElanMacTable(broker, elanName);
@@ -751,11 +758,11 @@ public class ElanL2GatewayUtils {
                 continue;
             }
             HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
-                    .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
+                    .createHwvtepPhysicalLocatorAugmentation(dpnTepIp);
             // TODO: Query ARP cache to get IP address corresponding to the
             // MAC
             RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
-                    macEntry.getMacAddress().getValue().toLowerCase(Locale.getDefault()), null /*IpAddress*/,
+                IetfYangUtil.INSTANCE.canonizePhysAddress(macEntry.getMacAddress()).getValue(), null /*IpAddress*/,
                     logicalSwitchName, physLocatorAug);
             lstRemoteUcastMacs.add(remoteUcastMac);
         }
@@ -779,7 +786,7 @@ public class ElanL2GatewayUtils {
                 dpId = rpcResult.getResult().getDpid();
             }
         } catch (InterruptedException | ExecutionException e) {
-            LOG.error("Failed to get the DPN ID for interface {}: {} ", interfaceName, e);
+            LOG.error("Failed to get the DPN ID for interface {}", interfaceName, e);
         }
         return dpId;
     }
@@ -805,30 +812,29 @@ public class ElanL2GatewayUtils {
             return Futures.immediateFailedFuture(new RuntimeException(errMsg));
         }
 
-        WriteTransaction transaction = broker.newWriteOnlyTransaction();
-        for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
-                 .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
-            //Removed the check for checking terminationPoint present in OP or not
-            //for coniguring vlan bindings
-            //As we are not any more dependent on it , plugin takes care of this
-            // with port reconcilation.
-            List<VlanBindings> vlanBindings = new ArrayList<>();
-            if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
-                for (Integer vlanId : deviceInterface.getSegmentationIds()) {
-                    vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, vlanId, logicalSwitchName));
+        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+            for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
+                    .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
+                //Removed the check for checking terminationPoint present in OP or not
+                //for coniguring vlan bindings
+                //As we are not any more dependent on it , plugin takes care of this
+                // with port reconcilation.
+                List<VlanBindings> vlanBindings = new ArrayList<>();
+                if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
+                    for (Integer vlanId : deviceInterface.getSegmentationIds()) {
+                        vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, vlanId, logicalSwitchName));
+                    }
+                } else {
+                    // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
+                    // ID not specified at interface level.
+                    vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
                 }
-            } else {
-                // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
-                // ID not specified at interface level.
-                vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
+                HwvtepUtils.mergeVlanBindings(tx, nodeId, hwVtepDevice.getDeviceName(),
+                        deviceInterface.getInterfaceName(), vlanBindings);
             }
-            HwvtepUtils.mergeVlanBindings(transaction, nodeId, hwVtepDevice.getDeviceName(),
-                    deviceInterface.getInterfaceName(), vlanBindings);
-        }
-        ListenableFuture<Void> future = transaction.submit();
-        LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}", nodeId.getValue(),
-                logicalSwitchName);
-        return future;
+            LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}", nodeId.getValue(),
+                    logicalSwitchName);
+        });
     }
 
     /**
@@ -846,11 +852,10 @@ public class ElanL2GatewayUtils {
      */
     public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String psName,
             String interfaceName, List<VlanBindings> vlanBindings) {
-        WriteTransaction transaction = broker.newWriteOnlyTransaction();
-        HwvtepUtils.mergeVlanBindings(transaction, nodeId, psName, interfaceName, vlanBindings);
-        ListenableFuture<Void> future = transaction.submit();
-        LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
-        return future;
+        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+            HwvtepUtils.mergeVlanBindings(tx, nodeId, psName, interfaceName, vlanBindings);
+            LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
+        });
     }
 
     /**
@@ -873,25 +878,23 @@ public class ElanL2GatewayUtils {
         }
         NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, hwVtepDevice.getDeviceName());
 
-        WriteTransaction transaction = broker.newWriteOnlyTransaction();
-        for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
-                 .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
-            String phyPortName = deviceInterface.getInterfaceName();
-            if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
-                for (Integer vlanId : deviceInterface.getSegmentationIds()) {
-                    HwvtepUtils.deleteVlanBinding(transaction, physicalSwitchNodeId, phyPortName, vlanId);
+        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+            for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
+                    .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
+                String phyPortName = deviceInterface.getInterfaceName();
+                if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
+                    for (Integer vlanId : deviceInterface.getSegmentationIds()) {
+                        HwvtepUtils.deleteVlanBinding(tx, physicalSwitchNodeId, phyPortName, vlanId);
+                    }
+                } else {
+                    // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
+                    // ID not specified at interface level.
+                    HwvtepUtils.deleteVlanBinding(tx, physicalSwitchNodeId, phyPortName, defaultVlanId);
                 }
-            } else {
-                // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
-                // ID not specified at interface level.
-                HwvtepUtils.deleteVlanBinding(transaction, physicalSwitchNodeId, phyPortName, defaultVlanId);
             }
-        }
-        ListenableFuture<Void> future = transaction.submit();
-
-        LOG.info("Deleted Hwvtep VlanBindings from config DS. NodeID: {}, hwVtepDevice: {}, defaultVlanId: {} ",
-                nodeId.getValue(), hwVtepDevice, defaultVlanId);
-        return future;
+            LOG.info("Deleted Hwvtep VlanBindings from config DS. NodeID: {}, hwVtepDevice: {}, defaultVlanId: {} ",
+                    nodeId.getValue(), hwVtepDevice, defaultVlanId);
+        });
     }
 
     /**
@@ -923,13 +926,11 @@ public class ElanL2GatewayUtils {
     /**
      * Gets the l2 gateway connection job key.
      *
-     * @param nodeId
-     *            the node id
      * @param logicalSwitchName
      *            the logical switch name
      * @return the l2 gateway connection job key
      */
-    public static String getL2GatewayConnectionJobKey(String nodeId, String logicalSwitchName) {
+    public static String getL2GatewayConnectionJobKey(String logicalSwitchName) {
         return logicalSwitchName;
     }
 
@@ -961,14 +962,13 @@ public class ElanL2GatewayUtils {
      *            from elan
      * @param elanName
      *            the elan name
-     * @throws ReadFailedException if a read fails
      */
     public void deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
-            String elanName) throws ReadFailedException {
+            String elanName) {
         LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
                 elanName);
 
-        ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
+        ElanInstance elan = elanInstanceCache.get(elanName).orNull();
         if (elan == null) {
             LOG.error("Could not find Elan by name: {}", elanName);
             return;
@@ -979,25 +979,94 @@ public class ElanL2GatewayUtils {
         unInstallL2GwUcastMacFromElanDpns(elan, l2GatewayDevice, localMacs);
     }
 
-    public static void createItmTunnels(ItmRpcService itmRpcService, String hwvtepId, String psName,
-            IpAddress tunnelIp) {
+    public static void createItmTunnels(DataBroker dataBroker, ItmRpcService itmRpcService,
+                                        String hwvtepId, String psName, IpAddress tunnelIp) {
         AddL2GwDeviceInputBuilder builder = new AddL2GwDeviceInputBuilder();
         builder.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID.getValue());
         builder.setNodeId(HwvtepSouthboundUtils.createManagedNodeId(new NodeId(hwvtepId), psName).getValue());
         builder.setIpAddress(tunnelIp);
         try {
-            Future<RpcResult<Void>> result = itmRpcService.addL2GwDevice(builder.build());
-            RpcResult<Void> rpcResult = result.get();
+            deleteStaleTunnelsOfHwvtepInITM(dataBroker, itmRpcService, hwvtepId, psName, tunnelIp);
+            RpcResult<AddL2GwDeviceOutput> rpcResult = itmRpcService.addL2GwDevice(builder.build()).get();
             if (rpcResult.isSuccessful()) {
                 LOG.info("Created ITM tunnels for {}", hwvtepId);
             } else {
-                LOG.error("Failed to create ITM Tunnels: ", rpcResult.getErrors());
+                LOG.error("Failed to create ITM Tunnels: {}", rpcResult.getErrors());
             }
         } catch (InterruptedException | ExecutionException e) {
             LOG.error("RPC to create ITM tunnels failed", e);
         }
     }
 
+    private static void deleteStaleTunnelsOfHwvtepInITM(DataBroker dataBroker,
+                                                        ItmRpcService itmRpcService,
+                                                        String globalNodeId,
+                                                        String psName,
+                                                        IpAddress tunnelIp) {
+        try {
+            Optional<TransportZones> tzonesoptional = readTransportZone(dataBroker);
+            if (!tzonesoptional.isPresent() || tzonesoptional.get().getTransportZone() == null) {
+                return;
+            }
+            String psNodeId = globalNodeId + HwvtepHAUtil.PHYSICALSWITCH + psName;
+            tzonesoptional.get().getTransportZone().stream()
+                .filter(transportZone -> transportZone.getSubnets() != null)
+                .flatMap(transportZone -> transportZone.getSubnets().stream())
+                .filter(subnet -> subnet.getDeviceVteps() != null)
+                .flatMap(subnet -> subnet.getDeviceVteps().stream())
+                .filter(deviceVteps -> Objects.equals(getPsName(deviceVteps), psName)) //get device with same ps name
+                .filter(deviceVteps -> !Objects.equals(psNodeId, deviceVteps.getNodeId())
+                        || !Objects.equals(tunnelIp, deviceVteps.getIpAddress()))//node id or tunnel ip is changed
+                .forEach(deviceVteps -> deleteStaleL2gwTep(dataBroker, itmRpcService, deviceVteps));
+        } catch (ReadFailedException e) {
+            LOG.error("Failed delete stale tunnels for {}", globalNodeId);
+        }
+    }
+
+    private static Optional<TransportZones> readTransportZone(DataBroker dataBroker) throws ReadFailedException {
+        return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.builder(TransportZones.class).build());
+    }
+
+    private static Optional<ElanInstances> readElanInstances(DataBroker dataBroker) throws ReadFailedException {
+        return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
+                InstanceIdentifier.builder(ElanInstances.class).build());
+    }
+
+    private static String getPsName(DeviceVteps deviceVteps) {
+        return HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
+    }
+
+    private static void deleteStaleL2gwTep(DataBroker dataBroker,
+                                           ItmRpcService itmRpcService,
+                                           DeviceVteps deviceVteps) {
+        String psName = HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
+        String globalNodeId = HwvtepHAUtil.convertToGlobalNodeId(deviceVteps.getNodeId());
+        try {
+            LOG.info("Deleting stale tep {} ", deviceVteps);
+            L2GatewayUtils.deleteItmTunnels(itmRpcService, globalNodeId, psName, deviceVteps.getIpAddress());
+            Optional<ElanInstances> optionalElan = readElanInstances(dataBroker);
+            if (!optionalElan.isPresent()) {
+                return;
+            }
+            JdkFutures.addErrorLogging(
+                new ManagedNewTransactionRunnerImpl(dataBroker).callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+                    tx -> {
+                        optionalElan.get().getElanInstance().stream()
+                        .flatMap(elan -> elan.getExternalTeps().stream()
+                                .map(externalTep -> ElanL2GatewayMulticastUtils.buildExternalTepPath(
+                                        elan.getElanInstanceName(), externalTep.getTepIp())))
+                        .filter(externalTepIid -> Objects.equals(
+                                deviceVteps.getIpAddress(), externalTepIid.firstKeyOf(ExternalTeps.class).getTepIp()))
+                        .peek(externalTepIid -> LOG.info("Deleting stale external tep {}", externalTepIid))
+                        .forEach(externalTepIid -> tx.delete(externalTepIid));
+                    }), LOG, "Failed to delete stale external teps {}", deviceVteps);
+            Thread.sleep(10000);//TODO remove the sleep currently it waits for interfacemgr to finish the cleanup
+        } catch (ReadFailedException | InterruptedException e) {
+            LOG.error("Failed to delete stale l2gw tep {}", deviceVteps, e);
+        }
+    }
+
     public static String getNodeIdFromDpnId(BigInteger dpnId) {
         return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
     }
@@ -1030,16 +1099,15 @@ public class ElanL2GatewayUtils {
 
     public void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName, final boolean clearUcast) {
         final Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
-        logicalSwitchDeletedTasks.computeIfAbsent(nodeIdLogicalSwitchNamePair, (key) -> {
-            return scheduler.getScheduledExecutorService().schedule(() -> {
+        logicalSwitchDeletedTasks.computeIfAbsent(nodeIdLogicalSwitchNamePair,
+            (key) -> scheduler.getScheduledExecutorService().schedule(() -> {
                 DeleteLogicalSwitchJob deleteLsJob = new DeleteLogicalSwitchJob(broker,
                         ElanL2GatewayUtils.this, hwvtepNodeId, lsName, clearUcast);
                 jobCoordinator.enqueueJob(deleteLsJob.getJobKey(), deleteLsJob,
                         SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
                 deleteJobs.put(nodeIdLogicalSwitchNamePair, deleteLsJob);
                 logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
-            }, getLogicalSwitchDeleteDelaySecs(), TimeUnit.SECONDS);
-        });
+            }, getLogicalSwitchDeleteDelaySecs(), TimeUnit.SECONDS));
     }
 
     public void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
@@ -1056,12 +1124,13 @@ public class ElanL2GatewayUtils {
     }
 
     @Nonnull
-    public List<DpnInterfaces> getElanDpns(String elanName) {
-        Set<DpnInterfaces> dpnInterfaces = ElanUtils.getElanInvolvedDPNsFromCache(elanName);
-        if (dpnInterfaces == null) {
-            return elanUtils.getElanDPNByName(elanName);
+    public Collection<DpnInterfaces> getElanDpns(String elanName) {
+        Collection<DpnInterfaces> dpnInterfaces = elanInstanceDpnsCache.get(elanName);
+        if (!dpnInterfaces.isEmpty()) {
+            return dpnInterfaces;
         }
-        return new ArrayList<>(dpnInterfaces);
+
+        return elanUtils.getElanDPNByName(elanName);
     }
 
     /**
@@ -1086,11 +1155,11 @@ public class ElanL2GatewayUtils {
         Optional<Node> configNode = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
                 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
         if (configNode.isPresent()) {
-            HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(HwvtepGlobalAugmentation.class);
+            HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(HwvtepGlobalAugmentation.class);
             if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
                 macs.addAll(augmentation.getLocalUcastMacs().stream()
                         .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
-                        .map(mac -> mac.getMacEntryKey())
+                        .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
                         .collect(Collectors.toSet()));
             }
         }