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.mdsal.binding.util.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.math.BigInteger;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Collections;
22 import java.util.HashSet;
23 import java.util.List;
24 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.mdsalutil.MDSALUtil;
45 import org.opendaylight.genius.mdsalutil.cache.InstanceIdDataObjectCache;
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.caches.CacheProvider;
51 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
52 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
53 import org.opendaylight.mdsal.binding.api.DataBroker;
54 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
55 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
56 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
57 import org.opendaylight.mdsal.common.api.CommitInfo;
58 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
59 import org.opendaylight.mdsal.common.api.ReadFailedException;
60 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
61 import org.opendaylight.netvirt.elan.cache.ElanInstanceDpnsCache;
62 import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
63 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
64 import org.opendaylight.netvirt.elan.l2gw.jobs.DeleteLogicalSwitchJob;
65 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
66 import org.opendaylight.netvirt.elan.utils.ElanConstants;
67 import org.opendaylight.netvirt.elan.utils.ElanDmacUtils;
68 import org.opendaylight.netvirt.elan.utils.ElanItmUtils;
69 import org.opendaylight.netvirt.elan.utils.ElanUtils;
70 import org.opendaylight.netvirt.elan.utils.Scheduler;
71 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
72 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
75 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
76 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
77 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.IetfYangUtil;
78 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
79 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.TransportZones;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.DeviceVteps;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceInputBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddL2GwDeviceOutput;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.forwarding.tables.MacTable;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ExternalTeps;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.forwarding.entries.MacEntry;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepMacTableGenericAttributes;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentation;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentationBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
111 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
112 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
113 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
114 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
115 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
116 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
117 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
118 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
119 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
120 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
121 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
122 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
123 import org.opendaylight.yangtools.yang.common.RpcResult;
124 import org.opendaylight.yangtools.yang.common.Uint64;
125 import org.slf4j.Logger;
126 import org.slf4j.LoggerFactory;
129 * It gathers a set of utility methods that handle ELAN configuration in
130 * external Devices (where external means "not-CSS". As of now: TORs).
132 * <p>It makes use of HwvtepUtils class located under ovsdb/hwvtepsouthbound
133 * project for low-level mdsal operations
138 public class ElanL2GatewayUtils {
139 private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
140 private static final int DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS = 20;
142 private final DataBroker broker;
143 private final ManagedNewTransactionRunner txRunner;
144 private final ElanDmacUtils elanDmacUtils;
145 private final ElanItmUtils elanItmUtils;
146 private final ElanClusterUtils elanClusterUtils;
147 private final OdlInterfaceRpcService interfaceManagerRpcService;
148 private final JobCoordinator jobCoordinator;
149 private final ElanUtils elanUtils;
150 private final ElanInstanceCache elanInstanceCache;
151 private final ElanInstanceDpnsCache elanInstanceDpnsCache;
153 private final ConcurrentMap<Pair<NodeId, String>, ScheduledFuture> logicalSwitchDeletedTasks
154 = new ConcurrentHashMap<>();
155 private final ConcurrentMap<Pair<NodeId, String>, DeleteLogicalSwitchJob> deleteJobs = new ConcurrentHashMap<>();
156 private final Scheduler scheduler;
157 private final ElanConfig elanConfig;
158 private final ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils;
159 private final InstanceIdDataObjectCache<TerminationPoint> portsCache;
162 public ElanL2GatewayUtils(DataBroker broker, ElanDmacUtils elanDmacUtils, ElanItmUtils elanItmUtils,
163 ElanClusterUtils elanClusterUtils, OdlInterfaceRpcService interfaceManagerRpcService,
164 JobCoordinator jobCoordinator, ElanUtils elanUtils,
165 Scheduler scheduler, ElanConfig elanConfig, ElanInstanceCache elanInstanceCache,
166 ElanInstanceDpnsCache elanInstanceDpnsCache,
167 ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
168 CacheProvider cacheProvider) {
169 this.broker = broker;
170 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
171 this.elanDmacUtils = elanDmacUtils;
172 this.elanItmUtils = elanItmUtils;
173 this.elanClusterUtils = elanClusterUtils;
174 this.interfaceManagerRpcService = interfaceManagerRpcService;
175 this.jobCoordinator = jobCoordinator;
176 this.elanUtils = elanUtils;
177 this.scheduler = scheduler;
178 this.elanConfig = elanConfig;
179 this.elanInstanceCache = elanInstanceCache;
180 this.elanInstanceDpnsCache = elanInstanceDpnsCache;
181 this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
182 InstanceIdentifier<TerminationPoint> iid = InstanceIdentifier.create(NetworkTopology.class)
183 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID))
184 .child(Node.class).child(TerminationPoint.class);
185 LOG.info("termination point iid: {}", iid);
186 portsCache = new InstanceIdDataObjectCache<>(TerminationPoint.class, broker,
187 LogicalDatastoreType.CONFIGURATION, iid, cacheProvider);
191 public void close() {
194 public long getLogicalSwitchDeleteDelaySecs() {
195 return elanConfig.getL2gwLogicalSwitchDelaySecs() != null
196 ? elanConfig.getL2gwLogicalSwitchDelaySecs().toJava() : DEFAULT_LOGICAL_SWITCH_DELETE_DELAY_SECS;
200 * gets the macs addresses for elan interfaces.
202 * @param lstElanInterfaceNames
203 * the lst elan interface names
207 public List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
208 List<PhysAddress> result = new ArrayList<>();
209 for (String interfaceName : lstElanInterfaceNames) {
210 ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(broker, interfaceName);
211 if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
212 for (MacEntry macEntry : elanInterfaceMac.getMacEntry()) {
213 result.add(macEntry.getMacAddress());
221 * Check if phy locator already exists in remote mcast entry.
225 * @param remoteMcastMac
226 * the remote mcast mac
227 * @param expectedPhyLocatorIp
228 * the expected phy locator ip
229 * @return true, if successful
231 public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
232 RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
233 if (remoteMcastMac != null) {
234 HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
235 .createHwvtepPhysicalLocatorAugmentation(expectedPhyLocatorIp);
236 HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
237 HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
238 if (remoteMcastMac.getLocatorSet() != null) {
239 for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
240 if (Objects.equals(locatorSet.getLocatorRef(), expectedPhyLocRef)) {
241 LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
251 * Gets the remote mcast mac.
255 * @param logicalSwitchName
256 * the logical switch name
257 * @param datastoreType
259 * @return the remote mcast mac
261 public RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
262 LogicalDatastoreType datastoreType) {
263 InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
264 .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
265 RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
266 new MacAddress(ElanConstants.UNKNOWN_DMAC));
268 return HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId, remoteMcastMacsKey);
269 } catch (ExecutionException | InterruptedException e) {
270 LOG.error("readRemoteMcastMac: Exception while reading LogicalSwitches DS for the nodeId {}, "
271 + "logicalSwitchName {}", nodeId.getValue(), logicalSwitch, e);
277 * Removes the given MAC Addresses from all the External Devices belonging
278 * to the specified ELAN.
280 * @param elanInstance
282 * @param macAddresses
285 public void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
286 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
287 .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
288 for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
289 removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
290 elanInstance.getElanInstanceName(), macAddresses);
295 * Removes the given MAC Addresses from the specified External Device.
297 * @param deviceNodeId
299 * @param macAddresses
301 * @return the listenable future
303 private FluentFuture<? extends @NonNull CommitInfo> removeRemoteUcastMacsFromExternalDevice(String deviceNodeId,
304 String logicalSwitchName, List<PhysAddress> macAddresses) {
305 NodeId nodeId = new NodeId(deviceNodeId);
308 List<MacAddress> lstMac = macAddresses.stream().filter(Objects::nonNull).map(
309 physAddress -> new MacAddress(physAddress.getValue().toLowerCase(Locale.getDefault())))
310 .collect(Collectors.toList());
311 return HwvtepUtils.deleteRemoteUcastMacs(broker, nodeId, logicalSwitchName, lstMac);
315 public ElanInstance getElanInstanceForUcastLocalMac(LocalUcastMacs localUcastMac) {
316 Optional<LogicalSwitches> lsOpc = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL,
317 (InstanceIdentifier<LogicalSwitches>) localUcastMac.getLogicalSwitchRef().getValue());
318 if (lsOpc.isPresent()) {
319 LogicalSwitches ls = lsOpc.get();
320 // Logical switch name is Elan name
321 String elanName = getElanFromLogicalSwitch(ls.getHwvtepNodeName().getValue());
322 return elanInstanceCache.get(elanName).orElse(null);
328 * Install external device local macs in dpn.
332 * @param l2gwDeviceNodeId
333 * the l2gw device node id
336 * @param interfaceName
339 public void installL2gwDeviceMacsInDpn(Uint64 dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan,
340 String interfaceName) {
341 L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
342 l2gwDeviceNodeId.getValue());
343 if (l2gwDevice == null) {
344 LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
348 installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
352 * Install dmac flows on dpn.
360 * @param interfaceName
363 public List<ListenableFuture<Void>> installDmacFlowsOnDpn(Uint64 dpnId, L2GatewayDevice l2gwDevice,
364 ElanInstance elan, String interfaceName) {
365 String elanName = elan.getElanInstanceName();
366 List<ListenableFuture<Void>> fts = new ArrayList<>();
367 Collection<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
368 if (l2gwDeviceLocalMacs != null && !l2gwDeviceLocalMacs.isEmpty()) {
369 for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
370 fts.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(dpnId, l2gwDevice.getHwvtepNodeId(),
371 elan.getElanTag().toJava(), ElanUtils.getVxlanSegmentationId(elan).longValue(),
372 localUcastMac.getMacEntryKey().getValue(), elanName, interfaceName));
374 LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
375 l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
381 * Install elan l2gw devices local macs in dpn.
387 * @param interfaceName
390 public void installElanL2gwDevicesLocalMacsInDpn(Uint64 dpnId, ElanInstance elan, String interfaceName) {
391 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
392 .getInvolvedL2GwDevices(elan.getElanInstanceName());
393 if (elanL2GwDevicesFromCache != null) {
394 for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
395 installDmacFlowsOnDpn(dpnId, l2gwDevice, elan, interfaceName);
398 LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
402 public void installL2GwUcastMacInElan(final ElanInstance elan, final L2GatewayDevice extL2GwDevice,
403 final String macToBeAdded, final LocalUcastMacs localUcastMacs, @Nullable String interfaceName) {
404 final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
405 final String elanInstanceName = elan.getElanInstanceName();
406 final Collection<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
407 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
408 .getInvolvedL2GwDevices(elanInstanceName);
410 // Retrieve all participating DPNs in this Elan. Populate this MAC in
412 // Looping through all DPNs in order to add/remove mac flows in their
414 if (elanDpns.size() > 0 || elanL2GwDevices.values().size() > 0) {
415 String jobKey = elanInstanceName + ":" + macToBeAdded;
416 IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
417 List<PhysAddress> macList = Lists.newArrayList(new PhysAddress(macToBeAdded));
419 elanClusterUtils.runOnlyInOwnerNode(jobKey, "install l2gw macs in dmac table", () -> {
420 if (doesLocalUcastMacExistsInCache(extL2GwDevice, localUcastMacs)) {
421 List<ListenableFuture<?>> futures = new ArrayList<>();
422 for (DpnInterfaces elanDpn : elanDpns) {
423 futures.addAll(elanDmacUtils.installDmacFlowsToExternalRemoteMacInBatch(elanDpn.getDpId(),
424 extDeviceNodeId, elan.getElanTag().toJava(),
425 ElanUtils.getVxlanSegmentationId(elan).longValue(),
426 macToBeAdded, elanInstanceName, interfaceName));
428 for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
429 if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
430 && !areMLAGDevices(extL2GwDevice, otherDevice)) {
431 final String hwvtepId = otherDevice.getHwvtepNodeId();
432 final String logicalSwitchName = elanInstanceName;
433 HwvtepUtils.installUcastMacs(
434 broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
439 LOG.trace("Skipping install of dmac flows for mac {} as it is not found in cache",
442 return Collections.emptyList();
448 * Does local ucast mac exists in cache.
450 * @param elanL2GwDevice
451 * the elan L2 Gw device
453 * the mac address to be verified
454 * @return true, if successful
456 private static boolean doesLocalUcastMacExistsInCache(L2GatewayDevice elanL2GwDevice, LocalUcastMacs macAddress) {
457 return elanL2GwDevice.containsUcastMac(macAddress);
461 * Uninstall l2gw macs from other l2gw devices in the elanName provided.
462 * @param elanName - Elan Name for which other l2gw devices will be scanned.
463 * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
464 * @param macAddresses - Mac address to be cleared.
466 public void unInstallL2GwUcastMacFromL2gwDevices(final String elanName,
467 final L2GatewayDevice l2GwDevice,
468 final Collection<MacAddress> macAddresses) {
469 if (macAddresses == null || macAddresses.isEmpty()) {
473 if (elanName == null) {
477 DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice,
479 elanClusterUtils.runOnlyInOwnerNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
483 * Uninstall l2gw macs from other DPNs in the elan instance provided.
484 * @param elan - Elan Instance for which other DPNs will be scanned.
485 * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
486 * @param macAddresses - Mac address to be cleared.
488 public void unInstallL2GwUcastMacFromElanDpns(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
489 final Collection<MacAddress> macAddresses) {
490 if (macAddresses == null || macAddresses.isEmpty()) {
493 if (elan == null || elan.getElanInstanceName() == null) {
494 LOG.error("Could not delete l2gw ucast macs, Failed to find the elan for device {}",
495 l2GwDevice.getHwvtepNodeId());
499 final Collection<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
501 // Retrieve all participating DPNs in this Elan. Populate this MAC in
502 // DMAC table. Looping through all DPNs in order to add/remove mac flows
503 // in their DMAC table
504 List<ListenableFuture<Void>> result = new ArrayList<>();
505 for (final MacAddress mac : macAddresses) {
506 elanClusterUtils.runOnlyInOwnerNode(elan.getElanInstanceName() + ":" + mac.getValue(),
507 "delete remote ucast macs in elan DPNs", () -> {
508 for (DpnInterfaces elanDpn : elanDpns) {
509 Uint64 dpnId = elanDpn.getDpId();
510 result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag().toJava(), dpnId,
511 l2GwDevice.getHwvtepNodeId(),
512 IetfYangUtil.INSTANCE.canonizeMacAddress(mac).getValue()));
520 * Delete elan l2 gateway devices ucast local macs from dpn.
527 public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final Uint64 dpnId) {
528 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
529 if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
530 LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
533 final ElanInstance elan = elanInstanceCache.get(elanName).orElse(null);
535 LOG.error("Could not find Elan by name: {}", elanName);
538 LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
540 final Long elanTag = elan.getElanTag().toJava();
541 for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
542 getL2GwDeviceLocalMacsAndRunCallback(elan.getElanInstanceName(), l2GwDevice, (localMacs) -> {
543 for (MacAddress mac : localMacs) {
544 String jobKey = elanName + ":" + mac.getValue();
545 elanClusterUtils.runOnlyInOwnerNode(jobKey,
546 () -> elanDmacUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
547 l2GwDevice.getHwvtepNodeId(), mac.getValue()));
554 public void getL2GwDeviceLocalMacsAndRunCallback(String elanName, L2GatewayDevice l2gwDevice,
555 Function<Collection<MacAddress>, Void> function) {
556 if (l2gwDevice == null) {
559 Set<MacAddress> macs = new HashSet<>();
560 Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
561 if (!lstUcastLocalMacs.isEmpty()) {
562 macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
563 .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault())))
564 .collect(Collectors.toList()));
567 InstanceIdentifier<Node> nodeIid = HwvtepSouthboundUtils.createInstanceIdentifier(
568 new NodeId(l2gwDevice.getHwvtepNodeId()));
569 Futures.addCallback(broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid),
570 new FutureCallback<Optional<Node>>() {
572 public void onSuccess(Optional<Node> configNode) {
573 if (configNode != null && configNode.isPresent()) {
574 HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(
575 HwvtepGlobalAugmentation.class);
576 if (augmentation != null && augmentation.nonnullLocalUcastMacs() != null) {
577 macs.addAll(augmentation.nonnullLocalUcastMacs().values().stream()
578 .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
579 .map(mac -> mac.getMacEntryKey())
580 .collect(Collectors.toSet()));
582 function.apply(macs);
587 public void onFailure(Throwable throwable) {
588 LOG.error("Failed to read config topology node {}", nodeIid);
590 }, MoreExecutors.directExecutor());
593 private String getLogicalSwitchName(LocalUcastMacs mac) {
594 return ((InstanceIdentifier<LogicalSwitches>)mac.getLogicalSwitchRef().getValue())
595 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
599 * Delete elan macs from L2 gateway device.<br>
600 * This includes deleting ELAN mac table entries plus external device
601 * UcastLocalMacs which are part of the same ELAN.
603 * @param hwvtepNodeId
607 * @return the listenable future
609 public FluentFuture<? extends @NonNull CommitInfo> deleteElanMacsFromL2GatewayDevice(String hwvtepNodeId,
612 String logicalSwitch = getLogicalSwitchFromElan(elanName);
613 List<MacAddress> lstElanMacs = getRemoteUcastMacs(new NodeId(hwvtepNodeId), logicalSwitch,
614 LogicalDatastoreType.CONFIGURATION);
615 if (LOG.isDebugEnabled()) {
616 List<String> elanMacs = lstElanMacs.stream().map(MacAddress::getValue).collect(Collectors.toList());
617 LOG.debug("Deleting elan [{}] macs from node [{}]. Deleted macs = {}", elanName, hwvtepNodeId, elanMacs);
619 return HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(hwvtepNodeId),
620 logicalSwitch, lstElanMacs);
624 * Gets the remote ucast macs from hwvtep node filtering based on logical
627 * @param hwvtepNodeId
629 * @param logicalSwitch
631 * @param datastoreType
633 * @return the remote ucast macs
635 public List<MacAddress> getRemoteUcastMacs(NodeId hwvtepNodeId, String logicalSwitch,
636 LogicalDatastoreType datastoreType) {
637 List<MacAddress> lstMacs = Collections.emptyList();
638 Node hwvtepNode = null;
640 hwvtepNode = HwvtepUtils.getHwVtepNode(broker, datastoreType, hwvtepNodeId);
641 } catch (InterruptedException | ExecutionException e) {
642 LOG.error("Exception While Reading Node {}", hwvtepNodeId, e);
644 if (hwvtepNode != null) {
645 Collection<RemoteUcastMacs> remoteUcastMacs = hwvtepNode.augmentation(HwvtepGlobalAugmentation.class)
646 .nonnullRemoteUcastMacs().values();
647 if (remoteUcastMacs != null && !remoteUcastMacs.isEmpty()) {
648 // Filtering remoteUcastMacs based on the logical switch and
649 // forming a list of MacAddress
650 lstMacs = remoteUcastMacs.stream()
651 .filter(mac -> logicalSwitch.equals(mac.getLogicalSwitchRef().getValue()
652 .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue()))
653 .map(HwvtepMacTableGenericAttributes::getMacEntryKey).collect(Collectors.toList());
660 * Install ELAN macs in L2 Gateway device.<br>
661 * This includes installing ELAN mac table entries plus external device
662 * UcastLocalMacs which are part of the same ELAN.
666 * @param l2GatewayDevice
667 * the l2 gateway device which has to be configured
668 * @return the listenable future
670 public FluentFuture<? extends CommitInfo> installElanMacsInL2GatewayDevice(String elanName,
671 L2GatewayDevice l2GatewayDevice) {
672 String logicalSwitchName = getLogicalSwitchFromElan(elanName);
673 NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
675 List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName, l2GatewayDevice, hwVtepNodeId,
677 List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
678 hwVtepNodeId, logicalSwitchName);
680 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
681 lstRemoteUcastMacs.addAll(lstElanMacTableEntries);
683 FluentFuture<? extends CommitInfo> future = HwvtepUtils.addRemoteUcastMacs(broker, hwVtepNodeId,
686 LOG.info("Added RemoteUcastMacs entries [{}] in config DS. NodeID: {}, LogicalSwitch: {}",
687 lstRemoteUcastMacs.size(), hwVtepNodeId.getValue(), logicalSwitchName);
692 * Gets the l2 gateway devices ucast local macs as remote ucast macs.
696 * @param l2GatewayDeviceToBeConfigured
697 * the l2 gateway device to be configured
698 * @param hwVtepNodeId
699 * the hw vtep node Id to be configured
700 * @param logicalSwitchName
701 * the logical switch name
702 * @return the l2 gateway devices macs as remote ucast macs
704 public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
705 L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
706 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
707 ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
708 .getInvolvedL2GwDevices(elanName);
710 if (elanL2GwDevicesFromCache != null) {
711 for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
712 if (l2GatewayDeviceToBeConfigured.getHwvtepNodeId().equals(otherDevice.getHwvtepNodeId())) {
715 if (!areMLAGDevices(l2GatewayDeviceToBeConfigured, otherDevice)) {
716 for (LocalUcastMacs localUcastMac : otherDevice.getUcastLocalMacs()) {
717 HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
718 .createHwvtepPhysicalLocatorAugmentation(otherDevice.getTunnelIp().stringValue());
719 RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
720 localUcastMac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault()),
721 localUcastMac.getIpaddr(), logicalSwitchName, physLocatorAug);
722 lstRemoteUcastMacs.add(remoteUcastMac);
727 return lstRemoteUcastMacs;
733 * @param l2GatewayDevice
734 * the l2 gateway device
735 * @param otherL2GatewayDevice
736 * the other l2 gateway device
737 * @return true, if both the specified l2 gateway devices are part of same
740 public static boolean areMLAGDevices(L2GatewayDevice l2GatewayDevice, L2GatewayDevice otherL2GatewayDevice) {
741 // If tunnel IPs are same, then it is considered to be part of same MLAG
742 return Objects.equals(l2GatewayDevice.getTunnelIp(), otherL2GatewayDevice.getTunnelIp());
746 * Gets the elan mac table entries as remote ucast macs. <br>
747 * Note: ELAN MAC table only contains internal switches MAC's. It doesn't
748 * contain external device MAC's.
752 * @param hwVtepNodeId
753 * the hw vtep node id
754 * @param logicalSwitchName
755 * the logical switch name
756 * @return the elan mac table entries as remote ucast macs
758 public List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
759 NodeId hwVtepNodeId, String logicalSwitchName) {
760 List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>();
762 MacTable macTable = ElanUtils.getElanMacTable(broker, elanName);
763 if (macTable == null || macTable.getMacEntry() == null || macTable.getMacEntry().isEmpty()) {
764 LOG.trace("MacTable is empty for elan: {}", elanName);
765 return lstRemoteUcastMacs;
768 for (MacEntry macEntry : macTable.nonnullMacEntry().values()) {
769 Uint64 dpnId = getDpidFromInterface(macEntry.getInterface());
771 LOG.error("DPN ID not found for interface {}", macEntry.getInterface());
775 IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpnId, hwVtepNodeId);
776 LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpnId, hwVtepNodeId.getValue());
777 if (dpnTepIp == null) {
778 LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpnId, hwVtepNodeId.getValue());
781 HwvtepPhysicalLocatorAugmentation physLocatorAug = HwvtepSouthboundUtils
782 .createHwvtepPhysicalLocatorAugmentation(dpnTepIp);
783 // TODO: Query ARP cache to get IP address corresponding to the
785 RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
786 IetfYangUtil.INSTANCE.canonizePhysAddress(macEntry.getMacAddress()).getValue(), null /*IpAddress*/,
787 logicalSwitchName, physLocatorAug);
788 lstRemoteUcastMacs.add(remoteUcastMac);
790 return lstRemoteUcastMacs;
794 * Gets the dpid from interface.
796 * @param interfaceName
798 * @return the dpid from interface
800 public Uint64 getDpidFromInterface(String interfaceName) {
802 Future<RpcResult<GetDpidFromInterfaceOutput>> output = interfaceManagerRpcService
803 .getDpidFromInterface(new GetDpidFromInterfaceInputBuilder().setIntfName(interfaceName).build());
805 RpcResult<GetDpidFromInterfaceOutput> rpcResult = output.get();
806 if (rpcResult != null && rpcResult.isSuccessful()) {
807 dpId = rpcResult.getResult().getDpid();
809 } catch (InterruptedException | ExecutionException e) {
810 LOG.error("Failed to get the DPN ID for interface: {} ", interfaceName, e);
816 * Update vlan bindings in l2 gateway device.
821 * the physical switch name
822 * @param interfaceName
823 * the interface in physical switch
824 * @param vlanBindings
825 * the vlan bindings to be configured
826 * @return the listenable future
828 public FluentFuture<?> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String psName,
829 String interfaceName,
830 List<VlanBindings> vlanBindings) {
831 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
832 mergeVlanBindings(tx, nodeId, psName, interfaceName, vlanBindings, false);
833 LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}", nodeId.getValue());
838 * Update vlan bindings in l2 gateway device.
842 * @param logicalSwitchName
843 * the logical switch name
844 * @param hwVtepDevice
845 * the hardware device
846 * @param defaultVlanId
847 * the default vlan id
848 * @return the listenable future
850 public FluentFuture<?> updateVlanBindingsInL2GatewayDevice(NodeId nodeId, String logicalSwitchName,
851 Devices hwVtepDevice, Integer defaultVlanId) {
852 if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
853 String errMsg = "HwVtepDevice is null or interfaces are empty.";
855 return FluentFutures.immediateFailedFluentFuture(new RuntimeException(errMsg));
857 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
858 for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
859 .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice
860 .nonnullInterfaces().values()) {
861 //Removed the check for checking terminationPoint present in OP or not
862 //for coniguring vlan bindings
863 //As we are not any more dependent on it , plugin takes care of this
864 // with port reconcilation.
865 List<VlanBindings> vlanBindings = new ArrayList<>();
866 if (deviceInterface.getSegmentationIds() != null && !deviceInterface
867 .getSegmentationIds().isEmpty()) {
868 for (Integer vlanId : deviceInterface.getSegmentationIds()) {
869 vlanBindings.add(HwvtepSouthboundUtils
870 .createVlanBinding(nodeId, vlanId, logicalSwitchName));
873 // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
874 // ID not specified at interface level.
875 vlanBindings.add(HwvtepSouthboundUtils
876 .createVlanBinding(nodeId, defaultVlanId, logicalSwitchName));
879 TerminationPointKey tpKey = new TerminationPointKey(
880 new TpId(deviceInterface.getInterfaceName()));
881 InstanceIdentifier<TerminationPoint> portIid = HwvtepSouthboundUtils
882 .createTerminationPointId(HwvtepSouthboundUtils.createManagedNodeId(nodeId,
883 hwVtepDevice.getDeviceName()), tpKey);
886 boolean createParent = false;
887 if (!portsCache.get(portIid).isPresent()) {
889 //pass additional flag
892 mergeVlanBindings(tx, nodeId, hwVtepDevice.getDeviceName(),
893 deviceInterface.getInterfaceName(), vlanBindings, createParent);
894 } catch (ReadFailedException e) {
895 LOG.error("Read Failed for PortIid {} {}", portIid, e.getMessage());
898 LOG.info("Updated Hwvtep VlanBindings in config DS. NodeID: {}, LogicalSwitch: {}",
899 nodeId.getValue(),logicalSwitchName);
903 private static void mergeVlanBindings(TypedWriteTransaction tx, NodeId nodeId, String phySwitchName,
904 String phyPortName, List<VlanBindings> vlanBindings,
905 boolean createParent) {
906 NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, phySwitchName);
907 mergeVlanBindings(tx, physicalSwitchNodeId, phyPortName, vlanBindings, createParent);
910 private static void mergeVlanBindings(TypedWriteTransaction tx, NodeId physicalSwitchNodeId,
911 String phyPortName, List<VlanBindings> vlanBindings,
912 boolean createParent) {
913 HwvtepPhysicalPortAugmentation phyPortAug = (new HwvtepPhysicalPortAugmentationBuilder())
914 .setHwvtepNodeName(new HwvtepNodeName(phyPortName)).setVlanBindings(vlanBindings).build();
915 InstanceIdentifier<HwvtepPhysicalPortAugmentation> iid = HwvtepSouthboundUtils
916 .createPhysicalPortInstanceIdentifier(physicalSwitchNodeId, phyPortName);
918 InstanceIdentifier<TerminationPoint> iid2 =
919 createPhysicalPortInstanceIdentifier(physicalSwitchNodeId, phyPortName);
920 TerminationPointBuilder tpBuilder = new TerminationPointBuilder().setTpId(new TpId(phyPortName))
921 .addAugmentation(phyPortAug);
922 tx.merge(iid2, tpBuilder.build());
924 tx.merge(iid, phyPortAug);
928 public static InstanceIdentifier<TerminationPoint> createPhysicalPortInstanceIdentifier(
929 NodeId physicalSwitchNodeId, String phyPortName) {
930 return createInstanceIdentifier(physicalSwitchNodeId).child(TerminationPoint.class,
931 new TerminationPointKey(new TpId(phyPortName)));
934 public static InstanceIdentifier<Node> createInstanceIdentifier(NodeId nodeId) {
935 return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class,
936 new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID)).child(Node.class, new NodeKey(nodeId));
940 * Delete vlan bindings from l2 gateway device.
944 * @param hwVtepDevice
946 * @param defaultVlanId
947 * the default vlan id
948 * @return the listenable future
950 public ListenableFuture<?> deleteVlanBindingsFromL2GatewayDevice(NodeId nodeId, Devices hwVtepDevice,
951 Integer defaultVlanId) {
952 if (hwVtepDevice == null || hwVtepDevice.getInterfaces() == null || hwVtepDevice.getInterfaces().isEmpty()) {
953 String errMsg = "HwVtepDevice is null or interfaces are empty.";
955 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
957 NodeId physicalSwitchNodeId = HwvtepSouthboundUtils.createManagedNodeId(nodeId, hwVtepDevice.getDeviceName());
959 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
960 for (org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712
961 .l2gateway.attributes.devices.Interfaces deviceInterface : hwVtepDevice.nonnullInterfaces().values()) {
962 String phyPortName = deviceInterface.getInterfaceName();
963 if (deviceInterface.getSegmentationIds() != null && !deviceInterface.getSegmentationIds().isEmpty()) {
964 for (Integer vlanId : deviceInterface.getSegmentationIds()) {
965 HwvtepUtils.deleteVlanBinding(tx, physicalSwitchNodeId, phyPortName, vlanId);
968 // Use defaultVlanId (specified in L2GatewayConnection) if Vlan
969 // ID not specified at interface level.
970 HwvtepUtils.deleteVlanBinding(tx, physicalSwitchNodeId, phyPortName, defaultVlanId);
973 LOG.info("Deleted Hwvtep VlanBindings from config DS. NodeID: {}, hwVtepDevice: {}, defaultVlanId: {} ",
974 nodeId.getValue(), hwVtepDevice, defaultVlanId);
979 * Gets the elan name from logical switch name.
981 * @param logicalSwitchName
982 * the logical switch name
983 * @return the elan name from logical switch name
985 public static String getElanFromLogicalSwitch(String logicalSwitchName) {
986 // Assuming elan name is same as logical switch name
987 String elanName = logicalSwitchName;
992 * Gets the logical switch name from elan name.
996 * @return the logical switch from elan name
998 public static String getLogicalSwitchFromElan(String elanName) {
999 // Assuming logical switch name is same as elan name
1000 String logicalSwitchName = elanName;
1001 return logicalSwitchName;
1005 * Gets the l2 gateway connection job key.
1007 * @param logicalSwitchName
1008 * the logical switch name
1009 * @return the l2 gateway connection job key
1011 public static String getL2GatewayConnectionJobKey(String logicalSwitchName) {
1012 return logicalSwitchName;
1015 public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
1016 InstanceIdentifier.InstanceIdentifierBuilder<Interface> interfaceInstanceIdentifierBuilder = InstanceIdentifier
1017 .builder(Interfaces.class).child(Interface.class, interfaceKey);
1018 return interfaceInstanceIdentifierBuilder.build();
1022 public static Interface getInterfaceFromConfigDS(InterfaceKey interfaceKey, DataBroker dataBroker) {
1023 InstanceIdentifier<Interface> interfaceId = getInterfaceIdentifier(interfaceKey);
1025 return SingleTransactionDataBroker
1026 .syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, interfaceId).orElse(null);
1027 } catch (InterruptedException | ExecutionException e) {
1028 // TODO remove this, and propagate ReadFailedException instead of re-throw RuntimeException
1029 LOG.error("getInterfaceFromConfigDS({}) failed", interfaceKey, e);
1030 throw new RuntimeException(e);
1035 * Delete l2 gateway device ucast local macs from elan.<br>
1036 * Deletes macs from internal ELAN nodes and also on rest of external l2
1037 * gateway devices which are part of the ELAN.
1039 * @param l2GatewayDevice
1040 * the l2 gateway device whose ucast local macs to be deleted
1045 public void deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
1047 LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
1050 ElanInstance elan = elanInstanceCache.get(elanName).orElse(null);
1052 LOG.error("Could not find Elan by name: {}", elanName);
1056 Collection<MacAddress> localMacs = getL2GwDeviceLocalMacs(elanName, l2GatewayDevice);
1057 unInstallL2GwUcastMacFromL2gwDevices(elanName, l2GatewayDevice, localMacs);
1058 unInstallL2GwUcastMacFromElanDpns(elan, l2GatewayDevice, localMacs);
1061 public static void createItmTunnels(DataBroker dataBroker, ItmRpcService itmRpcService,
1062 String hwvtepId, String psName, IpAddress tunnelIp) {
1063 AddL2GwDeviceInputBuilder builder = new AddL2GwDeviceInputBuilder();
1064 builder.setTopologyId(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID.getValue());
1065 builder.setNodeId(HwvtepSouthboundUtils.createManagedNodeId(new NodeId(hwvtepId), psName).getValue());
1066 builder.setIpAddress(tunnelIp);
1068 deleteStaleTunnelsOfHwvtepInITM(dataBroker, itmRpcService, hwvtepId, psName, tunnelIp);
1069 RpcResult<AddL2GwDeviceOutput> rpcResult = itmRpcService.addL2GwDevice(builder.build()).get();
1070 if (rpcResult.isSuccessful()) {
1071 LOG.info("Created ITM tunnels for {}", hwvtepId);
1073 LOG.error("Failed to create ITM Tunnels: {}", rpcResult.getErrors());
1075 } catch (InterruptedException | ExecutionException e) {
1076 LOG.error("RPC to create ITM tunnels failed", e);
1080 private static void deleteStaleTunnelsOfHwvtepInITM(DataBroker dataBroker,
1081 ItmRpcService itmRpcService,
1082 String globalNodeId,
1084 IpAddress tunnelIp) {
1086 Optional<TransportZones> tzonesoptional = readTransportZone(dataBroker);
1087 if (!tzonesoptional.isPresent() || tzonesoptional.get().getTransportZone() == null) {
1090 String psNodeId = globalNodeId + HwvtepHAUtil.PHYSICALSWITCH + psName;
1091 tzonesoptional.get().nonnullTransportZone().stream()
1092 .filter(zone -> zone.getDeviceVteps() != null)
1093 .flatMap(zone -> new ArrayList<>(zone.nonnullDeviceVteps().values()).stream())
1094 .filter(deviceVteps -> Objects.equals(getPsName(deviceVteps), psName)) //get device with same ps name
1095 .filter(deviceVteps -> !Objects.equals(psNodeId, deviceVteps.getNodeId())
1096 || !Objects.equals(tunnelIp, deviceVteps.getIpAddress()))//node id or tunnel ip is changed
1097 .forEach(deviceVteps -> deleteStaleL2gwTep(dataBroker, itmRpcService, deviceVteps));
1098 } catch (ExecutionException | InterruptedException e) {
1099 LOG.error("Failed delete stale tunnels for {}", globalNodeId);
1103 private static Optional<TransportZones> readTransportZone(DataBroker dataBroker) throws ExecutionException,
1104 InterruptedException {
1105 return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
1106 InstanceIdentifier.builder(TransportZones.class).build());
1109 private static String getPsName(DeviceVteps deviceVteps) {
1110 return HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
1113 private static void deleteStaleL2gwTep(DataBroker dataBroker,
1114 ItmRpcService itmRpcService,
1115 DeviceVteps deviceVteps) {
1116 String psName = HwvtepHAUtil.getPsName(HwvtepHAUtil.convertToInstanceIdentifier(deviceVteps.getNodeId()));
1117 String globalNodeId = HwvtepHAUtil.convertToGlobalNodeId(deviceVteps.getNodeId());
1119 LOG.info("Deleting stale tep {} ", deviceVteps);
1120 L2GatewayUtils.deleteItmTunnels(itmRpcService, globalNodeId, psName, deviceVteps.getIpAddress());
1121 Optional<ElanInstances> optionalElan = readElanInstances(dataBroker);
1122 if (!optionalElan.isPresent()) {
1125 LoggingFutures.addErrorLogging(
1126 new ManagedNewTransactionRunnerImpl(dataBroker).callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
1127 tx -> optionalElan.get().nonnullElanInstance().values().stream()
1128 .flatMap(elan -> elan.nonnullExternalTeps().values().stream()
1129 .map(externalTep -> ElanL2GatewayMulticastUtils.buildExternalTepPath(
1130 elan.getElanInstanceName(), externalTep.getTepIp())))
1131 .filter(externalTepIid -> Objects.equals(
1132 deviceVteps.getIpAddress(), externalTepIid.firstKeyOf(ExternalTeps.class).getTepIp()))
1133 .peek(externalTepIid -> LOG.info("Deleting stale external tep {}", externalTepIid))
1134 .forEach(tx::delete)), LOG,
1135 "Failed to delete stale external teps {}", deviceVteps);
1136 Thread.sleep(10000);//TODO remove the sleep currently it waits for interfacemgr to finish the cleanup
1137 } catch (ExecutionException | InterruptedException e) {
1138 LOG.error("Failed to delete stale l2gw tep {}", deviceVteps, e);
1142 private static Optional<ElanInstances> readElanInstances(DataBroker dataBroker) throws ExecutionException,
1143 InterruptedException {
1144 return new SingleTransactionDataBroker(dataBroker).syncReadOptional(LogicalDatastoreType.CONFIGURATION,
1145 InstanceIdentifier.builder(ElanInstances.class).build());
1147 /*public static void createItmTunnels(IpAddress tunnelIp, DataBroker dataBroker) {
1148 ManagedNewTransactionRunner txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
1149 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1150 InstanceIdentifier<L2GatewayIp> iid = InstanceIdentifier
1151 .builder(L2GatewayIpList.class)
1152 .child(L2GatewayIp.class, new L2GatewayIpKey(tunnelIp))
1154 tx.put(iid, new L2GatewayIpBuilder().setIpAddress(tunnelIp).build());
1158 public static FluentFuture<? extends CommitInfo> deleteItmTunnels(
1159 IpAddress tunnelIp, DataBroker dataBroker) {
1160 ManagedNewTransactionRunner txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
1161 return txRunner.callWithNewWriteOnlyTransactionAndSubmit(LogicalDatastoreType.CONFIGURATION, tx -> {
1162 InstanceIdentifier<L2GatewayIp> iid = InstanceIdentifier
1163 .builder(L2GatewayIpList.class)
1164 .child(L2GatewayIp.class, new L2GatewayIpKey(tunnelIp))
1170 public static String getNodeIdFromDpnId(BigInteger dpnId) {
1171 return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
1174 public void scheduleAddDpnMacInExtDevices(String elanName, Uint64 dpId,
1175 List<PhysAddress> staticMacAddresses) {
1176 ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
1177 for (final L2GatewayDevice externalDevice : elanDevices.values()) {
1178 scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
1182 public FluentFuture<? extends @NonNull CommitInfo> scheduleAddDpnMacsInExtDevice(final String elanName, Uint64 dpId,
1183 final List<PhysAddress> staticMacAddresses,
1184 final L2GatewayDevice externalDevice) {
1185 NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
1186 final IpAddress dpnTepIp = elanItmUtils.getSourceDpnTepIp(dpId, nodeId);
1187 LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
1188 if (dpnTepIp == null) {
1189 LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
1192 //TerminationPointKey tpKey = HwvtepSouthboundUtils.getTerminationPointKey(dpnTepIp
1193 // .getIpv4Address().getValue());
1194 //InstanceIdentifier<TerminationPoint> tpPath = HwvtepSouthboundUtils.createTerminationPointId(nodeId, tpKey);
1195 //TODO: to be batched in genius
1196 return HwvtepUtils.installUcastMacs(broker, externalDevice.getHwvtepNodeId(), staticMacAddresses,
1197 elanName, dpnTepIp);
1201 public void scheduleDeleteLogicalSwitch(NodeId hwvtepNodeId, String lsName) {
1202 scheduleDeleteLogicalSwitch(hwvtepNodeId, lsName, false);
1205 public void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName, final boolean clearUcast) {
1206 final Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1207 logicalSwitchDeletedTasks.computeIfAbsent(nodeIdLogicalSwitchNamePair,
1208 (key) -> scheduler.getScheduledExecutorService().schedule(() -> {
1209 DeleteLogicalSwitchJob deleteLsJob = new DeleteLogicalSwitchJob(broker,
1210 ElanL2GatewayUtils.this, hwvtepNodeId, lsName, clearUcast);
1211 jobCoordinator.enqueueJob(deleteLsJob.getJobKey(), deleteLsJob,
1212 SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
1213 deleteJobs.put(nodeIdLogicalSwitchNamePair, deleteLsJob);
1214 logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1215 }, getLogicalSwitchDeleteDelaySecs(), TimeUnit.SECONDS));
1218 public void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
1219 Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<>(hwvtepNodeId, lsName);
1220 ScheduledFuture logicalSwitchDeleteTask = logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
1221 if (logicalSwitchDeleteTask != null) {
1222 LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
1223 logicalSwitchDeleteTask.cancel(true);
1224 DeleteLogicalSwitchJob deleteLogicalSwitchJob = deleteJobs.remove(nodeIdLogicalSwitchNamePair);
1225 if (deleteLogicalSwitchJob != null) {
1226 deleteLogicalSwitchJob.cancel();
1232 public Collection<DpnInterfaces> getElanDpns(String elanName) {
1233 Collection<DpnInterfaces> dpnInterfaces = elanInstanceDpnsCache.get(elanName);
1234 if (!dpnInterfaces.isEmpty()) {
1235 return dpnInterfaces;
1238 return elanUtils.getElanDPNByName(elanName);
1242 * Gets the l2 gw device local macs.
1247 * @return the l2 gw device local macs
1249 public List<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
1250 Set<MacAddress> macs = new HashSet<>();
1251 if (l2gwDevice == null) {
1252 return Collections.EMPTY_LIST;
1254 Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
1255 if (lstUcastLocalMacs != null && !lstUcastLocalMacs.isEmpty()) {
1256 macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
1257 .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase(Locale.getDefault())))
1258 .collect(Collectors.toList()));
1260 Optional<Node> configNode = null;
1262 configNode = SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION,
1263 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
1264 } catch (ExecutionException | InterruptedException e) {
1265 LOG.error("getL2GwDeviceLocalMacs: Exception while reading l2gwDevice DS for the elan {}, l2gwDevice {}",
1266 elanName, l2gwDevice, e);
1267 return Collections.emptyList();
1270 if (configNode.isPresent()) {
1271 HwvtepGlobalAugmentation augmentation = configNode.get().augmentation(HwvtepGlobalAugmentation.class);
1272 if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
1273 macs.addAll(augmentation.nonnullLocalUcastMacs().values().stream()
1274 .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
1275 .map(mac -> mac.getMacEntryKey())
1276 .collect(Collectors.toSet()));
1279 return new ArrayList<>(macs);