ae3874d949c5b2559f6f3ec0dc580afbb3ad7e94
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / utils / ElanL2GatewayUtils.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 com.google.common.base.Optional;
11 import com.google.common.collect.Lists;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.Objects;
24 import java.util.Set;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.ScheduledFuture;
30 import java.util.concurrent.TimeUnit;
31 import java.util.function.Function;
32 import java.util.stream.Collectors;
33 import javax.annotation.Nonnull;
34 import javax.annotation.PreDestroy;
35 import javax.inject.Inject;
36 import javax.inject.Singleton;
37
38 import org.apache.commons.lang3.tuple.ImmutablePair;
39 import org.apache.commons.lang3.tuple.Pair;
40 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
41 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
42 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
43 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
44 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
45 import org.opendaylight.genius.mdsalutil.MDSALUtil;
46 import org.opendaylight.genius.utils.SystemPropertyReader;
47 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
48 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
49 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
50 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
51 import org.opendaylight.netvirt.elan.ElanException;
52 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
53 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteLogicalSwitchJob;
54 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
55 import org.opendaylight.netvirt.elan.utils.ElanConstants;
56 import org.opendaylight.netvirt.elan.utils.ElanDmacUtils;
57 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
58 import org.opendaylight.netvirt.elan.utils.ElanUtils;
59 import org.opendaylight.netvirt.elan.utils.Scheduler;
60 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
61 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
65 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
67 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepMacTableGenericAttributes;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
95 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
96 import org.opendaylight.yangtools.yang.common.RpcResult;
97 import org.slf4j.Logger;
98 import org.slf4j.LoggerFactory;
99
100 /**
101  * It gathers a set of utility methods that handle ELAN configuration in
102  * external Devices (where external means "not-CSS". As of now: TORs).
103  *
104  * <p>It makes use of HwvtepUtils class located under ovsdb/hwvtepsouthbound
105  * project for low-level mdsal operations
106  *
107  * @author eperefr
108  */
109 @Singleton
110 public class ElanL2GatewayUtils {
111     private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
112     private static final int DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS = 20;
113
114     private final DataBroker broker;
115     private final ElanDmacUtils elanDmacUtils;
116     private final ElanItmUtils elanItmUtils;
117     private final ElanClusterUtils elanClusterUtils;
118     private final OdlInterfaceRpcService interfaceManagerRpcService;
119     private final JobCoordinator jobCoordinator;
120     private final ElanUtils elanUtils;
121
122     private final ConcurrentMap<Pair<NodeId, String>, ScheduledFuture> logicalSwitchDeletedTasks
123             = new ConcurrentHashMap<>();
124     private final ConcurrentMap<Pair<NodeId, String>, DeleteLogicalSwitchJob> deleteJobs = new ConcurrentHashMap<>();
125     private final Scheduler scheduler;
126     private final ElanConfig elanConfig;
127
128     @Inject
129     public ElanL2GatewayUtils(DataBroker broker, ElanDmacUtils elanDmacUtils, ElanItmUtils elanItmUtils,
130             ElanClusterUtils elanClusterUtils, OdlInterfaceRpcService interfaceManagerRpcService,
131             JobCoordinator jobCoordinator, ElanUtils elanUtils,
132             Scheduler scheduler, ElanConfig elanConfig) {
133         this.broker = broker;
134         this.elanDmacUtils = elanDmacUtils;
135         this.elanItmUtils = elanItmUtils;
136         this.elanClusterUtils = elanClusterUtils;
137         this.interfaceManagerRpcService = interfaceManagerRpcService;
138         this.jobCoordinator = jobCoordinator;
139         this.elanUtils = elanUtils;
140         this.scheduler = scheduler;
141         this.elanConfig = elanConfig;
142     }
143
144     @PreDestroy
145     public void close() {
146     }
147
148     public long getLogicalSwitchDeleteDelaySecs() {
149         return elanConfig.getL2gwLogicalSwitchDelaySecs() != null
150                 ? elanConfig.getL2gwLogicalSwitchDelaySecs() : DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS;
151     }
152
153     /**
154      * gets the macs addresses for elan interfaces.
155      *
156      * @param lstElanInterfaceNames
157      *            the lst elan interface names
158      * @return the list
159      */
160     public List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
161         List<PhysAddress> result = new ArrayList<>();
162         for (String interfaceName : lstElanInterfaceNames) {
163             ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(broker, interfaceName);
164             if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
165                 for (MacEntry macEntry : elanInterfaceMac.getMacEntry()) {
166                     result.add(macEntry.getMacAddress());
167                 }
168             }
169         }
170         return result;
171     }
172
173     /**
174      * Check if phy locator already exists in remote mcast entry.
175      *
176      * @param nodeId
177      *            the node id
178      * @param remoteMcastMac
179      *            the remote mcast mac
180      * @param expectedPhyLocatorIp
181      *            the expected phy locator ip
182      * @return true, if successful
183      */
184     public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
185             RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
186         if (remoteMcastMac != null) {
187             HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
188                     .createHwvtepPhysicalLocatorAugmentation(String.valueOf(expectedPhyLocatorIp.getValue()));
189             HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
190                     HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
191             if (remoteMcastMac.getLocatorSet() != null) {
192                 for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
193                     if (locatorSet.getLocatorRef().equals(expectedPhyLocRef)) {
194                         LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
195                         return true;
196                     }
197                 }
198             }
199         }
200         return false;
201     }
202
203     /**
204      * Gets the remote mcast mac.
205      *
206      * @param nodeId
207      *            the node id
208      * @param logicalSwitchName
209      *            the logical switch name
210      * @param datastoreType
211      *            the datastore type
212      * @return the remote mcast mac
213      */
214     public RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
215             LogicalDatastoreType datastoreType) {
216         InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
217                 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
218         RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
219                 new MacAddress(ElanConstants.UNKNOWN_DMAC));
220         RemoteMcastMacs remoteMcastMac = HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId,
221                 remoteMcastMacsKey);
222         return remoteMcastMac;
223     }
224
225     /**
226      * Removes the given MAC Addresses from all the External Devices belonging
227      * to the specified ELAN.
228      *
229      * @param elanInstance
230      *            the elan instance
231      * @param macAddresses
232      *            the mac addresses
233      */
234     public void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
235         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
236                 .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
237         for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
238             removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
239                     elanInstance.getElanInstanceName(), macAddresses);
240         }
241     }
242
243     /**
244      * Removes the given MAC Addresses from the specified External Device.
245      *
246      * @param deviceNodeId
247      *            the device node id
248      * @param macAddresses
249      *            the mac addresses
250      * @return the listenable future
251      */
252     private ListenableFuture<Void> removeRemoteUcastMacsFromExternalDevice(String deviceNodeId,
253             String logicalSwitchName, List<PhysAddress> macAddresses) {
254         NodeId nodeId = new NodeId(deviceNodeId);
255
256         // TODO (eperefr)
257         List<MacAddress> lstMac = macAddresses.stream().filter(Objects::nonNull).map(
258             physAddress -> new MacAddress(physAddress.getValue())).collect(Collectors.toList());
259         return HwvtepUtils.deleteRemoteUcastMacs(broker, nodeId, logicalSwitchName, lstMac);
260     }
261
262     public ElanInstance getElanInstanceForUcastLocalMac(LocalUcastMacs localUcastMac) {
263         Optional<LogicalSwitches> lsOpc = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL,
264                 (InstanceIdentifier<LogicalSwitches>) localUcastMac.getLogicalSwitchRef().getValue());
265         if (lsOpc.isPresent()) {
266             LogicalSwitches ls = lsOpc.get();
267             if (ls != null) {
268                 // Logical switch name is Elan name
269                 String elanName = getElanFromLogicalSwitch(ls.getHwvtepNodeName().getValue());
270                 return ElanUtils.getElanInstanceByName(broker, elanName);
271             } else {
272                 String macAddress = localUcastMac.getMacEntryKey().getValue();
273                 LOG.error("Could not find logical_switch for {} being added/deleted", macAddress);
274             }
275         }
276         return null;
277     }
278
279     /**
280      * Install external device local macs in dpn.
281      *
282      * @param dpnId
283      *            the dpn id
284      * @param l2gwDeviceNodeId
285      *            the l2gw device node id
286      * @param elan
287      *            the elan
288      * @param interfaceName
289      *            the interface name
290      * @throws ElanException in case of issues creating the flow objects
291      */
292     public void installL2gwDeviceMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan,
293             String interfaceName) throws ElanException {
294         L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
295                 l2gwDeviceNodeId.getValue());
296         if (l2gwDevice == null) {
297             LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
298             return;
299         }
300
301         installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
302     }
303
304     /**
305      * Install dmac flows on dpn.
306      *
307      * @param dpnId
308      *            the dpn id
309      * @param l2gwDevice
310      *            the l2gw device
311      * @param elan
312      *            the elan
313      * @param interfaceName
314      *            the interface name
315      * @throws ElanException in case of issues creating the flow objects
316      */
317     public void installDmacFlowsOnDpn(BigInteger dpnId, L2GatewayDevice l2gwDevice, ElanInstance elan,
318             String interfaceName) throws ElanException {
319         String elanName = elan.getElanInstanceName();
320
321         Collection<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
322         if (!l2gwDeviceLocalMacs.isEmpty()) {
323             for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
324                 elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(dpnId, l2gwDevice.getHwvtepNodeId(),
325                         elan.getElanTag(), ElanUtils.getVxlanSegmentationId(elan),
326                         localUcastMac.getMacEntryKey().getValue(), elanName, interfaceName);
327             }
328             LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
329                     l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
330         }
331     }
332
333     /**
334      * Install elan l2gw devices local macs in dpn.
335      *
336      * @param dpnId
337      *            the dpn id
338      * @param elan
339      *            the elan
340      * @param interfaceName
341      *            the interface name
342      * @throws ElanException in case of issues creating the flow objects
343      */
344     public void installElanL2gwDevicesLocalMacsInDpn(BigInteger dpnId, ElanInstance elan, String interfaceName)
345             throws ElanException {
346         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
347                 .getInvolvedL2GwDevices(elan.getElanInstanceName());
348         if (elanL2GwDevicesFromCache != null) {
349             for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
350                 installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
351             }
352         } else {
353             LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
354         }
355     }
356
357     public void installL2GwUcastMacInElan(final ElanInstance elan, final L2GatewayDevice extL2GwDevice,
358             final String macToBeAdded, final LocalUcastMacs localUcastMacs, String interfaceName) {
359         final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
360         final String elanInstanceName = elan.getElanInstanceName();
361         final List<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
362         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
363                 .getInvolvedL2GwDevices(elanInstanceName);
364
365         // Retrieve all participating DPNs in this Elan. Populate this MAC in
366         // DMAC table.
367         // Looping through all DPNs in order to add/remove mac flows in their
368         // DMAC table
369         if (elanDpns.size() > 0 || elanL2GwDevices.values().size() > 0) {
370             String jobKey = elanInstanceName + ":" + macToBeAdded;
371             IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
372             List<PhysAddress> macList = Lists.newArrayList(new PhysAddress(macToBeAdded));
373
374             elanClusterUtils.runOnlyInOwnerNode(jobKey, "install l2gw macs in dmac table", () -> {
375                 if (doesLocalUcastMacExistsInCache(extL2GwDevice, localUcastMacs)) {
376                     List<ListenableFuture<Void>> futures = new ArrayList<>();
377                     for (DpnInterfaces elanDpn : elanDpns) {
378                         futures.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(elanDpn.getDpId(),
379                                 extDeviceNodeId, elan.getElanTag(), ElanUtils.getVxlanSegmentationId(elan),
380                                 macToBeAdded, elanInstanceName, interfaceName));
381                     }
382                     for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
383                         if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
384                                 && !areMLAGDevices(extL2GwDevice, otherDevice)) {
385                             final String hwvtepId = otherDevice.getHwvtepNodeId();
386                             final String logicalSwitchName = elanInstanceName;
387                             futures.add(HwvtepUtils.installUcastMacs(
388                                     broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp));
389                         }
390                     }
391                     return futures;
392                 } else {
393                     LOG.trace("Skipping install of dmac flows for mac {} as it is not found in cache",
394                             macToBeAdded);
395                 }
396                 return Collections.emptyList();
397             });
398         }
399     }
400
401     /**
402      * Does local ucast mac exists in cache.
403      *
404      * @param elanL2GwDevice
405      *            the elan L2 Gw device
406      * @param macAddress
407      *            the mac address to be verified
408      * @return true, if successful
409      */
410     private static boolean doesLocalUcastMacExistsInCache(L2GatewayDevice elanL2GwDevice, LocalUcastMacs macAddress) {
411         return elanL2GwDevice.containsUcastMac(macAddress);
412     }
413
414     /**
415      * Uninstall l2gw macs from other l2gw devices in the elanName provided.
416      * @param elanName - Elan Name for which other l2gw devices will be scanned.
417      * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
418      * @param macAddresses - Mac address to be cleared.
419      */
420     public void unInstallL2GwUcastMacFromL2gwDevices(final String elanName,
421                                                      final L2GatewayDevice l2GwDevice,
422                                                      final Collection<MacAddress> macAddresses) {
423         if (macAddresses == null || macAddresses.isEmpty()) {
424             return;
425         }
426
427         if (elanName == null) {
428             return;
429         }
430
431         DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice,
432                 macAddresses);
433         elanClusterUtils.runOnlyInOwnerNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
434     }
435
436     /**
437      * Uninstall l2gw macs from other DPNs in the elan instance provided.
438      * @param elan - Elan Instance for which other DPNs will be scanned.
439      * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
440      * @param macAddresses - Mac address to be cleared.
441      */
442     public void unInstallL2GwUcastMacFromElanDpns(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
443                                                   final Collection<MacAddress> macAddresses) {
444         if (macAddresses == null || macAddresses.isEmpty()) {
445             return;
446         }
447         if (elan == null || elan.getElanInstanceName() == null) {
448             LOG.error("Could not delete l2gw ucast macs, Failed to find the elan for device {}",
449                     l2GwDevice.getHwvtepNodeId());
450             return;
451         }
452
453         final List<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
454
455         // Retrieve all participating DPNs in this Elan. Populate this MAC in
456         // DMAC table. Looping through all DPNs in order to add/remove mac flows
457         // in their DMAC table
458         List<ListenableFuture<Void>> result = new ArrayList<>();
459         for (final MacAddress mac : macAddresses) {
460             elanClusterUtils.runOnlyInOwnerNode(elan.getElanInstanceName() + ":" + mac.getValue(),
461                     "delete remote ucast macs in elan DPNs", () -> {
462                     for (DpnInterfaces elanDpn : elanDpns) {
463                         BigInteger dpnId = elanDpn.getDpId();
464                         result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
465                                 l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase(Locale.getDefault())));
466                     }
467                     return result;
468                 });
469         }
470     }
471
472     /**
473      * Delete elan l2 gateway devices ucast local macs from dpn.
474      *
475      * @param elanName
476      *            the elan name
477      * @param dpnId
478      *            the dpn id
479      * @throws ReadFailedException if a read fails throws ReadFailedException
480      */
481     public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId)
482             throws ReadFailedException {
483         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
484         if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
485             LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
486             return;
487         }
488         final ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
489         if (elan == null) {
490             LOG.error("Could not find Elan by name: {}", elanName);
491             return;
492         }
493         LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
494
495         final Long elanTag = elan.getElanTag();
496         for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
497             getL2GwDeviceLocalMacsAndRunCallback(elan.getElanInstanceName(), l2GwDevice, (localMacs) -> {
498                 for (MacAddress mac : localMacs) {
499                     String jobKey = elanName + ":" + mac.getValue();
500                     elanClusterUtils.runOnlyInOwnerNode(jobKey,
501                         () -> elanDmacUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
502                                 l2GwDevice.getHwvtepNodeId(), mac.getValue()));
503                 }
504                 return null;
505             });
506         }
507     }
508
509     public void getL2GwDeviceLocalMacsAndRunCallback(String elanName, L2GatewayDevice l2gwDevice,
510                                                      Function<Collection<MacAddress>, Void> function) {
511         if (l2gwDevice == null) {
512             return;
513         }
514         Set<MacAddress> macs = new HashSet<>();
515         Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
516         if (!lstUcastLocalMacs.isEmpty()) {
517             macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
518                     .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase()))
519                     .collect(Collectors.toList()));
520         }
521
522         InstanceIdentifier<Node> nodeIid = HwvtepSouthboundUtils.createInstanceIdentifier(
523                 new NodeId(l2gwDevice.getHwvtepNodeId()));
524         Futures.addCallback(broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid),
525                 new FutureCallback<Optional<Node>>() {
526                     @Override
527                     public void onSuccess(Optional<Node> configNode) {
528                         if (configNode != null && configNode.isPresent()) {
529                             HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(
530                                     HwvtepGlobalAugmentation.class);
531                             if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
532                                 macs.addAll(augmentation.getLocalUcastMacs().stream()
533                                         .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
534                                         .map(mac -> mac.getMacEntryKey())
535                                         .collect(Collectors.toSet()));
536                             }
537                             function.apply(macs);
538                         }
539                     }
540
541                     @Override
542                     public void onFailure(Throwable throwable) {
543                         LOG.error("Failed to read config topology node ", nodeIid);
544                     }
545                 }, MoreExecutors.directExecutor());
546     }
547
548     private String getLogicalSwitchName(LocalUcastMacs mac) {
549         return ((InstanceIdentifier<LogicalSwitches>)mac.getLogicalSwitchRef().getValue())
550                 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
551     }
552
553     /**
554      * Delete elan macs from L2 gateway device.<br>
555      * This includes deleting ELAN mac table entries plus external device
556      * UcastLocalMacs which are part of the same ELAN.
557      *
558      * @param hwvtepNodeId
559      *            the hwvtepNodeId
560      * @param elanName
561      *            the elan name
562      * @return the listenable future
563      */
564     public ListenableFuture<Void> deleteElanMacsFromL2GatewayDevice(String hwvtepNodeId, String elanName) {
565         String logicalSwitch = getLogicalSwitchFromElan(elanName);
566
567         List<MacAddress> lstElanMacs = getRemoteUcastMacs(new NodeId(hwvtepNodeId), logicalSwitch,
568                 LogicalDatastoreType.CONFIGURATION);
569         ListenableFuture<Void> future = HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(hwvtepNodeId),
570                 logicalSwitch, lstElanMacs);
571
572         Futures.addCallback(future, new FutureCallback<Void>() {
573             @Override
574             public void onSuccess(Void noarg) {
575                 LOG.trace("Successful in batch deletion of elan [{}] macs from l2gw device [{}]", elanName,
576                         hwvtepNodeId);
577             }
578
579             @Override
580             public void onFailure(Throwable error) {
581                 LOG.warn(String.format("Failed during batch delete of elan [%s] macs from l2gw device [%s]. "
582                         + "Retrying with sequential deletes.", elanName, hwvtepNodeId), error);
583                 if (lstElanMacs != null && !lstElanMacs.isEmpty()) {
584                     for (MacAddress mac : lstElanMacs) {
585                         HwvtepUtils.deleteRemoteUcastMac(broker, new NodeId(hwvtepNodeId), logicalSwitch, mac);
586                     }
587                 }
588             }
589         }, MoreExecutors.directExecutor());
590
591         if (LOG.isDebugEnabled()) {
592             List<String> elanMacs = lstElanMacs.stream().map(MacAddress::getValue).collect(Collectors.toList());
593             LOG.debug("Deleting elan [{}] macs from node [{}]. Deleted macs = {}", elanName, hwvtepNodeId, elanMacs);
594         }
595         return future;
596     }
597
598     /**
599      * Gets the remote ucast macs from hwvtep node filtering based on logical
600      * switch.
601      *
602      * @param hwvtepNodeId
603      *            the hwvtep node id
604      * @param logicalSwitch
605      *            the logical switch
606      * @param datastoreType
607      *            the datastore type
608      * @return the remote ucast macs
609      */
610     public List<MacAddress> getRemoteUcastMacs(NodeId hwvtepNodeId, String logicalSwitch,
611             LogicalDatastoreType datastoreType) {
612         List<MacAddress> lstMacs = Collections.emptyList();
613         Node hwvtepNode = HwvtepUtils.getHwVtepNode(broker, datastoreType, hwvtepNodeId);
614         if (hwvtepNode != null) {
615             List<RemoteUcastMacs> remoteUcastMacs = hwvtepNode.getAugmentation(HwvtepGlobalAugmentation.class)
616                     .getRemoteUcastMacs();
617             if (remoteUcastMacs != null && !remoteUcastMacs.isEmpty()) {
618                 // Filtering remoteUcastMacs based on the logical switch and
619                 // forming a list of MacAddress
620                 lstMacs = remoteUcastMacs.stream()
621                         .filter(mac -> logicalSwitch.equals(mac.getLogicalSwitchRef().getValue()
622                                 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue()))
623                         .map(HwvtepMacTableGenericAttributes::getMacEntryKey).collect(Collectors.toList());
624             }
625         }
626         return lstMacs;
627     }
628
629     /**
630      * Install ELAN macs in L2 Gateway device.<br>
631      * This includes installing ELAN mac table entries plus external device
632      * UcastLocalMacs which are part of the same ELAN.
633      *
634      * @param elanName
635      *            the elan name
636      * @param l2GatewayDevice
637      *            the l2 gateway device which has to be configured
638      * @return the listenable future
639      */
640     public ListenableFuture<Void> installElanMacsInL2GatewayDevice(String elanName,
641             L2GatewayDevice l2GatewayDevice) {
642         String logicalSwitchName = getLogicalSwitchFromElan(elanName);
643         NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
644
645         List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName, l2GatewayDevice, hwVtepNodeId,
646                 logicalSwitchName);
647         List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName, l2GatewayDevice,
648                 hwVtepNodeId, logicalSwitchName);
649
650         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
651         lstRemoteUcastMacs.addAll(lstElanMacTableEntries);
652
653         ListenableFuture<Void> future = HwvtepUtils.addRemoteUcastMacs(broker, hwVtepNodeId, lstRemoteUcastMacs);
654
655         LOG.info("Added RemoteUcastMacs entries [{}] in config DS. NodeID: {}, LogicalSwitch: {}",
656                 lstRemoteUcastMacs.size(), hwVtepNodeId.getValue(), logicalSwitchName);
657         return future;
658     }
659
660     /**
661      * Gets the l2 gateway devices ucast local macs as remote ucast macs.
662      *
663      * @param elanName
664      *            the elan name
665      * @param l2GatewayDeviceToBeConfigured
666      *            the l2 gateway device to be configured
667      * @param hwVtepNodeId
668      *            the hw vtep node Id to be configured
669      * @param logicalSwitchName
670      *            the logical switch name
671      * @return the l2 gateway devices macs as remote ucast macs
672      */
673     public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
674             L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
675         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
676         ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
677                 .getInvolvedL2GwDevices(elanName);
678
679         if (elanL2GwDevicesFromCache != null) {
680             for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
681                 if (l2GatewayDeviceToBeConfigured.getHwvtepNodeId().equals(otherDevice.getHwvtepNodeId())) {
682                     continue;
683                 }
684                 if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
685                     for (LocalUcastMacs localUcastMac : otherDevice.getUcastLocalMacs()) {
686                         HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
687                                 .createHwvtepPhysicalLocatorAugmentation(
688                                         String.valueOf(otherDevice.getTunnelIp().getValue()));
689                         RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
690                                 localUcastMac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault()),
691                                 localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
692                         lstRemoteUcastMacs.add(remoteUcastMac);
693                     }
694                 }
695             }
696         }
697         return lstRemoteUcastMacs;
698     }
699
700     /**
701      * Are MLAG devices.
702      *
703      * @param l2GatewayDevice
704      *            the l2 gateway device
705      * @param otherL2GatewayDevice
706      *            the other l2 gateway device
707      * @return true, if both the specified l2 gateway devices are part of same
708      *         MLAG
709      */
710     public static boolean areMLAGDevices(L2GatewayDevice l2GatewayDevice, L2GatewayDevice otherL2GatewayDevice) {
711         // If tunnel IPs are same, then it is considered to be part of same MLAG
712         return Objects.equals(l2GatewayDevice.getTunnelIp(), otherL2GatewayDevice.getTunnelIp());
713     }
714
715     /**
716      * Gets the elan mac table entries as remote ucast macs. <br>
717      * Note: ELAN MAC table only contains internal switches MAC's. It doesn't
718      * contain external device MAC's.
719      *
720      * @param elanName
721      *            the elan name
722      * @param l2GatewayDeviceToBeConfigured
723      *            the l2 gateway device to be configured
724      * @param hwVtepNodeId
725      *            the hw vtep node id
726      * @param logicalSwitchName
727      *            the logical switch name
728      * @return the elan mac table entries as remote ucast macs
729      */
730     public List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
731             L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
732         List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
733
734         MacTable macTable = ElanUtils.getElanMacTable(broker, elanName);
735         if (macTable == null || macTable.getMacEntry() == null || macTable.getMacEntry().isEmpty()) {
736             LOG.trace("MacTable is empty for elan: {}", elanName);
737             return lstRemoteUcastMacs;
738         }
739
740         for (MacEntry macEntry : macTable.getMacEntry()) {
741             BigInteger dpnId = getDpidFromInterface(macEntry.getInterface());
742             if (dpnId == null) {
743                 LOG.error("DPN ID not found for interface {}", macEntry.getInterface());
744                 continue;
745             }
746
747             IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, hwVtepNodeId);
748             LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpnId, hwVtepNodeId.getValue());
749             if (dpnTepIp == null) {
750                 LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpnId, hwVtepNodeId.getValue());
751                 continue;
752             }
753             HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
754                     .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
755             // TODO: Query ARP cache to get IP address corresponding to the
756             // MAC
757             RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
758                     macEntry.getMacAddress().getValue().toLowerCase(Locale.getDefault()), null /*IpAddress*/,
759                     logicalSwitchName, physLocatorAug);
760             lstRemoteUcastMacs.add(remoteUcastMac);
761         }
762         return lstRemoteUcastMacs;
763     }
764
765     /**
766      * Gets the dpid from interface.
767      *
768      * @param interfaceName
769      *            the interface name
770      * @return the dpid from interface
771      */
772     public BigInteger getDpidFromInterface(String interfaceName) {
773         BigInteger dpId = null;
774         Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService
775                 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
776         try {
777             RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
778             if (rpcResult != null && rpcResult.isSuccessful()) {
779                 dpId = rpcResult.getResult().getDpid();
780             }
781         } catch (InterruptedException | ExecutionException e) {
782             LOG.error("Failed to get the DPN ID for interface {}: {} ", interfaceName, e);
783         }
784         return dpId;
785     }
786
787     /**
788      * Update vlan bindings in l2 gateway device.
789      *
790      * @param nodeId
791      *            the node id
792      * @param logicalSwitchName
793      *            the logical switch name
794      * @param hwVtepDevice
795      *            the hardware device
796      * @param defaultVlanId
797      *            the default vlan id
798      * @return the listenable future
799      */
800     public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String logicalSwitchName,
801             Devices hwVtepDevice, Integer defaultVlanId) {
802         if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
803             String errMsg = "HwVtepDevice is null or interfaces are empty.";
804             LOG.error(errMsg);
805             return Futures.immediateFailedFuture(new RuntimeException(errMsg));
806         }
807
808         WriteTransaction transaction = broker.newWriteOnlyTransaction();
809         for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
810                  .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
811             //Removed the check for checking terminationPoint present in OP or not
812             //for coniguring vlan bindings
813             //As we are not any more dependent on it , plugin takes care of this
814             // with port reconcilation.
815             List<VlanBindings> vlanBindings = new ArrayList<>();
816             if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
817                 for (Integer vlanId : deviceInterface.getSegmentationIds()) {
818                     vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, vlanId, logicalSwitchName));
819                 }
820             } else {
821                 // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
822                 // ID not specified at interface level.
823                 vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
824             }
825             HwvtepUtils.mergeVlanBindings(transaction, nodeId, hwVtepDevice.getDeviceName(),
826                     deviceInterface.getInterfaceName(), vlanBindings);
827         }
828         ListenableFuture<Void> future = transaction.submit();
829         LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}", nodeId.getValue(),
830                 logicalSwitchName);
831         return future;
832     }
833
834     /**
835      * Update vlan bindings in l2 gateway device.
836      *
837      * @param nodeId
838      *            the node id
839      * @param psName
840      *            the physical switch name
841      * @param interfaceName
842      *            the interface in physical switch
843      * @param vlanBindings
844      *            the vlan bindings to be configured
845      * @return the listenable future
846      */
847     public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String psName,
848             String interfaceName, List<VlanBindings> vlanBindings) {
849         WriteTransaction transaction = broker.newWriteOnlyTransaction();
850         HwvtepUtils.mergeVlanBindings(transaction, nodeId, psName, interfaceName, vlanBindings);
851         ListenableFuture<Void> future = transaction.submit();
852         LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
853         return future;
854     }
855
856     /**
857      * Delete vlan bindings from l2 gateway device.
858      *
859      * @param nodeId
860      *            the node id
861      * @param hwVtepDevice
862      *            the hw vtep device
863      * @param defaultVlanId
864      *            the default vlan id
865      * @return the listenable future
866      */
867     public ListenableFuture<Void> deleteVlanBindingsFromL2GatewayDevice(NodeId nodeId, Devices hwVtepDevice,
868             Integer defaultVlanId) {
869         if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
870             String errMsg = "HwVtepDevice is null or interfaces are empty.";
871             LOG.error(errMsg);
872             return Futures.immediateFailedFuture(new RuntimeException(errMsg));
873         }
874         NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, hwVtepDevice.getDeviceName());
875
876         WriteTransaction transaction = broker.newWriteOnlyTransaction();
877         for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
878                  .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
879             String phyPortName = deviceInterface.getInterfaceName();
880             if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
881                 for (Integer vlanId : deviceInterface.getSegmentationIds()) {
882                     HwvtepUtils.deleteVlanBinding(transaction, physicalSwitchNodeId, phyPortName, vlanId);
883                 }
884             } else {
885                 // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
886                 // ID not specified at interface level.
887                 HwvtepUtils.deleteVlanBinding(transaction, physicalSwitchNodeId, phyPortName, defaultVlanId);
888             }
889         }
890         ListenableFuture<Void> future = transaction.submit();
891
892         LOG.info("Deleted Hwvtep VlanBindings from config DS. NodeID: {}, hwVtepDevice: {}, defaultVlanId: {} ",
893                 nodeId.getValue(), hwVtepDevice, defaultVlanId);
894         return future;
895     }
896
897     /**
898      * Gets the elan name from logical switch name.
899      *
900      * @param logicalSwitchName
901      *            the logical switch name
902      * @return the elan name from logical switch name
903      */
904     public static String getElanFromLogicalSwitch(String logicalSwitchName) {
905         // Assuming elan name is same as logical switch name
906         String elanName = logicalSwitchName;
907         return elanName;
908     }
909
910     /**
911      * Gets the logical switch name from elan name.
912      *
913      * @param elanName
914      *            the elan name
915      * @return the logical switch from elan name
916      */
917     public static String getLogicalSwitchFromElan(String elanName) {
918         // Assuming logical switch name is same as elan name
919         String logicalSwitchName = elanName;
920         return logicalSwitchName;
921     }
922
923     /**
924      * Gets the l2 gateway connection job key.
925      *
926      * @param nodeId
927      *            the node id
928      * @param logicalSwitchName
929      *            the logical switch name
930      * @return the l2 gateway connection job key
931      */
932     public static String getL2GatewayConnectionJobKey(String nodeId, String logicalSwitchName) {
933         return logicalSwitchName;
934     }
935
936     public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
937         InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder = InstanceIdentifier
938                 .builder(Interfaces.class).child(Interface.class, interfaceKey);
939         return interfaceInstanceIdentifierBuilder.build();
940     }
941
942     public static Interface getInterfaceFromConfigDS(InterfaceKey interfaceKey, DataBroker dataBroker) {
943         InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
944         try {
945             return SingleTransactionDataBroker
946                     .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, interfaceId).orNull();
947         } catch (ReadFailedException e) {
948             // TODO remove this, and propagate ReadFailedException instead of re-throw RuntimeException
949             LOG.error("getInterfaceFromConfigDS({}) failed", interfaceKey, e);
950             throw new RuntimeException(e);
951         }
952     }
953
954     /**
955      * Delete l2 gateway device ucast local macs from elan.<br>
956      * Deletes macs from internal ELAN nodes and also on rest of external l2
957      * gateway devices which are part of the ELAN.
958      *
959      * @param l2GatewayDevice
960      *            the l2 gateway device whose ucast local macs to be deleted
961      *            from elan
962      * @param elanName
963      *            the elan name
964      * @throws ReadFailedException if a read fails
965      */
966     public void deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
967             String elanName) throws ReadFailedException {
968         LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
969                 elanName);
970
971         ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
972         if (elan == null) {
973             LOG.error("Could not find Elan by name: {}", elanName);
974             return;
975         }
976
977         Collection<MacAddress> localMacs = getL2GwDeviceLocalMacs(elanName, l2GatewayDevice);
978         unInstallL2GwUcastMacFromL2gwDevices(elanName, l2GatewayDevice, localMacs);
979         unInstallL2GwUcastMacFromElanDpns(elan, l2GatewayDevice, localMacs);
980     }
981
982     public static void createItmTunnels(ItmRpcService itmRpcService, String hwvtepId, String psName,
983             IpAddress tunnelIp) {
984         AddL2GwDeviceInputBuilder builder = new AddL2GwDeviceInputBuilder();
985         builder.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID.getValue());
986         builder.setNodeId(HwvtepSouthboundUtils.createManagedNodeId(new NodeId(hwvtepId), psName).getValue());
987         builder.setIpAddress(tunnelIp);
988         try {
989             Future<RpcResult<Void>> result = itmRpcService.addL2GwDevice(builder.build());
990             RpcResult<Void> rpcResult = result.get();
991             if (rpcResult.isSuccessful()) {
992                 LOG.info("Created ITM tunnels for {}", hwvtepId);
993             } else {
994                 LOG.error("Failed to create ITM Tunnels: ", rpcResult.getErrors());
995             }
996         } catch (InterruptedException | ExecutionException e) {
997             LOG.error("RPC to create ITM tunnels failed", e);
998         }
999     }
1000
1001     public static String getNodeIdFromDpnId(BigInteger dpnId) {
1002         return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
1003     }
1004
1005     public void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId,
1006             List<PhysAddress> staticMacAddresses) {
1007         ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
1008         for (final L2GatewayDevice externalDevice : elanDevices.values()) {
1009             scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
1010         }
1011     }
1012
1013     public void scheduleAddDpnMacsInExtDevice(final String elanName, BigInteger dpId,
1014             final List<PhysAddress> staticMacAddresses, final L2GatewayDevice externalDevice) {
1015         NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
1016         final IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpId, nodeId);
1017         LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
1018         if (dpnTepIp == null) {
1019             LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
1020             return;
1021         }
1022
1023         //TODO: to  be batched in genius
1024         HwvtepUtils.installUcastMacs(broker, externalDevice.getHwvtepNodeId(), staticMacAddresses, elanName, dpnTepIp);
1025     }
1026
1027     public void scheduleDeleteLogicalSwitch(NodeId hwvtepNodeId, String lsName) {
1028         scheduleDeleteLogicalSwitch(hwvtepNodeId, lsName, false);
1029     }
1030
1031     public void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName, final boolean clearUcast) {
1032         final Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1033         logicalSwitchDeletedTasks.computeIfAbsent(nodeIdLogicalSwitchNamePair, (key) -> {
1034             return scheduler.getScheduledExecutorService().schedule(() -> {
1035                 DeleteLogicalSwitchJob deleteLsJob = new DeleteLogicalSwitchJob(broker,
1036                         ElanL2GatewayUtils.this, hwvtepNodeId, lsName, clearUcast);
1037                 jobCoordinator.enqueueJob(deleteLsJob.getJobKey(), deleteLsJob,
1038                         SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
1039                 deleteJobs.put(nodeIdLogicalSwitchNamePair, deleteLsJob);
1040                 logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1041             }, getLogicalSwitchDeleteDelaySecs(), TimeUnit.SECONDS);
1042         });
1043     }
1044
1045     public void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
1046         Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1047         ScheduledFuture logicalSwitchDeleteTask = logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1048         if (logicalSwitchDeleteTask != null) {
1049             LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
1050             logicalSwitchDeleteTask.cancel(true);
1051             DeleteLogicalSwitchJob deleteLogicalSwitchJob = deleteJobs.remove(nodeIdLogicalSwitchNamePair);
1052             if (deleteLogicalSwitchJob != null) {
1053                 deleteLogicalSwitchJob.cancel();
1054             }
1055         }
1056     }
1057
1058     @Nonnull
1059     public List<DpnInterfaces> getElanDpns(String elanName) {
1060         Set<DpnInterfaces> dpnInterfaces = ElanUtils.getElanInvolvedDPNsFromCache(elanName);
1061         if (dpnInterfaces == null) {
1062             return elanUtils.getElanDPNByName(elanName);
1063         }
1064         return new ArrayList<>(dpnInterfaces);
1065     }
1066
1067     /**
1068      * Gets the l2 gw device local macs.
1069      * @param elanName
1070      *            name of the elan
1071      * @param l2gwDevice
1072      *            the l2gw device
1073      * @return the l2 gw device local macs
1074      */
1075     public Collection<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
1076         if (l2gwDevice == null) {
1077             return Collections.emptyList();
1078         }
1079         Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
1080         Set<MacAddress> macs = new HashSet<>();
1081         if (!lstUcastLocalMacs.isEmpty()) {
1082             macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
1083                     .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase()))
1084                     .collect(Collectors.toList()));
1085         }
1086         Optional<Node> configNode = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
1087                 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
1088         if (configNode.isPresent()) {
1089             HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(HwvtepGlobalAugmentation.class);
1090             if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
1091                 macs.addAll(augmentation.getLocalUcastMacs().stream()
1092                         .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
1093                         .map(mac -> mac.getMacEntryKey())
1094                         .collect(Collectors.toSet()));
1095             }
1096         }
1097         return macs;
1098     }
1099 }