Bulk merge of l2gw changes
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / utils / ElanL2GatewayUtils.java
index 3bf0d79e302e7b8a789f97c55b3c3fd501367f7a..6b612cc1cd4aa9ce3c6e38b04feb04e25edd011a 100644 (file)
@@ -7,10 +7,10 @@
  */
 package org.opendaylight.netvirt.elan.l2gw.utils;
 
-import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
 
-import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -23,6 +23,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -39,19 +40,23 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-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.mdsalutil.cache.InstanceIdDataObjectCache;
 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.caches.CacheProvider;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
+import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
 import org.opendaylight.netvirt.elan.cache.ElanInstanceDpnsCache;
 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
@@ -82,7 +87,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.A
 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;
@@ -95,6 +99,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentationBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
@@ -102,10 +108,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
+import org.opendaylight.yangtools.util.concurrent.FluentFutures;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -139,13 +155,17 @@ public class ElanL2GatewayUtils {
     private final ConcurrentMap<Pair<NodeId, String>, DeleteLogicalSwitchJob> deleteJobs = new ConcurrentHashMap<>();
     private final Scheduler scheduler;
     private final ElanConfig elanConfig;
+    private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
+    private final InstanceIdDataObjectCache<TerminationPoint> portsCache;
 
     @Inject
     public ElanL2GatewayUtils(DataBroker broker, ElanDmacUtils elanDmacUtils, ElanItmUtils elanItmUtils,
-            ElanClusterUtils elanClusterUtils, OdlInterfaceRpcService interfaceManagerRpcService,
-            JobCoordinator jobCoordinator, ElanUtils elanUtils,
-            Scheduler scheduler, ElanConfig elanConfig, ElanInstanceCache elanInstanceCache,
-            ElanInstanceDpnsCache elanInstanceDpnsCache) {
+                              ElanClusterUtils elanClusterUtils, OdlInterfaceRpcService interfaceManagerRpcService,
+                              JobCoordinator jobCoordinator, ElanUtils elanUtils,
+                              Scheduler scheduler, ElanConfig elanConfig, ElanInstanceCache elanInstanceCache,
+                              ElanInstanceDpnsCache elanInstanceDpnsCache,
+                              ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
+                              CacheProvider cacheProvider) {
         this.broker = broker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
         this.elanDmacUtils = elanDmacUtils;
@@ -158,6 +178,13 @@ public class ElanL2GatewayUtils {
         this.elanConfig = elanConfig;
         this.elanInstanceCache = elanInstanceCache;
         this.elanInstanceDpnsCache = elanInstanceDpnsCache;
+        this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
+        InstanceIdentifier<TerminationPoint> iid = InstanceIdentifier.create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
+                .child(Node.class).child(TerminationPoint.class);
+        LOG.info("termination point iid: {}", iid);
+        portsCache = new InstanceIdDataObjectCache<>(TerminationPoint.class, broker,
+                LogicalDatastoreType.CONFIGURATION, iid, cacheProvider);
     }
 
     @PreDestroy
@@ -166,7 +193,7 @@ public class ElanL2GatewayUtils {
 
     public long getLogicalSwitchDeleteDelaySecs() {
         return elanConfig.getL2gwLogicalSwitchDelaySecs() != null
-                ? elanConfig.getL2gwLogicalSwitchDelaySecs() : DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS;
+                ? elanConfig.getL2gwLogicalSwitchDelaySecs().toJava() : DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS;
     }
 
     /**
@@ -176,6 +203,7 @@ public class ElanL2GatewayUtils {
      *            the lst elan interface names
      * @return the list
      */
+    /*
     public List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
         List<PhysAddress> result = new ArrayList<>();
         for (String interfaceName : lstElanInterfaceNames) {
@@ -187,7 +215,7 @@ public class ElanL2GatewayUtils {
             }
         }
         return result;
-    }
+    }*/
 
     /**
      * Check if phy locator already exists in remote mcast entry.
@@ -236,7 +264,13 @@ public class ElanL2GatewayUtils {
                 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
         RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
                 new MacAddress(ElanConstants.UNKNOWN_DMAC));
-        return HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId, remoteMcastMacsKey);
+        try {
+            return HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId, remoteMcastMacsKey);
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("readRemoteMcastMac: Exception while reading LogicalSwitches DS for the nodeId {}, "
+                    + "logicalSwitchName {}", nodeId.getValue(), logicalSwitch, e);
+        }
+        return null;
     }
 
     /**
@@ -249,9 +283,11 @@ public class ElanL2GatewayUtils {
      *            the mac addresses
      */
     public void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
-        String elanName = elanInstance.getElanInstanceName();
-        for (L2GatewayDevice l2GatewayDevice : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
-            removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(), elanName, macAddresses);
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
+        for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
+            removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
+                    elanInstance.getElanInstanceName(), macAddresses);
         }
     }
 
