NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / utils / ElanL2GatewayMulticastUtils.java
index 6563f72bc455ed1f92a5b76d0b250c9a31beb3a2..c68a1d747d4cc907dbb2d899306909e4bffe7fee 100644 (file)
@@ -7,25 +7,31 @@
  */
 package org.opendaylight.netvirt.elan.l2gw.utils;
 
-import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlan;
+import static java.util.Collections.emptyList;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
 
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
-import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
-import java.util.concurrent.ConcurrentMap;
-import javax.annotation.Nonnull;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
 import javax.inject.Inject;
 import javax.inject.Singleton;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.infra.Datastore;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.TypedWriteTransaction;
 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
@@ -34,10 +40,18 @@ import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
 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.LoggingFutures;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+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.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
+import org.opendaylight.netvirt.elan.l2gw.jobs.McastUpdateJob;
+import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
 import org.opendaylight.netvirt.elan.utils.ElanConstants;
 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
 import org.opendaylight.netvirt.elan.utils.ElanUtils;
+import org.opendaylight.netvirt.elan.utils.Scheduler;
 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
@@ -50,10 +64,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.Desi
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
 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.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
 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.elan.instances.elan.instance.ExternalTepsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
 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;
@@ -68,6 +86,7 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.
 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.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.Uint64;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -89,29 +108,46 @@ public class ElanL2GatewayMulticastUtils {
     private final ElanUtils elanUtils;
     private final IMdsalApiManager mdsalManager;
     private final IInterfaceManager interfaceManager;
+    private final ElanRefUtil elanRefUtil;
+    private final ElanClusterUtils elanClusterUtils;
+    private final Scheduler scheduler;
+
 
     @Inject
-    public ElanL2GatewayMulticastUtils(DataBroker broker, ElanItmUtils elanItmUtils, JobCoordinator jobCoordinator,
-            ElanUtils elanUtils, IMdsalApiManager mdsalManager, IInterfaceManager interfaceManager) {
-        this.broker = broker;
-        this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
+    public ElanL2GatewayMulticastUtils(ElanItmUtils elanItmUtils, ElanUtils elanUtils, IMdsalApiManager mdsalManager,
+                                       IInterfaceManager interfaceManager, ElanRefUtil elanRefUtil) {
+        this.elanRefUtil = elanRefUtil;
+        this.broker = elanRefUtil.getDataBroker();
+        this.txRunner = new ManagedNewTransactionRunnerImpl(elanRefUtil.getDataBroker());
         this.elanItmUtils = elanItmUtils;
-        this.jobCoordinator = jobCoordinator;
+        this.jobCoordinator = elanRefUtil.getJobCoordinator();
         this.elanUtils = elanUtils;
         this.mdsalManager = mdsalManager;
         this.interfaceManager = interfaceManager;
+        this.elanClusterUtils = elanRefUtil.getElanClusterUtils();
+        this.scheduler = elanRefUtil.getScheduler();
     }
 
     /**
      * Handle mcast for elan l2 gw device add.
      * @param elanName the elan name
-     * @param elanInstance elanInstace
      * @param device the device
-     * @return the listenable future
      */
-    public ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, ElanInstance elanInstance,
-            L2GatewayDevice device) {
-        return updateMcastMacsForAllElanDevices(elanName, elanInstance, device, true/* updateThisDevice */);
+    public void handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
+        InstanceIdentifier<ExternalTeps> tepPath = buildExternalTepPath(elanName, device.getTunnelIp());
+        LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+            tx -> tx.put(tepPath, buildExternalTeps(device))), LOG, "Failed to write to config external tep {}",
+            tepPath);
+        updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
+    }
+
+    public static InstanceIdentifier<ExternalTeps> buildExternalTepPath(String elan, IpAddress tepIp) {
+        return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elan))
+                .child(ExternalTeps.class, new ExternalTepsKey(tepIp)).build();
+    }
+
+    protected ExternalTeps buildExternalTeps(L2GatewayDevice device) {
+        return new ExternalTepsBuilder().setTepIp(device.getTunnelIp()).setNodeid(device.getHwvtepNodeId()).build();
     }
 
     /**
@@ -121,15 +157,11 @@ public class ElanL2GatewayMulticastUtils {
      *
      * @param elanName
      *            the elan to be updated
-     * @return the listenable future
      */
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
-        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-            for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
-                prepareRemoteMcastMacUpdateOnDevice(tx, elanName, device);
-            }
-        });
+    public void updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
+        for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
+            prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
+        }
     }
 
     public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
