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 com.google.common.base.Optional;
11 import com.google.common.collect.Lists;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import java.math.BigInteger;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Locale;
23 import java.util.Objects;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.ScheduledFuture;
30 import java.util.concurrent.TimeUnit;
31 import java.util.function.Function;
32 import java.util.stream.Collectors;
33 import javax.annotation.Nonnull;
34 import javax.annotation.PreDestroy;
35 import javax.inject.Inject;
36 import javax.inject.Singleton;
37 import org.apache.commons.lang3.tuple.ImmutablePair;
38 import org.apache.commons.lang3.tuple.Pair;
39 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
42 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
43 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
44 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
45 import org.opendaylight.genius.mdsalutil.MDSALUtil;
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.JdkFutures;
52 import org.opendaylight.netvirt.elan.ElanException;
53 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
54 import org.opendaylight.netvirt.elan.cache.ElanInstanceDpnsCache;
55 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
56 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
57 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteLogicalSwitchJob;
58 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
59 import org.opendaylight.netvirt.elan.utils.ElanConstants;
60 import org.opendaylight.netvirt.elan.utils.ElanDmacUtils;
61 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
62 import org.opendaylight.netvirt.elan.utils.ElanUtils;
63 import org.opendaylight.netvirt.elan.utils.Scheduler;
64 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
65 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
66 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
67 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
68 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
71 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.DeviceVteps;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInputBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceOutput;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepMacTableGenericAttributes;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
102 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
103 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
104 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
105 import org.opendaylight.yangtools.yang.common.RpcResult;
106 import org.slf4j.Logger;
107 import org.slf4j.LoggerFactory;
110 * It gathers a set of utility methods that handle ELAN configuration in
111 * external Devices (where external means "not-CSS". As of now: TORs).
113 * <p>It makes use of HwvtepUtils class located under ovsdb/hwvtepsouthbound
114 * project for low-level mdsal operations
119 public class ElanL2GatewayUtils {
120 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
121 private static final int DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS = 20;
123 private final DataBroker broker;
124 private final ManagedNewTransactionRunner txRunner;
125 private final ElanDmacUtils elanDmacUtils;
126 private final ElanItmUtils elanItmUtils;
127 private final ElanClusterUtils elanClusterUtils;
128 private final OdlInterfaceRpcService interfaceManagerRpcService;
129 private final JobCoordinator jobCoordinator;
130 private final ElanUtils elanUtils;
131 private final ElanInstanceCache elanInstanceCache;
132 private final ElanInstanceDpnsCache elanInstanceDpnsCache;
134 private final ConcurrentMap<Pair<NodeId, String>, ScheduledFuture> logicalSwitchDeletedTasks
135 = new ConcurrentHashMap<>();
136 private final ConcurrentMap<Pair<NodeId, String>, DeleteLogicalSwitchJob> deleteJobs = new ConcurrentHashMap<>();
137 private final Scheduler scheduler;
138 private final ElanConfig elanConfig;
141 public ElanL2GatewayUtils(DataBroker broker, ElanDmacUtils elanDmacUtils, ElanItmUtils elanItmUtils,
142 ElanClusterUtils elanClusterUtils, OdlInterfaceRpcService interfaceManagerRpcService,
143 JobCoordinator jobCoordinator, ElanUtils elanUtils,
144 Scheduler scheduler, ElanConfig elanConfig, ElanInstanceCache elanInstanceCache,
145 ElanInstanceDpnsCache elanInstanceDpnsCache) {
146 this.broker = broker;
147 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
148 this.elanDmacUtils = elanDmacUtils;
149 this.elanItmUtils = elanItmUtils;
150 this.elanClusterUtils = elanClusterUtils;
151 this.interfaceManagerRpcService = interfaceManagerRpcService;
152 this.jobCoordinator = jobCoordinator;
153 this.elanUtils = elanUtils;
154 this.scheduler = scheduler;
155 this.elanConfig = elanConfig;
156 this.elanInstanceCache = elanInstanceCache;
157 this.elanInstanceDpnsCache = elanInstanceDpnsCache;
161 public void close() {
164 public long getLogicalSwitchDeleteDelaySecs() {
165 return elanConfig.getL2gwLogicalSwitchDelaySecs() != null
166 ? elanConfig.getL2gwLogicalSwitchDelaySecs() : DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS;
170 * gets the macs addresses for elan interfaces.
172 * @param lstElanInterfaceNames
173 * the lst elan interface names
176 public List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
177 List<PhysAddress> result = new ArrayList<>();
178 for (String interfaceName : lstElanInterfaceNames) {
179 ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(broker, interfaceName);
180 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
181 for (MacEntry macEntry : elanInterfaceMac.getMacEntry()) {
182 result.add(macEntry.getMacAddress());
190 * Check if phy locator already exists in remote mcast entry.
194 * @param remoteMcastMac
195 * the remote mcast mac
196 * @param expectedPhyLocatorIp
197 * the expected phy locator ip
198 * @return true, if successful
200 public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
201 RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
202 if (remoteMcastMac != null) {
203 HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
204 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(expectedPhyLocatorIp.getValue()));
205 HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
206 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
207 if (remoteMcastMac.getLocatorSet() != null) {
208 for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
209 if (locatorSet.getLocatorRef().equals(expectedPhyLocRef)) {
210 LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
220 * Gets the remote mcast mac.
224 * @param logicalSwitchName
225 * the logical switch name
226 * @param datastoreType
228 * @return the remote mcast mac
230 public RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
231 LogicalDatastoreType datastoreType) {
232 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
233 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
234 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
235 new MacAddress(ElanConstants.UNKNOWN_DMAC));
236 return HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId, remoteMcastMacsKey);
240 * Removes the given MAC Addresses from all the External Devices belonging
241 * to the specified ELAN.
243 * @param elanInstance
245 * @param macAddresses
248 public void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
249 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
250 .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
251 for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
252 removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
253 elanInstance.getElanInstanceName(), macAddresses);
258 * Removes the given MAC Addresses from the specified External Device.
260 * @param deviceNodeId
262 * @param macAddresses
264 * @return the listenable future
266 private ListenableFuture<Void> removeRemoteUcastMacsFromExternalDevice(String deviceNodeId,
267 String logicalSwitchName, List<PhysAddress> macAddresses) {
268 NodeId nodeId = new NodeId(deviceNodeId);
271 List<MacAddress> lstMac = macAddresses.stream().filter(Objects::nonNull).map(
272 physAddress -> new MacAddress(physAddress.getValue())).collect(Collectors.toList());
273 return HwvtepUtils.deleteRemoteUcastMacs(broker, nodeId, logicalSwitchName, lstMac);
276 public ElanInstance getElanInstanceForUcastLocalMac(LocalUcastMacs localUcastMac) {
277 Optional<LogicalSwitches> lsOpc = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL,
278 (InstanceIdentifier<LogicalSwitches>) localUcastMac.getLogicalSwitchRef().getValue());
279 if (lsOpc.isPresent()) {
280 LogicalSwitches ls = lsOpc.get();
281 // Logical switch name is Elan name
282 String elanName = getElanFromLogicalSwitch(ls.getHwvtepNodeName().getValue());
283 return elanInstanceCache.get(elanName).orNull();
289 * Install external device local macs in dpn.
293 * @param l2gwDeviceNodeId
294 * the l2gw device node id
297 * @param interfaceName
299 * @throws ElanException in case of issues creating the flow objects
301 public void installL2gwDeviceMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan,
302 String interfaceName) throws ElanException {
303 L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
304 l2gwDeviceNodeId.getValue());
305 if (l2gwDevice == null) {
306 LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
310 installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
314 * Install dmac flows on dpn.
322 * @param interfaceName
324 * @throws ElanException in case of issues creating the flow objects
326 public void installDmacFlowsOnDpn(BigInteger dpnId, L2GatewayDevice l2gwDevice, ElanInstance elan,
327 String interfaceName) throws ElanException {
328 String elanName = elan.getElanInstanceName();
330 Collection<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
331 if (!l2gwDeviceLocalMacs.isEmpty()) {
332 for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
333 elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(dpnId, l2gwDevice.getHwvtepNodeId(),
334 elan.getElanTag(), ElanUtils.getVxlanSegmentationId(elan),
335 localUcastMac.getMacEntryKey().getValue(), elanName, interfaceName);
337 LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
338 l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
343 * Install elan l2gw devices local macs in dpn.
349 * @param interfaceName
351 * @throws ElanException in case of issues creating the flow objects
353 public void installElanL2gwDevicesLocalMacsInDpn(BigInteger dpnId, ElanInstance elan, String interfaceName)
354 throws ElanException {
355 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
356 .getInvolvedL2GwDevices(elan.getElanInstanceName());
357 if (elanL2GwDevicesFromCache != null) {
358 for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
359 installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
362 LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
366 public void installL2GwUcastMacInElan(final ElanInstance elan, final L2GatewayDevice extL2GwDevice,
367 final String macToBeAdded, final LocalUcastMacs localUcastMacs, String interfaceName) {
368 final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
369 final String elanInstanceName = elan.getElanInstanceName();
370 final Collection<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
371 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
372 .getInvolvedL2GwDevices(elanInstanceName);
374 // Retrieve all participating DPNs in this Elan. Populate this MAC in
376 // Looping through all DPNs in order to add/remove mac flows in their
378 if (elanDpns.size() > 0 || elanL2GwDevices.values().size() > 0) {
379 String jobKey = elanInstanceName + ":" + macToBeAdded;
380 IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
381 List<PhysAddress> macList = Lists.newArrayList(new PhysAddress(macToBeAdded));
383 elanClusterUtils.runOnlyInOwnerNode(jobKey, "install l2gw macs in dmac table", () -> {
384 if (doesLocalUcastMacExistsInCache(extL2GwDevice, localUcastMacs)) {
385 List<ListenableFuture<Void>> futures = new ArrayList<>();
386 for (DpnInterfaces elanDpn : elanDpns) {
387 futures.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(elanDpn.getDpId(),
388 extDeviceNodeId, elan.getElanTag(), ElanUtils.getVxlanSegmentationId(elan),
389 macToBeAdded, elanInstanceName, interfaceName));
391 for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
392 if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
393 && !areMLAGDevices(extL2GwDevice, otherDevice)) {
394 final String hwvtepId = otherDevice.getHwvtepNodeId();
395 final String logicalSwitchName = elanInstanceName;
396 futures.add(HwvtepUtils.installUcastMacs(
397 broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp));
402 LOG.trace("Skipping install of dmac flows for mac {} as it is not found in cache",
405 return Collections.emptyList();
411 * Does local ucast mac exists in cache.
413 * @param elanL2GwDevice
414 * the elan L2 Gw device
416 * the mac address to be verified
417 * @return true, if successful
419 private static boolean doesLocalUcastMacExistsInCache(L2GatewayDevice elanL2GwDevice, LocalUcastMacs macAddress) {
420 return elanL2GwDevice.containsUcastMac(macAddress);
424 * Uninstall l2gw macs from other l2gw devices in the elanName provided.
425 * @param elanName - Elan Name for which other l2gw devices will be scanned.
426 * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
427 * @param macAddresses - Mac address to be cleared.
429 public void unInstallL2GwUcastMacFromL2gwDevices(final String elanName,
430 final L2GatewayDevice l2GwDevice,
431 final Collection<MacAddress> macAddresses) {
432 if (macAddresses == null || macAddresses.isEmpty()) {
436 if (elanName == null) {
440 DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice,
442 elanClusterUtils.runOnlyInOwnerNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
446 * Uninstall l2gw macs from other DPNs in the elan instance provided.
447 * @param elan - Elan Instance for which other DPNs will be scanned.
448 * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
449 * @param macAddresses - Mac address to be cleared.
451 public void unInstallL2GwUcastMacFromElanDpns(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
452 final Collection<MacAddress> macAddresses) {
453 if (macAddresses == null || macAddresses.isEmpty()) {
456 if (elan == null || elan.getElanInstanceName() == null) {
457 LOG.error("Could not delete l2gw ucast macs, Failed to find the elan for device {}",
458 l2GwDevice.getHwvtepNodeId());
462 final Collection<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
464 // Retrieve all participating DPNs in this Elan. Populate this MAC in
465 // DMAC table. Looping through all DPNs in order to add/remove mac flows
466 // in their DMAC table
467 List<ListenableFuture<Void>> result = new ArrayList<>();
468 for (final MacAddress mac : macAddresses) {
469 elanClusterUtils.runOnlyInOwnerNode(elan.getElanInstanceName() + ":" + mac.getValue(),
470 "delete remote ucast macs in elan DPNs", () -> {
471 for (DpnInterfaces elanDpn : elanDpns) {
472 BigInteger dpnId = elanDpn.getDpId();
473 result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
474 l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase(Locale.getDefault())));
482 * Delete elan l2 gateway devices ucast local macs from dpn.
489 public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId) {
490 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
491 if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
492 LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
495 final ElanInstance elan = elanInstanceCache.get(elanName).orNull();
497 LOG.error("Could not find Elan by name: {}", elanName);
500 LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
502 final Long elanTag = elan.getElanTag();
503 for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
504 getL2GwDeviceLocalMacsAndRunCallback(elan.getElanInstanceName(), l2GwDevice, (localMacs) -> {
505 for (MacAddress mac : localMacs) {
506 String jobKey = elanName + ":" + mac.getValue();
507 elanClusterUtils.runOnlyInOwnerNode(jobKey,
508 () -> elanDmacUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
509 l2GwDevice.getHwvtepNodeId(), mac.getValue()));
516 public void getL2GwDeviceLocalMacsAndRunCallback(String elanName, L2GatewayDevice l2gwDevice,
517 Function<Collection<MacAddress>, Void> function) {
518 if (l2gwDevice == null) {
521 Set<MacAddress> macs = new HashSet<>();
522 Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
523 if (!lstUcastLocalMacs.isEmpty()) {
524 macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
525 .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase()))
526 .collect(Collectors.toList()));
529 InstanceIdentifier<Node> nodeIid = HwvtepSouthboundUtils.createInstanceIdentifier(
530 new NodeId(l2gwDevice.getHwvtepNodeId()));
531 Futures.addCallback(broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid),
532 new FutureCallback<Optional<Node>>() {
534 public void onSuccess(Optional<Node> configNode) {
535 if (configNode != null && configNode.isPresent()) {
536 HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(
537 HwvtepGlobalAugmentation.class);
538 if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
539 macs.addAll(augmentation.getLocalUcastMacs().stream()
540 .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
541 .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
542 .collect(Collectors.toSet()));
544 function.apply(macs);
549 public void onFailure(Throwable throwable) {
550 LOG.error("Failed to read config topology node {}", nodeIid);
552 }, MoreExecutors.directExecutor());
555 private String getLogicalSwitchName(LocalUcastMacs mac) {
556 return ((InstanceIdentifier<LogicalSwitches>)mac.getLogicalSwitchRef().getValue())
557 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
561 * Delete elan macs from L2 gateway device.<br>
562 * This includes deleting ELAN mac table entries plus external device
563 * UcastLocalMacs which are part of the same ELAN.
565 * @param hwvtepNodeId
569 * @return the listenable future
571 public ListenableFuture<Void> deleteElanMacsFromL2GatewayDevice(String hwvtepNodeId, String elanName) {
572 String logicalSwitch = getLogicalSwitchFromElan(elanName);
574 List<MacAddress> lstElanMacs = getRemoteUcastMacs(new NodeId(hwvtepNodeId), logicalSwitch,
575 LogicalDatastoreType.CONFIGURATION);
576 ListenableFuture<Void> future = HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(hwvtepNodeId),
577 logicalSwitch, lstElanMacs);
579 Futures.addCallback(future, new FutureCallback<Void>() {
581 public void onSuccess(Void noarg) {
582 LOG.trace("Successful in batch deletion of elan [{}] macs from l2gw device [{}]", elanName,
587 public void onFailure(Throwable error) {
588 LOG.warn("Failed during batch delete of elan {} macs from l2gw device {}. "
589 + "Retrying with sequential deletes.", elanName, hwvtepNodeId, error);
590 if (lstElanMacs != null && !lstElanMacs.isEmpty()) {
591 for (MacAddress mac : lstElanMacs) {
592 HwvtepUtils.deleteRemoteUcastMac(broker, new NodeId(hwvtepNodeId), logicalSwitch, mac);
596 }, MoreExecutors.directExecutor());
598 if (LOG.isDebugEnabled()) {
599 List<String> elanMacs = lstElanMacs.stream().map(MacAddress::getValue).collect(Collectors.toList());
600 LOG.debug("Deleting elan [{}] macs from node [{}]. Deleted macs = {}", elanName, hwvtepNodeId, elanMacs);
606 * Gets the remote ucast macs from hwvtep node filtering based on logical
609 * @param hwvtepNodeId
611 * @param logicalSwitch
613 * @param datastoreType
615 * @return the remote ucast macs
617 public List<MacAddress> getRemoteUcastMacs(NodeId hwvtepNodeId, String logicalSwitch,
618 LogicalDatastoreType datastoreType) {
619 List<MacAddress> lstMacs = Collections.emptyList();
620 Node hwvtepNode = HwvtepUtils.getHwVtepNode(broker, datastoreType, hwvtepNodeId);
621 if (hwvtepNode != null) {
622 List<RemoteUcastMacs> remoteUcastMacs = hwvtepNode.augmentation(HwvtepGlobalAugmentation.class)
623 .getRemoteUcastMacs();
624 if (remoteUcastMacs != null && !remoteUcastMacs.isEmpty()) {
625 // Filtering remoteUcastMacs based on the logical switch and
626 // forming a list of MacAddress
627 lstMacs = remoteUcastMacs.stream()
628 .filter(mac -> logicalSwitch.equals(mac.getLogicalSwitchRef().getValue()
629 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue()))
630 .map(HwvtepMacTableGenericAttributes::getMacEntryKey).collect(Collectors.toList());
637 * Install ELAN macs in L2 Gateway device.<br>
638 * This includes installing ELAN mac table entries plus external device
639 * UcastLocalMacs which are part of the same ELAN.
643 * @param l2GatewayDevice
644 * the l2 gateway device which has to be configured
645 * @return the listenable future
647 public ListenableFuture<Void> installElanMacsInL2GatewayDevice(String elanName,
648 L2GatewayDevice l2GatewayDevice) {
649 String logicalSwitchName = getLogicalSwitchFromElan(elanName);
650 NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
652 List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName, l2GatewayDevice, hwVtepNodeId,
654 List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
655 hwVtepNodeId, logicalSwitchName);
657 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
658 lstRemoteUcastMacs.addAll(lstElanMacTableEntries);
660 ListenableFuture<Void> future = HwvtepUtils.addRemoteUcastMacs(broker, hwVtepNodeId, lstRemoteUcastMacs);
662 LOG.info("Added RemoteUcastMacs entries [{}] in config DS. NodeID: {}, LogicalSwitch: {}",
663 lstRemoteUcastMacs.size(), hwVtepNodeId.getValue(), logicalSwitchName);
668 * Gets the l2 gateway devices ucast local macs as remote ucast macs.
672 * @param l2GatewayDeviceToBeConfigured
673 * the l2 gateway device to be configured
674 * @param hwVtepNodeId
675 * the hw vtep node Id to be configured
676 * @param logicalSwitchName
677 * the logical switch name
678 * @return the l2 gateway devices macs as remote ucast macs
680 public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
681 L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
682 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
683 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
684 .getInvolvedL2GwDevices(elanName);
686 if (elanL2GwDevicesFromCache != null) {
687 for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
688 if (l2GatewayDeviceToBeConfigured.getHwvtepNodeId().equals(otherDevice.getHwvtepNodeId())) {
691 if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
692 for (LocalUcastMacs localUcastMac : otherDevice.getUcastLocalMacs()) {
693 HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
694 .createHwvtepPhysicalLocatorAugmentation(
695 String.valueOf(otherDevice.getTunnelIp().getValue()));
696 RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
697 localUcastMac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault()),
698 localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
699 lstRemoteUcastMacs.add(remoteUcastMac);
704 return lstRemoteUcastMacs;
710 * @param l2GatewayDevice
711 * the l2 gateway device
712 * @param otherL2GatewayDevice
713 * the other l2 gateway device
714 * @return true, if both the specified l2 gateway devices are part of same
717 public static boolean areMLAGDevices(L2GatewayDevice l2GatewayDevice, L2GatewayDevice otherL2GatewayDevice) {
718 // If tunnel IPs are same, then it is considered to be part of same MLAG
719 return Objects.equals(l2GatewayDevice.getTunnelIp(), otherL2GatewayDevice.getTunnelIp());
723 * Gets the elan mac table entries as remote ucast macs. <br>
724 * Note: ELAN MAC table only contains internal switches MAC's. It doesn't
725 * contain external device MAC's.
729 * @param hwVtepNodeId
730 * the hw vtep node id
731 * @param logicalSwitchName
732 * the logical switch name
733 * @return the elan mac table entries as remote ucast macs
735 public List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
736 NodeId hwVtepNodeId, String logicalSwitchName) {
737 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
739 MacTable macTable = ElanUtils.getElanMacTable(broker, elanName);
740 if (macTable == null || macTable.getMacEntry() == null || macTable.getMacEntry().isEmpty()) {
741 LOG.trace("MacTable is empty for elan: {}", elanName);
742 return lstRemoteUcastMacs;
745 for (MacEntry macEntry : macTable.getMacEntry()) {
746 BigInteger dpnId = getDpidFromInterface(macEntry.getInterface());
748 LOG.error("DPN ID not found for interface {}", macEntry.getInterface());
752 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, hwVtepNodeId);
753 LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpnId, hwVtepNodeId.getValue());
754 if (dpnTepIp == null) {
755 LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpnId, hwVtepNodeId.getValue());
758 HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
759 .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
760 // TODO: Query ARP cache to get IP address corresponding to the
762 RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
763 macEntry.getMacAddress().getValue().toLowerCase(Locale.getDefault()), null /*IpAddress*/,
764 logicalSwitchName, physLocatorAug);
765 lstRemoteUcastMacs.add(remoteUcastMac);
767 return lstRemoteUcastMacs;
771 * Gets the dpid from interface.
773 * @param interfaceName
775 * @return the dpid from interface
777 public BigInteger getDpidFromInterface(String interfaceName) {
778 BigInteger dpId = null;
779 Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService
780 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
782 RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
783 if (rpcResult != null && rpcResult.isSuccessful()) {
784 dpId = rpcResult.getResult().getDpid();
786 } catch (InterruptedException | ExecutionException e) {
787 LOG.error("Failed to get the DPN ID for interface {}", interfaceName, e);
793 * Update vlan bindings in l2 gateway device.
797 * @param logicalSwitchName
798 * the logical switch name
799 * @param hwVtepDevice
800 * the hardware device
801 * @param defaultVlanId
802 * the default vlan id
803 * @return the listenable future
805 public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String logicalSwitchName,
806 Devices hwVtepDevice, Integer defaultVlanId) {
807 if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
808 String errMsg = "HwVtepDevice is null or interfaces are empty.";
810 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
813 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
814 for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
815 .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
816 //Removed the check for checking terminationPoint present in OP or not
817 //for coniguring vlan bindings
818 //As we are not any more dependent on it , plugin takes care of this
819 // with port reconcilation.
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));
826 // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
827 // ID not specified at interface level.
828 vlanBindings.add(HwvtepSouthboundUtils.createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
830 HwvtepUtils.mergeVlanBindings(tx, nodeId, hwVtepDevice.getDeviceName(),
831 deviceInterface.getInterfaceName(), vlanBindings);
833 LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}", nodeId.getValue(),
839 * Update vlan bindings in l2 gateway device.
844 * the physical switch name
845 * @param interfaceName
846 * the interface in physical switch
847 * @param vlanBindings
848 * the vlan bindings to be configured
849 * @return the listenable future
851 public ListenableFuture<Void> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String psName,
852 String interfaceName, List<VlanBindings> vlanBindings) {
853 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
854 HwvtepUtils.mergeVlanBindings(tx, nodeId, psName, interfaceName, vlanBindings);
855 LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
860 * Delete vlan bindings from l2 gateway device.
864 * @param hwVtepDevice
866 * @param defaultVlanId
867 * the default vlan id
868 * @return the listenable future
870 public ListenableFuture<Void> deleteVlanBindingsFromL2GatewayDevice(NodeId nodeId, Devices hwVtepDevice,
871 Integer defaultVlanId) {
872 if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
873 String errMsg = "HwVtepDevice is null or interfaces are empty.";
875 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
877 NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, hwVtepDevice.getDeviceName());
879 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
880 for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
881 .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.getInterfaces()) {
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 elan name from logical switch name.
901 * @param logicalSwitchName
902 * the logical switch name
903 * @return the elan name from logical switch name
905 public static String getElanFromLogicalSwitch(String logicalSwitchName) {
906 // Assuming elan name is same as logical switch name
907 String elanName = logicalSwitchName;
912 * Gets the logical switch name from elan name.
916 * @return the logical switch from elan name
918 public static String getLogicalSwitchFromElan(String elanName) {
919 // Assuming logical switch name is same as elan name
920 String logicalSwitchName = elanName;
921 return logicalSwitchName;
925 * Gets the l2 gateway connection job key.
927 * @param logicalSwitchName
928 * the logical switch name
929 * @return the l2 gateway connection job key
931 public static String getL2GatewayConnectionJobKey(String logicalSwitchName) {
932 return logicalSwitchName;
935 public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
936 InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder = InstanceIdentifier
937 .builder(Interfaces.class).child(Interface.class, interfaceKey);
938 return interfaceInstanceIdentifierBuilder.build();
941 public static Interface getInterfaceFromConfigDS(InterfaceKey interfaceKey, DataBroker dataBroker) {
942 InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
944 return SingleTransactionDataBroker
945 .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, interfaceId).orNull();
946 } catch (ReadFailedException e) {
947 // TODO remove this, and propagate ReadFailedException instead of re-throw RuntimeException
948 LOG.error("getInterfaceFromConfigDS({}) failed", interfaceKey, e);
949 throw new RuntimeException(e);
954 * Delete l2 gateway device ucast local macs from elan.<br>
955 * Deletes macs from internal ELAN nodes and also on rest of external l2
956 * gateway devices which are part of the ELAN.
958 * @param l2GatewayDevice
959 * the l2 gateway device whose ucast local macs to be deleted
964 public void deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
966 LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
969 ElanInstance elan = elanInstanceCache.get(elanName).orNull();
971 LOG.error("Could not find Elan by name: {}", elanName);
975 Collection<MacAddress> localMacs = getL2GwDeviceLocalMacs(elanName, l2GatewayDevice);
976 unInstallL2GwUcastMacFromL2gwDevices(elanName, l2GatewayDevice, localMacs);
977 unInstallL2GwUcastMacFromElanDpns(elan, l2GatewayDevice, localMacs);
980 public static void createItmTunnels(DataBroker dataBroker, ItmRpcService itmRpcService,
981 String hwvtepId, String psName, IpAddress tunnelIp) {
982 AddL2GwDeviceInputBuilder builder = new AddL2GwDeviceInputBuilder();
983 builder.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID.getValue());
984 builder.setNodeId(HwvtepSouthboundUtils.createManagedNodeId(new NodeId(hwvtepId), psName).getValue());
985 builder.setIpAddress(tunnelIp);
987 deleteStaleTunnelsOfHwvtepInITM(dataBroker, itmRpcService, hwvtepId, psName, tunnelIp);
988 RpcResult<AddL2GwDeviceOutput> rpcResult = itmRpcService.addL2GwDevice(builder.build()).get();
989 if (rpcResult.isSuccessful()) {
990 LOG.info("Created ITM tunnels for {}", hwvtepId);
992 LOG.error("Failed to create ITM Tunnels: {}", rpcResult.getErrors());
994 } catch (InterruptedException | ExecutionException e) {
995 LOG.error("RPC to create ITM tunnels failed", e);
999 private static void deleteStaleTunnelsOfHwvtepInITM(DataBroker dataBroker,
1000 ItmRpcService itmRpcService,
1001 String globalNodeId,
1003 IpAddress tunnelIp) {
1005 Optional<TransportZones> tzonesoptional = readTransportZone(dataBroker);
1006 if (!tzonesoptional.isPresent() || tzonesoptional.get().getTransportZone() == null) {
1009 String psNodeId = globalNodeId + HwvtepHAUtil.PHYSICALSWITCH + psName;
1010 tzonesoptional.get().getTransportZone().stream()
1011 .filter(transportZone -> transportZone.getSubnets() != null)
1012 .flatMap(transportZone -> transportZone.getSubnets().stream())
1013 .filter(subnet -> subnet.getDeviceVteps() != null)
1014 .flatMap(subnet -> subnet.getDeviceVteps().stream())
1015 .filter(deviceVteps -> Objects.equals(getPsName(deviceVteps), psName)) //get device with same ps name
1016 .filter(deviceVteps -> !Objects.equals(psNodeId, deviceVteps.getNodeId())
1017 || !Objects.equals(tunnelIp, deviceVteps.getIpAddress()))//node id or tunnel ip is changed
1018 .forEach(deviceVteps -> deleteStaleL2gwTep(dataBroker, itmRpcService, deviceVteps));
1019 } catch (ReadFailedException e) {
1020 LOG.error("Failed delete stale tunnels for {}", globalNodeId);
1024 private static Optional<TransportZones> readTransportZone(DataBroker dataBroker) throws ReadFailedException {
1025 return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
1026 InstanceIdentifier.builder(TransportZones.class).build());
1029 private static Optional<ElanInstances> readElanInstances(DataBroker dataBroker) throws ReadFailedException {
1030 return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
1031 InstanceIdentifier.builder(ElanInstances.class).build());
1034 private static String getPsName(DeviceVteps deviceVteps) {
1035 return HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
1038 private static void deleteStaleL2gwTep(DataBroker dataBroker,
1039 ItmRpcService itmRpcService,
1040 DeviceVteps deviceVteps) {
1041 String psName = HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
1042 String globalNodeId = HwvtepHAUtil.convertToGlobalNodeId(deviceVteps.getNodeId());
1044 LOG.info("Deleting stale tep {} ", deviceVteps);
1045 L2GatewayUtils.deleteItmTunnels(itmRpcService, globalNodeId, psName, deviceVteps.getIpAddress());
1046 Optional<ElanInstances> optionalElan = readElanInstances(dataBroker);
1047 if (!optionalElan.isPresent()) {
1050 JdkFutures.addErrorLogging(
1051 new ManagedNewTransactionRunnerImpl(dataBroker).callWithNewReadWriteTransactionAndSubmit(tx -> {
1052 optionalElan.get().getElanInstance().stream()
1053 .flatMap(elan -> elan.getExternalTeps().stream()
1054 .map(externalTep -> ElanL2GatewayMulticastUtils.buildExternalTepPath(
1055 elan.getElanInstanceName(), externalTep.getTepIp())))
1056 .filter(externalTepIid -> Objects.equals(
1057 deviceVteps.getIpAddress(), externalTepIid.firstKeyOf(ExternalTeps.class).getTepIp()))
1058 .peek(externalTepIid -> LOG.info("Deleting stale external tep {}", externalTepIid))
1059 .forEach(externalTepIid -> tx.delete(LogicalDatastoreType.CONFIGURATION, externalTepIid));
1060 }), LOG, "Failed to delete stale external teps {}", deviceVteps);
1061 Thread.sleep(10000);//TODO remove the sleep currently it waits for interfacemgr to finish the cleanup
1062 } catch (ReadFailedException | InterruptedException e) {
1063 LOG.error("Failed to delete stale l2gw tep {}", deviceVteps, e);
1067 public static String getNodeIdFromDpnId(BigInteger dpnId) {
1068 return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
1071 public void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId,
1072 List<PhysAddress> staticMacAddresses) {
1073 ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
1074 for (final L2GatewayDevice externalDevice : elanDevices.values()) {
1075 scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
1079 public void scheduleAddDpnMacsInExtDevice(final String elanName, BigInteger dpId,
1080 final List<PhysAddress> staticMacAddresses, final L2GatewayDevice externalDevice) {
1081 NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
1082 final IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpId, nodeId);
1083 LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
1084 if (dpnTepIp == null) {
1085 LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
1089 //TODO: to be batched in genius
1090 HwvtepUtils.installUcastMacs(broker, externalDevice.getHwvtepNodeId(), staticMacAddresses, elanName, dpnTepIp);
1093 public void scheduleDeleteLogicalSwitch(NodeId hwvtepNodeId, String lsName) {
1094 scheduleDeleteLogicalSwitch(hwvtepNodeId, lsName, false);
1097 public void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName, final boolean clearUcast) {
1098 final Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1099 logicalSwitchDeletedTasks.computeIfAbsent(nodeIdLogicalSwitchNamePair,
1100 (key) -> scheduler.getScheduledExecutorService().schedule(() -> {
1101 DeleteLogicalSwitchJob deleteLsJob = new DeleteLogicalSwitchJob(broker,
1102 ElanL2GatewayUtils.this, hwvtepNodeId, lsName, clearUcast);
1103 jobCoordinator.enqueueJob(deleteLsJob.getJobKey(), deleteLsJob,
1104 SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
1105 deleteJobs.put(nodeIdLogicalSwitchNamePair, deleteLsJob);
1106 logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1107 }, getLogicalSwitchDeleteDelaySecs(), TimeUnit.SECONDS));
1110 public void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
1111 Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1112 ScheduledFuture logicalSwitchDeleteTask = logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1113 if (logicalSwitchDeleteTask != null) {
1114 LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
1115 logicalSwitchDeleteTask.cancel(true);
1116 DeleteLogicalSwitchJob deleteLogicalSwitchJob = deleteJobs.remove(nodeIdLogicalSwitchNamePair);
1117 if (deleteLogicalSwitchJob != null) {
1118 deleteLogicalSwitchJob.cancel();
1124 public Collection<DpnInterfaces> getElanDpns(String elanName) {
1125 Collection<DpnInterfaces> dpnInterfaces = elanInstanceDpnsCache.get(elanName);
1126 if (!dpnInterfaces.isEmpty()) {
1127 return dpnInterfaces;
1130 return elanUtils.getElanDPNByName(elanName);
1134 * Gets the l2 gw device local macs.
1139 * @return the l2 gw device local macs
1141 public Collection<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
1142 if (l2gwDevice == null) {
1143 return Collections.emptyList();
1145 Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
1146 Set<MacAddress> macs = new HashSet<>();
1147 if (!lstUcastLocalMacs.isEmpty()) {
1148 macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
1149 .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase()))
1150 .collect(Collectors.toList()));
1152 Optional<Node> configNode = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
1153 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
1154 if (configNode.isPresent()) {
1155 HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(HwvtepGlobalAugmentation.class);
1156 if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
1157 macs.addAll(augmentation.getLocalUcastMacs().stream()
1158 .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
1159 .map(HwvtepMacTableGenericAttributes::getMacEntryKey)
1160 .collect(Collectors.toSet()));