@@ -264,16 +300,30 @@ public class ElanL2GatewayUtils {
      *            the mac addresses
      * @return the listenable future
      */
-    private ListenableFuture<Void> removeRemoteUcastMacsFromExternalDevice(String deviceNodeId,
+    private FluentFuture<? extends @NonNull CommitInfo> removeRemoteUcastMacsFromExternalDevice(String deviceNodeId,
             String logicalSwitchName, List<PhysAddress> macAddresses) {
         NodeId nodeId = new NodeId(deviceNodeId);
 
         // TODO (eperefr)
         List<MacAddress> lstMac = macAddresses.stream().filter(Objects::nonNull).map(
-            physAddress -> new MacAddress(physAddress.getValue())).collect(Collectors.toList());
+            physAddress -> new MacAddress(physAddress.getValue().toLowerCase(Locale.getDefault())))
+            .collect(Collectors.toList());
         return HwvtepUtils.deleteRemoteUcastMacs(broker, nodeId, logicalSwitchName, lstMac);
     }
 
+    @Nullable
+    public ElanInstance getElanInstanceForUcastLocalMac(LocalUcastMacs localUcastMac) {
+        Optional<LogicalSwitches> lsOpc = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL,
+                (InstanceIdentifier<LogicalSwitches>) localUcastMac.getLogicalSwitchRef().getValue());
+        if (lsOpc.isPresent()) {
+            LogicalSwitches ls = lsOpc.get();
+            // Logical switch name is Elan name
+            String elanName = getElanFromLogicalSwitch(ls.getHwvtepNodeName().getValue());
+            return elanInstanceCache.get(elanName).orElse(null);
+        }
+        return null;
+    }
+
     /**
      * Install external device local macs in dpn.
      *
@@ -286,7 +336,7 @@ public class ElanL2GatewayUtils {
      * @param interfaceName
      *            the interface name
      */
-    public void installL2gwDeviceMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan,
+    public void installL2gwDeviceMacsInDpn(Uint64 dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan,
             String interfaceName) {
         L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
                 l2gwDeviceNodeId.getValue());
@@ -310,20 +360,21 @@ public class ElanL2GatewayUtils {
      * @param interfaceName
      *            the interface name
      */
-    public void installDmacFlowsOnDpn(BigInteger dpnId, L2GatewayDevice l2gwDevice, ElanInstance elan,
-            String interfaceName) {
+    public List<ListenableFuture<Void>> installDmacFlowsOnDpn(Uint64 dpnId, L2GatewayDevice l2gwDevice,
+                                                              ElanInstance elan, String interfaceName) {
         String elanName = elan.getElanInstanceName();
-
+        List<ListenableFuture<Void>> fts = new ArrayList<>();
         Collection<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
-        if (!l2gwDeviceLocalMacs.isEmpty()) {
+        if (l2gwDeviceLocalMacs != null && !l2gwDeviceLocalMacs.isEmpty()) {
             for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
-                elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(dpnId, l2gwDevice.getHwvtepNodeId(),
-                        elan.getElanTag(), ElanUtils.getVxlanSegmentationId(elan),
-                        localUcastMac.getMacEntryKey().getValue(), elanName, interfaceName);
+                fts.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(dpnId, l2gwDevice.getHwvtepNodeId(),
+                        elan.getElanTag().toJava(), ElanUtils.getVxlanSegmentationId(elan).longValue(),
+                        localUcastMac.getMacEntryKey().getValue(), elanName, interfaceName));
             }
             LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
                     l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
         }
+        return fts;
     }
 
     /**
@@ -336,9 +387,15 @@ public class ElanL2GatewayUtils {
      * @param interfaceName
      *            the interface name
      */
-    public void installElanL2gwDevicesLocalMacsInDpn(BigInteger dpnId, ElanInstance elan, String interfaceName) {
-        for (L2GatewayDevice l2gwDevice : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elan.getElanInstanceName())) {
-            installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
+    public void installElanL2gwDevicesLocalMacsInDpn(Uint64 dpnId, ElanInstance elan, String interfaceName) {
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elan.getElanInstanceName());
+        if (elanL2GwDevicesFromCache != null) {
+            for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
+                installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
+            }
+        } else {
+            LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
         }
     }
 
