--- /dev/null
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.elanmanager.api;
+
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+
+/**
+ * Created by eaksahu on 3/15/2017.
+ */
+public interface IL2gwService {
+ void provisionItmAndL2gwConnection(L2GatewayDevice l2GwDevice, String psName,
+ String hwvtepNodeId, IpAddress tunnelIpAddr) ;
+}
final String elanName = getElanName(identifier);
LOG.debug("Received ElanDpnInterface removed for for elan {} with Dp Id ", elanName,
dpnInterfaces.getDpId());
+ ElanUtils.removeDPNInterfaceFromElanInCache(getElanName(identifier), dpnInterfaces);
if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
LOG.debug("dpnInterface removed, no external l2 devices to update for elan {} with Dp Id:", elanName,
final DpnInterfaces dpnInterfaces) {
LOG.debug("dpninterfaces update fired new size {}", dpnInterfaces.getInterfaces().size());
if (dpnInterfaces.getInterfaces().size() == 0) {
+ ElanUtils.removeDPNInterfaceFromElanInCache(getElanName(identifier), dpnInterfaces);
LOG.debug("dpninterfaces last dpn interface on this elan {} ", dpnInterfaces.getKey());
// this is the last dpn interface on this elan
handleUpdate(identifier, dpnInterfaces);
@Override
protected void add(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+ ElanUtils.addDPNInterfaceToElanInCache(getElanName(identifier), dpnInterfaces);
if (dpnInterfaces.getInterfaces().size() == 1) {
LOG.debug("dpninterfaces first dpn interface on this elan {} {} ", dpnInterfaces.getKey(),
dpnInterfaces.getInterfaces().get(0));
*/
package org.opendaylight.netvirt.elan.l2gw.listeners;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
private final DataBroker broker;
private final L2GatewayConnectionUtils l2GatewayConnectionUtils;
+ private static final Map<String, List<Runnable>> WAITING_JOBS_LIST = new ConcurrentHashMap<>();
public ElanInstanceListener(final DataBroker db, ElanUtils elanUtils) {
super(ElanInstance.class, ElanInstanceListener.class);
broker = db;
this.l2GatewayConnectionUtils = elanUtils.getL2GatewayConnectionUtils();
- registerListener(LogicalDatastoreType.CONFIGURATION, db);
+ }
+
+ public void init() {
+ registerListener(LogicalDatastoreType.CONFIGURATION, broker);
}
@Override
@Override
protected void add(InstanceIdentifier<ElanInstance> identifier, ElanInstance add) {
-
+ List<Runnable> runnables = WAITING_JOBS_LIST.get(add.getElanInstanceName());
+ if (runnables != null) {
+ runnables.forEach(Runnable::run);
+ }
}
@Override
return InstanceIdentifier.create(ElanInstances.class).child(ElanInstance.class);
}
+ public static void runJobAfterElanIsAvailable(String elanName, Runnable runnable) {
+ WAITING_JOBS_LIST.computeIfAbsent(elanName, (name) -> new ArrayList<>());
+ WAITING_JOBS_LIST.get(elanName).add(runnable);
+ }
+
}
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
@Override
protected void removed(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs macRemoved) {
String hwvtepNodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
- String macAddress = macRemoved.getMacEntryKey().getValue();
+ String macAddress = macRemoved.getMacEntryKey().getValue().toLowerCase();
LOG.trace("LocalUcastMacs {} removed from {}", macAddress, hwvtepNodeId);
- ElanInstance elan = elanL2GatewayUtils.getElanInstanceForUcastLocalMac(macRemoved);
- if (elan == null) {
- LOG.warn("Could not find ELAN for mac {} being deleted", macAddress);
- return;
- }
+ String elanName = getElanName(macRemoved);
+ ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
- String elanName = elan.getElanInstanceName();
L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
if (elanL2GwDevice == null) {
LOG.warn("Could not find L2GatewayDevice for ELAN: {}, nodeID:{} from cache", elanName, hwvtepNodeId);
Lists.newArrayList(macRemoved.getMacEntryKey()));
}
+ protected String getElanName(LocalUcastMacs mac) {
+ return ((InstanceIdentifier<LogicalSwitches>) mac.getLogicalSwitchRef().getValue())
+ .firstKeyOf(LogicalSwitches.class).getHwvtepNodeName().getValue();
+ }
+
@Override
protected void updated(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs original,
LocalUcastMacs update) {
// Cache MAC for furthur processing later
elanL2GwDevice.addUcastLocalMac(macAdded);
- elanL2GatewayUtils.installL2GwUcastMacInElan(elan, elanL2GwDevice, macAddress, null);
+ elanL2GatewayUtils.installL2GwUcastMacInElan(elan, elanL2GwDevice, macAddress.toLowerCase(), macAdded, null);
}
@Override
LOG.debug("Received Add DataChange Notification for identifier: {}, LogicalSwitches: {}", identifier,
logicalSwitchNew);
try {
- L2GatewayDevice elanDevice = L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(
+ L2GatewayDevice elanDevice = L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(broker,
logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice, l2GwConnId,physicalDevice);
LogicalSwitchAddedJob logicalSwitchAddedWorker = new LogicalSwitchAddedJob(broker, elanL2GatewayUtils,
package org.opendaylight.netvirt.elan.l2gw.listeners;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
+
import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.genius.utils.hwvtep.HwvtepHACache;
import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAOpClusteredListener;
-import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils;
-import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
+import org.opendaylight.netvirt.elan.l2gw.utils.L2gwServiceProvider;
import org.opendaylight.netvirt.elan.utils.ElanUtils;
import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final HwvtepHACache hwvtepHACache = HwvtepHACache.getInstance();
+ protected final L2gwServiceProvider l2gwServiceProvider;
+
/**
* Instantiates a new hwvtep physical switch listener.
*
*/
public HwvtepPhysicalSwitchListener(final DataBroker dataBroker, ItmRpcService itmRpcService,
EntityOwnershipService entityOwnershipService,
- ElanUtils elanUtils) {
+ ElanUtils elanUtils, L2gwServiceProvider l2gwServiceProvider) {
super(PhysicalSwitchAugmentation.class, HwvtepPhysicalSwitchListener.class);
this.dataBroker = dataBroker;
this.itmRpcService = itmRpcService;
this.entityOwnershipService = entityOwnershipService;
this.l2GatewayConnectionUtils = elanUtils.getL2GatewayConnectionUtils();
+ this.l2gwServiceProvider = l2gwServiceProvider;
}
public void init() {
NodeId nodeId = getNodeId(identifier);
LOG.trace("Received PhysicalSwitch Update Event for node {}: PhysicalSwitch Before: {}, "
+ "PhysicalSwitch After: {}", nodeId.getValue(), phySwitchBefore, phySwitchAfter);
- String psName = phySwitchBefore.getHwvtepNodeName().getValue();
+ String psName = phySwitchAfter.getHwvtepNodeName() != null
+ ? phySwitchAfter.getHwvtepNodeName().getValue() : null;
+ if (psName == null) {
+ LOG.error("Could not find the physical switch name for node {}", nodeId.getValue());
+ return;
+ }
+ L2GatewayDevice existingDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
LOG.info("Received physical switch {} update event for node {}", psName, nodeId.getValue());
-
- if (isTunnelIpNewlyConfigured(phySwitchBefore, phySwitchAfter)) {
- final L2GatewayDevice l2GwDevice =
- updateL2GatewayCache(psName, phySwitchAfter.getManagedBy(), phySwitchAfter.getTunnelIps());
- handleAdd(l2GwDevice);
+ InstanceIdentifier<Node> globalNodeIid = getManagedByNodeIid(identifier);
+ if (isTunnelIpNewlyConfigured(phySwitchBefore, phySwitchAfter)
+ || existingDevice == null
+ || existingDevice.getHwvtepNodeId() == null
+ || !Objects.equals(existingDevice.getHwvtepNodeId(), globalNodeIid)) {
+ added(identifier, phySwitchAfter);
} else {
LOG.debug("Other updates in physical switch {} for node {}", psName, nodeId.getValue());
// TODO: handle tunnel ip change
@Override
protected void added(InstanceIdentifier<PhysicalSwitchAugmentation> identifier,
- final PhysicalSwitchAugmentation phySwitchAdded) {
- if (phySwitchAdded.getManagedBy() == null) {
- LOG.info("managed by field is missing ");
+ final PhysicalSwitchAugmentation phySwitchAdded) {
+ LOG.trace("L2gw node added {}", (phySwitchAdded.getHwvtepNodeName() != null
+ ? phySwitchAdded.getHwvtepNodeName() : "Node name doesn't exist"));
+ String globalNodeId = getManagedByNodeId(identifier);
+ final InstanceIdentifier<Node> globalNodeIid = getManagedByNodeIid(identifier);
+ final InstanceIdentifier<Node> wildCard = globalNodeIid.firstIdentifierOf(Topology.class).child(Node.class);
+ NodeId nodeId = getNodeId(identifier);
+ if (phySwitchAdded.getHwvtepNodeName() == null || HwvtepHAUtil.isEmpty(phySwitchAdded.getTunnelIps())) {
+ if (phySwitchAdded.getHwvtepNodeName() == null) {
+ LOG.error("Could not find the physical switch name for node {}", nodeId.getValue());
+ } else {
+ LOG.error("Could not find the /tunnel ips for node {}", nodeId.getValue());
+ }
return;
}
- InstanceIdentifier<Node> globalNodeId = (InstanceIdentifier<Node>)phySwitchAdded.getManagedBy().getValue();
- NodeId nodeId = getNodeId(identifier);
final String psName = phySwitchAdded.getHwvtepNodeName().getValue();
- LOG.info("Received physical switch {} added event received for node {}", psName, nodeId.getValue());
+ LOG.trace("Received physical switch {} added event received for node {}", psName, nodeId.getValue());
+ ReadOnlyTransaction tx = dataBroker.newReadOnlyTransaction();
+ ListenableFuture<Optional<Node>> ft = tx.read(OPERATIONAL, globalNodeIid);
+ Futures.addCallback(ft, new FutureCallback<Optional<Node>>() {
+ @Override
+ public void onSuccess(Optional<Node> globalNodeOptional) {
+ if (globalNodeOptional.isPresent()) {
+ LOG.trace("Running job for node {} ", globalNodeIid);
+ HAOpClusteredListener.addToCacheIfHAChildNode(globalNodeIid, (Node) globalNodeOptional.get());
+ if (hwvtepHACache.isHAEnabledDevice(globalNodeIid)) {
+ LOG.trace("Ha enabled device {}", globalNodeIid);
+ }
+ LOG.trace("Updating cache for node {}", globalNodeIid);
+ L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
+ if (!hwvtepHACache.isHAParentNode(globalNodeIid)
+ && l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null
+ && !Objects.equals(l2GwDevice.getHwvtepNodeId(), globalNodeId)) {
+ LOG.trace("Device {} {} is already Connected by ",
+ psName, globalNodeId, l2GwDevice.getHwvtepNodeId());
+ }
+ l2GwDevice = L2GatewayCacheUtils.updateCacheUponSwitchConnect(
+ psName, globalNodeId, phySwitchAdded.getTunnelIps());
+ handleAdd(l2GwDevice);
+ } else {
+ LOG.error("Global node doesn't exist for nodeiid {}", globalNodeIid);
+ }
+ }
- try {
- if (updateHACacheIfHANode(dataBroker, globalNodeId)) {
- updateL2GatewayCache(psName, new HwvtepGlobalRef(hwvtepHACache.getParent(globalNodeId)),
- phySwitchAdded.getTunnelIps());
- return;
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("Failed to handle physical switch add {}", identifier.firstKeyOf(Node.class).getNodeId());
}
- } catch (ExecutionException e) {
- LOG.error("Failed to read operational node {}", globalNodeId);
- //TODO add retry mechanism
- } catch (InterruptedException e) {
- LOG.error("Failed to read operational node {}", globalNodeId);
- //TODO add retry mechanism
- }
- L2GatewayDevice l2GwDevice =
- updateL2GatewayCache(psName, phySwitchAdded.getManagedBy(), phySwitchAdded.getTunnelIps());
- handleAdd(l2GwDevice);
+ });
}
boolean updateHACacheIfHANode(DataBroker broker, InstanceIdentifier<Node> globalNodeId)
if (L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
LOG.debug("L2Gateway {} associated for {} physical switch; creating ITM tunnels for {}",
l2GwDevice.getL2GatewayIds(), psName, tunnelIpAddr);
-
- // It's a pre-provision scenario
- // Initiate ITM tunnel creation
- ElanClusterUtils.runOnlyInLeaderNode(entityOwnershipService,
- "handling Physical Switch add create itm tunnels ",
- new Callable<List<ListenableFuture<Void>>>() {
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- ElanL2GatewayUtils.createItmTunnels(itmRpcService,
- hwvtepNodeId, psName, tunnelIpAddr);
- return Collections.emptyList();
- }
- });
-
- // Initiate Logical switch creation for associated L2
- // Gateway Connections
- List<L2gatewayConnection> l2GwConns = L2GatewayConnectionUtils.getAssociatedL2GwConnections(
- dataBroker, l2GwDevice.getL2GatewayIds());
- if (l2GwConns != null) {
- LOG.debug("L2GatewayConnections associated for {} physical switch", psName);
-
- for (L2gatewayConnection l2GwConn : l2GwConns) {
- LOG.trace("L2GatewayConnection {} changes executed on physical switch {}",
- l2GwConn.getL2gatewayId(), psName);
-
- l2GatewayConnectionUtils.addL2GatewayConnection(l2GwConn, psName);
- }
- }
- // TODO handle deleted l2gw connections while the device is
- // offline
+ l2gwServiceProvider.provisionItmAndL2gwConnection(l2GwDevice, psName, hwvtepNodeId, tunnelIpAddr);
+ } else {
+ LOG.info("l2gw.provision.skip {}", hwvtepNodeId, psName);
}
}
}
return l2GwDevice;
}
- /**
- * Gets the managed by node id.
- *
- * @param globalRef
- * the global ref
- * @return the managed by node id
- */
- private String getManagedByNodeId(HwvtepGlobalRef globalRef) {
- InstanceIdentifier<?> instId = globalRef.getValue();
- return instId.firstKeyOf(Node.class).getNodeId().getValue();
- }
-
/**
* Gets the node id.
*
&& phySwitchAfter.getTunnelIps() != null && !phySwitchAfter.getTunnelIps().isEmpty();
}
+ /**
+ * Gets the managed by node id.
+ *
+ * @param globalRef
+ * the global ref
+ * @return the managed by node id
+ */
+ private String getManagedByNodeId(HwvtepGlobalRef globalRef) {
+ InstanceIdentifier<?> instId = globalRef.getValue();
+ return instId.firstKeyOf(Node.class).getNodeId().getValue();
+ }
+
+ private String getManagedByNodeId(InstanceIdentifier<PhysicalSwitchAugmentation> identifier) {
+ String psNodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+ if (psNodeId.contains(HwvtepHAUtil.PHYSICALSWITCH)) {
+ return psNodeId.substring(0, psNodeId.indexOf(HwvtepHAUtil.PHYSICALSWITCH));
+ }
+ return psNodeId;
+ }
+
+ private InstanceIdentifier<Node> getManagedByNodeIid(InstanceIdentifier<PhysicalSwitchAugmentation> identifier) {
+ String psNodeId = identifier.firstKeyOf(Node.class).getNodeId().getValue();
+ if (psNodeId.contains(HwvtepHAUtil.PHYSICALSWITCH)) {
+ psNodeId = psNodeId.substring(0, psNodeId.indexOf(HwvtepHAUtil.PHYSICALSWITCH));
+ return identifier.firstIdentifierOf(Topology.class).child(Node.class, new NodeKey(new NodeId(psNodeId)));
+ }
+ return null;
+ }
+
}
}
public void installL2GwUcastMacInElan(final ElanInstance elan, final L2GatewayDevice extL2GwDevice,
- final String macToBeAdded, String interfaceName) {
+ final String macToBeAdded, final LocalUcastMacs localUcastMacs, String interfaceName) {
final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
final String elanInstanceName = elan.getElanInstanceName();
+ final List<DpnInterfaces> elanDpns = getElanDpns(elanInstanceName);
// Retrieve all participating DPNs in this Elan. Populate this MAC in
// DMAC table.
// Looping through all DPNs in order to add/remove mac flows in their
// DMAC table
- final List<DpnInterfaces> elanDpns = elanUtils.getInvolvedDpnsInElan(elanInstanceName);
if (elanDpns != null && elanDpns.size() > 0) {
String jobKey = elan.getElanInstanceName() + ":" + macToBeAdded;
ElanClusterUtils.runOnlyInLeaderNode(entityOwnershipService, jobKey, "install l2gw macs in dmac table",
() -> {
- List<ListenableFuture<Void>> fts = Lists.newArrayList();
- if (doesLocalUcastMacExistsInCache(extL2GwDevice, macToBeAdded)) {
+ List<ListenableFuture<Void>> fts = new ArrayList<>();
+ if (doesLocalUcastMacExistsInCache(extL2GwDevice, localUcastMacs)) {
for (DpnInterfaces elanDpn : elanDpns) {
// TODO batch the below call
fts.addAll(elanUtils.installDmacFlowsToExternalRemoteMac(elanDpn.getDpId(),
String jobKey = "hwvtep:" + elan.getElanInstanceName() + ":" + macToBeAdded;
ElanClusterUtils.runOnlyInLeaderNode(entityOwnershipService, jobKey, "install remote ucast macs in l2gw device",
() -> {
- List<ListenableFuture<Void>> fts = Lists.newArrayList();
- if (!doesLocalUcastMacExistsInCache(extL2GwDevice, macToBeAdded)) {
+ List<ListenableFuture<Void>> fts = new ArrayList<>();
+ if (!doesLocalUcastMacExistsInCache(extL2GwDevice, localUcastMacs)) {
LOG.trace(
"Skipping install of remote ucast macs {} in l2gw device as it is not found in cache",
macToBeAdded);
* the mac address to be verified
* @return true, if successful
*/
- private static boolean doesLocalUcastMacExistsInCache(L2GatewayDevice elanL2GwDevice, String macAddress) {
- java.util.Optional<LocalUcastMacs> macExistsInCache = elanL2GwDevice.getUcastLocalMacs().stream()
- .filter(mac -> mac.getMacEntryKey().getValue().equalsIgnoreCase(macAddress)).findFirst();
- return macExistsInCache.isPresent();
+ private static boolean doesLocalUcastMacExistsInCache(L2GatewayDevice elanL2GwDevice, LocalUcastMacs macAddress) {
+ return elanL2GwDevice.containsUcastMac(macAddress);
}
/**
}
final String elanName = elan.getElanInstanceName();
+ final List<DpnInterfaces> elanDpns = getElanDpns(elanName);
+
// Retrieve all participating DPNs in this Elan. Populate this MAC in
// DMAC table. Looping through all DPNs in order to add/remove mac flows
// in their DMAC table
for (final MacAddress mac : macAddresses) {
- final List<DpnInterfaces> elanDpns = elanUtils.getInvolvedDpnsInElan(elanName);
if (elanDpns != null && !elanDpns.isEmpty()) {
String jobKey = elanName + ":" + mac.getValue();
ElanClusterUtils.runOnlyInLeaderNode(entityOwnershipService, jobKey, "delete l2gw macs from dmac table",
BigInteger dpnId = elanDpn.getDpId();
// never batch deletes
fts.addAll(elanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
- l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+ l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase()));
}
return fts;
});
.createHwvtepPhysicalLocatorAugmentation(
String.valueOf(otherDevice.getTunnelIp().getValue()));
RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
- localUcastMac.getMacEntryKey().getValue(), localUcastMac.getIpaddr(),
+ localUcastMac.getMacEntryKey().getValue().toLowerCase(), localUcastMac.getIpaddr(),
logicalSwitchName, physLocatorAug);
lstRemoteUcastMacs.add(remoteUcastMac);
}
// MAC
IpAddress ipAddress = null;
RemoteUcastMacs remoteUcastMac = HwvtepSouthboundUtils.createRemoteUcastMac(hwVtepNodeId,
- macEntry.getMacAddress().getValue(), ipAddress, logicalSwitchName, physLocatorAug);
+ macEntry.getMacAddress().getValue().toLowerCase(), ipAddress, logicalSwitchName, physLocatorAug);
lstRemoteUcastMacs.add(remoteUcastMac);
}
return lstRemoteUcastMacs;
logicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
}
}
+
+ public List<DpnInterfaces> getElanDpns(String elanName) {
+ Set<DpnInterfaces> dpnInterfaces = ElanUtils.getElanInvolvedDPNsFromCache(elanName);
+ if (dpnInterfaces == null) {
+ return elanUtils.getInvolvedDpnsInElan(elanName);
+ }
+ return new ArrayList(dpnInterfaces);
+ }
}
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.SettableFuture;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.genius.mdsalutil.MDSALUtil;
+import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
import org.opendaylight.netvirt.elan.l2gw.jobs.AssociateHwvtepToElanJob;
import org.opendaylight.netvirt.elan.l2gw.jobs.DisAssociateHwvtepFromElanJob;
+import org.opendaylight.netvirt.elan.l2gw.listeners.ElanInstanceListener;
import org.opendaylight.netvirt.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
import org.opendaylight.netvirt.elan.utils.ElanUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gateway;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateways.attributes.l2gateways.L2gatewayKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LocalUcastMacs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Uuid networkUuid = input.getNetworkId();
ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
- if (elanInstance == null || (!ElanUtils.isVxlan(elanInstance) && !ElanUtils.isVxlanSegment(elanInstance))) {
- LOG.error("Neutron network with id {} is not present", networkUuid.getValue());
+ //Taking cluster reboot scenario , if Elan instance is not available when l2GatewayConnection add events
+ //comes we need to wait for elaninstance to resolve. Hence updating the map with the runnable .
+ //When elanInstance add comes , it look in to the map and run the associated runnable associated with it.
+ if (elanInstance == null) {
+ LOG.info("Waiting for elan {}", networkUuid.getValue());
+ ElanInstanceListener.runJobAfterElanIsAvailable(networkUuid.getValue(), () -> {
+ addL2GatewayConnection(input, l2GwDeviceName);
+ });
+ return;
+ }
+ if (!ElanUtils.isVxlan(elanInstance) && !ElanUtils.isVxlanSegment(elanInstance)) {
+ LOG.error("Neutron network with id {} is not VxlanNetwork", networkUuid.getValue());
} else {
Uuid l2GatewayId = input.getL2gatewayId();
L2gateway l2Gateway = getNeutronL2gateway(broker, l2GatewayId);
.get(input.getKey().getUuid()));
}
}
+ if (l2gwDevicesToBeDeleted.isEmpty()) {
+ //delete logical switch
+ Uuid l2GatewayId = input.getL2gatewayId();
+ L2gateway l2Gateway = L2GatewayConnectionUtils.getNeutronL2gateway(broker, l2GatewayId);
+ if (l2Gateway == null) {
+ LOG.error("Failed to find the l2gateway for the connection {}", input.getUuid());
+ return;
+ } else {
+ l2gwDevicesToBeDeleted.addAll(l2Gateway.getDevices());
+ }
+ }
for (Devices l2Device : l2gwDevicesToBeDeleted) {
String l2DeviceName = l2Device.getDeviceName();
L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
Uuid l2GwConnId = input.getKey().getUuid();
LOG.debug("Elan L2Gw Conn cache with id {} is being referred by other L2Gw Conns; so only "
+ "L2 Gw Conn {} reference is removed", hwvtepNodeId, l2GwConnId);
- elanL2GwDevice.removeL2GatewayId(l2GwConnId);
+ if (elanL2GwDevice != null) {
+ elanL2GwDevice.removeL2GatewayId(l2GwConnId);
+ } else {
+ isLastL2GwConnDeleted = true;
+ }
}
DisAssociateHwvtepFromElanJob disAssociateHwvtepToElanJob =
hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
createLogicalSwitch = true;
} else {
- addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice, l2GwConnId, l2Device);
+ addL2DeviceToElanL2GwCache(broker ,elanName, l2GatewayDevice, l2GwConnId, l2Device);
createLogicalSwitch = false;
}
AssociateHwvtepToElanJob associateHwvtepToElanJob = new AssociateHwvtepToElanJob(broker,
}
}
- public static L2GatewayDevice addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice,
+ public static L2GatewayDevice addL2DeviceToElanL2GwCache(final DataBroker broker, String elanName,
+ L2GatewayDevice l2GatewayDevice,
Uuid l2GwConnId, Devices l2Device) {
String l2gwDeviceNodeId = l2GatewayDevice.getHwvtepNodeId();
L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, l2gwDeviceNodeId);
l2gwDeviceNodeId, l2GwConnId);
}
elanL2GwDevice.addL2GatewayId(l2GwConnId);
- if (elanL2GwDevice.getL2gwConnectionIdToDevices().get(l2GwConnId) == null) {
- elanL2GwDevice.getL2gwConnectionIdToDevices().put(l2GwConnId, new ArrayList<Devices>());
- }
- elanL2GwDevice.getL2gwConnectionIdToDevices().get(l2GwConnId).add(l2Device);
+ elanL2GwDevice.getL2gwConnectionIdToDevices().computeIfAbsent(l2GwConnId, key -> new HashSet<>()).add(
+ l2Device);
+ readAndCopyLocalUcastMacsToCache(broker, elanName, l2GatewayDevice);
LOG.trace("Elan L2GwConn cache updated with below details: {}", elanL2GwDevice);
return elanL2GwDevice;
protected static boolean isLastL2GwConnBeingDeleted(L2GatewayDevice l2GwDevice) {
return l2GwDevice.getL2GatewayIds().size() == 1;
}
+
+ private static void readAndCopyLocalUcastMacsToCache(final DataBroker broker,
+ final String elanName,
+ final L2GatewayDevice l2GatewayDevice) {
+
+ final InstanceIdentifier<Node> nodeIid = HwvtepSouthboundUtils.createInstanceIdentifier(
+ new NodeId(l2GatewayDevice.getHwvtepNodeId()));
+ DataStoreJobCoordinator.getInstance().enqueueJob(elanName + ":" + l2GatewayDevice.getDeviceName(), () -> {
+ final SettableFuture settableFuture = SettableFuture.create();
+ Futures.addCallback(broker.newReadOnlyTransaction().read(LogicalDatastoreType.OPERATIONAL,
+ nodeIid),
+ new SettableFutureCallback<Optional<Node>>(settableFuture) {
+ @Override
+ public void onSuccess(Optional<Node> resultNode) {
+ Optional<Node> nodeOptional = (Optional<Node>) resultNode;
+ if (nodeOptional.isPresent()) {
+ Node node = nodeOptional.get();
+ if (node.getAugmentation(HwvtepGlobalAugmentation.class) != null) {
+ List<LocalUcastMacs> localUcastMacs =
+ node.getAugmentation(HwvtepGlobalAugmentation.class).getLocalUcastMacs();
+ if (localUcastMacs != null) {
+ localUcastMacs.forEach((mac) -> l2GatewayDevice.addUcastLocalMac(mac));
+ }
+ }
+ }
+ }
+ });
+ return Lists.newArrayList(settableFuture);
+ } , 5);
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.elan.l2gw.utils;
+
+import java.util.Collections;
+import java.util.List;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.infrautils.inject.AbstractLifecycle;
+import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
+import org.opendaylight.netvirt.elan.utils.ElanUtils;
+import org.opendaylight.netvirt.elanmanager.api.IL2gwService;
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by eaksahu on 3/15/2017.
+ */
+public class L2gwServiceProvider extends AbstractLifecycle implements IL2gwService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(L2gwServiceProvider.class);
+
+ private final DataBroker dataBroker;
+ private final ItmRpcService itmRpcService;
+ private final ElanUtils elanUtils;
+ private final EntityOwnershipService entityOwnershipService;
+
+ public L2gwServiceProvider(final DataBroker dataBroker, final EntityOwnershipService entityOwnershipService,
+ ItmRpcService itmRpcService, ElanUtils elanUtils) {
+ this.dataBroker = dataBroker;
+ this.entityOwnershipService = entityOwnershipService;
+ this.itmRpcService = itmRpcService;
+ this.elanUtils = elanUtils;
+ }
+
+ @Override
+ public void provisionItmAndL2gwConnection(L2GatewayDevice l2GwDevice, String psName,
+ String hwvtepNodeId, IpAddress tunnelIpAddr) {
+ ElanClusterUtils.runOnlyInLeaderNode(entityOwnershipService,
+ "Handling Physical Switch add create itm tunnels ", () -> {
+ ElanL2GatewayUtils.createItmTunnels(itmRpcService, hwvtepNodeId, psName, tunnelIpAddr);
+ return Collections.emptyList();
+ });
+
+ List<L2gatewayConnection> l2GwConns = L2GatewayConnectionUtils.getAssociatedL2GwConnections(
+ dataBroker, l2GwDevice.getL2GatewayIds());
+ if (l2GwConns != null) {
+ LOG.debug("L2GatewayConnections associated for {} physical switch", psName);
+ for (L2gatewayConnection l2GwConn : l2GwConns) {
+ LOG.trace("L2GatewayConnection {} changes executed on physical switch {}",
+ l2GwConn.getL2gatewayId(), psName);
+ elanUtils.getL2GatewayConnectionUtils().addL2GatewayConnection(l2GwConn, psName);
+ }
+ }
+ }
+
+ @Override
+ protected void start() throws Exception {
+ LOG.info("Starting L2gwServiceProvider");
+ }
+
+ @Override
+ protected void stop() throws Exception {
+
+ }
+}
package org.opendaylight.netvirt.elan.utils;
import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import org.apache.commons.lang3.StringUtils;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.PacketException;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.genius.mdsalutil.MatchFieldType;
import org.opendaylight.genius.mdsalutil.MatchInfo;
import org.opendaylight.genius.mdsalutil.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NWUtil;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.packet.ARP;
+import org.opendaylight.genius.mdsalutil.packet.Ethernet;
+import org.opendaylight.genius.mdsalutil.packet.IPv4;
import org.opendaylight.genius.utils.ServiceIndex;
import org.opendaylight.netvirt.elan.ElanException;
import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddressBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
private static Map<String, ElanInstance> elanInstanceLocalCache = new ConcurrentHashMap<>();
private static Map<String, ElanInterface> elanInterfaceLocalCache = new ConcurrentHashMap<>();
+ private static Map<String, Set<DpnInterfaces>> elanInstancToDpnsCache = new ConcurrentHashMap<>();
private final DataBroker broker;
private final IMdsalApiManager mdsalManager;
futures.add(Futures.immediateFailedCheckedFuture((TransactionCommitFailedException) cause));
}
}
+
+ public static List<PhysAddress> getPhysAddress(List<String> macAddress) {
+ Preconditions.checkNotNull(macAddress, "macAddress cannot be null");
+ List<PhysAddress> physAddresses = new ArrayList<>();
+ for (String mac : macAddress) {
+ physAddresses.add(new PhysAddress(mac));
+ }
+ return physAddresses;
+ }
+
+ public Optional<IpAddress> getSourceIpV4Address(byte[] data) {
+ IPv4 ip = new IPv4();
+ try {
+ ip.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+ } catch (PacketException e) {
+ LOG.error("ip.deserialize throws exception {}", e);
+ return Optional.absent();
+ }
+ return Optional.of(IpAddressBuilder.getDefaultInstance(Integer.toString(ip.getSourceAddress())));
+ }
+
+ public Optional<IpAddress> getSrcIpAddrFromArp(byte[] data) {
+ ARP arp = new ARP();
+ try {
+ arp.deserialize(data, 0, data.length * NetUtils.NumBitsInAByte);
+ } catch (PacketException e) {
+ LOG.error("ip.deserialize throws exception {}", e);
+ return Optional.absent();
+ }
+ return Optional.of(IpAddressBuilder.getDefaultInstance(
+ NWUtil.toStringIpAddress(arp.getSenderProtocolAddress())));
+ }
+
+ public Optional<IpAddress> getSourceIpAddress(Ethernet ethernet, byte[] data) {
+ /*IPV6 is not yet present in genius, hence V6 case ignored*/
+ Optional<IpAddress> srcIpAddress = Optional.absent();
+ if (NwConstants.ETHTYPE_IPV4 == ethernet.getEtherType()) {
+ srcIpAddress = getSourceIpV4Address(data);
+ } else if (NwConstants.ETHTYPE_ARP == ethernet.getEtherType()) {
+ srcIpAddress = getSrcIpAddrFromArp(data);
+ }
+ return srcIpAddress;
+ }
+
+ public static <T> List<T> diffOf(List<T> orig, List<T> updated) {
+ if (isEmpty(orig)) {
+ return Collections.EMPTY_LIST;
+ }
+ List<T> diff = Lists.newArrayList(orig);
+ if (isNotEmpty(updated)) {
+ diff.removeAll(updated);
+ }
+ return diff;
+ }
+
+ public static boolean isEmpty(Collection collection) {
+ return collection == null || collection.isEmpty();
+ }
+
+ public static boolean isNotEmpty(Collection collection) {
+ return (!isEmpty(collection));
+ }
+
+ public static void setElanInstancToDpnsCache(Map<String, Set<DpnInterfaces>> elanInstancToDpnsCache) {
+ ElanUtils.elanInstancToDpnsCache = elanInstancToDpnsCache;
+ }
+
+ public static Set<DpnInterfaces> getElanInvolvedDPNsFromCache(String elanName) {
+ return elanInstancToDpnsCache.get(elanName);
+ }
+
+ public static void addDPNInterfaceToElanInCache(String elanName, DpnInterfaces dpnInterfaces) {
+ elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<>()).add(dpnInterfaces);
+ }
+
+ public static void removeDPNInterfaceFromElanInCache(String elanName, DpnInterfaces dpnInterfaces) {
+ elanInstancToDpnsCache.computeIfAbsent(elanName, key -> new HashSet<DpnInterfaces>()).remove(dpnInterfaces);
+ }
}
<argument ref="itmRpcService" />
<argument ref="entityOwnershipService" />
<argument ref="elanUtils" />
+ <argument ref="l2gwService" />
</bean>
<bean id="hwvtepTerminationPointListener"
<argument ref="elanUtils" />
<argument ref="entityOwnershipService" />
</bean>
+
+ <bean id="TransportZoneNotificationUtil"
+ class="org.opendaylight.netvirt.elan.utils.TransportZoneNotificationUtil">
+ <argument ref="dataBroker" />
+ <argument ref="interfaceManager" />
+ <argument ref="elanService" />
+ <argument ref="elanConfig" />
+ </bean>
+
+ <bean id="ElanDpnToTransportZoneListener"
+ class="org.opendaylight.netvirt.elan.internal.ElanDpnToTransportZoneListener"
+ init-method="start" destroy-method="close">
+ <argument ref="dataBroker" />
+ <argument ref="interfaceManager" />
+ <argument ref="elanConfig" />
+ <argument ref="TransportZoneNotificationUtil" />
+ </bean>
+
+ <bean id="VpnDpnToTransportZoneListener"
+ class="org.opendaylight.netvirt.elan.internal.VpnDpnToTransportZoneListener"
+ init-method="start" destroy-method="close">
+ <argument ref="dataBroker" />
+ <argument ref="interfaceManager" />
+ <argument ref="elanConfig" />
+ <argument ref="TransportZoneNotificationUtil" />
+ </bean>
+
+ <bean id="l2gwService"
+ class="org.opendaylight.netvirt.elan.l2gw.utils.L2gwServiceProvider"
+ init-method="init">
+ <argument ref="dataBroker" />
+ <argument ref="entityOwnershipService" />
+ <argument ref="itmRpcService" />
+ <argument ref="elanUtils" />
+ </bean>
+ <service ref="l2gwService" odl:type="default"
+ interface="org.opendaylight.netvirt.elanmanager.api.IL2gwService" />
+
+ <bean id="elanInstanceListener"
+ class="org.opendaylight.netvirt.elan.l2gw.listeners.ElanInstanceListener"
+ init-method="init" destroy-method="close">
+ <argument ref="dataBroker" />
+ <argument ref="elanUtils" />
+ </bean>
+
</blueprint>
/** the status of this device connectin */
AtomicBoolean connected = new AtomicBoolean(false);
-
- /** Connection Id to Devices */
- Map<Uuid,List<Devices>> l2gwConnectionIdToDevices = new HashMap<>();
+ Map<Uuid,Set<Devices>> l2gwConnectionIdToDevices = new HashMap<>();
/**
* VTEP device name mentioned with L2 Gateway.
return tunnelIps;
}
- public Map<Uuid, List<Devices>> getL2gwConnectionIdToDevices() {
+ public Map<Uuid, Set<Devices>> getL2gwConnectionIdToDevices() {
return l2gwConnectionIdToDevices;
}
- public void setL2gwConnectionIdToDevices(Map<Uuid, List<Devices>> l2gwConnectionIdToDevices) {
+ public void setL2gwConnectionIdToDevices(Map<Uuid, Set<Devices>> l2gwConnectionIdToDevices) {
this.l2gwConnectionIdToDevices = l2gwConnectionIdToDevices;
}
return true;
}
+ public boolean containsUcastMac(LocalUcastMacs mac) {
+ return ucastLocalMacs.contains(mac);
+ }
+
/*
* (non-Javadoc)
*
*/
package org.opendaylight.netvirt.neutronvpn.api.l2gw.utils;
+import java.util.List;
import java.util.concurrent.ConcurrentMap;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.genius.utils.cache.CacheUtil;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
public class L2GatewayCacheUtils {
public static final String L2GATEWAY_CACHE_NAME = "L2GW";
.getCache(L2GatewayCacheUtils.L2GATEWAY_CACHE_NAME);
}
+ public static synchronized L2GatewayDevice updateCacheUponL2GatewayAdd(final String psName, final Uuid l2gwUuid) {
+ L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
+ if (l2GwDevice == null) {
+ l2GwDevice = new L2GatewayDevice();
+ l2GwDevice.setDeviceName(psName);
+ l2GwDevice.addL2GatewayId(l2gwUuid);
+ } else {
+ l2GwDevice.addL2GatewayId(l2gwUuid);
+ }
+ addL2DeviceToCache(psName, l2GwDevice);
+ return l2GwDevice;
+ }
+
+ public static synchronized L2GatewayDevice updateCacheUponSwitchConnect(final String psName, final String
+ hwvtepNodeId, final List<TunnelIps> tunnelIps) {
+ L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
+ if (l2GwDevice == null) {
+ l2GwDevice = new L2GatewayDevice();
+ l2GwDevice.setDeviceName(psName);
+ }
+ l2GwDevice.setConnected(true);
+ l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
+
+ if (tunnelIps != null && !tunnelIps.isEmpty()) {
+ for (TunnelIps tunnelIp : tunnelIps) {
+ IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
+ l2GwDevice.addTunnelIp(tunnelIpAddr);
+ }
+ }
+ addL2DeviceToCache(psName, l2GwDevice);
+ return l2GwDevice;
+ }
}
import org.opendaylight.genius.utils.clustering.ClusteringUtils;
import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.netvirt.elanmanager.api.IL2gwService;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
private static final Logger LOG = LoggerFactory.getLogger(L2GatewayListener.class);
private final DataBroker dataBroker;
private final ItmRpcService itmRpcService;
+ private final IL2gwService l2gwService;
private final EntityOwnershipService entityOwnershipService;
public L2GatewayListener(final DataBroker dataBroker, final EntityOwnershipService entityOwnershipService,
- ItmRpcService itmRpcService) {
+ ItmRpcService itmRpcService, IL2gwService l2gwService) {
super(L2gateway.class, L2GatewayListener.class);
this.dataBroker = dataBroker;
this.entityOwnershipService = entityOwnershipService;
this.itmRpcService = itmRpcService;
+ this.l2gwService = l2gwService;
}
public void start() {
LOG.trace("Updating L2gateway : key: {}, original value={}, update value={}", identifier, original, update);
}
- private void addL2Device(Devices l2Device, L2gateway input) {
- final String l2DeviceName = l2Device.getDeviceName();
- L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
- if (l2GwDevice != null) {
- if (!L2GatewayUtils.isGatewayAssociatedToL2Device(l2GwDevice)
- && l2GwDevice.isConnected()) {
- // VTEP already discovered; create ITM tunnels
- final String hwvtepId = l2GwDevice.getHwvtepNodeId();
- InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
- ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
- HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
- final Set<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
- Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("Creating ITM Tunnels for {} connected to cluster node owner", l2DeviceName);
- for (IpAddress tunnelIp : tunnelIps) {
- L2GatewayUtils.createItmTunnels(itmRpcService, hwvtepId, l2DeviceName, tunnelIp);
- }
- } else {
- LOG.info("ITM Tunnels are not created on the cluster node as this is not owner for {}",
- l2DeviceName);
- }
- }
-
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to create ITM tunnels", error);
- }
- });
- } else {
- LOG.trace("ITM tunnels are already created for device {}", l2DeviceName);
- }
+ private synchronized void addL2Device(Devices l2Device, L2gateway input) {
+ String l2DeviceName = l2Device.getDeviceName();
+ L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.updateCacheUponL2GatewayAdd(l2DeviceName, input.getUuid());
+ if (l2GwDevice.getHwvtepNodeId() == null) {
+ LOG.info("L2GW provisioning skipped for device {}",l2DeviceName);
} else {
- LOG.trace("{} is not connected; ITM tunnels will be created when device comes up", l2DeviceName);
- // Pre-provision scenario. Create L2GatewayDevice without VTEP
- // details for pushing configurations as soon as device discovered
- l2GwDevice = new L2GatewayDevice();
- l2GwDevice.setDeviceName(l2DeviceName);
- L2GatewayCacheUtils.addL2DeviceToCache(l2DeviceName, l2GwDevice);
+ LOG.info("Provisioning l2gw for device {}",l2DeviceName);
+ l2gwService.provisionItmAndL2gwConnection(l2GwDevice, l2DeviceName, l2GwDevice.getHwvtepNodeId(),
+ l2GwDevice.getTunnelIp());
}
- l2GwDevice.addL2GatewayId(input.getUuid());
}
private void removeL2Device(Devices l2Device, L2gateway input) {
odl:type="default" />
<reference id="elanService"
interface="org.opendaylight.netvirt.elanmanager.api.IElanService" />
+ <reference id="l2gwService"
+ interface="org.opendaylight.netvirt.elanmanager.api.IL2gwService" />
<reference id="entityOwnershipService"
interface="org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService" />
<reference id="notificationPublishService"
<argument ref="dataBroker" />
<argument ref="entityOwnershipService" />
<argument ref="itmRpcService" />
+ <argument ref="l2gwService" />
</bean>
<bean id="l2GwTransportZoneListener"