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