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