@@ -144,21 +176,64 @@ public class ElanL2GatewayMulticastUtils {
      *            the elan name
      * @param device
      *            the device
-     * @return the listenable future
      */
-    public ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
-        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(
-            tx -> prepareRemoteMcastMacUpdateOnDevice(tx, elanName, device));
+    public void updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
+        prepareRemoteMcastMacUpdateOnDevice(elanName, device, false, null);
     }
 
-    public void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
-                                                           L2GatewayDevice device) {
-        ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
-                .getInvolvedL2GwDevices(elanName);
-        List<DpnInterfaces> dpns = elanUtils.getElanDPNByName(elanName);
+    public ListenableFuture<Void> prepareRemoteMcastMacUpdateOnDevice(String elanName, L2GatewayDevice device,
+                                                                      boolean addCase, IpAddress removedDstTep) {
+        NodeId dstNodeId = new NodeId(device.getHwvtepNodeId());
+        RemoteMcastMacs existingMac = null;
+        try {
+            Optional<RemoteMcastMacs> mac  = elanRefUtil.getConfigMcastCache().get(getRemoteMcastIid(dstNodeId,
+                    elanName));
+            if (mac.isPresent()) {
+                existingMac = mac.get();
+            }
+        } catch (ReadFailedException e) {
+            LOG.error("Failed to read iid for elan {}", elanName, e);
+        }
+
+        if (!addCase && removedDstTep != null) {
+            LOG.debug(" RemoteMcast update delete tep {} of elan {} ", removedDstTep.getIpv4Address().getValue(),
+                    elanName);
+            //incase of dpn flap immediately after cluster reboot just remove its tep alone
+            if (existingMac != null) {
+                return deleteLocatorFromMcast(elanName, dstNodeId, removedDstTep, existingMac);
+            }
+        }
+        Collection<L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
+        Collection<DpnInterfaces> dpns = elanRefUtil.getElanInstanceDpnsCache().get(elanName);
         List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
         List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
-        preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+        return prepareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps, addCase);
+    }
+
+    private ListenableFuture<Void> deleteLocatorFromMcast(String elanName, NodeId dstNodeId,
+                                                          IpAddress removedDstTep,
+                                                          RemoteMcastMacs existingMac) {
+
+        LocatorSet tobeDeleted = buildLocatorSet(dstNodeId, removedDstTep);
+        RemoteMcastMacsBuilder newMacBuilder = new RemoteMcastMacsBuilder(existingMac);
+
+        List<LocatorSet> locatorList = new ArrayList<>(existingMac.nonnullLocatorSet());
+        locatorList.remove(tobeDeleted);
+        newMacBuilder.setLocatorSet(locatorList);
+        RemoteMcastMacs mac = newMacBuilder.build();
+        //configMcastCache.add(macIid, mac);
+        InstanceIdentifier<RemoteMcastMacs> macIid = HwvtepSouthboundUtils
+                .createRemoteMcastMacsInstanceIdentifier(dstNodeId, existingMac.key());
+        return ResourceBatchingManager.getInstance().put(
+                ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY, macIid, mac);
+    }
+
+    LocatorSet buildLocatorSet(NodeId nodeId, IpAddress tepIp) {
+        HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+                .createHwvtepPhysicalLocatorAugmentation(tepIp.stringValue());
+        HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
+                HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
+        return new LocatorSetBuilder().setLocatorRef(phyLocRef).build();
     }
 
     /**
@@ -168,71 +243,50 @@ public class ElanL2GatewayMulticastUtils {
      *
      * @param elanName
      *            the elan name
-     * @param elanInstance
-     *            the ElanInstance
      * @param device
      *            the device
      * @param updateThisDevice
      *            the update this device
-     * @return the listenable future
      */
-    private ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, ElanInstance elanInstance,
-            L2GatewayDevice device, boolean updateThisDevice) {
-
-        SettableFuture<Void> ft = SettableFuture.create();
-        ft.set(null);
-
-        updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
-
-        List<DpnInterfaces> dpns = elanUtils.getElanDPNByName(elanName);
-
-        ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
-                .getInvolvedL2GwDevices(elanName);
-
-        List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
-        List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
-        // if (allTepIps.size() < 2) {
-        // LOG.debug("no other devices are found in the elan {}", elanName);
-        // return ft;
-        // }
-
-        return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-            if (updateThisDevice) {
-                preapareRemoteMcastMacEntry(tx, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
-            }
-
-            // TODO: Need to revisit below logic as logical switches might not be
-            // present to configure RemoteMcastMac entry
-            for (L2GatewayDevice otherDevice : devices.values()) {
-                if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
-                    preapareRemoteMcastMacEntry(tx, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
-                }
-            }
-        });
-
+    public void updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
+                                                                    boolean updateThisDevice) {
+        if (updateThisDevice) {
+            McastUpdateJob.updateAllMcastsForConnectionAdd(elanName, this, elanClusterUtils);
+        } else {
+            McastUpdateJob.updateAllMcastsForConnectionDelete(elanName, this, elanClusterUtils, device);
+        }
     }
 
