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