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