-    public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
+    public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, boolean createCase,
+            TypedWriteTransaction<Datastore.Configuration> confTx) {
         List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
         for (DpnInterfaces dpn : dpns) {
-            setupElanBroadcastGroups(elanInfo, dpn.getDpId());
+            setupStandardElanBroadcastGroups(elanInfo, null, dpn.getDpId(), createCase, confTx);
         }
     }
 
-    public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
-        setupElanBroadcastGroups(elanInfo, null, dpnId);
+    public void setupElanBroadcastGroups(ElanInstance elanInfo, Uint64 dpnId,
+            TypedWriteTransaction<Datastore.Configuration> confTx) {
+        setupElanBroadcastGroups(elanInfo, null, dpnId, confTx);
+    }
+
+    public void setupElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, Uint64 dpnId,
+                                         TypedWriteTransaction<Datastore.Configuration> confTx) {
+        setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
+        setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
     }
 
-    public void setupElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
-        setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
-        setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId);
+    public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, Uint64 dpnId,
+                                                 TypedWriteTransaction<Datastore.Configuration> confTx) {
+        setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, true, confTx);
     }
 
-    public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
+    public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
+            Uint64 dpnId, boolean createCase, TypedWriteTransaction<Datastore.Configuration> confTx) {
         List<Bucket> listBucket = new ArrayList<>();
         int bucketId = 0;
         int actionKey = 0;
-        Long elanTag = elanInfo.getElanTag();
+        Long elanTag = elanInfo.getElanTag().toJava();
         List<Action> listAction = new ArrayList<>();
         listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
         listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
@@ -244,13 +298,18 @@ public class ElanL2GatewayMulticastUtils {
         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
                 MDSALUtil.buildBucketLists(listBucket));
         LOG.trace("Installing the remote BroadCast Group:{}", group);
-        mdsalManager.syncInstallGroup(dpnId, group);
+        if (createCase) {
+            elanUtils.syncUpdateGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND, confTx);
+        } else {
+            mdsalManager.addGroup(confTx, dpnId, group);
+        }
     }
 
-    public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId) {
-        EtreeInstance etreeInstance = elanInfo.getAugmentation(EtreeInstance.class);
+    public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
+            Uint64 dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
+        EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
         if (etreeInstance != null) {
-            long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
+            long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue().toJava();
             List<Bucket> listBucket = new ArrayList<>();
             int bucketId = 0;
             int actionKey = 0;
@@ -266,14 +325,15 @@ public class ElanL2GatewayMulticastUtils {
             Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
                     MDSALUtil.buildBucketLists(listBucket));
             LOG.trace("Installing the remote BroadCast Group:{}", group);
-            mdsalManager.syncInstallGroup(dpnId, group);
+            mdsalManager.addGroup(confTx, dpnId, group);
         }
     }
 
-    private DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
+    @Nullable
+    private static DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, Uint64 dpnId) {
         if (elanDpns != null) {
-            for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
-                if (dpnInterface.getDpId().equals(dpnId)) {
+            for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces()) {
+                if (Objects.equals(dpnInterface.getDpId(), dpnId)) {
                     return dpnInterface;
                 }
             }
@@ -282,11 +342,11 @@ public class ElanL2GatewayMulticastUtils {
     }
 
     private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
-            DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
+            DpnInterfaces dpnInterfaces, Uint64 dpnId, int bucketId) {
         DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
         if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
                 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
-            return Collections.emptyList();
+            return emptyList();
         }
         List<Bucket> listBucketInfo = new ArrayList<>();
         for (String interfaceName : currDpnInterfaces.getInterfaces()) {
@@ -302,38 +362,37 @@ public class ElanL2GatewayMulticastUtils {
         return listBucketInfo;
     }
 
-    @Nonnull
-    public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
-                                                int bucketId, long elanTag) {
+    @NonNull
+    public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
+                                                Uint64 dpnId, int bucketId, long elanTag) {
         List<Bucket> listBucketInfo = new ArrayList<>();
         ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
 
-        if (isVxlan(elanInfo)) {
+        if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
+            // Adding 270000 to avoid collision between LPort and elan for broadcast group actions
             listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
-                    elanUtils.isOpenstackVniSemanticsEnforced() ? elanInfo.getSegmentationId() : elanTag));
+                    elanUtils.isOpenstackVniSemanticsEnforced()
+                            ? ElanUtils.getVxlanSegmentationId(elanInfo).longValue() : elanTag
+                            + ElanConstants.ELAN_TAG_ADDEND));
         }
         listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