@@ -347,32 +404,34 @@ public class ElanL2GatewayUtils {
         final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
         final String elanInstanceName = elan.getElanInstanceName();
         final Collection<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
-        Collection<L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInstanceName);
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elanInstanceName);
 
         // Retrieve all participating DPNs in this Elan. Populate this MAC in
         // DMAC table.
         // Looping through all DPNs in order to add/remove mac flows in their
         // DMAC table
-        if (elanDpns.size() > 0 || elanL2GwDevices.size() > 0) {
+        if (elanDpns.size() > 0 || elanL2GwDevices.values().size() > 0) {
             String jobKey = elanInstanceName + ":" + macToBeAdded;
             IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
             List<PhysAddress> macList = Lists.newArrayList(new PhysAddress(macToBeAdded));
 
             elanClusterUtils.runOnlyInOwnerNode(jobKey, "install l2gw macs in dmac table", () -> {
                 if (doesLocalUcastMacExistsInCache(extL2GwDevice, localUcastMacs)) {
-                    List<ListenableFuture<Void>> futures = new ArrayList<>();
+                    List<ListenableFuture<?>> futures = new ArrayList<>();
                     for (DpnInterfaces elanDpn : elanDpns) {
                         futures.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(elanDpn.getDpId(),
-                                extDeviceNodeId, elan.getElanTag(), ElanUtils.getVxlanSegmentationId(elan),
+                                extDeviceNodeId, elan.getElanTag().toJava(),
+                                ElanUtils.getVxlanSegmentationId(elan).longValue(),
                                 macToBeAdded, elanInstanceName, interfaceName));
                     }
-                    for (L2GatewayDevice otherDevice : elanL2GwDevices) {
+                    for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
                         if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
                                 && !areMLAGDevices(extL2GwDevice, otherDevice)) {
                             final String hwvtepId = otherDevice.getHwvtepNodeId();
                             final String logicalSwitchName = elanInstanceName;
-                            futures.add(HwvtepUtils.installUcastMacs(
-                                    broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp));
+                            HwvtepUtils.installUcastMacs(
+                                    broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
                         }
                     }
                     return futures;
@@ -447,10 +506,10 @@ public class ElanL2GatewayUtils {
             elanClusterUtils.runOnlyInOwnerNode(elan.getElanInstanceName() + ":" + mac.getValue(),
                     "delete remote ucast macs in elan DPNs", () -> {
                     for (DpnInterfaces elanDpn : elanDpns) {
-                        BigInteger dpnId = elanDpn.getDpId();
-                        result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
-                                l2GwDevice.getHwvtepNodeId(),
-                                IetfYangUtil.INSTANCE.canonizeMacAddress(mac).getValue()));
+                        Uint64 dpnId = elanDpn.getDpId();
+                        result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag().toJava(), dpnId,
+                            l2GwDevice.getHwvtepNodeId(),
+                            IetfYangUtil.INSTANCE.canonizeMacAddress(mac).getValue()));
                     }
                     return result;
                 });
@@ -465,21 +524,21 @@ public class ElanL2GatewayUtils {
      * @param dpnId
      *            the dpn id
      */
-    public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId) {
-        Collection<L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
-        if (elanL2GwDevices.isEmpty()) {
+    public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final Uint64 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 = elanInstanceCache.get(elanName).orNull();
+        final ElanInstance elan = elanInstanceCache.get(elanName).orElse(null);
         if (elan == null) {
             LOG.error("Could not find Elan by name: {}", elanName);
             return;
         }
         LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
 
-        final Long elanTag = elan.getElanTag();
-        for (final L2GatewayDevice l2GwDevice : elanL2GwDevices) {
+        final Long elanTag = elan.getElanTag().toJava();
+        for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
             getL2GwDeviceLocalMacsAndRunCallback(elan.getElanInstanceName(), l2GwDevice, (localMacs) -> {
                 for (MacAddress mac : localMacs) {
                     String jobKey = elanName + ":" + mac.getValue();
@@ -501,7 +560,7 @@ public class ElanL2GatewayUtils {
         Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
         if (!lstUcastLocalMacs.isEmpty()) {
             macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
-                    .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.ENGLISH)))
+                    .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault())))
                     .collect(Collectors.toList()));
         }
 
@@ -514,10 +573,10 @@ public class ElanL2GatewayUtils {
                         if (configNode != null && configNode.isPresent()) {
                             HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(
                                     HwvtepGlobalAugmentation.class);
-                            if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
-                                macs.addAll(augmentation.getLocalUcastMacs().stream()
+                            if (augmentation != null && augmentation.nonnullLocalUcastMacs() != null) {
+                                macs.addAll(augmentation.nonnullLocalUcastMacs().values().stream()
                                         .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
-                                        .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
+                                        .map(mac -> mac.getMacEntryKey())
                                         .collect(Collectors.toSet()));
                             }
                             function.apply(macs);
@@ -531,7 +590,7 @@ public class ElanL2GatewayUtils {
                 }, MoreExecutors.directExecutor());
     }
 
-    private static String getLogicalSwitchName(LocalUcastMacs mac) {
+    private String getLogicalSwitchName(LocalUcastMacs mac) {
         return ((InstanceIdentifier<LogicalSwitches>)mac.getLogicalSwitchRef().getValue())
                 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
     }
@@ -547,38 +606,18 @@ public class ElanL2GatewayUtils {
      *            the elan name
      * @return the listenable future
      */
-    public ListenableFuture<Void> deleteElanMacsFromL2GatewayDevice(String hwvtepNodeId, String elanName) {
-        String logicalSwitch = getLogicalSwitchFromElan(elanName);
+    public FluentFuture<? extends @NonNull CommitInfo> deleteElanMacsFromL2GatewayDevice(String hwvtepNodeId,
+        String elanName) {
 
+        String logicalSwitch = getLogicalSwitchFromElan(elanName);
         List<MacAddress> lstElanMacs = getRemoteUcastMacs(new NodeId(hwvtepNodeId), logicalSwitch,
                 LogicalDatastoreType.CONFIGURATION);
-        ListenableFuture<Void> future = HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(hwvtepNodeId),
-                logicalSwitch, lstElanMacs);
-
-        Futures.addCallback(future, new FutureCallback<Void>() {
-            @Override
-            public void onSuccess(Void noarg) {
-                LOG.trace("Successful in batch deletion of elan [{}] macs from l2gw device [{}]", elanName,
-                        hwvtepNodeId);
-            }
-
-            @Override
-            public void onFailure(Throwable 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);
-                    }
-                }
-            }
-        }, MoreExecutors.directExecutor());
-
         if (LOG.isDebugEnabled()) {
             List<String> elanMacs = lstElanMacs.stream().map(MacAddress::getValue).collect(Collectors.toList());
             LOG.debug("Deleting elan [{}] macs from node [{}]. Deleted macs = {}", elanName, hwvtepNodeId, elanMacs);
         }
-        return future;
+        return HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(hwvtepNodeId),
+                logicalSwitch, lstElanMacs);
     }
 
     /**
@@ -596,10 +635,15 @@ public class ElanL2GatewayUtils {
     public List<MacAddress> getRemoteUcastMacs(NodeId hwvtepNodeId, String logicalSwitch,
             LogicalDatastoreType datastoreType) {
         List<MacAddress> lstMacs = Collections.emptyList();
-        Node hwvtepNode = HwvtepUtils.getHwVtepNode(broker, datastoreType, hwvtepNodeId);
+        Node hwvtepNode = null;
+        try {
+            hwvtepNode = HwvtepUtils.getHwVtepNode(broker, datastoreType, hwvtepNodeId);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Exception While Reading Node {}", hwvtepNodeId, e);
+        }
         if (hwvtepNode != null) {
-            List<RemoteUcastMacs> remoteUcastMacs = hwvtepNode.augmentation(HwvtepGlobalAugmentation.class)
-                    .getRemoteUcastMacs();
+            Collection<RemoteUcastMacs> remoteUcastMacs = hwvtepNode.augmentation(HwvtepGlobalAugmentation.class)
+                .nonnullRemoteUcastMacs().values();
             if (remoteUcastMacs != null && !remoteUcastMacs.isEmpty()) {
                 // Filtering remoteUcastMacs based on the logical switch and
                 // forming a list of MacAddress
@@ -623,7 +667,7 @@ public class ElanL2GatewayUtils {
      *            the l2 gateway device which has to be configured
      * @return the listenable future
      */
