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