-            getNextAvailableBucketId(listBucketInfo.size())));
-        listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId,
-            getNextAvailableBucketId(listBucketInfo.size())));
+                getNextAvailableBucketId(listBucketInfo.size())));
         listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
                 getNextAvailableBucketId(listBucketInfo.size())));
         return listBucketInfo;
     }
 
-    public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
+    public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, Uint64 dpnId,
             int bucketId) {
         List<Bucket> listBucketInfo = new ArrayList<>();
-        ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
-                .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
-        for (L2GatewayDevice device : map.values()) {
+        for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInfo.getElanInstanceName())) {
             String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
                     device.getHwvtepNodeId());
             if (interfaceName == null) {
                 continue;
             }
             List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
-                    ElanUtils.getVxlanSegmentationId(elanInfo));
+                    ElanUtils.getVxlanSegmentationId(elanInfo).longValue(), true);
             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
                     MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
             bucketId++;
@@ -341,22 +400,36 @@ public class ElanL2GatewayMulticastUtils {
         return listBucketInfo;
     }
 
-    public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, BigInteger dpnId,
+    public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, Uint64 dpnId,
             int bucketId) {
-        List<Bucket> listBucketInfo = new ArrayList<>();
-        List<ExternalTeps> teps = elanInfo.getExternalTeps();
+        ElanInstance operElanInstance = null;
+        try {
+            operElanInstance = new SingleTransactionDataBroker(broker).syncReadOptional(
+                LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, elanInfo.key())
+                    .build()).orElse(null);
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to read elan instance operational path {}", elanInfo, e);
+            return emptyList();
+        }
+        if (operElanInstance == null) {
+            return emptyList();
+        }
+        List<ExternalTeps> teps = operElanInstance.getExternalTeps();
         if (teps == null || teps.isEmpty()) {
-            return listBucketInfo;
+            return emptyList();
         }
+        List<Bucket> listBucketInfo = new ArrayList<>();
         for (ExternalTeps tep : teps) {
+            String externalTep = tep.getNodeid() != null ? tep.getNodeid() : tep.getTepIp().toString();
             String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
-                    tep.getTepIp().toString());
+                    externalTep);
             if (interfaceName == null) {
                 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
                 continue;
             }
             List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
-                    elanInfo.getSegmentationId());
+                    ElanUtils.getVxlanSegmentationId(elanInfo).longValue(), false);
             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
                     MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
             bucketId++;
@@ -364,21 +437,23 @@ public class ElanL2GatewayMulticastUtils {
         return listBucketInfo;
     }
 
