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