update mcast only from eos singleton leader node
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / utils / ElanL2GatewayMulticastUtils.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.elan.l2gw.utils;
9
10 import static java.util.Collections.emptyList;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.netvirt.elan.utils.ElanUtils.isVxlanNetworkOrVxlanSegment;
13
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.math.BigInteger;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.Collection;
19 import java.util.List;
20 import java.util.Objects;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.eclipse.jdt.annotation.NonNull;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.infra.Datastore;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
31 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
32 import org.opendaylight.genius.infra.TypedWriteTransaction;
33 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
36 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
37 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
38 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
39 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
40 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
41 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
42 import org.opendaylight.netvirt.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
43 import org.opendaylight.netvirt.elan.l2gw.jobs.McastUpdateJob;
44 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
45 import org.opendaylight.netvirt.elan.utils.ElanConstants;
46 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
47 import org.opendaylight.netvirt.elan.utils.ElanUtils;
48 import org.opendaylight.netvirt.elan.utils.Scheduler;
49 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
50 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInstance;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstanceKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTepsKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
79 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
81 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86 /**
87  * The utility class to handle ELAN L2 Gateway related to multicast.
88  */
89 @Singleton
90 public class ElanL2GatewayMulticastUtils {
91
92     /** The Constant LOG. */
93     private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayMulticastUtils.class);
94
95     /** The broker. */
96     private final DataBroker broker;
97     private final ManagedNewTransactionRunner txRunner;
98
99     private final ElanItmUtils elanItmUtils;
100     private final JobCoordinator jobCoordinator;
101     private final ElanUtils elanUtils;
102     private final IMdsalApiManager mdsalManager;
103     private final IInterfaceManager interfaceManager;
104     private final ElanClusterUtils elanClusterUtils;
105     private final Scheduler scheduler;
106
107     @Inject
108     public ElanL2GatewayMulticastUtils(DataBroker broker, ElanItmUtils elanItmUtils, JobCoordinator jobCoordinator,
109                                        ElanUtils elanUtils, IMdsalApiManager mdsalManager,
110                                        IInterfaceManager interfaceManager, ElanClusterUtils elanClusterUtils,
111                                        Scheduler scheduler) {
112         this.broker = broker;
113         this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
114         this.elanItmUtils = elanItmUtils;
115         this.jobCoordinator = jobCoordinator;
116         this.elanUtils = elanUtils;
117         this.mdsalManager = mdsalManager;
118         this.interfaceManager = interfaceManager;
119         this.elanClusterUtils = elanClusterUtils;
120         this.scheduler = scheduler;
121     }
122
123     /**
124      * Handle mcast for elan l2 gw device add.
125      * @param elanName the elan name
126      * @param device the device
127      */
128     public void handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
129         InstanceIdentifier<ExternalTeps> tepPath = buildExternalTepPath(elanName, device.getTunnelIp());
130         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
131             tx -> tx.put(tepPath, buildExternalTeps(device))), LOG, "Failed to write to config external tep {}",
132             tepPath);
133         updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
134     }
135
136     public static InstanceIdentifier<ExternalTeps> buildExternalTepPath(String elan, IpAddress tepIp) {
137         return InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, new ElanInstanceKey(elan))
138                 .child(ExternalTeps.class, new ExternalTepsKey(tepIp)).build();
139     }
140
141     protected ExternalTeps buildExternalTeps(L2GatewayDevice device) {
142         return new ExternalTepsBuilder().setTepIp(device.getTunnelIp()).setNodeid(device.getHwvtepNodeId()).build();
143     }
144
145     /**
146      * Updates the remote mcast mac table for all the devices in this elan
147      * includes all the dpn tep ips and other devices tep ips in broadcast
148      * locator set.
149      *
150      * @param elanName
151      *            the elan to be updated
152      */
153     public void updateRemoteMcastMacOnElanL2GwDevices(String elanName) {
154         for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
155             prepareRemoteMcastMacUpdateOnDevice(elanName, device);
156         }
157     }
158
159     public void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
160         HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(this, elanName,device);
161         jobCoordinator.enqueueJob(job.getJobKey(), job);
162     }
163
164     /**
165      * Update remote mcast mac on elan l2 gw device.
166      *
167      * @param elanName
168      *            the elan name
169      * @param device
170      *            the device
171      */
172     public void updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
173         prepareRemoteMcastMacUpdateOnDevice(elanName, device);
174     }
175
176     public ListenableFuture<Void> prepareRemoteMcastMacUpdateOnDevice(String elanName, L2GatewayDevice device) {
177         Collection<L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
178         List<DpnInterfaces> dpns = elanUtils.getElanDPNByName(elanName);
179         List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
180         List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
181         return prepareRemoteMcastMacEntry(elanName, device, dpnsTepIps, l2GwDevicesTepIps);
182     }
183
184     /**
185      * Update mcast macs for this elan.
186      * for all dpns in this elan  recompute and update broadcast group
187      * for all l2gw devices in this elan recompute and update remote mcast mac entry
188      *
189      * @param elanName
190      *            the elan name
191      * @param device
192      *            the device
193      * @param updateThisDevice
194      *            the update this device
195      */
196     public void updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
197                                                                     boolean updateThisDevice) {
198         if (updateThisDevice) {
199             McastUpdateJob.updateAllMcastsForConnectionAdd(elanName, this, elanClusterUtils);
200         } else {
201             McastUpdateJob.updateAllMcastsForConnectionDelete(elanName, this, elanClusterUtils, device);
202         }
203     }
204
205     public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo,
206             TypedWriteTransaction<Datastore.Configuration> confTx) {
207         List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
208         for (DpnInterfaces dpn : dpns) {
209             setupElanBroadcastGroups(elanInfo, dpn.getDpId(), confTx);
210         }
211     }
212
213     public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId,
214             TypedWriteTransaction<Datastore.Configuration> confTx) {
215         setupElanBroadcastGroups(elanInfo, null, dpnId, confTx);
216     }
217
218     public void setupElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, BigInteger dpnId,
219             TypedWriteTransaction<Datastore.Configuration> confTx) {
220         setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
221         setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
222     }
223
224     public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
225             BigInteger dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
226         List<Bucket> listBucket = new ArrayList<>();
227         int bucketId = 0;
228         int actionKey = 0;
229         Long elanTag = elanInfo.getElanTag();
230         List<Action> listAction = new ArrayList<>();
231         listAction.add(new ActionGroup(ElanUtils.getElanLocalBCGId(elanTag)).buildAction(++actionKey));
232         listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
233                 MDSALUtil.WATCH_GROUP));
234         bucketId++;
235         List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId, elanTag);
236         listBucket.addAll(listBucketInfoRemote);
237         long groupId = ElanUtils.getElanRemoteBCGId(elanTag);
238         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
239                 MDSALUtil.buildBucketLists(listBucket));
240         LOG.trace("Installing the remote BroadCast Group:{}", group);
241         mdsalManager.addGroup(confTx, dpnId, group);
242     }
243
244     public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
245             BigInteger dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
246         EtreeInstance etreeInstance = elanInfo.augmentation(EtreeInstance.class);
247         if (etreeInstance != null) {
248             long etreeLeafTag = etreeInstance.getEtreeLeafTagVal().getValue();
249             List<Bucket> listBucket = new ArrayList<>();
250             int bucketId = 0;
251             int actionKey = 0;
252             List<Action> listAction = new ArrayList<>();
253             listAction.add(new ActionGroup(ElanUtils.getEtreeLeafLocalBCGId(etreeLeafTag)).buildAction(++actionKey));
254             listBucket.add(MDSALUtil.buildBucket(listAction, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT,
255                     MDSALUtil.WATCH_GROUP));
256             bucketId++;
257             List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnInterfaces, dpnId, bucketId,
258                     etreeLeafTag);
259             listBucket.addAll(listBucketInfoRemote);
260             long groupId = ElanUtils.getEtreeLeafRemoteBCGId(etreeLeafTag);
261             Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
262                     MDSALUtil.buildBucketLists(listBucket));
263             LOG.trace("Installing the remote BroadCast Group:{}", group);
264             mdsalManager.addGroup(confTx, dpnId, group);
265         }
266     }
267
268     @Nullable
269     private static DpnInterfaces getDpnInterfaces(ElanDpnInterfacesList elanDpns, BigInteger dpnId) {
270         if (elanDpns != null) {
271             for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces()) {
272                 if (Objects.equals(dpnInterface.getDpId(), dpnId)) {
273                     return dpnInterface;
274                 }
275             }
276         }
277         return null;
278     }
279
280     private List<Bucket> getRemoteBCGroupExternalPortBuckets(ElanDpnInterfacesList elanDpns,
281             DpnInterfaces dpnInterfaces, BigInteger dpnId, int bucketId) {
282         DpnInterfaces currDpnInterfaces = dpnInterfaces != null ? dpnInterfaces : getDpnInterfaces(elanDpns, dpnId);
283         if (currDpnInterfaces == null || !elanUtils.isDpnPresent(currDpnInterfaces.getDpId())
284                 || currDpnInterfaces.getInterfaces() == null || currDpnInterfaces.getInterfaces().isEmpty()) {
285             return emptyList();
286         }
287         List<Bucket> listBucketInfo = new ArrayList<>();
288         for (String interfaceName : currDpnInterfaces.getInterfaces()) {
289             if (interfaceManager.isExternalInterface(interfaceName)) {
290                 List<Action> listActionInfo = elanItmUtils.getExternalPortItmEgressAction(interfaceName);
291                 if (!listActionInfo.isEmpty()) {
292                     listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
293                             MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
294                     bucketId++;
295                 }
296             }
297         }
298         return listBucketInfo;
299     }
300
301     @NonNull
302     public List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
303                                                 BigInteger dpnId, int bucketId, long elanTag) {
304         List<Bucket> listBucketInfo = new ArrayList<>();
305         ElanDpnInterfacesList elanDpns = elanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
306
307         if (isVxlanNetworkOrVxlanSegment(elanInfo)) {
308             listBucketInfo.addAll(getRemoteBCGroupTunnelBuckets(elanDpns, dpnId, bucketId,
309                     elanUtils.isOpenstackVniSemanticsEnforced()
310                             ? ElanUtils.getVxlanSegmentationId(elanInfo) : elanTag));
311         }
312         listBucketInfo.addAll(getRemoteBCGroupExternalPortBuckets(elanDpns, dpnInterfaces, dpnId,
313                 getNextAvailableBucketId(listBucketInfo.size())));
314         listBucketInfo.addAll(getRemoteBCGroupBucketsOfElanExternalTeps(elanInfo, dpnId,
315                 getNextAvailableBucketId(listBucketInfo.size())));
316         return listBucketInfo;
317     }
318
319     public List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
320             int bucketId) {
321         List<Bucket> listBucketInfo = new ArrayList<>();
322         for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInfo.getElanInstanceName())) {
323             String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
324                     device.getHwvtepNodeId());
325             if (interfaceName == null) {
326                 continue;
327             }
328             List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
329                     ElanUtils.getVxlanSegmentationId(elanInfo), true);
330             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
331                     MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
332             bucketId++;
333         }
334         return listBucketInfo;
335     }
336
337     public List<Bucket> getRemoteBCGroupBucketsOfElanExternalTeps(ElanInstance elanInfo, BigInteger dpnId,
338             int bucketId) {
339         ElanInstance operElanInstance = null;
340         try {
341             operElanInstance = new SingleTransactionDataBroker(broker).syncReadOptional(
342                 LogicalDatastoreType.OPERATIONAL,
343                 InstanceIdentifier.builder(ElanInstances.class).child(ElanInstance.class, elanInfo.key())
344                     .build()).orNull();
345         } catch (ReadFailedException e) {
346             LOG.error("Failed to read elan instance operational path {}", elanInfo, e);
347             return emptyList();
348         }
349         if (operElanInstance == null) {
350             return emptyList();
351         }
352         List<ExternalTeps> teps = operElanInstance.getExternalTeps();
353         if (teps == null || teps.isEmpty()) {
354             return emptyList();
355         }
356         List<Bucket> listBucketInfo = new ArrayList<>();
357         for (ExternalTeps tep : teps) {
358             String externalTep = tep.getNodeid() != null ? tep.getNodeid() : tep.getTepIp().toString();
359             String interfaceName = elanItmUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
360                     externalTep);
361             if (interfaceName == null) {
362                 LOG.error("Could not get interface name to ext tunnel {} {}", dpnId, tep.getTepIp());
363                 continue;
364             }
365             List<Action> listActionInfo = elanItmUtils.buildTunnelItmEgressActions(interfaceName,
366                     ElanUtils.getVxlanSegmentationId(elanInfo), false);
367             listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
368                     MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
369             bucketId++;
370         }
371         return listBucketInfo;
372     }
373
374     private static int getNextAvailableBucketId(int bucketSize) {
375         return bucketSize + 1;
376     }
377
378     @SuppressWarnings("checkstyle:IllegalCatch")
379     private List<Bucket> getRemoteBCGroupTunnelBuckets(ElanDpnInterfacesList elanDpns, BigInteger dpnId, int bucketId,
380             long elanTagOrVni) {
381         List<Bucket> listBucketInfo = new ArrayList<>();
382         if (elanDpns != null) {
383             for (DpnInterfaces dpnInterface : elanDpns.nonnullDpnInterfaces())  {
384                 if (!Objects.equals(dpnInterface.getDpId(), dpnId) && dpnInterface.getInterfaces() != null
385                         && !dpnInterface.getInterfaces().isEmpty()) {
386                     try {
387                         List<Action> listActionInfo = elanItmUtils.getInternalTunnelItmEgressAction(dpnId,
388                                 dpnInterface.getDpId(), elanTagOrVni);
389                         if (listActionInfo.isEmpty()) {
390                             continue;
391                         }
392                         listBucketInfo.add(MDSALUtil.buildBucket(listActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId,
393                                 MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
394                         bucketId++;
395                     } catch (Exception ex) {
396                         LOG.error("Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
397                                 dpnId, dpnInterface.getDpId(), ex);
398                     }
399                 }
400             }
401         }
402         return listBucketInfo;
403     }
404
405     /**
406      * Update remote mcast mac.
407      *
408      * @param elanName
409      *            the elan name
410      * @param device
411      *            the device
412      * @param dpnsTepIps
413      *            the dpns tep ips
414      * @param l2GwDevicesTepIps
415      *            the l2 gw devices tep ips
416      * @return the write transaction
417      */
418     private ListenableFuture<Void> prepareRemoteMcastMacEntry(String elanName,
419                                              L2GatewayDevice device, List<IpAddress> dpnsTepIps,
420                                              List<IpAddress> l2GwDevicesTepIps) {
421         NodeId nodeId = new NodeId(device.getHwvtepNodeId());
422
423         ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
424         remoteTepIps.remove(device.getTunnelIp());
425         remoteTepIps.addAll(dpnsTepIps);
426         IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
427         if (dpnsTepIps.isEmpty()) {
428             // If no dpns in elan, configure dhcp designated switch Tep Ip as a
429             // physical locator in l2 gw device
430             if (dhcpDesignatedSwitchTepIp != null) {
431                 remoteTepIps.add(dhcpDesignatedSwitchTepIp);
432
433                 HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
434                         .createHwvtepPhysicalLocatorAugmentation(dhcpDesignatedSwitchTepIp);
435                 InstanceIdentifier<TerminationPoint> iid =
436                         HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug);
437                 TerminationPoint terminationPoint = new TerminationPointBuilder()
438                                 .withKey(HwvtepSouthboundUtils.getTerminationPointKey(phyLocatorAug))
439                                 .addAugmentation(HwvtepPhysicalLocatorAugmentation.class, phyLocatorAug).build();
440                 ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
441                         iid, terminationPoint);
442                 LOG.info("Adding PhysicalLocator for node: {} with Dhcp designated switch Tep Ip {} "
443                         + "as physical locator, elan {}", device.getHwvtepNodeId(),
444                         dhcpDesignatedSwitchTepIp.stringValue(), elanName);
445             } else {
446                 LOG.warn("Dhcp designated switch Tep Ip not found for l2 gw node {} and elan {}",
447                         device.getHwvtepNodeId(), elanName);
448             }
449         }
450         if (dhcpDesignatedSwitchTepIp != null && !remoteTepIps.contains(dhcpDesignatedSwitchTepIp)) {
451             remoteTepIps.add(dhcpDesignatedSwitchTepIp);
452         }
453         String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
454         LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
455                 remoteTepIps);
456         return putRemoteMcastMac(nodeId, logicalSwitchName, remoteTepIps);
457     }
458
459     /**
460      * Put remote mcast mac in config DS.
461      *
462      * @param nodeId
463      *            the node id
464      * @param logicalSwitchName
465      *            the logical switch name
466      * @param tepIps
467      *            the tep ips
468      */
469     private static ListenableFuture<Void> putRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
470             ArrayList<IpAddress> tepIps) {
471         List<LocatorSet> locators = new ArrayList<>();
472         for (IpAddress tepIp : tepIps) {
473             HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
474                     .createHwvtepPhysicalLocatorAugmentation(tepIp);
475             HwvtepPhysicalLocatorRef phyLocRef = new HwvtepPhysicalLocatorRef(
476                     HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, phyLocatorAug));
477             locators.add(new LocatorSetBuilder().setLocatorRef(phyLocRef).build());
478         }
479
480         HwvtepLogicalSwitchRef lsRef = new HwvtepLogicalSwitchRef(HwvtepSouthboundUtils
481                 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName)));
482         RemoteMcastMacs remoteMcastMac = new RemoteMcastMacsBuilder()
483                 .setMacEntryKey(new MacAddress(ElanConstants.UNKNOWN_DMAC)).setLogicalSwitchRef(lsRef)
484                 .setLocatorSet(locators).build();
485         InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
486                 remoteMcastMac.key());
487         return ResourceBatchingManager.getInstance().put(ResourceBatchingManager.ShardResource.CONFIG_TOPOLOGY,
488                 iid, remoteMcastMac);
489
490     }
491
492     /**
493      * Gets all the tep ips of dpns.
494      *
495      * @param l2GwDevice
496      *            the device
497      * @param dpns
498      *            the dpns
499      * @return the all tep ips of dpns and devices
500      */
501     private List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
502         List<IpAddress> tepIps = new ArrayList<>();
503         for (DpnInterfaces dpn : dpns) {
504             IpAddress internalTunnelIp = elanItmUtils.getSourceDpnTepIp(dpn.getDpId(),
505                     new NodeId(l2GwDevice.getHwvtepNodeId()));
506             if (internalTunnelIp != null) {
507                 tepIps.add(internalTunnelIp);
508             }
509         }
510         return tepIps;
511     }
512
513     /**
514      * Gets the all tep ips of l2 gw devices.
515      *
516      * @param devices
517      *            the devices
518      * @return the all tep ips of l2 gw devices
519      */
520     private static List<IpAddress> getAllTepIpsOfL2GwDevices(Collection<L2GatewayDevice> devices) {
521         List<IpAddress> tepIps = new ArrayList<>();
522         for (L2GatewayDevice otherDevice : devices) {
523             // There is no need to add the same tep ip to the list.
524             if (!tepIps.contains(otherDevice.getTunnelIp())) {
525                 tepIps.add(otherDevice.getTunnelIp());
526             }
527         }
528         return tepIps;
529     }
530
531     /**
532      * Handle mcast for elan l2 gw device delete.
533      *
534      * @param elanName
535      *            the elan instance name
536      * @param l2GatewayDevice
537      *            the l2 gateway device
538      * @return the listenable future
539      */
540     public List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(String elanName,
541                                                                            L2GatewayDevice l2GatewayDevice) {
542         ListenableFuture<Void> deleteTepFuture =
543             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
544                 tx -> tx.delete(buildExternalTepPath(elanName, l2GatewayDevice.getTunnelIp())));
545         updateMcastMacsForAllElanDevices(elanName, l2GatewayDevice, false/* updateThisDevice */);
546         ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
547                 new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
548         return Arrays.asList(deleteRemoteMcastMacFuture, deleteTepFuture);
549     }
550
551     /**
552      * Delete remote mcast mac from Hwvtep node.
553      *
554      * @param nodeId
555      *            the node id
556      * @param logicalSwitchName
557      *            the logical switch name
558      * @return the listenable future
559      */
560     public ListenableFuture<Void> deleteRemoteMcastMac(NodeId nodeId, String logicalSwitchName) {
561         InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
562                 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
563         RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
564                 new MacAddress(ElanConstants.UNKNOWN_DMAC));
565
566         LOG.info("Deleting RemoteMcastMacs entry on node: {} for logical switch: {}", nodeId.getValue(),
567                 logicalSwitchName);
568         return HwvtepUtils.deleteRemoteMcastMac(broker, nodeId, remoteMcastMacsKey);
569     }
570
571     /**
572      * Gets the tep ip of designated switch for external tunnel.
573      *
574      * @param l2GwDevice
575      *            the l2 gw device
576      * @param elanInstanceName
577      *            the elan instance name
578      * @return the tep ip of designated switch for external tunnel
579      */
580     public IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
581             String elanInstanceName) {
582         IpAddress tepIp = null;
583         if (l2GwDevice.getTunnelIp() == null) {
584             LOG.warn("Tunnel IP not found for {}", l2GwDevice.getDeviceName());
585             return tepIp;
586         }
587         DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
588                 elanInstanceName);
589         if (desgSwitch != null) {
590             tepIp = elanItmUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
591                     new NodeId(l2GwDevice.getHwvtepNodeId()));
592         }
593         return tepIp;
594     }
595
596     /**
597      * Gets the designated switch for external tunnel.
598      *
599      * @param tunnelIp
600      *            the tunnel ip
601      * @param elanInstanceName
602      *            the elan instance name
603      * @return the designated switch for external tunnel
604      */
605     public DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
606             String elanInstanceName) {
607         InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
608                 .builder(DesignatedSwitchesForExternalTunnels.class)
609                 .child(DesignatedSwitchForTunnel.class, new DesignatedSwitchForTunnelKey(elanInstanceName, tunnelIp))
610                 .build();
611         return MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, instanceIdentifier).orNull();
612     }
613
614 }