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