-    private int getNextAvailableBucketId(int bucketSize) {
+    private static int getNextAvailableBucketId(int bucketSize) {
         return bucketSize + 1;
     }
 
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
+    private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, Uint64 dpnId, int bucketId,
             long elanTagOrVni) {
         List<Bucket> listBucketInfo = new ArrayList<>();
         if (elanDpns != null) {
-            for (DpnInterfaces dpnInterface : elanDpns.getDpnInterfaces()) {
-                if (elanUtils.isDpnPresent(dpnInterface.getDpId()) && !Objects.equals(dpnInterface.getDpId(), dpnId)
-                        && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
+            for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces())  {
+                if (!Objects.equals(dpnInterface.getDpId(), dpnId) && dpnInterface.getInterfaces() != null
+                        && !dpnInterface.getInterfaces().isEmpty()) {
                     try {
                         List<Action> listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId,
                                 dpnInterface.getDpId(), elanTagOrVni);
+                        LOG.trace("configuring broadcast group for elan {} for source DPN {} and destination DPN {} "
+                                + "with actions {}", elanTagOrVni, dpnId, dpnInterface.getDpId(), listActionInfo);
                         if (listActionInfo.isEmpty()) {
                             continue;
                         }
@@ -398,8 +473,6 @@ public class ElanL2GatewayMulticastUtils {
     /**
      * Update remote mcast mac.
      *
-     * @param transaction
-     *            the transaction
      * @param elanName
      *            the elan name
      * @param device
@@ -410,9 +483,9 @@ public class ElanL2GatewayMulticastUtils {
      *            the l2 gw devices tep ips
      * @return the write transaction
      */
-    private void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName,
-                                                    L2GatewayDevice device, List<IpAddress> dpnsTepIps,
-                                                    List<IpAddress> l2GwDevicesTepIps) {
+    private ListenableFuture<Void> prepareRemoteMcastMacEntry(String elanName,
+                                             L2GatewayDevice device, List<IpAddress> dpnsTepIps,
+                                             List<IpAddress> l2GwDevicesTepIps, boolean addCase) {
         NodeId nodeId = new NodeId(device.getHwvtepNodeId());
 
         ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
@@ -426,17 +499,17 @@ public class ElanL2GatewayMulticastUtils {
                 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
 
                 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
-                        .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
+                        .createHwvtepPhysicalLocatorAugmentation(dhcpDesignatedSwitchTepIp);
                 InstanceIdentifier<TerminationPoint> iid =
                         HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug);
                 TerminationPoint terminationPoint = new TerminationPointBuilder()
-                                .setKey(HwvtepSouthboundUtils.getTerminationPointKey(phyLocatorAug))
+                                .withKey(HwvtepSouthboundUtils.getTerminationPointKey(phyLocatorAug))
                                 .addAugmentation(HwvtepPhysicalLocatorAugmentation.class, phyLocatorAug).build();
                 ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
                         iid, terminationPoint);
                 LOG.info("Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} "
                         + "as physical locator, elan {}", device.getHwvtepNodeId(),
-                        String.valueOf(dhcpDesignatedSwitchTepIp.getValue()), elanName);
+                        dhcpDesignatedSwitchTepIp.stringValue(), elanName);
             } else {
                 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
                         device.getHwvtepNodeId(), elanName);
@@ -446,16 +519,14 @@ public class ElanL2GatewayMulticastUtils {
             remoteTepIps.add(dhcpDesignatedSwitchTepIp);
         }
         String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
-        putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
         LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
                 remoteTepIps);
+        return putRemoteMcastMac(nodeId, logicalSwitchName, remoteTepIps, addCase);
     }
 
     /**
      * Put remote mcast mac in config DS.
      *
-     * @param transaction
-     *            the transaction
      * @param nodeId
      *            the node id
      * @param logicalSwitchName
@@ -463,12 +534,12 @@ public class ElanL2GatewayMulticastUtils {
      * @param tepIps
      *            the tep ips
      */
-    private static void putRemoteMcastMac(WriteTransaction transaction, NodeId nodeId, String logicalSwitchName,
-            ArrayList<IpAddress> tepIps) {
+    private ListenableFuture<Void> putRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
+            ArrayList<IpAddress> tepIps, boolean addCase) {
         List<LocatorSet> locators = new ArrayList<>();
         for (IpAddress tepIp : tepIps) {
             HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
-                    .createHwvtepPhysicalLocatorAugmentation(String.valueOf(tepIp.getValue()));
+                    .createHwvtepPhysicalLocatorAugmentation(tepIp);
             HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
                     HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
             locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
@@ -476,14 +547,47 @@ public class ElanL2GatewayMulticastUtils {
 
         HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
                 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
-        RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder()
+        RemoteMcastMacs newRemoteMcastMac = new RemoteMcastMacsBuilder()
                 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
                 .setLocatorSet(locators).build();
         InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
-                remoteMcastMac.getKey());
-        ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
-                iid, remoteMcastMac);
+                newRemoteMcastMac.key());
+        RemoteMcastMacs existingRemoteMcastMac = null;
+        try {
+            Optional<RemoteMcastMacs> mac  = elanRefUtil.getConfigMcastCache().get(iid);
+            if (mac.isPresent()) {
+                existingRemoteMcastMac = mac.get();
+            }
+        } catch (ReadFailedException e) {
+            LOG.error("Failed to read iid {}", iid, e);
+        }
 
+        if (addCase && areLocatorsAlreadyConfigured(existingRemoteMcastMac, newRemoteMcastMac)) {
+            return Futures.immediateFuture(null);
+        }
+
+        return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
+                iid, newRemoteMcastMac);
+
+    }
+
+    private boolean areLocatorsAlreadyConfigured(RemoteMcastMacs existingMac, RemoteMcastMacs newMac) {
+        if (existingMac == null) {
+            return false;
+        }
+        Set existingLocators = new HashSet<>(existingMac.getLocatorSet());
+        List newLocators = newMac.getLocatorSet();
+        return existingLocators.containsAll(newLocators);
+    }
+
+    private InstanceIdentifier<RemoteMcastMacs> getRemoteMcastIid(NodeId nodeId, String logicalSwitchName) {
+        HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
+                .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
+        RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder()
+                .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
+                .build();
+        return HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
+                remoteMcastMac.key());
     }
 
     /**
@@ -495,7 +599,7 @@ public class ElanL2GatewayMulticastUtils {
      *            the dpns
      * @return the all tep ips of dpns and devices
      */