-    public ListenableFuture<Void> installElanMacsInL2GatewayDevice(String elanName,
+    public FluentFuture<? extends CommitInfo> installElanMacsInL2GatewayDevice(String elanName,
             L2GatewayDevice l2GatewayDevice) {
         String logicalSwitchName = getLogicalSwitchFromElan(elanName);
         NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
@@ -636,7 +680,8 @@ public class ElanL2GatewayUtils {
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
         lstRemoteUcastMacs.addAll(lstElanMacTableEntries);
 
-        ListenableFuture<Void> future = HwvtepUtils.addRemoteUcastMacs(broker, hwVtepNodeId, lstRemoteUcastMacs);
+        FluentFuture<? extends CommitInfo> future = HwvtepUtils.addRemoteUcastMacs(broker, hwVtepNodeId,
+            lstRemoteUcastMacs);
 
         LOG.info("Added RemoteUcastMacs entries [{}] in config DS. NodeID: {}, LogicalSwitch: {}",
                 lstRemoteUcastMacs.size(), hwVtepNodeId.getValue(), logicalSwitchName);
@@ -659,19 +704,23 @@ public class ElanL2GatewayUtils {
     public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
             L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
+        ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+                .getInvolvedL2GwDevices(elanName);
 
-        for (L2GatewayDevice otherDevice : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
-            if (l2GatewayDeviceToBeConfigured.getHwvtepNodeId().equals(otherDevice.getHwvtepNodeId())) {
-                continue;
-            }
-            if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
-                for (LocalUcastMacs localUcastMac : otherDevice.getUcastLocalMacs()) {
-                    HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
-                            .createHwvtepPhysicalLocatorAugmentation(otherDevice.getTunnelIp());
-                    RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
-                        IetfYangUtil.INSTANCE.canonizeMacAddress(localUcastMac.getMacEntryKey()).getValue(),
-                        localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
-                    lstRemoteUcastMacs.add(remoteUcastMac);
+        if (elanL2GwDevicesFromCache != null) {
+            for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
+                if (l2GatewayDeviceToBeConfigured.getHwvtepNodeId().equals(otherDevice.getHwvtepNodeId())) {
+                    continue;
+                }
+                if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
+                    for (LocalUcastMacs localUcastMac : otherDevice.getUcastLocalMacs()) {
+                        HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
+                                .createHwvtepPhysicalLocatorAugmentation(otherDevice.getTunnelIp().stringValue());
+                        RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
+                                localUcastMac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault()),
+                                localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
+                        lstRemoteUcastMacs.add(remoteUcastMac);
+                    }
                 }
             }
         }
@@ -716,8 +765,8 @@ public class ElanL2GatewayUtils {
             return lstRemoteUcastMacs;
         }
 
-        for (MacEntry macEntry : macTable.getMacEntry()) {
-            BigInteger dpnId = getDpidFromInterface(macEntry.getInterface());
+        for (MacEntry macEntry : macTable.nonnullMacEntry().values()) {
+            Uint64 dpnId = getDpidFromInterface(macEntry.getInterface());
             if (dpnId == null) {
                 LOG.error("DPN ID not found for interface {}", macEntry.getInterface());
                 continue;
@@ -734,7 +783,7 @@ public class ElanL2GatewayUtils {
             // TODO: Query ARP cache to get IP address corresponding to the
             // MAC
             RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
-                IetfYangUtil.INSTANCE.canonizePhysAddress(macEntry.getMacAddress()).getValue(), null /*IpAddress*/,
+                    IetfYangUtil.INSTANCE.canonizePhysAddress(macEntry.getMacAddress()).getValue(), null /*IpAddress*/,
                     logicalSwitchName, physLocatorAug);
             lstRemoteUcastMacs.add(remoteUcastMac);
         }
@@ -748,9 +797,8 @@ public class ElanL2GatewayUtils {
      *            the interface name
      * @return the dpid from interface
      */
-    @Nullable
-    public BigInteger getDpidFromInterface(String interfaceName) {
-        BigInteger dpId = null;
+    public Uint64 getDpidFromInterface(String interfaceName) {
+        Uint64 dpId = null;
         Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService
                 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
         try {
@@ -759,11 +807,33 @@ 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;
     }
 
+    /**
+     * Update vlan bindings in l2 gateway device.
+     *
+     * @param nodeId
+     *            the node id
+     * @param psName
+     *            the physical switch name
+     * @param interfaceName
+     *            the interface in physical switch
+     * @param vlanBindings
+     *            the vlan bindings to be configured
+     * @return the listenable future
+     */
+    public FluentFuture<?> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String psName,
+                                                                      String interfaceName,
+                                                                      List<VlanBindings> vlanBindings) {
+        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+            mergeVlanBindings(tx, nodeId, psName, interfaceName, vlanBindings, false);
+            LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
+        });
+    }
+
     /**
      * Update vlan bindings in l2 gateway device.
      *
@@ -777,58 +847,93 @@ public class ElanL2GatewayUtils {
      *            the default vlan id
      * @return the listenable future
      */
-    public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String logicalSwitchName,
+    public FluentFuture<?> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String logicalSwitchName,
             Devices hwVtepDevice, Integer defaultVlanId) {
         if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
             String errMsg = "HwVtepDevice is null or interfaces are empty.";
             LOG.error(errMsg);
-            return Futures.immediateFailedFuture(new RuntimeException(errMsg));
+            return FluentFutures.immediateFailedFluentFuture(new RuntimeException(errMsg));
         }
-
         return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
             for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
-                    .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
+                .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice
+                .nonnullInterfaces().values()) {
                 //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()) {
+                if (deviceInterface.getSegmentationIds() != null && !deviceInterface
+                    .getSegmentationIds().isEmpty()) {
                     for (Integer vlanId : deviceInterface.getSegmentationIds()) {
-                        vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, vlanId, logicalSwitchName));
+                        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));
+                    vlanBindings.add(HwvtepSouthboundUtils
+                        .createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
+                }
+
+                TerminationPointKey tpKey = new TerminationPointKey(
+                    new TpId(deviceInterface.getInterfaceName()));
+                InstanceIdentifier<TerminationPoint> portIid = HwvtepSouthboundUtils
+                    .createTerminationPointId(HwvtepSouthboundUtils.createManagedNodeId(nodeId,
+                        hwVtepDevice.getDeviceName()), tpKey);
+
+                try {
+                    boolean createParent = false;
+                    if (!portsCache.get(portIid).isPresent()) {
+                        //create port
+                        //pass additional flag
+                        createParent = true;
+                    }
+                    mergeVlanBindings(tx, nodeId, hwVtepDevice.getDeviceName(),
+                        deviceInterface.getInterfaceName(), vlanBindings, createParent);
+                } catch (ReadFailedException e) {
+                    LOG.error("Read Failed for PortIid {} {}", portIid, e.getMessage());
                 }
-                HwvtepUtils.mergeVlanBindings(tx, nodeId, hwVtepDevice.getDeviceName(),
-                        deviceInterface.getInterfaceName(), vlanBindings);
             }
-            LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}", nodeId.getValue(),
-                    logicalSwitchName);
+            LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}",
+                nodeId.getValue(),logicalSwitchName);
         });
     }
 
