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