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