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