* @param dataBroker DataBroker
* @param elanConfig the elan configuration
* @param interfaceManager InterfaceManager
+ * @param southboundUtils southboutUtils
+ * @param mdsalUtils mdsalUtils
*/
@Inject
public ElanBridgeManager(DataBroker dataBroker, ElanConfig elanConfig, IInterfaceManager interfaceManager,
* @param elanConfig the elan configuration
* @param bridgeMgr bridge manager
* @param elanProvider elan provider
+ * @param tzUtil TransportzoneNotificationUtils
*/
@Inject
public ElanOvsdbNodeListener(final DataBroker dataBroker, ElanConfig elanConfig,
}
return true;
}
+
+ public static String getPsName(InstanceIdentifier<Node> psNodeIid) {
+ String psNodeId = psNodeIid.firstKeyOf(Node.class).getNodeId().getValue();
+ if (psNodeId.contains(PHYSICALSWITCH)) {
+ return psNodeId.substring(psNodeId.indexOf(PHYSICALSWITCH) + PHYSICALSWITCH.length());
+ }
+ return null;
+ }
}
* @param updated Updated List
* @param original Origina list to be compared with
* @param comparator based on which diff will be returned
+ * @param <T> T extends DataObject
* @return List of diff based on comparator
*/
public <T> List<T> diffOf(List<T> updated, final List<T> original, final Comparator comparator) {
futures.add(HwvtepUtils.deleteLogicalSwitch(broker, hwvtepNodeId, logicalSwitchName));
if (clearUcast) {
LOG.trace("Clearing the local ucast macs of device {} macs ", hwvtepNodeId.getValue());
- futures.addAll(
- elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, logicalSwitchName));
+ elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, logicalSwitchName);
}
return futures;
}
elanInstanceSupplier.get(), l2GatewayDevice));
LOG.info("delete local ucast macs {} {}", elanName, strHwvtepNodeId);
- futures.addAll(elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
+ elanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName);
LOG.info("scheduled delete logical switch {} {}", elanName, strHwvtepNodeId);
elanL2GatewayUtils.scheduleDeleteLogicalSwitch(hwvtepNodeId,
LOG.trace("LocalUcastMacs {} removed from {}", macAddress, hwvtepNodeId);
String elanName = getElanName(macRemoved);
- ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
if (elanL2GwDevice == null) {
// Remove MAC from cache
elanL2GwDevice.removeUcastLocalMac(macRemoved);
-
- elanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elan, elanL2GwDevice,
+ elanL2GatewayUtils.unInstallL2GwUcastMacFromL2gwDevices(elanName, elanL2GwDevice,
Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
+ elanL2GatewayUtils.unInstallL2GwUcastMacFromElanDpns(ElanUtils.getElanInstanceByName(broker, elanName),
+ elanL2GwDevice, Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
}
protected String getElanName(LocalUcastMacs mac) {
/**
* Instantiates a new hardware vtep logical switch listener.
+ * @param elanInstanceManager ElanInstanceManager
+ * @param elanL2GatewayUtils ElanL2GatewayUtils
+ * @param elanClusterUtils ElanClusterUtils
+ * @param elanL2GatewayMulticastUtils ElanL2GatewayMulticastUtils
+ * @param l2GatewayConnectionUtils L2GatewayConnectionUtils
+ * @param l2GatewayDevice L2GatewayDevice for which the listener is initiated
+ * @param logicalSwitchName LS name of the network
+ * @param physicalDevice Devices from cache
+ * @param defaultVlanId default vlanId of the LS
+ * @param l2GwConnId L2gateway connection UUID
*/
public HwvtepLogicalSwitchListener(ElanInstanceManager elanInstanceManager, ElanL2GatewayUtils elanL2GatewayUtils,
ElanClusterUtils elanClusterUtils, ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
+
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.ReadWriteTransaction;
import org.opendaylight.genius.utils.hwvtep.HwvtepHACache;
import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
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.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.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
/**
* Instantiates a new hwvtep physical switch listener.
+ * @param dataBroker DataBroker
+ * @param itmRpcService ItmRpcService
+ * @param elanClusterUtils ElanClusterUtils
+ * @param l2gwServiceProvider L2gwServiceProvider
+ * @param haListener HAOpClusteredListener
+ * @param l2GatewayCache L2GatewayCache
+ * @param staleVlanBindingsCleaner StaleVlanBindingsCleaner
*/
@Inject
public HwvtepPhysicalSwitchListener(final DataBroker dataBroker, ItmRpcService itmRpcService,
}
handleAdd(l2GwDevice);
+ elanClusterUtils.runOnlyInOwnerNode("Update config tunnels IP ", () -> {
+ updateConfigTunnelIp(identifier, phySwitchAdded);
+ });
return;
});
}
}
return null;
}
+
+ private void updateConfigTunnelIp(InstanceIdentifier<PhysicalSwitchAugmentation> identifier,
+ PhysicalSwitchAugmentation phySwitchAdded) {
+ if (phySwitchAdded.getTunnelIps() != null) {
+ ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
+ PhysicalSwitchAugmentationBuilder psBuilder = new PhysicalSwitchAugmentationBuilder();
+ psBuilder.setTunnelIps(phySwitchAdded.getTunnelIps());
+ tx.merge(LogicalDatastoreType.CONFIGURATION, identifier, psBuilder.build());
+ LOG.trace("Updating config tunnel ips {}", identifier);
+ ListenableFutures.addErrorLogging(tx.submit(), LOG,
+ "Failed to update config tunnel ip for iid {}", identifier);
+ }
+ }
}
/**
* Instantiates a new remote mcast mac listener.
+ * @param broker DataBroker
+ * @param elanUtils ElanUtils
+ * @param logicalSwitchName LS name of the network
+ * @param l2GatewayDevice L2GatewayDevice
+ * @param expectedPhyLocatorIps List of IP addresses
+ * @param task List of tasks to be executed on callbacks
+ * @param jobCoordinator JobCoordinator
+ * @throws Exception throws Exception
*/
public HwvtepRemoteMcastMacListener(DataBroker broker, ElanUtils elanUtils, String logicalSwitchName,
L2GatewayDevice l2GatewayDevice,
*/
package org.opendaylight.netvirt.elan.l2gw.listeners;
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+
+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.MoreExecutors;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+import java.util.function.Predicate;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Singleton;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
+import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.netvirt.elan.l2gw.ha.HwvtepHAUtil;
import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.netvirt.elan.utils.Scheduler;
+import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
+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.neutron.l2gateways.rev150712.l2gateway.connections.attributes.L2gatewayConnections;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
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.PhysicalSwitchAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+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;
public class L2GatewayConnectionListener extends AsyncClusteredDataTreeChangeListenerBase<L2gatewayConnection,
L2GatewayConnectionListener> {
private static final Logger LOG = LoggerFactory.getLogger(L2GatewayConnectionListener.class);
+ private static final int MAX_READ_TRIALS = 120;
+
+ private static final Function<Node, InstanceIdentifier<Node>> TO_GLOBAL_PATH = (psNode) -> {
+ return HwvtepHAUtil.getGlobalNodePathFromPSNode(psNode);
+ };
+
+ private static final Function<Node, InstanceIdentifier<Node>> TO_NODE_PATH = (node) -> {
+ return HwvtepSouthboundUtils.createInstanceIdentifier(node.getNodeId());
+ };
+
+ private static final Function<InstanceIdentifier<Node>, String> GET_DEVICE_NAME = (psIid) -> {
+ return HwvtepHAUtil.getPsName(psIid);
+ };
+
+ private static final Predicate<InstanceIdentifier<Node>> IS_PS_NODE = (psIid) -> {
+ return HwvtepHAUtil.getPsName(psIid) != null;
+ };
+
+ private static final Predicate<Node> IS_HA_PARENT_NODE = (node) -> {
+ HwvtepGlobalAugmentation augmentation = node.getAugmentation(HwvtepGlobalAugmentation.class);
+ if (augmentation != null && augmentation.getManagers() != null) {
+ return augmentation.getManagers().stream().anyMatch(
+ manager -> manager.getKey().getTarget().getValue().equals(HwvtepHAUtil.MANAGER_KEY));
+ }
+ return false;
+ };
+
+ private static final BiPredicate<InstanceIdentifier<Node>, Node> PS_NODE_OF_PARENT_NODE = (psIid, node) -> {
+ return psIid.firstKeyOf(Node.class).getNodeId().getValue().contains(node.getNodeId().getValue());
+ };
private final DataBroker broker;
private final L2GatewayConnectionUtils l2GatewayConnectionUtils;
+ private final Scheduler scheduler;
+ private final L2GatewayCache l2GatewayCache;
@Inject
- public L2GatewayConnectionListener(final DataBroker db, L2GatewayConnectionUtils l2GatewayConnectionUtils) {
+ public L2GatewayConnectionListener(final DataBroker db, L2GatewayConnectionUtils l2GatewayConnectionUtils,
+ Scheduler scheduler, L2GatewayCache l2GatewayCache) {
super(L2gatewayConnection.class, L2GatewayConnectionListener.class);
this.broker = db;
this.l2GatewayConnectionUtils = l2GatewayConnectionUtils;
+ this.scheduler = scheduler;
+ this.l2GatewayCache = l2GatewayCache;
}
@PostConstruct
public void init() {
- registerListener(LogicalDatastoreType.CONFIGURATION, broker);
+ loadL2GwDeviceCache(1);
}
@Override
protected L2GatewayConnectionListener getDataTreeChangeListener() {
return this;
}
+
+ private void loadL2GwDeviceCache(final int trialNo) {
+ scheduler.getScheduledExecutorService().schedule(() -> {
+ if (trialNo == MAX_READ_TRIALS) {
+ LOG.error("Failed to read config topology");
+ return;
+ }
+ ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
+ InstanceIdentifier<Topology> topoIid = HwvtepSouthboundUtils.createHwvtepTopologyInstanceIdentifier();
+ Futures.addCallback(tx.read(CONFIGURATION, topoIid), new FutureCallback<Optional<Topology>>() {
+ @Override
+ public void onSuccess(Optional<Topology> topologyOptional) {
+ if (topologyOptional != null && topologyOptional.isPresent()) {
+ loadL2GwDeviceCache(topologyOptional.get().getNode());
+ }
+ registerListener(CONFIGURATION, broker);
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ loadL2GwDeviceCache(trialNo + 1);
+ }
+ }, MoreExecutors.directExecutor());
+ tx.close();
+ }, 1, TimeUnit.SECONDS);
+ }
+
+ private void loadL2GwDeviceCache(List<Node> nodes) {
+ if (nodes == null) {
+ LOG.debug("No config topology nodes are present");
+ return;
+ }
+ Map<InstanceIdentifier<Node>, Node> allNodes = nodes
+ .stream()
+ .collect(toMap(TO_NODE_PATH, Function.identity()));
+
+ LOG.trace("Loading all config nodes");
+
+ Set<InstanceIdentifier<Node>> allIids = allNodes.keySet();
+
+ Map<String, List<InstanceIdentifier<Node>>> psNodesByDeviceName = allIids
+ .stream()
+ .filter(IS_PS_NODE)
+ .collect(groupingBy(GET_DEVICE_NAME, toList()));
+
+ //Process HA nodes
+ allNodes.values().stream()
+ .filter(IS_HA_PARENT_NODE)
+ .forEach(parentNode -> {
+ allIids.stream()
+ .filter(IS_PS_NODE)
+ .filter(psIid -> PS_NODE_OF_PARENT_NODE.test(psIid, parentNode))
+ .forEach(psIid -> {
+ addL2DeviceToCache(psIid, parentNode, allNodes.get(psIid));
+ });
+ });
+
+ //Process non HA nodes there will be only one ps node iid for each device for non ha nodes
+ psNodesByDeviceName.values().stream()
+ .filter(psIids -> psIids.size() == 1)
+ .map(psIids -> psIids.get(0))
+ .forEach(psIid -> {
+ Node psNode = allNodes.get(psIid);
+ Node globalNode = allNodes.get(TO_GLOBAL_PATH.apply(psNode));
+ if (globalNode != null) {
+ addL2DeviceToCache(psIid, globalNode, psNode);
+ }
+ });
+ }
+
+ void addL2DeviceToCache(InstanceIdentifier<Node> psIid, Node globalNode, Node psNode) {
+ LOG.trace("Adding device to cache {}", psNode.getNodeId().getValue());
+ String deviceName = HwvtepHAUtil.getPsName(psIid);
+ L2GatewayDevice l2GwDevice = l2GatewayCache.addOrGet(deviceName);
+ l2GwDevice.setConnected(true);
+ l2GwDevice.setHwvtepNodeId(globalNode.getNodeId().getValue());
+
+ List<TunnelIps> tunnelIps = psNode.getAugmentation(PhysicalSwitchAugmentation.class) != null
+ ? psNode.getAugmentation(PhysicalSwitchAugmentation.class).getTunnelIps() : null;
+ if (tunnelIps != null) {
+ for (TunnelIps tunnelIp : tunnelIps) {
+ IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
+ l2GwDevice.addTunnelIp(tunnelIpAddr);
+ }
+ }
+ }
}
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.utils.ElanClusterUtils;
import org.opendaylight.netvirt.elan.utils.ElanUtils;
import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
private final ElanL2GatewayUtils elanL2GatewayUtils;
private final HAOpClusteredListener haOpClusteredListener;
private final JobCoordinator jobCoordinator;
- private final ElanClusterUtils elanClusterUtils;
@Inject
public LocalUcastMacListener(final DataBroker dataBroker,
final HAOpClusteredListener haOpClusteredListener,
final ElanL2GatewayUtils elanL2GatewayUtils,
- final ElanClusterUtils elanClusterUtils,
final JobCoordinator jobCoordinator) {
super(dataBroker, false);
this.elanL2GatewayUtils = elanL2GatewayUtils;
this.haOpClusteredListener = haOpClusteredListener;
- this.elanClusterUtils = elanClusterUtils;
this.jobCoordinator = jobCoordinator;
}
elanL2GwDevice.removeUcastLocalMac(macRemoved);
ElanInstance elanInstance = ElanUtils.getElanInstanceByName(dataBroker, elanName);
-
- elanClusterUtils.runOnlyInOwnerNode(elanName + ":" + macAddress,
- "Delete l2gw local ucast mac", () -> {
- return elanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elanInstance, elanL2GwDevice,
- Collections.singletonList(new MacAddress(macAddress.toLowerCase()))); });
+ elanL2GatewayUtils.unInstallL2GwUcastMacFromL2gwDevices(elanName, elanL2GwDevice,
+ Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
+ elanL2GatewayUtils.unInstallL2GwUcastMacFromElanDpns(elanInstance, elanL2GwDevice,
+ Collections.singletonList(new MacAddress(macAddress.toLowerCase(Locale.getDefault()))));
return null;
});
}
/**
* Handle mcast for elan l2 gw device add.
- *
- * @param elanName
- * the elan name
- * @param device
- * the device
+ * @param elanName the elan name
+ * @param elanInstance elanInstace
+ * @param device the device
* @return the listenable future
*/
public ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, ElanInstance elanInstance,
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.SettableFuture;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
}
/**
- * Un install l2 gw ucast mac from elan.
- *
- * @param elan
- * the elan
- * @param l2GwDevice
- * the l2 gw device
- * @param macAddresses
- * the mac addresses
- * @return a list of ListenableFutures
+ * Uninstall l2gw macs from other l2gw devices in the elanName provided.
+ * @param elanName - Elan Name for which other l2gw devices will be scanned.
+ * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
+ * @param macAddresses - Mac address to be cleared.
*/
- public List<ListenableFuture<Void>> unInstallL2GwUcastMacFromElan(final ElanInstance elan,
- final L2GatewayDevice l2GwDevice,
- final Collection<MacAddress> macAddresses) {
+ public void unInstallL2GwUcastMacFromL2gwDevices(final String elanName,
+ final L2GatewayDevice l2GwDevice,
+ final Collection<MacAddress> macAddresses) {
if (macAddresses == null || macAddresses.isEmpty()) {
- return Collections.emptyList();
+ return;
+ }
+
+ if (elanName == null) {
+ return;
}
- final String elanName = elan.getElanInstanceName();
- final List<DpnInterfaces> elanDpns = getElanDpns(elanName);
+ DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice,
+ macAddresses);
+ elanClusterUtils.runOnlyInOwnerNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
+ }
+
+ /**
+ * Uninstall l2gw macs from other DPNs in the elan instance provided.
+ * @param elan - Elan Instance for which other DPNs will be scanned.
+ * @param l2GwDevice - l2gwDevice whose macs are required to be cleared from other devices.
+ * @param macAddresses - Mac address to be cleared.
+ */
+ public void unInstallL2GwUcastMacFromElanDpns(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
+ final Collection<MacAddress> macAddresses) {
+ if (macAddresses == null || macAddresses.isEmpty()) {
+ return;
+ }
+ if (elan == null || elan.getElanInstanceName() == null) {
+ LOG.error("Could not delete l2gw ucast macs, Failed to find the elan for device {}",
+ l2GwDevice.getHwvtepNodeId());
+ return;
+ }
+
+ final List<DpnInterfaces> elanDpns = getElanDpns(elan.getElanInstanceName());
- List<ListenableFuture<Void>> result = new ArrayList<>();
// 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
+ List<ListenableFuture<Void>> result = new ArrayList<>();
for (final MacAddress mac : macAddresses) {
- for (DpnInterfaces elanDpn : elanDpns) {
- BigInteger dpnId = elanDpn.getDpId();
- result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
- l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase(Locale.getDefault())));
- }
+ elanClusterUtils.runOnlyInOwnerNode(elan.getElanInstanceName() + ":" + mac.getValue(),
+ "delete remote ucast macs in elan DPNs", () -> {
+ for (DpnInterfaces elanDpn : elanDpns) {
+ BigInteger dpnId = elanDpn.getDpId();
+ result.addAll(elanDmacUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
+ l2GwDevice.getHwvtepNodeId(), mac.getValue().toLowerCase(Locale.getDefault())));
+ }
+ return result;
+ });
}
-
- //Batched job
- result.addAll(new DeleteL2GwDeviceMacsFromElanJob(elanName, l2GwDevice, macAddresses).call());
- return result;
}
/**
* the elan name
* @param dpnId
* the dpn id
- * @throws ReadFailedException if a read fails
+ * @throws ReadFailedException if a read fails throws ReadFailedException
*/
public void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId)
throws ReadFailedException {
InstanceIdentifier<Node> nodeIid = HwvtepSouthboundUtils.createInstanceIdentifier(
new NodeId(l2gwDevice.getHwvtepNodeId()));
- ListenableFuture<Optional<Node>> ft
- = broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid);
- Futures.addCallback(ft, new FutureCallback<Optional<Node>>() {
- @Override
- public void onSuccess(Optional<Node> configNode) {
- if (configNode != null && configNode.isPresent()) {
- HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(
- HwvtepGlobalAugmentation.class);
- if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
- macs.addAll(augmentation.getLocalUcastMacs().stream()
- .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
- .map(mac -> mac.getMacEntryKey())
- .collect(Collectors.toSet()));
+ Futures.addCallback(broker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, nodeIid),
+ new FutureCallback<Optional<Node>>() {
+ @Override
+ public void onSuccess(Optional<Node> configNode) {
+ if (configNode != null && configNode.isPresent()) {
+ HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(
+ HwvtepGlobalAugmentation.class);
+ if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
+ macs.addAll(augmentation.getLocalUcastMacs().stream()
+ .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
+ .map(mac -> mac.getMacEntryKey())
+ .collect(Collectors.toSet()));
+ }
+ function.apply(macs);
+ }
}
- function.apply(macs);
- }
- }
- @Override
- public void onFailure(Throwable throwable) {
- LOG.error("Failed to read config topology node ", nodeIid);
- }
- }, MoreExecutors.directExecutor());
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("Failed to read config topology node ", nodeIid);
+ }
+ }, MoreExecutors.directExecutor());
}
private String getLogicalSwitchName(LocalUcastMacs mac) {
* from elan
* @param elanName
* the elan name
- * @return the listenable future
* @throws ReadFailedException if a read fails
*/
- public List<ListenableFuture<Void>> deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
+ public void deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
String elanName) throws ReadFailedException {
LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(),
elanName);
ElanInstance elan = ElanUtils.getElanInstanceByName(broker, elanName);
if (elan == null) {
LOG.error("Could not find Elan by name: {}", elanName);
- return Collections.emptyList();
+ return;
}
- SettableFuture<Void> settableFuture = SettableFuture.create();
- getL2GwDeviceLocalMacsAndRunCallback(elanName, l2GatewayDevice, (localMacs) -> {
- Futures.addCallback(
- Futures.allAsList(unInstallL2GwUcastMacFromElan(elan, l2GatewayDevice, localMacs)),
- new FutureCallback<List<Void>>() {
- @Override
- public void onSuccess(List<Void> voids) {
- settableFuture.set(null);
- }
-
- @Override
- public void onFailure(Throwable throwable) {
- settableFuture.setException(throwable);
- }
- }, MoreExecutors.directExecutor());
- return null;
- });
- return Collections.singletonList(settableFuture);
+ Collection<MacAddress> localMacs = getL2GwDeviceLocalMacs(elanName, l2GatewayDevice);
+ unInstallL2GwUcastMacFromL2gwDevices(elanName, l2GatewayDevice, localMacs);
+ unInstallL2GwUcastMacFromElanDpns(elan, l2GatewayDevice, localMacs);
}
public static void createItmTunnels(ItmRpcService itmRpcService, String hwvtepId, String psName,
}
return new ArrayList<>(dpnInterfaces);
}
+
+ /**
+ * Gets the l2 gw device local macs.
+ * @param elanName
+ * name of the elan
+ * @param l2gwDevice
+ * the l2gw device
+ * @return the l2 gw device local macs
+ */
+ public Collection<MacAddress> getL2GwDeviceLocalMacs(String elanName, L2GatewayDevice l2gwDevice) {
+ if (l2gwDevice == null) {
+ return Collections.emptyList();
+ }
+ Collection<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
+ Set<MacAddress> macs = new HashSet<>();
+ if (!lstUcastLocalMacs.isEmpty()) {
+ macs.addAll(lstUcastLocalMacs.stream().filter(Objects::nonNull)
+ .map(mac -> new MacAddress(mac.getMacEntryKey().getValue().toLowerCase()))
+ .collect(Collectors.toList()));
+ }
+ Optional<Node> configNode = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION,
+ HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2gwDevice.getHwvtepNodeId())));
+ if (configNode.isPresent()) {
+ HwvtepGlobalAugmentation augmentation = configNode.get().getAugmentation(HwvtepGlobalAugmentation.class);
+ if (augmentation != null && augmentation.getLocalUcastMacs() != null) {
+ macs.addAll(augmentation.getLocalUcastMacs().stream()
+ .filter(mac -> getLogicalSwitchName(mac).equals(elanName))
+ .map(mac -> mac.getMacEntryKey())
+ .collect(Collectors.toSet()));
+ }
+ }
+ return macs;
+ }
}
import org.opendaylight.genius.utils.hwvtep.HwvtepUtils;
import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
import org.opendaylight.netvirt.elan.internal.ElanInstanceManager;
+import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAOpClusteredListener;
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.HwvtepLocalUcastMacListener;
import org.opendaylight.netvirt.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
+import org.opendaylight.netvirt.elan.l2gw.listeners.LocalUcastMacListener;
import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
private final JobCoordinator jobCoordinator;
private final L2GatewayCache l2GatewayCache;
private final List<AutoCloseable> closeables = new CopyOnWriteArrayList<>();
+ private final HAOpClusteredListener haOpClusteredListener;
@Inject
public L2GatewayConnectionUtils(DataBroker dataBroker, ElanInstanceManager elanInstanceManager,
ElanClusterUtils elanClusterUtils, ElanL2GatewayUtils elanL2GatewayUtils,
JobCoordinator jobCoordinator, ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
- L2GatewayCache l2GatewayCache) {
+ L2GatewayCache l2GatewayCache, HAOpClusteredListener haOpClusteredListener) {
this.broker = dataBroker;
this.elanInstanceManager = elanInstanceManager;
this.elanL2GatewayUtils = elanL2GatewayUtils;
this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
this.jobCoordinator = jobCoordinator;
this.l2GatewayCache = l2GatewayCache;
+ this.haOpClusteredListener = haOpClusteredListener;
}
@Override
// Add L2 Gateway device to 'ElanL2GwDevice' cache
boolean createLogicalSwitch;
- LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.OPERATIONAL,
+ LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.CONFIGURATION,
hwvtepNodeId, elanName);
if (logicalSwitch == null) {
HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
nodeIid), new SettableFutureCallback<Optional<Node>>(settableFuture) {
@Override
public void onSuccess(@Nonnull Optional<Node> resultNode) {
- HwvtepLocalUcastMacListener localUcastMacListener =
- new HwvtepLocalUcastMacListener(broker, elanL2GatewayUtils);
+ LocalUcastMacListener localUcastMacListener =
+ new LocalUcastMacListener(broker, haOpClusteredListener,
+ elanL2GatewayUtils, jobCoordinator);
settableFuture.set(resultNode);
Optional<Node> nodeOptional = resultNode;
if (nodeOptional.isPresent()) {
*
* @deprecated Consider using {@link #read2(LogicalDatastoreType, InstanceIdentifier)} with proper exception
* handling instead
+ * @param broker dataBroker
+ * @param datastoreType Logical DataStore type
+ * @param path IID to read
+ * @param <T> T extends DataObject
+ * @return the read value T
*/
@Deprecated
@SuppressWarnings("checkstyle:IllegalCatch")
* macAddress
* @param displayName
* display Name
+ * @param elanInstance
+ * elanInstance
* @return the flow remote Dmac
* @throws ElanException in case of issues creating the flow objects
*/
/**
* Add Mac Address to ElanInterfaceForwardingEntries and ElanForwardingTables
* Install SMAC and DMAC flows.
+ * @param interfaceName interface name
+ * @param macAddress mac addresses
+ * @param elanName elan Name
+ * @param interfaceTx write transaction
+ * @param flowTx flow write transaction
+ * @param macTimeOut timeout value
+ * @throws ElanException elan exception is thrown upon write failure
*/
public void addMacEntryToDsAndSetupFlows(String interfaceName,
String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx, int macTimeOut)
/**
* Remove Mac Address from ElanInterfaceForwardingEntries and ElanForwardingTables
* Remove SMAC and DMAC flows.
+ * @param interfaceName interface name
+ * @param macAddress mac addresses
+ * @param elanName elan name
+ * @param interfaceTx write transaction
+ * @param flowTx flow write transaction
*/
public void deleteMacEntryFromDsAndRemoveFlows(String interfaceName,
String macAddress, String elanName, WriteTransaction interfaceTx, WriteTransaction flowTx) {
import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInstances;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeFlat;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.SegmentTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.instances.elan.instance.ElanSegmentsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeFlat;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.NetworkTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.Networks;
@Nonnull
private List<ElanSegments> buildSegments(Network input) {
Long numSegments = NeutronUtils.getNumberSegmentsFromNeutronNetwork(input);
- Long index = 0L;
List<ElanSegments> segments = new ArrayList<>();
- while (index < numSegments) {
- index++;
+
+ for (long index = 0L; index < numSegments; index++) {
ElanSegmentsBuilder elanSegmentsBuilder = new ElanSegmentsBuilder();
- elanSegmentsBuilder.setSegmentationId(Long.valueOf(NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(
- input, index)));
+ elanSegmentsBuilder.setSegmentationId(0L);
+ if (NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(input, index) != null) {
+ try {
+ elanSegmentsBuilder.setSegmentationId(
+ Long.valueOf(NeutronUtils.getSegmentationIdFromNeutronNetworkSegment(input, index)));
+ } catch (NumberFormatException error) {
+ LOG.error("Failed to get the segment id for network {}", input);
+ }
+ }
if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeVxlan.class)) {
elanSegmentsBuilder.setSegmentType(SegmentTypeVxlan.class);
} else if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeVlan.class)) {
elanSegmentsBuilder.setSegmentType(SegmentTypeVlan.class);
+ } else if (NeutronUtils.isNetworkSegmentType(input, index, NetworkTypeFlat.class)) {
+ elanSegmentsBuilder.setSegmentType(SegmentTypeFlat.class);
}
elanSegmentsBuilder.setSegmentationIndex(index);
segments.add(elanSegmentsBuilder.build());
- LOG.debug("Added segment {} to ELANInstance{}", segments.get(Integer.valueOf(index.intValue() - 1)));
+ LOG.debug("Added segment {} to ELANInstance{}", segments.get((int)index - 1));
}
return segments;
}