-    /**
-     * Update vlan bindings in l2 gateway device.
-     *
-     * @param nodeId
-     *            the node id
-     * @param psName
-     *            the physical switch name
-     * @param interfaceName
-     *            the interface in physical switch
-     * @param vlanBindings
-     *            the vlan bindings to be configured
-     * @return the listenable future
-     */
-    public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String psName,
-            String interfaceName, List<VlanBindings> vlanBindings) {
-        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
-            HwvtepUtils.mergeVlanBindings(tx, nodeId, psName, interfaceName, vlanBindings);
-            LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
-        });
+    private static void mergeVlanBindings(TypedWriteTransaction tx, NodeId nodeId, String phySwitchName,
+                                         String phyPortName, List<VlanBindings> vlanBindings,
+                                         boolean createParent) {
+        NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, phySwitchName);
+        mergeVlanBindings(tx, physicalSwitchNodeId, phyPortName, vlanBindings, createParent);
+    }
+
+    private static void mergeVlanBindings(TypedWriteTransaction tx, NodeId physicalSwitchNodeId,
+                                         String phyPortName, List<VlanBindings> vlanBindings,
+                                         boolean createParent) {
+        HwvtepPhysicalPortAugmentation phyPortAug = (new HwvtepPhysicalPortAugmentationBuilder())
+                .setHwvtepNodeName(new HwvtepNodeName(phyPortName)).setVlanBindings(vlanBindings).build();
+        InstanceIdentifier<HwvtepPhysicalPortAugmentation> iid = HwvtepSouthboundUtils
+                .createPhysicalPortInstanceIdentifier(physicalSwitchNodeId, phyPortName);
+        if (createParent) {
+            InstanceIdentifier<TerminationPoint> iid2 =
+                    createPhysicalPortInstanceIdentifier(physicalSwitchNodeId, phyPortName);
+            TerminationPointBuilder tpBuilder = new TerminationPointBuilder().setTpId(new TpId(phyPortName))
+                    .addAugmentation(phyPortAug);
+            tx.merge(iid2, tpBuilder.build());
+        } else {
+            tx.merge(iid, phyPortAug);
+        }
+    }
+
+    public static InstanceIdentifier<TerminationPoint> createPhysicalPortInstanceIdentifier(
+            NodeId physicalSwitchNodeId, String phyPortName) {
+        return createInstanceIdentifier(physicalSwitchNodeId).child(TerminationPoint.class,
+                new TerminationPointKey(new TpId(phyPortName)));
+    }
+
+    public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
+        return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
+                new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID)).child(Node.class, new NodeKey(nodeId));
     }
 
     /**
@@ -842,7 +947,7 @@ public class ElanL2GatewayUtils {
      *            the default vlan id
      * @return the listenable future
      */
