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