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