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