-    private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
+    private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, Collection<DpnInterfaces> dpns) {
         List<IpAddress> tepIps = new ArrayList<>();
         for (DpnInterfaces dpn : dpns) {
             IpAddress internalTunnelIp = elanItmUtils.getSourceDpnTepIp(dpn.getDpId(),
@@ -514,9 +618,9 @@ public class ElanL2GatewayMulticastUtils {
      *            the devices
      * @return the all tep ips of l2 gw devices
      */
-    private static List<IpAddress> getAllTepIpsOfL2GwDevices(ConcurrentMap<String, L2GatewayDevice> devices) {
+    private static List<IpAddress> getAllTepIpsOfL2GwDevices(Collection<L2GatewayDevice> devices) {
         List<IpAddress> tepIps = new ArrayList<>();
-        for (L2GatewayDevice otherDevice : devices.values()) {
+        for (L2GatewayDevice otherDevice : devices) {
             // There is no need to add the same tep ip to the list.
             if (!tepIps.contains(otherDevice.getTunnelIp())) {
                 tepIps.add(otherDevice.getTunnelIp());
@@ -530,19 +634,19 @@ public class ElanL2GatewayMulticastUtils {
      *
      * @param elanName
      *            the elan instance name
-     * @param elanInstance
-     *            the ElanInstance
      * @param l2GatewayDevice
      *            the l2 gateway device
      * @return the listenable future
      */
-    public List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(String elanName,
-            ElanInstance elanInstance, L2GatewayDevice l2GatewayDevice) {
-        ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(
-                elanName, elanInstance, l2GatewayDevice, false/* updateThisDevice */);
-        ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
+    public List<FluentFuture<?>> handleMcastForElanL2GwDeviceDelete(String elanName,
+                                                                           L2GatewayDevice l2GatewayDevice) {
+        FluentFuture<?> deleteTepFuture =
+            txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                tx -> tx.delete(buildExternalTepPath(elanName, l2GatewayDevice.getTunnelIp())));
+        updateMcastMacsForAllElanDevices(elanName, l2GatewayDevice, false/* updateThisDevice */);
+        FluentFuture<?> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
                 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
-        return Arrays.asList(updateMcastMacsFuture, deleteRemoteMcastMacFuture);
+        return Arrays.asList(deleteRemoteMcastMacFuture, deleteTepFuture);
     }
 
     /**
@@ -554,7 +658,7 @@ public class ElanL2GatewayMulticastUtils {
      *            the logical switch name
      * @return the listenable future
      */
-    private ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
+    public FluentFuture<? extends @NonNull CommitInfo> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
         InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
                 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
         RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
@@ -584,7 +688,7 @@ public class ElanL2GatewayMulticastUtils {
         DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
                 elanInstanceName);
         if (desgSwitch != null) {
-            tepIp = elanItmUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
+            tepIp = elanItmUtils.getSourceDpnTepIp(Uint64.valueOf(desgSwitch.getDpId()),
                     new NodeId(l2GwDevice.getHwvtepNodeId()));
         }
         return tepIp;
@@ -601,11 +705,22 @@ public class ElanL2GatewayMulticastUtils {
      */
     public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
             String elanInstanceName) {
-        InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
+        try {
+            InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
                 .builder(DesignatedSwitchesForExternalTunnels.class)
-                .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
+                .child(DesignatedSwitchForTunnel.class,
+                    new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
                 .build();
-        return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier).orNull();
+            return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier)
+                .orElse(null);
+        } catch (ExecutionException e) {
+            LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}",
+                elanInstanceName, tunnelIp, e);
+        } catch (InterruptedException e) {
+            LOG.error("Exception while retriving DesignatedSwitch for elan {} and tunnel {}",
+                elanInstanceName, tunnelIp, e);
+        }
+        return null;
     }
 
 }