2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.elan.l2gw.utils;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import com.google.common.collect.Lists;
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Locale;
25 import java.util.Objects;
26 import java.util.Optional;
28 import java.util.concurrent.ConcurrentHashMap;
29 import java.util.concurrent.ConcurrentMap;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.Future;
32 import java.util.concurrent.ScheduledFuture;
33 import java.util.concurrent.TimeUnit;
34 import java.util.function.Function;
35 import java.util.stream.Collectors;
36 import javax.annotation.PreDestroy;
37 import javax.inject.Inject;
38 import javax.inject.Singleton;
39 import org.apache.commons.lang3.tuple.ImmutablePair;
40 import org.apache.commons.lang3.tuple.Pair;
41 import org.eclipse.jdt.annotation.NonNull;
42 import org.eclipse.jdt.annotation.Nullable;
43 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
44 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
45 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
46 import org.opendaylight.genius.utils.SystemPropertyReader;
47 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
48 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
49 import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
50 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
51 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
52 import org.opendaylight.mdsal.binding.api.DataBroker;
53 import org.opendaylight.mdsal.common.api.CommitInfo;
54 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
55 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
56 import org.opendaylight.netvirt.elan.cache.ElanInstanceDpnsCache;
57 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
58 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
59 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteLogicalSwitchJob;
60 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
61 import org.opendaylight.netvirt.elan.utils.ElanConstants;
62 import org.opendaylight.netvirt.elan.utils.ElanDmacUtils;
63 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
64 import org.opendaylight.netvirt.elan.utils.ElanUtils;
65 import org.opendaylight.netvirt.elan.utils.Scheduler;
66 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
67 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
68 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
71 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.IetfYangUtil;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.DeviceVteps;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInputBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceOutput;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepMacTableGenericAttributes;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacsKey;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
106 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
107 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
108 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
109 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
110 import org.opendaylight.yangtools.yang.common.RpcResult;
111 import org.opendaylight.yangtools.yang.common.Uint64;
112 import org.slf4j.Logger;
113 import org.slf4j.LoggerFactory;
116 * It gathers a set of utility methods that handle ELAN configuration in
117 * external Devices (where external means "not-CSS". As of now: TORs).
119 * <p>It makes use of HwvtepUtils class located under ovsdb/hwvtepsouthbound
120 * project for low-level mdsal operations
125 public class ElanL2GatewayUtils {
126 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
127 private static final int DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS = 20;
129 private final DataBroker broker;
130 private final ManagedNewTransactionRunner txRunner;
131 private final ElanDmacUtils elanDmacUtils;
132 private final ElanItmUtils elanItmUtils;
133 private final ElanClusterUtils elanClusterUtils;
134 private final OdlInterfaceRpcService interfaceManagerRpcService;
135 private final JobCoordinator jobCoordinator;
136 private final ElanUtils elanUtils;
137 private final ElanInstanceCache elanInstanceCache;
138 private final ElanInstanceDpnsCache elanInstanceDpnsCache;
140 private final ConcurrentMap<Pair<NodeId, String>, ScheduledFuture> logicalSwitchDeletedTasks
141 = new ConcurrentHashMap<>();
142 private final ConcurrentMap<Pair<NodeId, String>, DeleteLogicalSwitchJob> deleteJobs = new ConcurrentHashMap<>();
143 private final Scheduler scheduler;
144 private final ElanConfig elanConfig;
147 public ElanL2GatewayUtils(DataBroker broker, ElanDmacUtils elanDmacUtils, ElanItmUtils elanItmUtils,
148 ElanClusterUtils elanClusterUtils, OdlInterfaceRpcService interfaceManagerRpcService,
149 JobCoordinator jobCoordinator, ElanUtils elanUtils,
150 Scheduler scheduler, ElanConfig elanConfig, ElanInstanceCache elanInstanceCache,
151 ElanInstanceDpnsCache elanInstanceDpnsCache) {
152 this.broker = broker;
153 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
154 this.elanDmacUtils = elanDmacUtils;
155 this.elanItmUtils = elanItmUtils;
156 this.elanClusterUtils = elanClusterUtils;
157 this.interfaceManagerRpcService = interfaceManagerRpcService;
158 this.jobCoordinator = jobCoordinator;
159 this.elanUtils = elanUtils;
160 this.scheduler = scheduler;
161 this.elanConfig = elanConfig;
162 this.elanInstanceCache = elanInstanceCache;
163 this.elanInstanceDpnsCache = elanInstanceDpnsCache;
167 public void close() {
170 public long getLogicalSwitchDeleteDelaySecs() {
171 return elanConfig.getL2gwLogicalSwitchDelaySecs() != null
172 ? elanConfig.getL2gwLogicalSwitchDelaySecs().toJava() : DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS;
176 * gets the macs addresses for elan interfaces.
178 * @param lstElanInterfaceNames
179 * the lst elan interface names
182 public List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
183 List<PhysAddress> result = new ArrayList<>();
184 for (String interfaceName : lstElanInterfaceNames) {
185 ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(broker, interfaceName);
186 if (elanInterfaceMac != null && elanInterfaceMac.nonnullMacEntry() != null) {
187 for (MacEntry macEntry : new ArrayList<>(elanInterfaceMac.nonnullMacEntry().values())) {
188 result.add(macEntry.getMacAddress());
196 * Check if phy locator already exists in remote mcast entry.
200 * @param remoteMcastMac
201 * the remote mcast mac
202 * @param expectedPhyLocatorIp
203 * the expected phy locator ip
204 * @return true, if successful
206 public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
207 RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
208 if (remoteMcastMac != null) {
209 HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
210 .createHwvtepPhysicalLocatorAugmentation(expectedPhyLocatorIp);
211 HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
212 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
213 if (remoteMcastMac.getLocatorSet() != null) {
214 for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
215 if (Objects.equals(locatorSet.getLocatorRef(), expectedPhyLocRef)) {
216 LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
226 * Gets the remote mcast mac.
230 * @param logicalSwitchName
231 * the logical switch name
232 * @param datastoreType
234 * @return the remote mcast mac
236 public RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
237 LogicalDatastoreType datastoreType) {
238 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
239 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
240 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
241 new MacAddress(ElanConstants.UNKNOWN_DMAC));
243 return HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId, remoteMcastMacsKey);
244 } catch (ExecutionException | InterruptedException e) {
245 LOG.error("readRemoteMcastMac: Exception while reading LogicalSwitches DS for the nodeId {}, "
246 + "logicalSwitchName {}", nodeId.getValue(), logicalSwitch, e);
252 * Removes the given MAC Addresses from all the External Devices belonging
253 * to the specified ELAN.
255 * @param elanInstance
257 * @param macAddresses
259 * @return Future which completes once the removal is done.
261 public FluentFuture<?> removeMacsFromElanExternalDevices(ElanInstance elanInstance,
262 List<PhysAddress> macAddresses) {
263 final String elanName = elanInstance.getElanInstanceName();
264 final Collection<L2GatewayDevice> devices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
265 if (devices.isEmpty()) {
266 return FluentFutures.immediateNullFluentFuture();
269 final List<MacAddress> lstMac = macAddresses.stream()
270 .filter(Objects::nonNull)
271 .map(physAddress -> new MacAddress(physAddress.getValue()))
272 .collect(Collectors.toList());
273 if (lstMac.isEmpty()) {
274 return FluentFutures.immediateNullFluentFuture();
277 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, transaction -> {
278 for (L2GatewayDevice l2GatewayDevice : devices) {
279 final NodeId nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
280 for (MacAddress mac : lstMac) {
281 HwvtepUtils.deleteRemoteUcastMac(transaction, nodeId, elanName, mac);
288 * Install external device local macs in dpn.
292 * @param l2gwDeviceNodeId
293 * the l2gw device node id
296 * @param interfaceName
299 public void installL2gwDeviceMacsInDpn(Uint64 dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan,
300 String interfaceName) {
301 L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
302 l2gwDeviceNodeId.getValue());
303 if (l2gwDevice == null) {
304 LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
308 installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
312 * Install dmac flows on dpn.
320 * @param interfaceName
323 public List<ListenableFuture<Void>> installDmacFlowsOnDpn(Uint64 dpnId, L2GatewayDevice l2gwDevice,
324 ElanInstance elan, String interfaceName) {
325 String elanName = elan.getElanInstanceName();
326 List<ListenableFuture<Void>> fts = new ArrayList<>();
327 Collection<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
328 if (!l2gwDeviceLocalMacs.isEmpty()) {
329 for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
330 fts.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(dpnId, l2gwDevice.getHwvtepNodeId(),
331 elan.getElanTag().toJava(), ElanUtils.getVxlanSegmentationId(elan).longValue(),
332 localUcastMac.getMacEntryKey().getValue(), elanName, interfaceName));
334 LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
335 l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
341 * Install elan l2gw devices local macs in dpn.
347 * @param interfaceName
350 public void installElanL2gwDevicesLocalMacsInDpn(Uint64 dpnId, ElanInstance elan, String interfaceName) {
351 for (L2GatewayDevice l2gwDevice : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elan.getElanInstanceName())) {
352 installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
356 public void installL2GwUcastMacInElan(final ElanInstance elan, final L2GatewayDevice extL2GwDevice,
357 final String macToBeAdded, final LocalUcastMacs localUcastMacs, @Nullable String interfaceName) {
358 final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
359 final String elanInstanceName = elan.getElanInstanceName();
360 final Collection<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
361 Collection<L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInstanceName);
363 // Retrieve all participating DPNs in this Elan. Populate this MAC in
365 // Looping through all DPNs in order to add/remove mac flows in their
367 if (elanDpns.size() > 0 || elanL2GwDevices.size() > 0) {
368 String jobKey = elanInstanceName + ":" + macToBeAdded;
369 IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
370 List<PhysAddress> macList = Lists.newArrayList(new PhysAddress(macToBeAdded));
372 elanClusterUtils.runOnlyInOwnerNode(jobKey, "install l2gw macs in dmac table", () -> {
373 if (doesLocalUcastMacExistsInCache(extL2GwDevice, localUcastMacs)) {
374 List<ListenableFuture<Void>> futures = new ArrayList<>();
375 for (DpnInterfaces elanDpn : elanDpns) {
376 futures.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(
378 extDeviceNodeId, elan.getElanTag().toJava(),
379 ElanUtils.getVxlanSegmentationId(elan).longValue(),
380 macToBeAdded, elanInstanceName, interfaceName));
382 for (L2GatewayDevice otherDevice : elanL2GwDevices) {
383 if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
384 && !areMLAGDevices(extL2GwDevice, otherDevice)) {
385 final String hwvtepId = otherDevice.getHwvtepNodeId();
386 final String logicalSwitchName = elanInstanceName;
387 HwvtepUtils.installUcastMacs(broker, hwvtepId, macList, logicalSwitchName,
393 LOG.trace("Skipping install of dmac flows for mac {} as it is not found in cache",
396 return Collections.emptyList();
402 * Does local ucast mac exists in cache.
404 * @param elanL2GwDevice
405 * the elan L2 Gw device
407 * the mac address to be verified
408 * @return true, if successful
410 private static boolean doesLocalUcastMacExistsInCache(L2GatewayDevice elanL2GwDevice, LocalUcastMacs macAddress) {
411 return elanL2GwDevice.containsUcastMac(macAddress);
415 * Uninstall l2gw macs from other l2gw devices in the elanName provided.
416 * @param elanName - Elan Name for which other l2gw devices will be scanned.
417 * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
418 * @param macAddresses - Mac address to be cleared.
420 public void unInstallL2GwUcastMacFromL2gwDevices(final String elanName,
421 final L2GatewayDevice l2GwDevice,
422 final Collection<MacAddress> macAddresses) {
423 if (macAddresses == null || macAddresses.isEmpty()) {
427 if (elanName == null) {
431 DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice,
433 elanClusterUtils.runOnlyInOwnerNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
437 * Uninstall l2gw macs from other DPNs in the elan instance provided.
438 * @param elan - Elan Instance for which other DPNs will be scanned.
439 * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
440 * @param macAddresses - Mac address to be cleared.
442 public void unInstallL2GwUcastMacFromElanDpns(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
443 final Collection<MacAddress> macAddresses) {
444 if (macAddresses == null || macAddresses.isEmpty()) {
447 if (elan == null || elan.getElanInstanceName() == null) {
448 LOG.error("Could not delete l2gw ucast macs, Failed to find the elan for device {}",
449 l2GwDevice.getHwvtepNodeId());
453 final Collection<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
455 // Retrieve all participating DPNs in this Elan. Populate this MAC in
456 // DMAC table. Looping through all DPNs in order to add/remove mac flows
457 // in their DMAC table
458 List<ListenableFuture<Void>> result = new ArrayList<>();
459 for (final MacAddress mac : macAddresses) {
460 elanClusterUtils.runOnlyInOwnerNode(elan.getElanInstanceName() + ":" + mac.getValue(),
461 "delete remote ucast macs in elan DPNs", () -> {
462 for (DpnInterfaces elanDpn : elanDpns) {
463 Uint64 dpnId = elanDpn.getDpId();
464 result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag().toJava(), dpnId,
465 l2GwDevice.getHwvtepNodeId(),
466 IetfYangUtil.INSTANCE.canonizeMacAddress(mac).getValue()));
474 * Delete elan l2 gateway devices ucast local macs from dpn.
481 public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final Uint64 dpnId) {
482 Collection<L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
483 if (elanL2GwDevices.isEmpty()) {
484 LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
487 final ElanInstance elan = elanInstanceCache.get(elanName).orElse(null);
489 LOG.error("Could not find Elan by name: {}", elanName);
492 LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
494 final Long elanTag = elan.getElanTag().toJava();
495 for (final L2GatewayDevice l2GwDevice : elanL2GwDevices) {
496 getL2GwDeviceLocalMacsAndRunCallback(elan.getElanInstanceName(), l2GwDevice, (localMacs) -> {
497 for (MacAddress mac : localMacs) {
498 String jobKey = elanName + ":" + mac.getValue();
499 elanClusterUtils.runOnlyInOwnerNode(jobKey,
500 () -> elanDmacUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
501 l2GwDevice.getHwvtepNodeId(), mac.getValue()));
508 public void getL2GwDeviceLocalMacsAndRunCallback(String elanName, L2GatewayDevice l2gwDevice,
509 Function<Collection<MacAddress>, Void> function) {
510 if (l2gwDevice == null) {
513 Set<MacAddress> macs = new HashSet<>();
514 Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
515 if (!lstUcastLocalMacs.isEmpty()) {
516 macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
517 .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.ENGLISH)))
518 .collect(Collectors.toList()));
521 InstanceIdentifier<Node> nodeIid = HwvtepSouthboundUtils.createInstanceIdentifier(
522 new NodeId(l2gwDevice.getHwvtepNodeId()));
523 Futures.addCallback(broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid),
524 new FutureCallback<Optional<Node>>() {
526 public void onSuccess(Optional<Node> configNode) {
527 if (configNode != null && configNode.isPresent()) {
528 HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(
529 HwvtepGlobalAugmentation.class);
530 if (augmentation != null && augmentation.nonnullLocalUcastMacs() != null) {
531 macs.addAll(new ArrayList<>(augmentation
532 .nonnullLocalUcastMacs().values()).stream()
533 .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
534 .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
535 .collect(Collectors.toSet()));
537 function.apply(macs);
542 public void onFailure(Throwable throwable) {
543 LOG.error("Failed to read config topology node {}", nodeIid);
545 }, MoreExecutors.directExecutor());
548 private static String getLogicalSwitchName(LocalUcastMacs mac) {
549 return ((InstanceIdentifier<LogicalSwitches>)mac.getLogicalSwitchRef().getValue())
550 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
554 * Delete elan macs from L2 gateway device.<br>
555 * This includes deleting ELAN mac table entries plus external device
556 * UcastLocalMacs which are part of the same ELAN.
558 * @param hwvtepNodeId
562 * @return the listenable future
564 public FluentFuture<? extends CommitInfo> deleteElanMacsFromL2GatewayDevice(String hwvtepNodeId, String elanName) {
565 String logicalSwitch = getLogicalSwitchFromElan(elanName);
567 List<MacAddress> lstElanMacs = getRemoteUcastMacs(new NodeId(hwvtepNodeId), logicalSwitch,
568 LogicalDatastoreType.CONFIGURATION);
569 FluentFuture<? extends CommitInfo> future = HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(hwvtepNodeId),
570 logicalSwitch, lstElanMacs);
572 Futures.addCallback(future, new FutureCallback<CommitInfo>() {
574 public void onSuccess(CommitInfo noarg) {
575 LOG.trace("Successful in batch deletion of elan [{}] macs from l2gw device [{}]", elanName,
580 public void onFailure(Throwable error) {
581 LOG.warn("Failed during batch delete of elan {} macs from l2gw device {}. "
582 + "Retrying with sequential deletes.", elanName, hwvtepNodeId, error);
583 if (lstElanMacs != null && !lstElanMacs.isEmpty()) {
584 for (MacAddress mac : lstElanMacs) {
585 HwvtepUtils.deleteRemoteUcastMac(broker, new NodeId(hwvtepNodeId), logicalSwitch, mac);
589 }, MoreExecutors.directExecutor());
591 if (LOG.isDebugEnabled()) {
592 List<String> elanMacs = lstElanMacs.stream().map(MacAddress::getValue).collect(Collectors.toList());
593 LOG.debug("Deleting elan [{}] macs from node [{}]. Deleted macs = {}", elanName, hwvtepNodeId, elanMacs);
599 * Gets the remote ucast macs from hwvtep node filtering based on logical
602 * @param hwvtepNodeId
604 * @param logicalSwitch
606 * @param datastoreType
608 * @return the remote ucast macs
610 public List<MacAddress> getRemoteUcastMacs(NodeId hwvtepNodeId, String logicalSwitch,
611 LogicalDatastoreType datastoreType) {
612 List<MacAddress> lstMacs = Collections.emptyList();
615 hwvtepNode = HwvtepUtils.getHwVtepNode(broker, datastoreType, hwvtepNodeId);
616 } catch (ExecutionException | InterruptedException e) {
617 LOG.error("getRemoteUcastMacs: Exception while reading hwvtepNodeId DS for the hwvtepNodeId {}",
618 hwvtepNodeId.getValue(), e);
619 return Collections.emptyList();
621 if (hwvtepNode != null) {
622 Map<RemoteUcastMacsKey, RemoteUcastMacs> keyRemoteUcastMacsMap
623 = hwvtepNode.augmentation(HwvtepGlobalAugmentation.class)
624 .nonnullRemoteUcastMacs();
625 if (keyRemoteUcastMacsMap != null && !keyRemoteUcastMacsMap.isEmpty()) {
626 // Filtering keyRemoteUcastMacsMap based on the logical switch and
627 // forming a list of MacAddress
628 lstMacs = keyRemoteUcastMacsMap.values().stream()
629 .filter(mac -> logicalSwitch.equals(mac.getLogicalSwitchRef().getValue()
630 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue()))
631 .map(HwvtepMacTableGenericAttributes::getMacEntryKey).collect(Collectors.toList());
638 * Install ELAN macs in L2 Gateway device.<br>
639 * This includes installing ELAN mac table entries plus external device
640 * UcastLocalMacs which are part of the same ELAN.
644 * @param l2GatewayDevice
645 * the l2 gateway device which has to be configured
646 * @return the listenable future
648 public FluentFuture<? extends CommitInfo> installElanMacsInL2GatewayDevice(String elanName,
649 L2GatewayDevice l2GatewayDevice) {
650 String logicalSwitchName = getLogicalSwitchFromElan(elanName);
651 NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
653 List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName, l2GatewayDevice, hwVtepNodeId,
655 List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
656 hwVtepNodeId, logicalSwitchName);
658 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
659 lstRemoteUcastMacs.addAll(lstElanMacTableEntries);
661 FluentFuture<? extends CommitInfo> future = HwvtepUtils.addRemoteUcastMacs(broker, hwVtepNodeId,
664 LOG.info("Added RemoteUcastMacs entries [{}] in config DS. NodeID: {}, LogicalSwitch: {}",
665 lstRemoteUcastMacs.size(), hwVtepNodeId.getValue(), logicalSwitchName);
670 * Gets the l2 gateway devices ucast local macs as remote ucast macs.
674 * @param l2GatewayDeviceToBeConfigured
675 * the l2 gateway device to be configured
676 * @param hwVtepNodeId
677 * the hw vtep node Id to be configured
678 * @param logicalSwitchName
679 * the logical switch name
680 * @return the l2 gateway devices macs as remote ucast macs
682 public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
683 L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
684 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
686 for (L2GatewayDevice otherDevice : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
687 if (l2GatewayDeviceToBeConfigured.getHwvtepNodeId().equals(otherDevice.getHwvtepNodeId())) {
690 if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
691 for (LocalUcastMacs localUcastMac : otherDevice.getUcastLocalMacs()) {
692 HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
693 .createHwvtepPhysicalLocatorAugmentation(otherDevice.getTunnelIp());
694 RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
695 IetfYangUtil.INSTANCE.canonizeMacAddress(localUcastMac.getMacEntryKey()).getValue(),
696 localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
697 lstRemoteUcastMacs.add(remoteUcastMac);
701 return lstRemoteUcastMacs;
707 * @param l2GatewayDevice
708 * the l2 gateway device
709 * @param otherL2GatewayDevice
710 * the other l2 gateway device
711 * @return true, if both the specified l2 gateway devices are part of same
714 public static boolean areMLAGDevices(L2GatewayDevice l2GatewayDevice, L2GatewayDevice otherL2GatewayDevice) {
715 // If tunnel IPs are same, then it is considered to be part of same MLAG
716 return Objects.equals(l2GatewayDevice.getTunnelIp(), otherL2GatewayDevice.getTunnelIp());
720 * Gets the elan mac table entries as remote ucast macs. <br>
721 * Note: ELAN MAC table only contains internal switches MAC's. It doesn't
722 * contain external device MAC's.
726 * @param hwVtepNodeId
727 * the hw vtep node id
728 * @param logicalSwitchName
729 * the logical switch name
730 * @return the elan mac table entries as remote ucast macs
732 public List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
733 NodeId hwVtepNodeId, String logicalSwitchName) {
734 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
736 MacTable macTable = ElanUtils.getElanMacTable(broker, elanName);
737 if (macTable == null || macTable.getMacEntry() == null || macTable.getMacEntry().isEmpty()) {
738 LOG.trace("MacTable is empty for elan: {}", elanName);
739 return lstRemoteUcastMacs;
742 for (MacEntry macEntry : new ArrayList<>(macTable.nonnullMacEntry().values())) {
743 Uint64 dpnId = getDpidFromInterface(macEntry.getInterface());
745 LOG.error("DPN ID not found for interface {}", macEntry.getInterface());
749 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, hwVtepNodeId);
750 LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpnId, hwVtepNodeId.getValue());
751 if (dpnTepIp == null) {
752 LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpnId, hwVtepNodeId.getValue());
755 HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
756 .createHwvtepPhysicalLocatorAugmentation(dpnTepIp);
757 // TODO: Query ARP cache to get IP address corresponding to the
759 RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
760 IetfYangUtil.INSTANCE.canonizePhysAddress(macEntry.getMacAddress()).getValue(), null /*IpAddress*/,
761 logicalSwitchName, physLocatorAug);
762 lstRemoteUcastMacs.add(remoteUcastMac);
764 return lstRemoteUcastMacs;
768 * Gets the dpid from interface.
770 * @param interfaceName
772 * @return the dpid from interface
775 public Uint64 getDpidFromInterface(String interfaceName) {
777 Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService
778 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
780 RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
781 if (rpcResult != null && rpcResult.isSuccessful()) {
782 dpId = rpcResult.getResult().getDpid();
784 } catch (InterruptedException | ExecutionException e) {
785 LOG.error("Failed to get the DPN ID for interface {}", interfaceName, e);
791 * Update vlan bindings in l2 gateway device.
795 * @param logicalSwitchName
796 * the logical switch name
797 * @param hwVtepDevice
798 * the hardware device
799 * @param defaultVlanId
800 * the default vlan id
801 * @return the listenable future
803 public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String logicalSwitchName,
804 Devices hwVtepDevice, Integer defaultVlanId) {
805 if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
806 String errMsg = "HwVtepDevice is null or interfaces are empty.";
808 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
811 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
812 for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
813 .l2gateway.attributes.devices.Interfaces deviceInterface : new ArrayList<>(hwVtepDevice
814 .nonnullInterfaces().values())) {
815 //Removed the check for checking terminationPoint present in OP or not
816 //for coniguring vlan bindings
817 //As we are not any more dependent on it , plugin takes care of this
818 // with port reconcilation.
819 List<VlanBindings> vlanBindings = new ArrayList<>();
820 if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
821 for (Integer vlanId : deviceInterface.getSegmentationIds()) {
822 vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, vlanId, logicalSwitchName));
825 // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
826 // ID not specified at interface level.
827 vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
829 HwvtepUtils.mergeVlanBindings(tx, nodeId, hwVtepDevice.getDeviceName(),
830 deviceInterface.getInterfaceName(), vlanBindings);
832 LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}", nodeId.getValue(),
838 * Update vlan bindings in l2 gateway device.
843 * the physical switch name
844 * @param interfaceName
845 * the interface in physical switch
846 * @param vlanBindings
847 * the vlan bindings to be configured
848 * @return the listenable future
850 public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String psName,
851 String interfaceName, List<VlanBindings> vlanBindings) {
852 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
853 HwvtepUtils.mergeVlanBindings(tx, nodeId, psName, interfaceName, vlanBindings);
854 LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
859 * Delete vlan bindings from l2 gateway device.
863 * @param hwVtepDevice
865 * @param defaultVlanId
866 * the default vlan id
867 * @return the listenable future
869 public ListenableFuture<Void> deleteVlanBindingsFromL2GatewayDevice(NodeId nodeId, Devices hwVtepDevice,
870 Integer defaultVlanId) {
871 if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
872 String errMsg = "HwVtepDevice is null or interfaces are empty.";
874 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
876 NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, hwVtepDevice.getDeviceName());
878 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
879 for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
880 .l2gateway.attributes.devices.Interfaces deviceInterface : new ArrayList<>(hwVtepDevice
881 .nonnullInterfaces().values())) {
882 String phyPortName = deviceInterface.getInterfaceName();
883 if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
884 for (Integer vlanId : deviceInterface.getSegmentationIds()) {
885 HwvtepUtils.deleteVlanBinding(tx, physicalSwitchNodeId, phyPortName, vlanId);
888 // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
889 // ID not specified at interface level.
890 HwvtepUtils.deleteVlanBinding(tx, physicalSwitchNodeId, phyPortName, defaultVlanId);
893 LOG.info("Deleted Hwvtep VlanBindings from config DS. NodeID: {}, hwVtepDevice: {}, defaultVlanId: {} ",
894 nodeId.getValue(), hwVtepDevice, defaultVlanId);
899 * Gets the logical switch name from elan name.
903 * @return the logical switch from elan name
905 public static String getLogicalSwitchFromElan(String elanName) {
906 // Assuming logical switch name is same as elan name
907 String logicalSwitchName = elanName;
908 return logicalSwitchName;
912 * Gets the l2 gateway connection job key.
914 * @param logicalSwitchName
915 * the logical switch name
916 * @return the l2 gateway connection job key
918 public static String getL2GatewayConnectionJobKey(String logicalSwitchName) {
919 return logicalSwitchName;
922 public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
923 InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder = InstanceIdentifier
924 .builder(Interfaces.class).child(Interface.class, interfaceKey);
925 return interfaceInstanceIdentifierBuilder.build();
929 public static Interface getInterfaceFromConfigDS(InterfaceKey interfaceKey, DataBroker dataBroker) {
930 InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
932 return SingleTransactionDataBroker
933 .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, interfaceId).orElse(null);
934 } catch (InterruptedException | ExecutionException e) {
935 // TODO remove this, and propagate ReadFailedException instead of re-throw RuntimeException
936 LOG.error("getInterfaceFromConfigDS({}) failed", interfaceKey, e);
937 throw new RuntimeException(e);
942 * Delete l2 gateway device ucast local macs from elan.<br>
943 * Deletes macs from internal ELAN nodes and also on rest of external l2
944 * gateway devices which are part of the ELAN.
946 * @param l2GatewayDevice
947 * the l2 gateway device whose ucast local macs to be deleted
952 public void deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
954 LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
957 ElanInstance elan = elanInstanceCache.get(elanName).orElse(null);
959 LOG.error("Could not find Elan by name: {}", elanName);
963 Collection<MacAddress> localMacs = getL2GwDeviceLocalMacs(elanName, l2GatewayDevice);
964 unInstallL2GwUcastMacFromL2gwDevices(elanName, l2GatewayDevice, localMacs);
965 unInstallL2GwUcastMacFromElanDpns(elan, l2GatewayDevice, localMacs);
968 public static void createItmTunnels(DataBroker dataBroker, ItmRpcService itmRpcService,
969 String hwvtepId, String psName, IpAddress tunnelIp) {
970 AddL2GwDeviceInputBuilder builder = new AddL2GwDeviceInputBuilder();
971 builder.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID.getValue());
972 builder.setNodeId(HwvtepSouthboundUtils.createManagedNodeId(new NodeId(hwvtepId), psName).getValue());
973 builder.setIpAddress(tunnelIp);
975 deleteStaleTunnelsOfHwvtepInITM(dataBroker, itmRpcService, hwvtepId, psName, tunnelIp);
976 RpcResult<AddL2GwDeviceOutput> rpcResult = itmRpcService.addL2GwDevice(builder.build()).get();
977 if (rpcResult.isSuccessful()) {
978 LOG.info("Created ITM tunnels for {}", hwvtepId);
980 LOG.error("Failed to create ITM Tunnels: {}", rpcResult.getErrors());
982 } catch (InterruptedException | ExecutionException e) {
983 LOG.error("RPC to create ITM tunnels failed", e);
987 private static void deleteStaleTunnelsOfHwvtepInITM(DataBroker dataBroker,
988 ItmRpcService itmRpcService,
991 IpAddress tunnelIp) {
993 Optional<TransportZones> tzonesoptional = readTransportZone(dataBroker);
994 if (!tzonesoptional.isPresent() || tzonesoptional.get().getTransportZone() == null) {
997 String psNodeId = globalNodeId + HwvtepHAUtil.PHYSICALSWITCH + psName;
998 tzonesoptional.get().nonnullTransportZone().stream()
999 .filter(zone -> zone.getDeviceVteps() != null)
1000 .flatMap(zone -> new ArrayList<>(zone.nonnullDeviceVteps().values()).stream())
1001 .filter(deviceVteps -> Objects.equals(getPsName(deviceVteps), psName)) //get device with same ps name
1002 .filter(deviceVteps -> !Objects.equals(psNodeId, deviceVteps.getNodeId())
1003 || !Objects.equals(tunnelIp, deviceVteps.getIpAddress()))//node id or tunnel ip is changed
1004 .forEach(deviceVteps -> deleteStaleL2gwTep(dataBroker, itmRpcService, deviceVteps));
1005 } catch (ExecutionException | InterruptedException e) {
1006 LOG.error("Failed delete stale tunnels for {}", globalNodeId);
1010 private static Optional<TransportZones> readTransportZone(DataBroker dataBroker) throws ExecutionException,
1011 InterruptedException {
1012 return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
1013 InstanceIdentifier.builder(TransportZones.class).build());
1016 private static Optional<ElanInstances> readElanInstances(DataBroker dataBroker) throws ExecutionException,
1017 InterruptedException {
1018 return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
1019 InstanceIdentifier.builder(ElanInstances.class).build());
1022 private static String getPsName(DeviceVteps deviceVteps) {
1023 return HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
1026 private static void deleteStaleL2gwTep(DataBroker dataBroker,
1027 ItmRpcService itmRpcService,
1028 DeviceVteps deviceVteps) {
1029 String psName = HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
1030 String globalNodeId = HwvtepHAUtil.convertToGlobalNodeId(deviceVteps.getNodeId());
1032 LOG.info("Deleting stale tep {} ", deviceVteps);
1033 L2GatewayUtils.deleteItmTunnels(itmRpcService, globalNodeId, psName, deviceVteps.getIpAddress());
1034 Optional<ElanInstances> optionalElan = readElanInstances(dataBroker);
1035 if (!optionalElan.isPresent()) {
1038 LoggingFutures.addErrorLogging(
1039 new ManagedNewTransactionRunnerImpl(dataBroker).callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
1040 tx -> optionalElan.get().nonnullElanInstance().values().stream()
1041 .flatMap(elan -> elan.nonnullExternalTeps().values().stream()
1042 .map(externalTep -> ElanL2GatewayMulticastUtils.buildExternalTepPath(
1043 elan.getElanInstanceName(), externalTep.getTepIp())))
1044 .filter(externalTepIid -> Objects.equals(
1045 deviceVteps.getIpAddress(), externalTepIid.firstKeyOf(ExternalTeps.class).getTepIp()))
1046 .peek(externalTepIid -> LOG.info("Deleting stale external tep {}", externalTepIid))
1047 .forEach(tx::delete)), LOG,
1048 "Failed to delete stale external teps {}", deviceVteps);
1049 Thread.sleep(10000);//TODO remove the sleep currently it waits for interfacemgr to finish the cleanup
1050 } catch (ExecutionException | InterruptedException e) {
1051 LOG.error("Failed to delete stale l2gw tep {}", deviceVteps, e);
1055 public void scheduleAddDpnMacInExtDevices(String elanName, Uint64 dpId,
1056 List<PhysAddress> staticMacAddresses) {
1057 for (final L2GatewayDevice externalDevice : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName)) {
1058 scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
1062 public void scheduleAddDpnMacsInExtDevice(final String elanName, Uint64 dpId,
1063 final List<PhysAddress> staticMacAddresses, final L2GatewayDevice externalDevice) {
1064 NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
1065 final IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpId, nodeId);
1066 LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
1067 if (dpnTepIp == null) {
1068 LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
1072 //TODO: to be batched in genius
1073 HwvtepUtils.installUcastMacs(broker, externalDevice.getHwvtepNodeId(), staticMacAddresses, elanName, dpnTepIp);
1076 public void scheduleDeleteLogicalSwitch(NodeId hwvtepNodeId, String lsName) {
1077 scheduleDeleteLogicalSwitch(hwvtepNodeId, lsName, false);
1080 public void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName, final boolean clearUcast) {
1081 final Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1082 logicalSwitchDeletedTasks.computeIfAbsent(nodeIdLogicalSwitchNamePair,
1083 (key) -> scheduler.getScheduledExecutorService().schedule(() -> {
1084 DeleteLogicalSwitchJob deleteLsJob = new DeleteLogicalSwitchJob(broker,
1085 ElanL2GatewayUtils.this, hwvtepNodeId, lsName, clearUcast);
1086 jobCoordinator.enqueueJob(deleteLsJob.getJobKey(), deleteLsJob,
1087 SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
1088 deleteJobs.put(nodeIdLogicalSwitchNamePair, deleteLsJob);
1089 logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1090 }, getLogicalSwitchDeleteDelaySecs(), TimeUnit.SECONDS));
1093 public void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
1094 Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1095 ScheduledFuture logicalSwitchDeleteTask = logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1096 if (logicalSwitchDeleteTask != null) {
1097 LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
1098 logicalSwitchDeleteTask.cancel(true);
1099 DeleteLogicalSwitchJob deleteLogicalSwitchJob = deleteJobs.remove(nodeIdLogicalSwitchNamePair);
1100 if (deleteLogicalSwitchJob != null) {
1101 deleteLogicalSwitchJob.cancel();
1107 public Collection<DpnInterfaces> getElanDpns(String elanName) {
1108 Collection<DpnInterfaces> dpnInterfaces = elanInstanceDpnsCache.get(elanName);
1109 if (!dpnInterfaces.isEmpty()) {
1110 return dpnInterfaces;
1113 return elanUtils.getElanDPNByName(elanName);
1117 * Gets the l2 gw device local macs.
1122 * @return the l2 gw device local macs
1124 public Collection<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
1125 if (l2gwDevice == null) {
1126 return Collections.emptyList();
1128 Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
1129 Set<MacAddress> macs = new HashSet<>();
1130 if (!lstUcastLocalMacs.isEmpty()) {
1131 macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
1132 .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.ENGLISH)))
1133 .collect(Collectors.toList()));
1135 Optional<Node> configNode;
1137 configNode = SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION,
1138 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
1139 } catch (ExecutionException | InterruptedException e) {
1140 LOG.error("getL2GwDeviceLocalMacs: Exception while reading l2gwDevice DS for the elan {}, l2gwDevice {}",
1141 elanName, l2gwDevice, e);
1142 return Collections.emptyList();
1144 if (configNode.isPresent()) {
1145 HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(HwvtepGlobalAugmentation.class);
1146 if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
1147 macs.addAll(augmentation.nonnullLocalUcastMacs().values().stream()
1148 .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
1149 .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
1150 .collect(Collectors.toSet()));