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