-    public ListenableFuture<Void> deleteVlanBindingsFromL2GatewayDevice(NodeId nodeId, Devices hwVtepDevice,
+    public ListenableFuture<?> deleteVlanBindingsFromL2GatewayDevice(NodeId nodeId, Devices hwVtepDevice,
             Integer defaultVlanId) {
         if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
             String errMsg = "HwVtepDevice is null or interfaces are empty.";
@@ -853,7 +958,7 @@ public class ElanL2GatewayUtils {
 
         return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
             for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
-                    .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
+                .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.nonnullInterfaces().values()) {
                 String phyPortName = deviceInterface.getInterfaceName();
                 if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
                     for (Integer vlanId : deviceInterface.getSegmentationIds()) {
@@ -870,6 +975,19 @@ public class ElanL2GatewayUtils {
         });
     }
 
+    /**
+     * Gets the elan name from logical switch name.
+     *
+     * @param logicalSwitchName
+     *            the logical switch name
+     * @return the elan name from logical switch name
+     */
+    public static String getElanFromLogicalSwitch(String logicalSwitchName) {
+        // Assuming elan name is same as logical switch name
+        String elanName = logicalSwitchName;
+        return elanName;
+    }
+
     /**
      * Gets the logical switch name from elan name.
      *
@@ -905,8 +1023,8 @@ public class ElanL2GatewayUtils {
         InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
         try {
             return SingleTransactionDataBroker
-                    .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, interfaceId).orNull();
-        } catch (ReadFailedException e) {
+                    .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, interfaceId).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
             // TODO remove this, and propagate ReadFailedException instead of re-throw RuntimeException
             LOG.error("getInterfaceFromConfigDS({}) failed", interfaceKey, e);
             throw new RuntimeException(e);
@@ -929,7 +1047,7 @@ public class ElanL2GatewayUtils {
         LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
                 elanName);
 
-        ElanInstance elan = elanInstanceCache.get(elanName).orNull();
+        ElanInstance elan = elanInstanceCache.get(elanName).orElse(null);
         if (elan == null) {
             LOG.error("Could not find Elan by name: {}", elanName);
             return;
@@ -972,24 +1090,20 @@ public class ElanL2GatewayUtils {
             String psNodeId = globalNodeId + HwvtepHAUtil.PHYSICALSWITCH + psName;
             tzonesoptional.get().nonnullTransportZone().stream()
                 .filter(zone -> zone.getDeviceVteps() != null)
-                .flatMap(zone -> zone.getDeviceVteps().stream())
+                .flatMap(zone -> new ArrayList<>(zone.nonnullDeviceVteps().values()).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) {
+        } catch (ExecutionException | InterruptedException 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 {
+    private static Optional<TransportZones> readTransportZone(DataBroker dataBroker) throws ExecutionException,
+            InterruptedException {
         return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
-                InstanceIdentifier.builder(ElanInstances.class).build());
+            InstanceIdentifier.builder(TransportZones.class).build());
     }
 
     private static String getPsName(DeviceVteps deviceVteps) {
@@ -997,8 +1111,8 @@ public class ElanL2GatewayUtils {
     }
 
     private static void deleteStaleL2gwTep(DataBroker dataBroker,
-                                           ItmRpcService itmRpcService,
-                                           DeviceVteps deviceVteps) {
+                                            ItmRpcService itmRpcService,
+                                            DeviceVteps deviceVteps) {
         String psName = HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
         String globalNodeId = HwvtepHAUtil.convertToGlobalNodeId(deviceVteps.getNodeId());
         try {
@@ -1010,8 +1124,8 @@ public class ElanL2GatewayUtils {
             }
             LoggingFutures.addErrorLogging(
                 new ManagedNewTransactionRunnerImpl(dataBroker).callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
-                    tx -> optionalElan.get().nonnullElanInstance().stream()
-                        .flatMap(elan -> elan.nonnullExternalTeps().stream()
+                    tx -> optionalElan.get().nonnullElanInstance().values().stream()
+                        .flatMap(elan -> elan.nonnullExternalTeps().values().stream()
                             .map(externalTep -> ElanL2GatewayMulticastUtils.buildExternalTepPath(
                                 elan.getElanInstanceName(), externalTep.getTepIp())))
                         .filter(externalTepIid -> Objects.equals(
@@ -1020,30 +1134,68 @@ public class ElanL2GatewayUtils {
                         .forEach(tx::delete)), 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) {
+        } catch (ExecutionException | InterruptedException e) {
             LOG.error("Failed to delete stale l2gw tep {}", deviceVteps, e);
         }
     }
 
-    public void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId,
+    private static Optional<ElanInstances> readElanInstances(DataBroker dataBroker) throws ExecutionException,
+        InterruptedException {
+        return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
+            InstanceIdentifier.builder(ElanInstances.class).build());
+    }
+    /*public static void createItmTunnels(IpAddress tunnelIp, DataBroker dataBroker) {
+        ManagedNewTransactionRunner txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
+        txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
+            InstanceIdentifier<L2GatewayIp> iid = InstanceIdentifier
+                .builder(L2GatewayIpList.class)
+                .child(L2GatewayIp.class, new L2GatewayIpKey(tunnelIp))
+                .build();
+            tx.put(iid, new L2GatewayIpBuilder().setIpAddress(tunnelIp).build());
+        });
+    }
+
+    public static FluentFuture<? extends CommitInfo> deleteItmTunnels(
+            IpAddress tunnelIp, DataBroker dataBroker) {
+        ManagedNewTransactionRunner txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
+        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(LogicalDatastoreType.CONFIGURATION, tx -> {
+            InstanceIdentifier<L2GatewayIp> iid = InstanceIdentifier
+                .builder(L2GatewayIpList.class)
+                .child(L2GatewayIp.class, new L2GatewayIpKey(tunnelIp))
+                .build();
+            tx.delete(iid);
+        });
+    }*/
+
+    public static String getNodeIdFromDpnId(BigInteger dpnId) {
+        return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
+    }
+
+    public void scheduleAddDpnMacInExtDevices(String elanName, Uint64 dpId,
             List<PhysAddress> staticMacAddresses) {
-        for (final L2GatewayDevice externalDevice : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
+        ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
+        for (final L2GatewayDevice externalDevice : elanDevices.values()) {
             scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
         }
     }
 
-    public void scheduleAddDpnMacsInExtDevice(final String elanName, BigInteger dpId,
-            final List<PhysAddress> staticMacAddresses, final L2GatewayDevice externalDevice) {
+    public FluentFuture<? extends @NonNull CommitInfo> scheduleAddDpnMacsInExtDevice(final String elanName, Uint64 dpId,
+                                                                      final List<PhysAddress> staticMacAddresses,
+                                                                      final L2GatewayDevice externalDevice) {
         NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
         final IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpId, nodeId);
         LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
         if (dpnTepIp == null) {
             LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
-            return;
+            return null;
         }
-
+        //TerminationPointKey tpKey = HwvtepSouthboundUtils.getTerminationPointKey(dpnTepIp
+        // .getIpv4Address().getValue());
+        //InstanceIdentifier<TerminationPoint> tpPath = HwvtepSouthboundUtils.createTerminationPointId(nodeId, tpKey);
         //TODO: to  be batched in genius
-        HwvtepUtils.installUcastMacs(broker, externalDevice.getHwvtepNodeId(), staticMacAddresses, elanName, dpnTepIp);
+        return HwvtepUtils.installUcastMacs(broker, externalDevice.getHwvtepNodeId(), staticMacAddresses,
+                elanName, dpnTepIp);
+
     }
 
     public void scheduleDeleteLogicalSwitch(NodeId hwvtepNodeId, String lsName) {
@@ -1094,28 +1246,36 @@ public class ElanL2GatewayUtils {
      *            the l2gw device
      * @return the l2 gw device local macs
      */
-    public Collection<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
+    public List<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
+        Set<MacAddress> macs = new HashSet<>();
         if (l2gwDevice == null) {
-            return Collections.emptyList();
+            return Collections.EMPTY_LIST;
         }
         Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
-        Set<MacAddress> macs = new HashSet<>();
-        if (!lstUcastLocalMacs.isEmpty()) {
+        if (lstUcastLocalMacs != null && !lstUcastLocalMacs.isEmpty()) {
             macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
-                    .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.ENGLISH)))
+                    .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault())))
                     .collect(Collectors.toList()));
         }
-        Optional<Node> configNode = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
+        Optional<Node> configNode = null;
+        try {
+            configNode = SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION,
                 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
+        } catch (ExecutionException | InterruptedException e) {
+            LOG.error("getL2GwDeviceLocalMacs: Exception while reading l2gwDevice DS for the elan {}, l2gwDevice {}",
+                elanName, l2gwDevice, e);
+            return Collections.emptyList();
+        }
+
         if (configNode.isPresent()) {
             HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(HwvtepGlobalAugmentation.class);
             if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
-                macs.addAll(augmentation.getLocalUcastMacs().stream()
+                macs.addAll(augmentation.nonnullLocalUcastMacs().values().stream()
                         .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
-                        .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
+                        .map(mac -> mac.getMacEntryKey())
                         .collect(Collectors.toSet()));
             }
         }
-        return macs;
+        return new ArrayList<>(macs);
     }
 }