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