- Used entity ownership service to handle l2gw requests only in one cluster node.
- Registered for entity ownership for elan entity to process all the l2gw requests.
- Taken out the datastore jobcoordinator jobs into separate classes.
- Handled external tunnel state events.
Change-Id: I39a2a24c8927e48fc7d0299de008cfff9ca6d2b4
Signed-off-by: Shashidhar R <shashidhar.raja@ericsson.com>
package org.opendaylight.vpnservice.dhcpservice;
import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
-
-import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.DhcpConfig;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.dhcp.config.Configs;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
String elanInstanceName = update.getElanInstanceName();
dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()), original.getTunnelRemoteIpAddress(), original.getElanInstanceName());
dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
-/* List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+ List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
if (elanDpns == null || elanDpns.isEmpty()) {
dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
- }*/
+ }
}
@Override
IpAddress tunnelRemoteIpAddress = add.getTunnelRemoteIpAddress();
String elanInstanceName = add.getElanInstanceName();
dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
-/* List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
+ List<BigInteger> elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker);
if (elanDpns == null || elanDpns.isEmpty()) {
dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName);
- }*/
+ }
}
@Override
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
import org.opendaylight.vpnservice.neutronvpn.api.utils.NeutronUtils;
import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
designatedDpnId = dpn;
}
}
- if (!elanDpnAvailableFlag) {
- installRemoteMcastMac(designatedDpnId, device, elanInstanceName);
- }
writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
return designatedDpnId;
}
public void installDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- eos, MDSALUtil.NODE_PREFIX, nodeId);
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean isOwner) {
public void unInstallDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- eos, MDSALUtil.NODE_PREFIX, nodeId);
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean isOwner) {
public void installDhcpDropAction(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) {
final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId);
ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- eos, MDSALUtil.NODE_PREFIX, nodeId);
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
@Override
public void onSuccess(Boolean isOwner) {
public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
String tunnelInterfaceName = null;
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
try {
Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
.getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
- .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+ .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
if (rpcResult.isSuccessful()) {
return transaction;
}
- private void installRemoteMcastMac(BigInteger designatedDpnId, L2GatewayDevice device, String elanInstanceName) {
- String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
- IpAddress internalTunnelIp = null;
- if (tunnelInterfaceName != null) {
- Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
- if (tunnelInterface == null) {
- logger.debug("Tunnel Interface is not present {}", tunnelInterfaceName);
- return;
+ public void installRemoteMcastMac(final BigInteger designatedDpnId, final IpAddress tunnelIp, final String elanInstanceName) {
+ if (designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
+ return;
+ }
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ logger.info("Installing remote McastMac");
+ L2GatewayDevice device = getDeviceFromTunnelIp(elanInstanceName, tunnelIp);
+ String tunnelInterfaceName = getExternalTunnelInterfaceName(String.valueOf(designatedDpnId), device.getHwvtepNodeId());
+ IpAddress internalTunnelIp = null;
+ if (tunnelInterfaceName != null) {
+ Interface tunnelInterface = DhcpServiceUtils.getInterfaceFromConfigDS(tunnelInterfaceName, broker);
+ if (tunnelInterface == null) {
+ logger.trace("Tunnel Interface is not present {}", tunnelInterfaceName);
+ return;
+ }
+ internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
+ if (transaction != null) {
+ transaction.submit();
+ }
+ }
+ } else {
+ logger.info("Installing remote McastMac is not executed for this node.");
+ }
}
- internalTunnelIp = tunnelInterface.getAugmentation(IfTunnel.class).getTunnelSource();
- WriteTransaction transaction = broker.newWriteOnlyTransaction();
- putRemoteMcastMac(transaction, elanInstanceName, device, internalTunnelIp);
- if (transaction != null) {
- transaction.submit();
+
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Failed to install remote McastMac", error);
}
- }
+ });
}
private L2GatewayDevice getDeviceFromTunnelIp(String elanInstanceName, IpAddress tunnelIp) {
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.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;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
}
return;
}
- if (update.getOperStatus() == OperStatus.Down) {
- unInstallDhcpEntries(interfaceName, dpId);
- dhcpManager.removeInterfaceCache(interfaceName);
- } else if (update.getOperStatus() == OperStatus.Up) {
- if (!dpId.equals(DHCPMConstants.INVALID_DPID)) {
- installDhcpEntries(interfaceName, dpId);
- dhcpManager.updateInterfaceCache(interfaceName, new ImmutablePair<BigInteger, String>(dpId, update.getPhysAddress().getValue()));
- }
- }
}
@Override
.child(L2gateway.class, new L2gatewayKey(gatewayId));
Optional<L2gateway> l2Gateway = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, inst);
if (!l2Gateway.isPresent()) {
+ logger.trace("L2Gw not present id {}", gatewayId);
return;
}
Uuid networkUuid = del.getNetworkId();
- boolean isLastConnection = true;
- InstanceIdentifier<L2gatewayConnections> l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class);
- Optional<L2gatewayConnections> l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier);
- List<L2gatewayConnection> l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection();
- for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) {
- if (networkUuid.equals(l2gatewayConnection.getNetworkId())) {
- isLastConnection = false;
- break;
- }
- }
+ boolean isLastConnection = isLastGatewayConnection(networkUuid);
if (!isLastConnection) {
+ logger.trace("Not the last L2GatewayConnection. Not removing flows.");
return;
}
List<Devices> l2Devices = l2Gateway.get().getDevices();
}
}
+ private boolean isLastGatewayConnection(Uuid networkUuid) {
+ boolean isLastConnection = true;
+ InstanceIdentifier<L2gatewayConnections> l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class);
+ Optional<L2gatewayConnections> l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier);
+ List<L2gatewayConnection> l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection();
+ for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) {
+ if (networkUuid.equals(l2gatewayConnection.getNetworkId())) {
+ isLastConnection = false;
+ break;
+ }
+ }
+ return isLastConnection;
+ }
+
@Override
protected void update(InstanceIdentifier<L2gatewayConnection> identifier,
L2gatewayConnection original, L2gatewayConnection update) {
BigInteger designatedDpnId;
designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
- logger.error("Could not find designated DPN ID");
+ logger.info("Could not find designated DPN ID");
return;
}
dhcpExternalTunnelManager.removeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName);
BigInteger designatedDpnId;
designatedDpnId = dhcpExternalTunnelManager.designateDpnId(tunnelIp, elanInstanceName, dpns);
if (designatedDpnId == null || designatedDpnId.equals(DHCPMConstants.INVALID_DPID)) {
- logger.error("Unable to designate a DPN");
+ logger.info("Unable to designate a DPN");
return;
}
}
getDhcpFlowRef(dpId, tableId, vmMacAddress),
DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
DHCPMConstants.COOKIE_DHCP_BASE, matches, null);
- logger.trace("Removing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+ logger.trace("Removing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
mdsalUtil.removeFlow(flowEntity);
} else {
FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,
getDhcpFlowRef(dpId, tableId, vmMacAddress),DHCPMConstants.DEFAULT_DHCP_FLOW_PRIORITY, "DHCP", 0, 0,
DHCPMConstants.COOKIE_DHCP_BASE, matches, instructions);
- logger.trace("Installing DHCP Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
+ logger.trace("Installing DHCP Drop Flow DpId {}, vmMacAddress {}", dpId, vmMacAddress);
mdsalUtil.installFlow(flowEntity);
}
}
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
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;
}
LogicalSwitches logicalSwitch = logicalSwitchOptional.get();
String elanInstanceName = logicalSwitch.getHwvtepNodeName().getValue();
+ String macAddress = add.getMacEntryKey().getValue();
+ BigInteger vni = new BigInteger(logicalSwitch.getTunnelKey());
+ Port port = dhcpExternalTunnelManager.readVniMacToPortCache(vni, macAddress);
+ if (port == null) {
+ logger.trace("No neutron port created for macAddress {}, tunnelKey {}", macAddress, vni);
+ return;
+ }
L2GatewayDevice device = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanInstanceName, torNodeId.getValue());
if (device == null) {
logger.error("Logical Switch Device with name {} is not present in L2GWCONN cache", elanInstanceName);
}
IpAddress tunnelIp = device.getTunnelIp();
BigInteger designatedDpnId = dhcpExternalTunnelManager.readDesignatedSwitchesForExternalTunnel(tunnelIp, elanInstanceName);
- dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName, DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, add.getMacEntryKey().getValue());
+ dhcpExternalTunnelManager.installDhcpFlowsForVms(tunnelIp, elanInstanceName, DhcpServiceUtils.getListOfDpns(broker), designatedDpnId, macAddress);
}
@Override
package org.opendaylight.elanmanager.utils;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.vpnservice.utils.cache.CacheUtil;
}
- public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String deviceName) {
+ public static L2GatewayDevice removeL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
(ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
if (deviceMap != null) {
- L2GatewayDevice device = deviceMap.remove(deviceName);
+ L2GatewayDevice device = deviceMap.remove(l2gwDeviceNodeId);
return device;
} else {
return null;
}
}
- public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String deviceName) {
+ public static L2GatewayDevice getL2GatewayDeviceFromCache(String elanName, String l2gwDeviceNodeId) {
ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap =
(ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil.getCache(
ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
ConcurrentMap<String, L2GatewayDevice> deviceMap = cachedMap.get(elanName);
if (deviceMap != null) {
- return deviceMap.get(deviceName);
+ return deviceMap.get(l2gwDeviceNodeId);
} else {
return null;
}
}
- public static ConcurrentMap<String, L2GatewayDevice> getAllElanL2GatewayDevicesFromCache(String elanName) {
+ public static ConcurrentMap<String, L2GatewayDevice> getInvolvedL2GwDevices(String elanName) {
ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>> cachedMap = (ConcurrentMap<String, ConcurrentMap<String, L2GatewayDevice>>) CacheUtil
.getCache(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME);
ConcurrentMap<String, L2GatewayDevice> result = cachedMap.get(elanName);
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <version>${mdsal.version}</version>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
-
</project>
<type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
<name>entity-ownership-service</name>
</entity-ownership-service>
- <binding-normalized-node-serializer>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
- <name>runtime-mapping-singleton</name>
- </binding-normalized-node-serializer>
</module>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
return;
}
ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
print(elanName, elanDevices);
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.internal;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.ElanDpnInterfacesList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanDpnInterfaceClusteredListener
+ extends AsyncClusteredDataChangeListenerBase<DpnInterfaces, ElanDpnInterfaceClusteredListener>
+ implements AutoCloseable {
+ private DataBroker broker;
+ private ElanInterfaceManager elanInterfaceManager;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+ private static final Logger LOG = LoggerFactory.getLogger(ElanDpnInterfaceClusteredListener.class);
+
+ public ElanDpnInterfaceClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+ super(DpnInterfaces.class, ElanDpnInterfaceClusteredListener.class);
+ broker = db;
+ elanInterfaceManager = ifManager;
+ registerListener(db);
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), ElanDpnInterfaceClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+ } catch (final Exception e) {
+ LOG.error("DpnInterfaces DataChange listener registration fail!", e);
+ }
+ }
+
+ @Override
+ public InstanceIdentifier<DpnInterfaces> getWildCardPath() {
+ return InstanceIdentifier.builder(ElanDpnInterfaces.class).child(ElanDpnInterfacesList.class)
+ .child(DpnInterfaces.class).build();
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return ElanDpnInterfaceClusteredListener.this;
+ }
+
+ @Override
+ protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.BASE;
+ }
+
+ void handleUpdate(InstanceIdentifier<DpnInterfaces> id, DpnInterfaces dpnInterfaces) {
+ final String elanName = getElanName(id);
+ if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+ LOG.debug("dpnInterface updation, no external l2 devices to update for elan {} with Dp Id:", elanName,
+ dpnInterfaces.getDpId());
+ return;
+ }
+ ElanClusterUtils.runOnlyInLeaderNode(elanName, "updating mcast mac upon tunnel event",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ return Lists.newArrayList(
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+ }
+ });
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<DpnInterfaces> identifier, final DpnInterfaces dpnInterfaces) {
+ // this is the last dpn interface on this elan
+ final String elanName = getElanName(identifier);
+ LOG.debug("Received ElanDpnInterface removed for for elan {} with Dp Id ", elanName,
+ dpnInterfaces.getDpId());
+
+ if (ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).isEmpty()) {
+ LOG.debug("dpnInterface removed, no external l2 devices to update for elan {} with Dp Id:", elanName,
+ dpnInterfaces.getDpId());
+ return;
+ }
+ ElanClusterUtils.runOnlyInLeaderNode(elanName, "handling ElanDpnInterface removed",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ // deleting Elan L2Gw Devices UcastLocalMacs From Dpn
+ ElanL2GatewayUtils.deleteElanL2GwDevicesUcastLocalMacsFromDpn(elanName,
+ dpnInterfaces.getDpId());
+ // updating remote mcast mac on l2gw devices
+ return Lists.newArrayList(
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName));
+ }
+ });
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<DpnInterfaces> identifier, DpnInterfaces original,
+ final DpnInterfaces dpnInterfaces) {
+ LOG.debug("dpninterfaces update fired new size {}", dpnInterfaces.getInterfaces().size());
+ if (dpnInterfaces.getInterfaces().size() == 0) {
+ 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) {
+ if (dpnInterfaces.getInterfaces().size() == 1) {
+ LOG.debug("dpninterfaces first dpn interface on this elan {} {} ", dpnInterfaces.getKey(),
+ dpnInterfaces.getInterfaces().get(0));
+ // this is the first dpn interface on this elan
+ handleUpdate(identifier, dpnInterfaces);
+ }
+ }
+
+ /**
+ * @param identifier
+ * @return
+ */
+ private String getElanName(InstanceIdentifier<DpnInterfaces> identifier) {
+ return identifier.firstKeyOf(ElanDpnInterfacesList.class).getElanInstanceName();
+ }
+}
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
private ListenerRegistration<DataChangeListener> elanInstanceListenerRegistration;
private IdManagerService idManager;
private ElanInterfaceManager elanInterfaceManager;
+ private IInterfaceManager interfaceManager;
private static final Logger logger = LoggerFactory.getLogger(ElanInstanceManager.class);
this.elanInterfaceManager = elanInterfaceManager;
}
+ public void setInterfaceManager(IInterfaceManager interfaceManager) {
+ this.interfaceManager = interfaceManager;
+ }
+
/**
* Starts listening for changes in elan.yang:elan-instance container
if(elanInterfaces != null && !elanInterfaces.isEmpty()) {
for (String elanInterfaceName : elanInterfaces) {
InstanceIdentifier<ElanInterface> elanInterfaceId = ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName);
- elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName);
+ InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(elanInterfaceName);
+ elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName, interfaceInfo);
ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.interfaces.ElanInterface;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceAddWorker implements Callable<List<ListenableFuture<Void>>> {
+ private String key;
+ private ElanInterface elanInterface;
+ private ElanInstance elanInstance;
+ private InterfaceInfo interfaceInfo;
+ private ElanInterfaceManager dataChangeListener;
+
+ public ElanInterfaceAddWorker(String key, ElanInterface elanInterface, InterfaceInfo interfaceInfo,
+ ElanInstance elanInstance, ElanInterfaceManager dataChangeListener) {
+ super();
+ this.key = key;
+ this.elanInterface = elanInterface;
+ this.interfaceInfo = interfaceInfo;
+ this.elanInstance = elanInstance;
+ this.dataChangeListener = dataChangeListener;
+ }
+
+ @Override
+ public String toString() {
+ return "ElanInterfaceAddWorker [key=" + key + ", elanInterface=" + elanInterface + ", elanInstance="
+ + elanInstance + ", interfaceInfo=" + interfaceInfo + "]";
+ }
+
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ dataChangeListener.addElanInterface(elanInterface, interfaceInfo, elanInstance);
+ return futures;
+ }
+
+
+
+}
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
-import com.google.common.base.Optional;
-import com.google.common.collect.Maps;
-
+import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo.InterfaceType;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
-import org.opendaylight.vpnservice.itm.api.IITMProvider;
import org.opendaylight.vpnservice.itm.globals.ITMConstants;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
import org.opendaylight.vpnservice.mdsalutil.ActionType;
-import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
-import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
import org.opendaylight.vpnservice.mdsalutil.InstructionType;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
import org.opendaylight.vpnservice.mdsalutil.NwConstants;
-import org.opendaylight.vpnservice.itm.globals.ITMConstants;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
-import org.opendaylight.vpnservice.mdsalutil.*;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+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.yang.types.rev130715.PhysAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.servicebinding.rev151015.service.bindings.services.info.BoundServices;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanDpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.ElanForwardingTables;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-
/**
* Class in charge of handling creations, modifications and removals of ElanInterfaces.
protected void remove(InstanceIdentifier<ElanInterface> identifier, ElanInterface del) {
String interfaceName = del.getName();
ElanInstance elanInfo = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
- removeElanInterface(elanInfo, interfaceName);
- }
-
- public void removeElanService(ElanInterface del, InterfaceInfo interfaceInfo) {
- ElanInstance elanInstance = ElanUtils.getElanInstanceByName(del.getElanInstanceName());
- String interfaceName = del.getName();
- removeElanInterface(elanInstance, interfaceInfo);
- unbindService(elanInstance, interfaceName);
+ InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
+ String elanInstanceName = elanInfo.getElanInstanceName();
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ ElanInterfaceRemoveWorker configWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInfo, interfaceName, interfaceInfo, this);
+ coordinator.enqueueJob(elanInstanceName, configWorker, ElanConstants.JOB_MAX_RETRIES);
}
- public void removeElanInterface(ElanInstance elanInfo, String interfaceName) {
+ public void removeElanInterface(ElanInstance elanInfo, String interfaceName, InterfaceInfo interfaceInfo) {
String elanName = elanInfo.getElanInstanceName();
- InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(interfaceName);
-
if (interfaceInfo == null) {
// Interface does not exist in ConfigDS, so lets remove everything about that interface related to Elan
ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
BigInteger dpId = interfaceInfo.getDpId();
String elanName = elanInfo.getElanInstanceName();
+ long elanTag = elanInfo.getElanTag();
String interfaceName = interfaceInfo.getInterfaceName();
Elan elanState = ElanUtils.getElanByName(elanName);
logger.debug("Removing the Interface:{} from elan:{}", interfaceName, elanName);
DpnInterfaces dpnIfLists = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpnInterface.getDpId());
if (dpnIfLists.getInterfaces().contains(interfaceName)) {
logger.debug("deleting the elanInterface from the ElanDpnInterface cache in pre-provision scenario of elan:{} dpn:{} interfaceName:{}", elanName, dpId, interfaceName);
- removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+ removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
break;
}
}
}
} else {
- removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName);
+ removeElanDpnInterfaceFromOperationalDataStore(elanName, dpId, interfaceName, elanTag);
}
removeStaticELanFlows(elanInfo, interfaceInfo);
}
}
- private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName) {
+ private void removeElanDpnInterfaceFromOperationalDataStore(String elanName, BigInteger dpId, String interfaceName, long elanTag) {
DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
if(dpnInterfaces != null) {
List<String> interfaceLists = dpnInterfaces.getInterfaces();
interfaceLists.remove(interfaceName);
if (interfaceLists == null || interfaceLists.isEmpty()) {
+ deleteAllRemoteMacsInADpn(elanName, dpId, elanTag);
deleteElanDpnInterface(elanName, dpId);
- ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName);
} else {
updateElanDpnInterfacesList(elanName, dpId, interfaceLists);
}
}
}
+ private void deleteAllRemoteMacsInADpn(String elanName, BigInteger dpId, long elanTag) {
+ List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
+ for (DpnInterfaces dpnInterface : dpnInterfaces) {
+ BigInteger currentDpId = dpnInterface.getDpId();
+ if (!currentDpId.equals(dpId)) {
+ for (String elanInterface : dpnInterface.getInterfaces()) {
+ ElanInterfaceMac macs = ElanUtils.getElanInterfaceMacByInterfaceName(elanInterface);
+ if (macs == null) {
+ continue;
+ }
+ for (MacEntry mac : macs.getMacEntry())
+ mdsalManager.removeFlow(dpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
+ ElanUtils.getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, dpId, currentDpId, mac.getMacAddress().getValue(), elanTag)));
+ }
+ }
+ }
+ }
+
@Override
protected void update(InstanceIdentifier<ElanInterface> identifier, ElanInterface original, ElanInterface update) {
// updating the static-Mac Entries for the existing elanInterface
unProcessedElanInterfaces.put(elanInstanceName, elanInterfaces);
return;
}
- addElanInterface(elanInterfaceAdded, interfaceInfo, elanInstance);
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ ElanInterfaceAddWorker addWorker = new ElanInterfaceAddWorker(elanInstanceName, elanInterfaceAdded,
+ interfaceInfo, elanInstance, this);
+ coordinator.enqueueJob(elanInstanceName, addWorker, ElanConstants.JOB_MAX_RETRIES);
}
void handleunprocessedElanInterfaces(ElanInstance elanInstance) {
if ( elanInstance.getVni() != null && elanInstance.getVni().longValue() != 0 ) {
setExternalTunnelTable(dpId, elanInstance);
}
- ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+ ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
} else {
List<String> elanInterfaces = existingElanDpnInterfaces.get().getInterfaces();
elanInterfaces.add(interfaceName);
if (elanInterfaces.size() == 1) {//1st dpn interface
- ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanInstanceName);
+ ElanL2GatewayUtils.installElanL2gwDevicesLocalMacsInDpn(dpId, elanInstance);
}
updateElanDpnInterfacesList(elanInstanceName, dpId, elanInterfaces);
}
if( isInterfaceOperational ) {
// Add MAC in TOR's remote MACs via OVSDB. Outside of the loop on purpose.
- ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, staticMacAddresses);
+ ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId, staticMacAddresses);
}
}
}
if (isOperational(interfaceInfo)) {
// LocalBroadcast Group creation with elan-Interfaces
- setupElanBroadcastGroups(elanInfo, interfaceInfo);
+ setupElanBroadcastGroups(elanInfo, interfaceInfo.getDpId());
setupLocalBroadcastGroups(elanInfo, interfaceInfo);
//Terminating Service , UnknownDMAC Table.
setupTerminateServiceTable(elanInfo, interfaceInfo);
+ ElanUtils.setupTermDmacFlows(interfaceInfo, mdsalManager);
setupUnknownDMacTable(elanInfo, interfaceInfo);
setupFilterEqualsTable(elanInfo, interfaceInfo);
// bind the Elan service to the Interface
return listBuckets;
}
- private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo,
- InterfaceInfo interfaceInfo, int bucketId) {
- BigInteger dpnId = interfaceInfo.getDpId();
+ private List<Bucket> getRemoteBCGroupBuckets(ElanInstance elanInfo, BigInteger dpnId, int bucketId) {
int elanTag = elanInfo.getElanTag().intValue();
List<Bucket> listBucketInfo = new ArrayList<Bucket>();
ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName());
}
}
- private void updateRemoteBCGrouponDpnTunnelEvent(ElanInstance elanInfo,
- InterfaceInfo interfaceInfo, BigInteger dstDpId) {
- int elanTag = elanInfo.getElanTag().intValue();
- long groupId = ElanUtils.getElanRemoteBCGID(elanTag);
- List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
- if(elanDpns != null) {
- for(DpnInterfaces dpnInterface : elanDpns) {
- int bucketId = 0;
- List<Bucket> remoteListBucket = new ArrayList<Bucket>();
- if(ElanUtils.isDpnPresent(dstDpId) && dpnInterface.getDpId().equals(dstDpId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) {
- try {
- List<Action> remoteListActionInfo = ElanUtils.getInternalItmEgressAction(interfaceInfo.getDpId(), dstDpId, elanTag);
- remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
- bucketId++;
- } catch (Exception ex) {
- logger.error( "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} " ,dpnInterface.getDpId(), dstDpId);
- return;
- }
- List<Action> remoteListActionInfo = new ArrayList<Action>();
- remoteListActionInfo.add(new ActionInfo(ActionType.group, new String[] {String.valueOf(ElanUtils.getElanLocalBCGID(elanTag))}).buildAction());
- remoteListBucket.add(MDSALUtil.buildBucket(remoteListActionInfo, MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
-
- List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dstDpId, bucketId);
- remoteListBucket.addAll(elanL2GwDevicesBuckets);
-
- Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(remoteListBucket));
- mdsalManager.syncInstallGroup(interfaceInfo.getDpId(), group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
- break;
- }
- }
- }
- }
-
-
/**
* Returns the bucket info with the given interface as the only bucket.
*/
}
}
- public void setupElanBroadcastGroups(ElanInstance elanInfo, InterfaceInfo interfaceInfo) {
+ public void setupElanBroadcastGroups(ElanInstance elanInfo, BigInteger dpnId) {
List<Bucket> listBucket = new ArrayList<Bucket>();
int bucketId = 0;
- BigInteger dpnId = interfaceInfo.getDpId();
long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanInfo.getElanInstanceName(), dpnId);
for(String ifName : dpnInterfaces.getInterfaces()) {
// In case if there is a InterfacePort in the cache which is not in
// operational state, skip processing it
- InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceInfo.getInterfaceType());
+ // FIXME: interfaceType to be obtained dynamically. It doesn't
+ // affect the functionality here as it is nowhere used.
+ InterfaceType interfaceType = InterfaceInfo.InterfaceType.VLAN_INTERFACE;
+ InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(ifName, interfaceType);
if (!isOperational(ifInfo)) {
continue;
}
listBucket.add(MDSALUtil.buildBucket(getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT, bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
bucketId++;
}
- List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, interfaceInfo, bucketId);
+ List<Bucket> listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, dpnId, bucketId);
listBucket.addAll(listBucketInfoRemote);
Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll, MDSALUtil.buildBucketLists(listBucket));
- logger.trace("installing the localBroadCast Group:{}", group);
+ logger.trace("installing the remote BroadCast Group:{}", group);
mdsalManager.syncInstallGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND);
}
String flowId = getFlowRef(NwConstants.EXTERNAL_TUNNEL_TABLE, elanInfo.getElanTag());
FlowEntity flowEntity = new FlowEntity(dpnId);
+ flowEntity.setTableId(NwConstants.EXTERNAL_TUNNEL_TABLE);
flowEntity.setFlowId(flowId);
mdsalManager.removeFlow(flowEntity);
}
// No more Elan Interfaces in this DPN
logger.debug("deleting the elan: {} present on dpId: {}", elanInfo.getElanInstanceName(), dpId);
removeDefaultTermFlow(dpId, elanInfo.getElanTag());
+ removeDefaultTermFlow(dpId, interfaceInfo.getInterfaceTag());
removeUnknownDmacFlow(dpId, elanInfo);
removeElanBroadcastGroup(elanInfo, interfaceInfo);
removeLocalBroadcastGroup(elanInfo, interfaceInfo);
}
removeFilterEqualsTable(elanInfo, interfaceInfo);
} else {
- setupElanBroadcastGroups(elanInfo, interfaceInfo);
+ setupElanBroadcastGroups(elanInfo, dpId);
setupLocalBroadcastGroups(elanInfo, interfaceInfo);
removeFilterEqualsTable(elanInfo, interfaceInfo);
}
if (interfaceInfo == null) {
return false;
}
- return ((interfaceInfo.getOpState() == InterfaceInfo.InterfaceOpState.UP) && (interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED));
+ return interfaceInfo.getAdminState() == InterfaceInfo.InterfaceAdminState.ENABLED;
}
protected void updatedIfPrimaryAttributeChanged(ElanInterface elanInterface, boolean isUpdated) {
}
}
- public void handleTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
+ public void handleInternalTunnelStateEvent(BigInteger srcDpId, BigInteger dstDpId) {
ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
- Set<String> elanInstancesMap = new HashSet<>();
if(dpnInterfaceLists == null) {
return;
}
}
if(cnt == 2) {
logger.debug("Elan instance:{} is present b/w srcDpn:{} and dstDpn:{}", elanName, srcDpId, dstDpId);
+ ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+ // update Remote BC Group
+ setupElanBroadcastGroups(elanInfo, srcDpId);
+
DpnInterfaces dpnInterface = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, srcDpId);
Set<String> interfaceLists = new HashSet<>();
- ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
interfaceLists.addAll(dpnInterface.getInterfaces());
for(String ifName : interfaceLists) {
InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(ifName);
if (isOperational(interfaceInfo)) {
- if (interfaceInfo.getDpId().equals(srcDpId) && !elanInstancesMap.contains(elanDpns.getElanInstanceName())) {
- elanInstancesMap.add(elanDpns.getElanInstanceName());
- elanInterfaceManager.updateRemoteBCGrouponDpnTunnelEvent(elanInfo, interfaceInfo, dstDpId);
- }
elanInterfaceManager.installDMacAddressTables(elanInfo, interfaceInfo, dstDpId);
}
}
}
}
+ /**
+ * Handle external tunnel state event.
+ *
+ * @param externalTunnel
+ * the external tunnel
+ * @param intrf
+ * the interface
+ */
+ public void handleExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+ if (!validateExternalTunnelStateEvent(externalTunnel, intrf)) {
+ return;
+ }
+ // dpId/externalNodeId will be available either in source or destination
+ // based on the tunnel end point
+ BigInteger dpId = null;
+ NodeId externalNodeId = null;
+ if (StringUtils.isNumeric(externalTunnel.getSourceDevice())) {
+ dpId = new BigInteger(externalTunnel.getSourceDevice());
+ externalNodeId = new NodeId(externalTunnel.getDestinationDevice());
+ } else if (StringUtils.isNumeric(externalTunnel.getDestinationDevice())) {
+ dpId = new BigInteger(externalTunnel.getDestinationDevice());
+ externalNodeId = new NodeId(externalTunnel.getSourceDevice());
+ }
+ if (dpId == null || externalNodeId == null) {
+ logger.error("Dp ID / externalNodeId not found in external tunnel {}", externalTunnel);
+ return;
+ }
+
+ ElanDpnInterfaces dpnInterfaceLists = ElanUtils.getElanDpnInterfacesList();
+ if (dpnInterfaceLists == null) {
+ return;
+ }
+ List<ElanDpnInterfacesList> elanDpnIf = dpnInterfaceLists.getElanDpnInterfacesList();
+ for (ElanDpnInterfacesList elanDpns : elanDpnIf) {
+ String elanName = elanDpns.getElanInstanceName();
+ ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanName);
+
+ DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
+ if (dpnInterfaces == null || dpnInterfaces.getInterfaces() == null
+ || dpnInterfaces.getInterfaces().isEmpty()) {
+ continue;
+ }
+ logger.debug("Elan instance:{} is present in Dpn:{} ", elanName, dpId);
+
+ setupElanBroadcastGroups(elanInfo, dpId);
+ // install L2gwDevices local macs in dpn.
+ ElanL2GatewayUtils.installL2gwDeviceMacsInDpn(dpId, externalNodeId, elanInfo);
+ // Install dpn macs on external device
+ ElanL2GatewayUtils.installDpnMacsInL2gwDevice(elanName, new HashSet<>(dpnInterfaces.getInterfaces()), dpId,
+ externalNodeId);
+ }
+ logger.info("Handled ExternalTunnelStateEvent for {}", externalTunnel);
+ }
+
+ /**
+ * Validate external tunnel state event.
+ *
+ * @param externalTunnel
+ * the external tunnel
+ * @param intrf
+ * the intrf
+ * @return true, if successful
+ */
+ private boolean validateExternalTunnelStateEvent(ExternalTunnel externalTunnel, Interface intrf) {
+ if (intrf.getOperStatus() == Interface.OperStatus.Up) {
+ String srcDevice = externalTunnel.getDestinationDevice();
+ String destDevice = externalTunnel.getSourceDevice();
+ ExternalTunnel otherEndPointExtTunnel = ElanUtils.getExternalTunnel(srcDevice, destDevice,
+ LogicalDatastoreType.CONFIGURATION);
+ if (logger.isTraceEnabled()) {
+ logger.trace("Validating external tunnel state: src tunnel {}, dest tunnel {}", externalTunnel,
+ otherEndPointExtTunnel);
+ }
+ if (otherEndPointExtTunnel != null) {
+ boolean otherEndPointInterfaceOperational = ElanUtils
+ .isInterfaceOperational(otherEndPointExtTunnel.getTunnelInterfaceName(), broker);
+ if (otherEndPointInterfaceOperational) {
+ return true;
+ } else {
+ logger.debug("Other end [{}] of the external tunnel is not yet UP for {}",
+ otherEndPointExtTunnel.getTunnelInterfaceName(), externalTunnel);
+ }
+ }
+ }
+ return false;
+ }
+
public void handleInterfaceUpdated(InterfaceInfo interfaceInfo, ElanInstance elanInstance, boolean isStateUp) {
BigInteger dpId = interfaceInfo.getDpId();
String elanName = elanInstance.getElanInstanceName();
logger.trace("ElanInterface Service is installed for interface:{}", ifName);
elanInterfaceManager.installFlowsAndGroups(elanInstance, interfaceInfo);
elanInterfaceManager.installMacAddressTables(elanInstance, interfaceInfo);
+
+ if (elanInstance.getVni() != null && elanInstance.getVni() != 0) {
+ List<PhysAddress> macAddresses = ElanUtils
+ .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName());
+ if (macAddresses != null && !macAddresses.isEmpty()) {
+ ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(),
+ dpId, macAddresses);
+ }
+ }
} else {
DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId);
return mkMatches;
}
- public void updateElanBroadcastGroup(ElanInstance elanInfo) {
- int bucketId = 0;
- long groupId = ElanUtils.getElanRemoteBCGID(elanInfo.getElanTag());
-
- List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo
- .getElanInstanceName());
+ public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) {
+ List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
if (dpns == null) {
return;
}
for (DpnInterfaces dpn : dpns) {
- bucketId = 0;
- List<Bucket> listBucket = new ArrayList<Bucket>();
- bucketId = getLocalBcGroupBuckets(dpn, listBucket, bucketId);
- getRemoteBCGroupBuckets(elanInfo, dpn.getDpId(), listBucket,
- bucketId);
- Group group = MDSALUtil.buildGroup(groupId,
- elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
- MDSALUtil.buildBucketLists(listBucket));
- logger.trace("installing the localBroadCast Group:{}", group);
- mdsalManager.syncInstallGroup(dpn.getDpId(), group,
- ElanConstants.DELAY_TIME_IN_MILLISECOND);
- }
- }
-
- private int getLocalBcGroupBuckets(DpnInterfaces dpn,
- List<Bucket> listBucket, int bucketId) {
- for (String intf : dpn.getInterfaces()) {
- InterfaceInfo ifInfo = interfaceManager.getInterfaceInfo(intf);
- if (!isOperational(ifInfo)) {
- continue;
- }
- listBucket.add(MDSALUtil.buildBucket(
- getInterfacePortActions(ifInfo), MDSALUtil.GROUP_WEIGHT,
- bucketId, MDSALUtil.WATCH_PORT, MDSALUtil.WATCH_GROUP));
- bucketId++;
- }
- return bucketId;
- }
-
- private void getRemoteBCGroupBuckets(ElanInstance elanInfo,
- BigInteger dpnId, List<Bucket> listBucket, int bucketId) {
- int elanTag = elanInfo.getElanTag().intValue();
- ElanDpnInterfacesList elanDpns = ElanUtils
- .getElanDpnInterfacesList(elanInfo.getElanInstanceName());
- if (elanDpns != null) {
- List<DpnInterfaces> dpnInterfaceses = elanDpns.getDpnInterfaces();
- for (DpnInterfaces dpnInterface : dpnInterfaceses) {
- if (ElanUtils.isDpnPresent(dpnInterface.getDpId())
- && dpnInterface.getDpId() != dpnId
- && dpnInterface.getInterfaces() != null
- && !dpnInterface.getInterfaces().isEmpty()) {
- try {
- List<Action> listActionInfo = ElanUtils
- .getInternalItmEgressAction(dpnId,
- dpnInterface.getDpId(), elanTag);
- listBucket.add(MDSALUtil.buildBucket(listActionInfo, 0,
- bucketId, 0xffffffffL, 0xffffffffL));
- bucketId++;
- } catch (Exception ex) {
- logger.error(
- "Logical Group Interface not found between source Dpn - {}, destination Dpn - {} ",
- dpnId, dpnInterface.getDpId());
- }
- }
- }
+ setupElanBroadcastGroups(elanInfo, dpn.getDpId());
}
- List<Bucket> elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId);
- listBucket.addAll(elanL2GwDevicesBuckets);
}
public static List<Bucket> getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId,
int bucketId) {
List<Bucket> listBucketInfo = new ArrayList<Bucket>();
ConcurrentMap<String, L2GatewayDevice> map = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanInfo.getElanInstanceName());
+ .getInvolvedL2GwDevices(elanInfo.getElanInstanceName());
for (L2GatewayDevice device : map.values()) {
String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId),
device.getHwvtepNodeId());
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class ElanInterfaceRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
+ private String key;
+ private ElanInstance elanInfo;
+ private String interfaceName;
+ private InterfaceInfo interfaceInfo;
+ private ElanInterfaceManager dataChangeListener;
+
+ public ElanInterfaceRemoveWorker(String key, ElanInstance elanInfo, String interfaceName,
+ InterfaceInfo interfaceInfo, ElanInterfaceManager dataChangeListener) {
+ super();
+ this.key = key;
+ this.elanInfo = elanInfo;
+ this.interfaceName = interfaceName;
+ this.interfaceInfo = interfaceInfo;
+ this.dataChangeListener = dataChangeListener;
+ }
+
+ @Override
+ public String toString() {
+ return "ElanInterfaceRemoveWorker [key=" + key + ", elanInfo=" + elanInfo +
+ ", interfaceName=" + interfaceName
+ + ", interfaceInfo=" + interfaceInfo + "]";
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ dataChangeListener.removeElanInterface(elanInfo, interfaceName, interfaceInfo);
+ return futures;
+ }
+
+}
package org.opendaylight.vpnservice.elan.internal;
-import com.google.common.base.Optional;
+import java.math.BigInteger;
+import java.util.List;
+
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.globals.InterfaceInfo;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.math.BigInteger;
-import java.util.List;
-
public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
private DataBroker broker;
private IInterfaceManager interfaceManager;
this.interfaceManager = interfaceManager;
}
- private void handleVlanInterfaceOperationalStateChange(String interfaceName, boolean isStateUp) {
- //fetching the elanInstanceName from elan-interface config data-store
- ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
- if (elanInterface == null) {
- return;
- }
- ElanInstance elanInfo = ElanUtils.getElanInstanceByName(elanInterface.getElanInstanceName());
- InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName,
- InterfaceInfo.InterfaceType.VLAN_INTERFACE);
- if (interfaceInfo == null) {
- logger.warn("Interface {} doesn't exist in operational datastore", interfaceName);
- return;
- }
-
- logger.trace("ElanService Interface Operational state has changes for Interface:{}", interfaceName);
- elanInterfaceManager.handleInterfaceUpdated(interfaceInfo, elanInfo , isStateUp);
- }
-
@Override
protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
logger.trace("Received interface {} Down event", delIf);
interfaceInfo.setInterfaceName(interfaceName);
interfaceInfo.setInterfaceType(InterfaceInfo.InterfaceType.VLAN_INTERFACE);
interfaceInfo.setInterfaceTag(delIf.getIfIndex());
- elanInterfaceManager.removeElanService(elanInterface, interfaceInfo);
+ String elanInstanceName = elanInterface.getElanInstanceName();
+ ElanInstance elanInstance = ElanUtils.getElanInstanceByName(elanInstanceName);
+ DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
+ ElanInterfaceRemoveWorker removeWorker = new ElanInterfaceRemoveWorker(elanInstanceName, elanInstance,
+ interfaceName, interfaceInfo, elanInterfaceManager);
+ coordinator.enqueueJob(elanInstanceName, removeWorker, ElanConstants.JOB_MAX_RETRIES);
}
@Override
protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
logger.trace("Operation Interface update event - Old: {}, New: {}", original, update);
String interfaceName = update.getName();
- if(update.getType() != null && update.getType().equals(Tunnel.class)) {
+ if (update.getType() == null) {
+ logger.trace("Interface type for interface {} is null", interfaceName);
+ return;
+ }
+ if(update.getType().equals(Tunnel.class)) {
if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
InternalTunnel internalTunnel = getTunnelState(interfaceName);
if (internalTunnel != null) {
- elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+ elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
}
}
- } else if(update.getType().equals(L2vlan.class)) {
- ElanInterface elanInterface = ElanUtils.getElanInterfaceByElanInterfaceName(interfaceName);
- if(elanInterface == null) {
- logger.debug("No Elan Interface is created for the interface:{} ", interfaceName);
- return;
- }
- if (update.getOperStatus().equals(Interface.OperStatus.Up) && update.getAdminStatus() == Interface.AdminStatus.Up) {
- logger.trace("Operation Status for Interface:{} event state UP ", interfaceName);
- handleVlanInterfaceOperationalStateChange(interfaceName, true);
- } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
- logger.trace("Operation Status for Interface:{} event state DOWN ", interfaceName);
- handleVlanInterfaceOperationalStateChange(interfaceName, false);
- }
-
}
}
if(intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
InternalTunnel internalTunnel = getTunnelState(interfaceName);
if (internalTunnel != null) {
- elanInterfaceManager.handleTunnelStateEvent(internalTunnel.getSourceDPN(), internalTunnel.getDestinationDPN());
+ elanInterfaceManager.handleInternalTunnelStateEvent(internalTunnel.getSourceDPN(),
+ internalTunnel.getDestinationDPN());
}
}
}
public InternalTunnel getTunnelState(String interfaceName) {
InternalTunnel internalTunnel = null;
TunnelList tunnelList = ElanUtils.buildInternalTunnel(broker);
- if (tunnelList.getInternalTunnel() != null) {
+ if (tunnelList != null && tunnelList.getInternalTunnel() != null) {
List<InternalTunnel> internalTunnels = tunnelList.getInternalTunnel();
for (InternalTunnel tunnel : internalTunnels) {
if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) {
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.internal;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
+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.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ElanInterfaceStateClusteredListener extends
+ AsyncClusteredDataChangeListenerBase<Interface, ElanInterfaceStateClusteredListener> implements AutoCloseable {
+ private DataBroker broker;
+ private ElanInterfaceManager elanInterfaceManager;
+ private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+ private static final Logger logger = LoggerFactory.getLogger(ElanInterfaceStateClusteredListener.class);
+
+ public ElanInterfaceStateClusteredListener(final DataBroker db, final ElanInterfaceManager ifManager) {
+ super(Interface.class, ElanInterfaceStateClusteredListener.class);
+ broker = db;
+ elanInterfaceManager = ifManager;
+ registerListener(db);
+ }
+
+ private void registerListener(final DataBroker db) {
+ try {
+ listenerRegistration = broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ getWildCardPath(), ElanInterfaceStateClusteredListener.this, AsyncDataBroker.DataChangeScope.BASE);
+ } catch (final Exception e) {
+ logger.error("Elan Interfaces DataChange listener registration fail!", e);
+ throw new IllegalStateException("ElanInterface registration Listener failed.", e);
+ }
+ }
+
+ @Override
+ public InstanceIdentifier<Interface> getWildCardPath() {
+ return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return ElanInterfaceStateClusteredListener.this;
+ }
+
+ @Override
+ protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
+ return AsyncDataBroker.DataChangeScope.BASE;
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<Interface> identifier, Interface delIf) {
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<Interface> identifier, Interface original, final Interface update) {
+ add(identifier, update);
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<Interface> identifier, final Interface intrf) {
+ if (intrf.getType() != null && intrf.getType().equals(Tunnel.class)) {
+ if (intrf.getOperStatus().equals(Interface.OperStatus.Up)) {
+ final String interfaceName = intrf.getName();
+
+ ElanClusterUtils.runOnlyInLeaderNode(new Runnable() {
+ @Override
+ public void run() {
+ logger.debug("running external tunnel update job for interface {} added", interfaceName);
+ handleExternalTunnelUpdate(interfaceName, intrf);
+ }
+ });
+ }
+ }
+ }
+
+ private void handleExternalTunnelUpdate(String interfaceName, Interface update) {
+ ExternalTunnel externalTunnel = ElanUtils.getExternalTunnel(interfaceName, LogicalDatastoreType.CONFIGURATION);
+ if (externalTunnel != null) {
+ logger.debug("handling external tunnel update event for ext device dst {} src {} ",
+ externalTunnel.getDestinationDevice(), externalTunnel.getSourceDevice());
+ elanInterfaceManager.handleExternalTunnelStateEvent(externalTunnel, update);
+ } else {
+ logger.trace("External tunnel not found with interfaceName: {}", interfaceName);
+ }
+ }
+}
import org.opendaylight.vpnservice.mdsalutil.NWUtil;
import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.NoMatch;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.interfacemgr.impl.rev150325.InterfacemgrImpl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.state.Elan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.tag.name.map.ElanTagName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntryBuilder;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
-import java.math.BigInteger;
+
import java.util.Arrays;
-import java.util.List;
@SuppressWarnings("deprecation")
public class ElanPacketInHandler implements PacketProcessingListener {
ElanUtils.setupMacFlows(elanInstance, interfaceManager.getInterfaceInfo(interfaceName), elanInstance.getMacTimeout(), macAddress);
BigInteger dpId = interfaceManager.getDpnForInterface(interfaceName);
- ElanL2GatewayUtils.installMacsInElanExternalDevices(elanInstance, dpId, Arrays.asList(physAddress));
+ ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), dpId,
+ Arrays.asList(physAddress));
} catch (Exception e) {
logger.trace("Failed to decode packet: {}", e);
}
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.elanmanager.api.IElanService;
import org.opendaylight.elanmanager.exceptions.MacNotFoundException;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.vpnservice.elan.l2gw.internal.ElanL2GatewayProvider;
import org.opendaylight.vpnservice.elan.statisitcs.ElanStatisticsImpl;
import org.opendaylight.vpnservice.elan.statusanddiag.ElanStatusMonitor;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.interfaces.IInterfaceManager;
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.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
private ElanPacketInHandler elanPacketInHandler;
private ElanSmacFlowEventListener elanSmacFlowEventListener;
private ElanInterfaceStateChangeListener elanInterfaceStateChangeListener;
+ private ElanInterfaceStateClusteredListener infStateChangeClusteredListener;
+ private ElanDpnInterfaceClusteredListener elanDpnInterfaceClusteredListener;
private ElanNodeListener elanNodeListener;
private NotificationService notificationService;
private RpcProviderRegistry rpcProviderRegistry;
private ElanL2GatewayProvider elanL2GatewayProvider;
private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private static final ElanStatusMonitor elanStatusMonitor = ElanStatusMonitor.getInstance();
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
+ public static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+ if (dataStoreJobCoordinator == null) {
+ dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+ }
+ return dataStoreJobCoordinator;
+ }
+
public ElanServiceProvider(RpcProviderRegistry rpcRegistry) {
rpcProviderRegistry = rpcRegistry;
elanStatusMonitor.reportStatus("STARTING");
try {
createIdPool();
+ getDataStoreJobCoordinator();
broker = session.getSALService(DataBroker.class);
ElanUtils.setDataBroker(broker);
elanInstanceManager.setDataBroker(broker);
elanInstanceManager.setIdManager(idManager);
elanInstanceManager.setElanInterfaceManager(elanInterfaceManager);
+ elanInstanceManager.setInterfaceManager(interfaceManager);
elanNodeListener = new ElanNodeListener(broker, mdsalManager);
elanInterfaceStateChangeListener = new ElanInterfaceStateChangeListener(broker, elanInterfaceManager);
elanInterfaceStateChangeListener.setInterfaceManager(interfaceManager);
+ infStateChangeClusteredListener = new ElanInterfaceStateClusteredListener(broker, elanInterfaceManager);
+ elanDpnInterfaceClusteredListener = new ElanDpnInterfaceClusteredListener(broker, elanInterfaceManager);
+ ElanClusterUtils.setEntityOwnershipService(entityOwnershipService);
+ ElanClusterUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
this.elanL2GatewayProvider = new ElanL2GatewayProvider(this);
elanInterfaceManager.registerListener();
this.entityOwnershipService = entityOwnershipService;
}
- public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
- }
-
public IInterfaceManager getInterfaceManager() {
return this.interfaceManager;
}
return entityOwnershipService;
}
- public BindingNormalizedNodeSerializer getBindingNormalizedNodeSerializer() {
- return bindingNormalizedNodeSerializer;
- }
-
private void createIdPool() {
CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(ElanConstants.ELAN_ID_POOL_NAME)
.setLow(ElanConstants.ELAN_ID_LOW_VALUE).setHigh(ElanConstants.ELAN_ID_HIGH_VALUE).build();
package org.opendaylight.vpnservice.elan.l2gw.internal;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
import org.opendaylight.vpnservice.elan.internal.ElanServiceProvider;
import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLocalUcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepNodeListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
import org.opendaylight.vpnservice.elan.l2gw.listeners.L2GatewayConnectionListener;
import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
+import org.opendaylight.vpnservice.utils.clustering.EntityOwnerUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private DataBroker broker;
private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private ItmRpcService itmRpcService;
private ElanInstanceManager elanInstanceManager;
private ElanInterfaceManager elanInterfaceManager;
private L2GatewayConnectionListener l2GwConnListener;
private HwvtepNodeListener hwvtepNodeListener;
private HwvtepLocalUcastMacListener torMacsListener;
+ private HwvtepPhysicalLocatorListener physicalLocatorListener;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
/**
* Instantiates a new elan l2 gateway provider.
public ElanL2GatewayProvider(ElanServiceProvider elanServiceProvider) {
this.broker = elanServiceProvider.getBroker();
this.entityOwnershipService = elanServiceProvider.getEntityOwnershipService();
- this.bindingNormalizedNodeSerializer = elanServiceProvider.getBindingNormalizedNodeSerializer();
this.itmRpcService = elanServiceProvider.getItmRpcService();
this.elanInstanceManager = elanServiceProvider.getElanInstanceManager();
this.elanInterfaceManager = elanServiceProvider.getElanInterfaceManager();
-
+ dataStoreJobCoordinator = elanServiceProvider.getDataStoreJobCoordinator();
init();
LOG.info("ElanL2GatewayProvider Initialized");
ElanL2GwCacheUtils.createElanL2GwDeviceCache();
ElanL2GatewayUtils.setDataBroker(broker);
ElanL2GatewayUtils.setItmRpcService(itmRpcService);
+ ElanL2GatewayUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
ElanL2GatewayMulticastUtils.setBroker(broker);
ElanL2GatewayMulticastUtils.setElanInstanceManager(elanInstanceManager);
ElanL2GatewayMulticastUtils.setElanInterfaceManager(elanInterfaceManager);
+ ElanL2GatewayMulticastUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+ L2GatewayConnectionUtils.setElanInstanceManager(elanInstanceManager);
+ L2GatewayConnectionUtils.setBroker(broker);
+ L2GatewayConnectionUtils.setDataStoreJobCoordinator(dataStoreJobCoordinator);
- this.torMacsListener = new HwvtepLocalUcastMacListener(broker, entityOwnershipService,
- bindingNormalizedNodeSerializer);
- this.l2GwConnListener = new L2GatewayConnectionListener(broker, entityOwnershipService,
- bindingNormalizedNodeSerializer, elanInstanceManager);
- this.hwvtepNodeListener = new HwvtepNodeListener(broker, entityOwnershipService,
- bindingNormalizedNodeSerializer, elanInstanceManager, itmRpcService);
+ HwvtepRemoteMcastMacListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+ HwvtepLogicalSwitchListener.setDataStoreJobCoordinator(dataStoreJobCoordinator);
+
+ this.torMacsListener = new HwvtepLocalUcastMacListener(broker);
+ this.l2GwConnListener = new L2GatewayConnectionListener(broker, elanInstanceManager);
+ this.hwvtepNodeListener = new HwvtepNodeListener(broker, elanInstanceManager, itmRpcService);
this.hwvtepNodeListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+
+ physicalLocatorListener = new HwvtepPhysicalLocatorListener(broker);
+ try {
+ EntityOwnerUtils.registerEntityCandidateForOwnerShip(entityOwnershipService,
+ HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ null/*listener*/);
+ } catch (CandidateAlreadyRegisteredException e) {
+ LOG.error("failed to register the entity");
+ }
}
/*
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.l2gw.jobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
+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.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class AssociateHwvtepToElanJob implements Callable<List<ListenableFuture<Void>>> {
+ DataBroker broker;
+ L2GatewayDevice l2GatewayDevice;
+ ElanInstance elanInstance;
+ Devices l2Device;
+ Integer defaultVlan;
+ boolean createLogicalSwitch;
+ private static final Logger LOG = LoggerFactory.getLogger(AssociateHwvtepToElanJob.class);
+
+ public AssociateHwvtepToElanJob(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+ Devices l2Device, Integer defaultVlan, boolean createLogicalSwitch) {
+ this.broker = broker;
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.elanInstance = elanInstance;
+ this.l2Device = l2Device;
+ this.defaultVlan = defaultVlan;
+ this.createLogicalSwitch = createLogicalSwitch;
+ LOG.debug("created assosiate l2gw connection job for {} {} ", elanInstance.getElanInstanceName(),
+ l2GatewayDevice.getHwvtepNodeId());
+ }
+
+ public String getJobKey() {
+ return elanInstance.getElanInstanceName();
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+ String elanInstanceName = elanInstance.getElanInstanceName();
+ LOG.debug("running assosiate l2gw connection job for {} {} ", elanInstanceName, hwvtepNodeId);
+
+ // Create Logical Switch if it's not created already in the device
+ if (createLogicalSwitch) {
+ LOG.info("creating logical switch {} for {} ", elanInstanceName, hwvtepNodeId);
+
+ ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance);
+ futures.add(lsCreateFuture);
+ } else {
+ String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstanceName);
+ LOG.info("{} is already created in {}; adding remaining configurations", logicalSwitchName, hwvtepNodeId);
+
+ LogicalSwitchAddedJob logicalSwitchAddedJob = new LogicalSwitchAddedJob(logicalSwitchName, l2Device,
+ l2GatewayDevice, defaultVlan);
+ return logicalSwitchAddedJob.call();
+ }
+
+ return futures;
+ }
+
+ private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance) {
+ final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(
+ elanInstance.getElanInstanceName());
+ String segmentationId = elanInstance.getVni().toString();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("logical switch {} is created on {} with VNI {}", logicalSwitchName,
+ l2GatewayDevice.getHwvtepNodeId(), segmentationId);
+ }
+ NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+ InstanceIdentifier<LogicalSwitches> path = HwvtepSouthboundUtils
+ .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName));
+ LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName,
+ elanInstance.getDescription(), segmentationId);
+
+ ListenableFuture<Void> lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch);
+ Futures.addCallback(lsCreateFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ // Listener will be closed after all configuration completed
+ // on hwvtep by
+ // listener itself
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Successful in initiating logical switch {} creation", logicalSwitchName);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error("Failed logical switch {} creation", logicalSwitchName, error);
+ }
+ });
+ return lsCreateFuture;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.l2gw.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The Job class to delete L2 gateway device local ucast macs from other Elan L2
+ * gateway devices.
+ */
+public class DeleteL2GwDeviceMacsFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+
+ /** The Constant JOB_KEY_PREFIX. */
+ private static final String JOB_KEY_PREFIX = "hwvtep:";
+
+ /** The Constant LOG. */
+ private static final Logger LOG = LoggerFactory.getLogger(DeleteL2GwDeviceMacsFromElanJob.class);
+
+ /** The broker. */
+ private final DataBroker broker;
+
+ /** The elan name. */
+ private final String elanName;
+
+ /** The l2 gw device. */
+ private final L2GatewayDevice l2GwDevice;
+
+ /** The mac addresses. */
+ private final List<MacAddress> macAddresses;
+
+ /**
+ * Instantiates a new delete l2 gw device macs from elan job.
+ *
+ * @param broker
+ * the broker
+ * @param elanName
+ * the elan name
+ * @param l2GwDevice
+ * the l2 gw device
+ * @param macAddresses
+ * the mac addresses
+ */
+ public DeleteL2GwDeviceMacsFromElanJob(DataBroker broker, String elanName, L2GatewayDevice l2GwDevice,
+ List<MacAddress> macAddresses) {
+ this.broker = broker;
+ this.elanName = elanName;
+ this.l2GwDevice = l2GwDevice;
+ this.macAddresses = macAddresses;
+ }
+
+ public String getJobKey() {
+ return JOB_KEY_PREFIX + this.elanName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.concurrent.Callable#call()
+ */
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ LOG.debug("Deleting l2gw device [{}] macs from other l2gw devices for elan [{}]",
+ this.l2GwDevice.getHwvtepNodeId(), this.elanName);
+ final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(this.elanName);
+
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(this.elanName);
+ List<ListenableFuture<Void>> futures = Lists.newArrayList();
+ for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+ if (!otherDevice.getHwvtepNodeId().equals(this.l2GwDevice.getHwvtepNodeId())
+ && !ElanL2GatewayUtils.areMLAGDevices(this.l2GwDevice, otherDevice)) {
+ final String hwvtepId = otherDevice.getHwvtepNodeId();
+ // never batch deletes
+ ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMacs(this.broker,
+ new NodeId(hwvtepId), logicalSwitchName, this.macAddresses);
+ Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ LOG.trace("Successful in initiating ucast_remote_macs deletion related to {} in {}",
+ logicalSwitchName, hwvtepId);
+ }
+
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error(String.format("Failed removing ucast_remote_macs related to %s in %s",
+ logicalSwitchName, hwvtepId), error);
+ }
+ });
+ // TODO: why to create a new arraylist for uninstallFuture?
+ futures.addAll(Lists.newArrayList(uninstallFuture));
+ }
+ }
+ return futures;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.l2gw.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+* Created by ekvsver on 4/15/2016.
+*/
+public class DisAssociateHwvtepFromElanJob implements Callable<List<ListenableFuture<Void>>> {
+ DataBroker broker;
+ L2GatewayDevice l2GatewayDevice;
+ ElanInstance elanInstance;
+ Devices l2Device;
+ Integer defaultVlan;
+ boolean isLastL2GwConnDeleted;
+
+ private static final Logger LOG = LoggerFactory.getLogger(DisAssociateHwvtepFromElanJob.class);
+
+ public DisAssociateHwvtepFromElanJob(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
+ Devices l2Device, Integer defaultVlan, boolean isLastL2GwConnDeleted) {
+ this.broker = broker;
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.elanInstance = elanInstance;
+ this.l2Device = l2Device;
+ this.defaultVlan = defaultVlan;
+ this.isLastL2GwConnDeleted = isLastL2GwConnDeleted;
+ LOG.info("created disassosiate l2gw connection job for {} {}", elanInstance.getElanInstanceName(),
+ l2GatewayDevice.getHwvtepNodeId());
+ }
+
+ public String getJobKey() {
+ return elanInstance.getElanInstanceName();
+ }
+
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ String elanName = elanInstance.getElanInstanceName();
+ String strHwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+ NodeId hwvtepNodeId = new NodeId(strHwvtepNodeId);
+ LOG.info("running disassosiate l2gw connection job for {} {}", elanName, strHwvtepNodeId);
+
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+
+ // Remove remote MACs and vlan mappings from physical port
+ // Once all above configurations are deleted, delete logical
+ // switch
+ LOG.info("delete vlan bindings for {} {}", elanName, strHwvtepNodeId);
+ futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
+
+ if (isLastL2GwConnDeleted) {
+ LOG.info("delete remote ucast macs {} {}", elanName, strHwvtepNodeId);
+ futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
+
+ LOG.info("delete mcast mac for {} {}", elanName, strHwvtepNodeId);
+ futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
+ l2GatewayDevice));
+
+ LOG.info("delete local ucast macs {} {}", elanName, strHwvtepNodeId);
+ futures.addAll(ElanL2GatewayUtils.deleteL2GwDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
+
+ LOG.info("scheduled delete logical switch {} {}", elanName, strHwvtepNodeId);
+ ElanL2GatewayUtils.scheduleDeleteLogicalSwitch(hwvtepNodeId,
+ ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName));
+ }
+
+ return futures;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.l2gw.jobs;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+public class HwvtepDeviceMcastMacUpdateJob implements Callable<List<ListenableFuture<Void>>> {
+ private static final Logger LOG = LoggerFactory.getLogger(HwvtepDeviceMcastMacUpdateJob.class);
+
+ String elanName;
+ L2GatewayDevice l2GatewayDevice;
+
+ public HwvtepDeviceMcastMacUpdateJob(String elanName, L2GatewayDevice l2GatewayDevice) {
+ this.l2GatewayDevice = l2GatewayDevice;
+ this.elanName = elanName;
+ }
+
+ public String getJobKey() {
+ return elanName;
+ }
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ LOG.info("running update mcast mac entry job for {} {}",
+ elanName, l2GatewayDevice.getHwvtepNodeId());
+ return Lists.newArrayList(
+ ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevice(elanName, l2GatewayDevice));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.l2gw.jobs;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * The Class LogicalSwitchAddedWorker.
+ */
+public class LogicalSwitchAddedJob implements Callable<List<ListenableFuture<Void>>> {
+ /** The logical switch name. */
+ private String logicalSwitchName;
+
+ /** The physical device. */
+ private Devices physicalDevice;
+
+ /** The l2 gateway device. */
+ private L2GatewayDevice elanL2GwDevice;
+
+ /** The default vlan id. */
+ private Integer defaultVlanId;
+
+ private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchAddedJob.class);
+
+ public LogicalSwitchAddedJob(String logicalSwitchName, Devices physicalDevice, L2GatewayDevice l2GatewayDevice,
+ Integer defaultVlanId) {
+ this.logicalSwitchName = logicalSwitchName;
+ this.physicalDevice = physicalDevice;
+ this.elanL2GwDevice = l2GatewayDevice;
+ this.defaultVlanId = defaultVlanId;
+ LOG.debug("created logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ }
+
+ public String getJobKey() {
+ return logicalSwitchName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.concurrent.Callable#call()
+ */
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ try {
+ LOG.debug("running logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
+
+ LOG.info("creating vlan bindings for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
+ new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
+ LOG.info("creating mast mac entries for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId());
+ futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
+
+ List<IpAddress> expectedPhyLocatorIps = Lists.newArrayList();
+ HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
+ logicalSwitchName, elanL2GwDevice, expectedPhyLocatorIps,
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ LOG.info("adding remote ucast macs for {} {}", logicalSwitchName,
+ elanL2GwDevice.getHwvtepNodeId());
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
+ logicalSwitchName, elanL2GwDevice));
+ return futures;
+ }
+ });
+
+ return futures;
+ } catch (Throwable e) {
+ LOG.error("failed to add ls ", e);
+ return null;
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.l2gw.jobs;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * The Class LogicalSwitchDeletedJob.
+ */
+public class LogicalSwitchDeletedJob implements Callable<List<ListenableFuture<Void>>> {
+ private DataBroker broker;
+
+ /** The logical switch name. */
+ private String logicalSwitchName;
+
+ /** The physical device. */
+ private NodeId hwvtepNodeId;
+
+ private static final Logger LOG = LoggerFactory.getLogger(LogicalSwitchDeletedJob.class);
+
+ public LogicalSwitchDeletedJob(DataBroker broker, NodeId hwvtepNodeId, String logicalSwitchName) {
+ this.broker = broker;
+ this.hwvtepNodeId = hwvtepNodeId;
+ this.logicalSwitchName = logicalSwitchName;
+ LOG.debug("created logical switch deleted job for {} on {}", logicalSwitchName, hwvtepNodeId);
+ }
+
+ public String getJobKey() {
+ return logicalSwitchName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.util.concurrent.Callable#call()
+ */
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ try {
+ LOG.debug("running logical switch deleted job for {} in {}", logicalSwitchName, hwvtepNodeId);
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(HwvtepUtils.deleteLogicalSwitch(broker, hwvtepNodeId, logicalSwitchName));
+ return futures;
+ } catch (Throwable e) {
+ LOG.error("failed to delete ls ", e);
+ return null;
+ }
+ }
+}
*/
package org.opendaylight.vpnservice.elan.l2gw.listeners;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
-import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
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.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.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
-import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
-import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
-import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.Lists;
+
/**
* A listener for Ucast MAC entries that are added/removed to/from an External Device (e.g., TOR).
*
AsyncClusteredDataChangeListenerBase<LocalUcastMacs, HwvtepLocalUcastMacListener> implements AutoCloseable {
private DataBroker broker;
- private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private ListenerRegistration<DataChangeListener> lstnerRegistration;
private static final Logger logger = LoggerFactory.getLogger(HwvtepLocalUcastMacListener.class);
- public HwvtepLocalUcastMacListener(DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ public HwvtepLocalUcastMacListener(DataBroker broker) {
super(LocalUcastMacs.class, HwvtepLocalUcastMacListener.class);
this.broker = broker;
- this.entityOwnershipService = entityOwnershipService;
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
registerListener();
}
// Remove MAC from cache
elanL2GwDevice.removeUcastLocalMac(macRemoved);
- ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
- elanL2GwDevice, macRemoved); }
+ ElanL2GatewayUtils.unInstallL2GwUcastMacFromElan(elan, elanL2GwDevice,
+ Lists.newArrayList(macRemoved.getMacEntryKey()));
+ }
@Override
protected void update(InstanceIdentifier<LocalUcastMacs> identifier, LocalUcastMacs original,
// Cache MAC for furthur processing later
elanL2GwDevice.addUcastLocalMac(macAdded);
- ElanL2GatewayUtils.installL2GwUcastMacInElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan,
- elanL2GwDevice, macAddress);
+ ElanL2GatewayUtils.installL2GwUcastMacInElan(elan, elanL2GwDevice, macAddress);
}
@Override
*/
package org.opendaylight.vpnservice.elan.l2gw.listeners;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
-import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.vpnservice.datastoreutils.AsyncDataChangeListenerBase;
import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayMulticastUtils;
-import org.opendaylight.vpnservice.elan.l2gw.utils.ElanL2GatewayUtils;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.LogicalSwitchAddedJob;
import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils;
-import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.vpnservice.utils.SystemPropertyReader;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+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.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.util.concurrent.ListenableFuture;
-
/**
* The listener class for listening to {@code LogicalSwitches}
* add/delete/update.
/** The default vlan id. */
private Integer defaultVlanId;
+ /** Id of L2 Gateway connection responsible for this logical switch creation */
+ private Uuid l2GwConnId;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
/**
* Instantiates a new hardware vtep logical switch listener.
*
* the physical device
* @param defaultVlanId
* the default vlan id
+ * @param l2GwConnId
+ * the l2 gateway connection id
*/
public HwvtepLogicalSwitchListener(L2GatewayDevice l2GatewayDevice, String logicalSwitchName,
- Devices physicalDevice, Integer defaultVlanId) {
+ Devices physicalDevice, Integer defaultVlanId, Uuid l2GwConnId) {
super(LogicalSwitches.class, HwvtepLogicalSwitchListener.class);
this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
this.logicalSwitchName = logicalSwitchName;
this.physicalDevice = physicalDevice;
this.l2GatewayDevice = l2GatewayDevice;
this.defaultVlanId = defaultVlanId;
+ this.l2GwConnId = l2GwConnId;
}
/*
LOG.debug("Received Add DataChange Notification for identifier: {}, LogicalSwitches: {}", identifier,
logicalSwitchNew);
try {
- L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice);
- DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
- LogicalSwitchAddedWorker logicalSwitchAddedWorker = new LogicalSwitchAddedWorker(nodeId, logicalSwitchNew);
- String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(),
- logicalSwitchNew.getHwvtepNodeName().getValue());
- jobCoordinator.enqueueJob(jobKey, logicalSwitchAddedWorker,
+ L2GatewayDevice elanDevice = L2GatewayConnectionUtils.addL2DeviceToElanL2GwCache(
+ logicalSwitchNew.getHwvtepNodeName().getValue(), l2GatewayDevice, l2GwConnId);
+
+ LogicalSwitchAddedJob logicalSwitchAddedWorker = new LogicalSwitchAddedJob(
+ logicalSwitchName, physicalDevice, elanDevice, defaultVlanId);
+ dataStoreJobCoordinator.enqueueJob(logicalSwitchAddedWorker.getJobKey(), logicalSwitchAddedWorker,
SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
} catch (Exception e) {
}
}
- /**
- * The Class LogicalSwitchAddedWorker.
- */
- private class LogicalSwitchAddedWorker implements Callable<List<ListenableFuture<Void>>> {
- /** The logical switch new. */
- LogicalSwitches logicalSwitchNew;
-
- /**
- * Instantiates a new logical switch added worker.
- *
- * @param nodeId
- * the node id
- * @param logicalSwitchNew
- * the logical switch new
- */
- public LogicalSwitchAddedWorker(NodeId nodeId, LogicalSwitches logicalSwitchNew) {
- this.logicalSwitchNew = logicalSwitchNew;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.util.concurrent.Callable#call()
- */
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- try {
- List<ListenableFuture<Void>> futures = new ArrayList<>();
- String elan = ElanL2GatewayUtils.getElanFromLogicalSwitch(logicalSwitchName);
- final L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils
- .getL2GatewayDeviceFromCache(elan, l2GatewayDevice.getHwvtepNodeId());
- if (elanL2GwDevice == null) {
- LOG.error("Could not find L2GatewayDevice for ELAN: {}, nodeID:{} from cache",
- l2GatewayDevice.getHwvtepNodeId());
- return null;
- } else {
- LOG.trace("got logical switch device {}", elanL2GwDevice);
- futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
- new NodeId(elanL2GwDevice.getHwvtepNodeId()), logicalSwitchName, physicalDevice, defaultVlanId));
- futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, elanL2GwDevice));
-
- HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
- logicalSwitchName, elanL2GwDevice,
- new Callable<List<ListenableFuture<Void>>>() {
-
- @Override
- public List<ListenableFuture<Void>> call() {
- List<ListenableFuture<Void>> futures = new ArrayList<>();
- futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
- logicalSwitchName, elanL2GwDevice));
- return futures;
- }}
- );
- return futures;
- }
- } catch (Throwable e) {
- LOG.error("failed to add ls ", e);
- return null;
- }
- }
-
- }
}
\ No newline at end of file
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.controller.md.sal.common.api.data.AsyncDataBroker;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
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.NodeKey;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger LOG = LoggerFactory.getLogger(HwvtepNodeListener.class);
private DataBroker dataBroker;
- private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private ItmRpcService itmRpcService;
ElanInstanceManager elanInstanceManager;
- public HwvtepNodeListener(final DataBroker dataBroker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
+ public HwvtepNodeListener(final DataBroker dataBroker, ElanInstanceManager elanInstanceManager,
ItmRpcService itmRpcService) {
super(Node.class, HwvtepNodeListener.class);
this.dataBroker = dataBroker;
- this.entityOwnershipService = entityOwnershipService;
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
this.itmRpcService = itmRpcService;
this.elanInstanceManager = elanInstanceManager;
}
@Override
protected void remove(InstanceIdentifier<Node> key, Node nodeDeleted) {
- LOG.debug("Received Node Remove Event: {}, {}", key, nodeDeleted.getNodeId().getValue());
+ String nodeId = nodeDeleted.getNodeId().getValue();
+ LOG.debug("Received Node Remove Event for {}", nodeId);
PhysicalSwitchAugmentation psAugmentation = nodeDeleted.getAugmentation(PhysicalSwitchAugmentation.class);
if (psAugmentation != null) {
String psName = psAugmentation.getHwvtepNodeName().getValue();
+ LOG.info("Physical switch {} removed from node {} event received", psName, nodeId);
+
L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
if (l2GwDevice != null) {
if (!L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
L2GatewayCacheUtils.removeL2DeviceFromCache(psName);
+ LOG.debug("{} details removed from L2Gateway Cache", psName);
+ } else {
+ LOG.debug("{} details are not removed from L2Gateway Cache as it has L2Gateway refrence", psName);
}
+
l2GwDevice.setConnected(false);
ElanL2GwCacheUtils.removeL2GatewayDeviceFromAllElanCache(psName);
} else {
LOG.error("Unable to find L2 Gateway details for {}", psName);
}
+ } else {
+ LOG.trace("Received Node Remove Event for {} is not related to Physical switch; it's not processed",
+ nodeId);
}
}
@Override
protected void update(InstanceIdentifier<Node> key, Node nodeBefore, Node nodeAfter) {
- LOG.debug("Received Node Update Event: {}, {}, {}", key, nodeBefore, nodeAfter);
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Received Node Update Event: Node Before: {}, Node After: {}", nodeBefore, nodeAfter);
+ }
}
@Override
protected void add(InstanceIdentifier<Node> key, Node nodeAdded) {
- LOG.debug("Received Node Add Event: {}, {}", key, nodeAdded.getNodeId().getValue());
+ String nodeId = nodeAdded.getNodeId().getValue();
+ LOG.debug("Received Node Add Event for {}", nodeId);
PhysicalSwitchAugmentation psAugmentation = nodeAdded.getAugmentation(PhysicalSwitchAugmentation.class);
if (psAugmentation != null) {
String psName = psAugmentation.getHwvtepNodeName().getValue();
+ LOG.info("Physical switch {} added to node {} event received", psName, nodeId);
+
L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
if (l2GwDevice == null) {
+ LOG.debug("{} details are not present in L2Gateway Cache; added now!", psName);
+
l2GwDevice = new L2GatewayDevice();
l2GwDevice.setDeviceName(psName);
L2GatewayCacheUtils.addL2DeviceToCache(psName, l2GwDevice);
+ } else {
+ LOG.debug("{} details are present in L2Gateway Cache and same reference used for updates", psName);
}
+ l2GwDevice.setConnected(true);
String hwvtepNodeId = getManagedByNodeId(psAugmentation.getManagedBy());
l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
List<TunnelIps> tunnelIps = psAugmentation.getTunnelIps();
IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
l2GwDevice.addTunnelIp(tunnelIpAddr);
if (L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
+ if (LOG.isDebugEnabled()) {
+ 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
ElanL2GatewayUtils.createItmTunnels(itmRpcService, hwvtepNodeId, psName, tunnelIpAddr);
List<L2gatewayConnection> l2GwConns = getAssociatedL2GwConnections(dataBroker,
l2GwDevice.getL2GatewayIds());
if (l2GwConns != null) {
+ LOG.debug("L2GatewayConnections associated for {} physical switch", psName);
+
for (L2gatewayConnection l2GwConn : l2GwConns) {
- L2GatewayConnectionUtils.addL2GatewayConnection(dataBroker, entityOwnershipService,
- bindingNormalizedNodeSerializer, elanInstanceManager, l2GwConn, psName);
+ 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
}
}
}
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("L2Gateway cache updated with below details: {}", l2GwDevice);
+ }
+ } else {
+ LOG.trace("Received Node Add Event for {} is not related to Physical switch; it's not processed", nodeId);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.l2gw.listeners;
+
+import com.google.common.collect.Lists;
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
+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.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.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * Listener for physical locator presence in operational datastore
+ *
+ *
+ *
+ */
+public class HwvtepPhysicalLocatorListener extends
+ AsyncClusteredDataChangeListenerBase<TerminationPoint, HwvtepPhysicalLocatorListener> implements AutoCloseable {
+
+ private DataBroker broker;
+ private ListenerRegistration<DataChangeListener> lstnerRegistration;
+
+ private static final Logger logger = LoggerFactory.getLogger(HwvtepPhysicalLocatorListener.class);
+
+ public HwvtepPhysicalLocatorListener(DataBroker broker) {
+ super(TerminationPoint.class, HwvtepPhysicalLocatorListener.class);
+
+ this.broker = broker;
+ registerListener();
+ logger.debug("created HwvtepPhysicalLocatorListener");
+ }
+
+ static Map<InstanceIdentifier<TerminationPoint>, List<Runnable>> waitingJobsList = new ConcurrentHashMap<>();
+ static Map<InstanceIdentifier<TerminationPoint>, Boolean> teps = new ConcurrentHashMap<>();
+
+ public static void runJobAfterPhysicalLocatorIsAvialable(InstanceIdentifier<TerminationPoint> key, Runnable runnable) {
+ if (teps.get(key) != null) {
+ logger.debug("physical locator already available {} running job ", key);
+ runnable.run();
+ return;
+ }
+ synchronized (HwvtepPhysicalLocatorListener.class) {
+ List<Runnable> list = waitingJobsList.get(key);
+ if (list == null) {
+ waitingJobsList.put(key, Lists.newArrayList(runnable));
+ } else {
+ list.add(runnable);
+ }
+ logger.debug("added the job to wait list of physical locator {}", key);
+ }
+ }
+
+ protected void registerListener() {
+ try {
+ lstnerRegistration = this.broker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+ InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+ child(TerminationPoint.class), this, DataChangeScope.BASE);
+ } catch (final Exception e) {
+ logger.error("Hwvtep LocalUcasMacs DataChange listener registration failed !", e);
+ throw new IllegalStateException("Hwvtep LocalUcasMacs DataChange listener registration failed .", e);
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (lstnerRegistration != null) {
+ try {
+ lstnerRegistration.close();
+ } catch (final Exception e) {
+ logger.error("Error when cleaning up DataChangeListener.", e);
+ }
+ lstnerRegistration = null;
+ }
+ }
+
+ @Override
+ protected void remove(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint del) {
+ logger.trace("physical locator removed {}", identifier);
+ teps.remove(identifier);
+ }
+
+ @Override
+ protected void update(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint original, TerminationPoint update) {
+ logger.trace("physical locator available {}", identifier);
+ }
+
+ @Override
+ protected void add(InstanceIdentifier<TerminationPoint> identifier, TerminationPoint add) {
+ logger.trace("physical locator available {}", identifier);
+ teps.put(identifier, true);
+ List<Runnable> runnableList = null;
+ synchronized (HwvtepPhysicalLocatorListener.class) {
+ runnableList = waitingJobsList.get(identifier);
+ waitingJobsList.remove(identifier);
+ }
+ if (runnableList != null) {
+ logger.debug("physical locator available {} running jobs ", identifier);
+ for (Runnable r : runnableList) {
+ r.run();
+ }
+ } else {
+ logger.debug("no jobs are waiting for physical locator {}", identifier);
+ }
+ }
+
+ @Override
+ protected InstanceIdentifier<TerminationPoint> getWildCardPath() {
+ return InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class).
+ child(TerminationPoint.class);
+ }
+
+ @Override
+ protected ClusteredDataChangeListener getDataChangeListener() {
+ return HwvtepPhysicalLocatorListener.this;
+ }
+
+ @Override
+ protected DataChangeScope getDataChangeScope() {
+ return DataChangeScope.BASE;
+ }
+}
*/
package org.opendaylight.vpnservice.elan.l2gw.listeners;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.vpnservice.utils.SystemPropertyReader;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
+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.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/** The node id. */
private NodeId nodeId;
+ private List<IpAddress> expectedPhyLocatorIps;
+
DataBroker broker;
String logicalSwitchName;
AtomicBoolean executeTask = new AtomicBoolean(true);
Callable<List<ListenableFuture<Void>>> taskToRun;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
/**
* Instantiates a new remote mcast mac listener.
*
* @param broker
* the mdsal databroker reference
* @param logicalSwitchName
+ * the logical switch name
* @param l2GatewayDevice
* the l2 gateway device
+ * @param expectedPhyLocatorIps
+ * the expected phy locator ips
* @param task
* the task to be run upon data presence
* @throws Exception
+ * the exception
*/
public HwvtepRemoteMcastMacListener(DataBroker broker, String logicalSwitchName, L2GatewayDevice l2GatewayDevice,
- Callable<List<ListenableFuture<Void>>> task) throws Exception {
+ List<IpAddress> expectedPhyLocatorIps, Callable<List<ListenableFuture<Void>>> task) throws Exception {
super(RemoteMcastMacs.class, HwvtepRemoteMcastMacListener.class);
this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
this.broker = broker;
this.taskToRun = task;
this.logicalSwitchName = logicalSwitchName;
- LOG.debug("registering the listener for mcast mac ");
+ this.expectedPhyLocatorIps = expectedPhyLocatorIps;
+ LOG.info("registering the listener for mcast mac ");
registerListener(LogicalDatastoreType.OPERATIONAL, broker);
+ LOG.info("registered the listener for mcast mac ");
if (isDataPresentInOpDs(getWildCardPath())) {
- LOG.debug("mcast mac already present running the task ");
+ LOG.info("mcast mac already present running the task ");
if (executeTask.compareAndSet(true, false)) {
runTask();
}
}
}
- private boolean isDataPresentInOpDs(InstanceIdentifier<? extends DataObject> path) throws Exception {
- Optional<? extends DataObject> mac = null;
+ private boolean isDataPresentInOpDs(InstanceIdentifier<RemoteMcastMacs> path) throws Exception {
+ Optional<RemoteMcastMacs> mac = null;
try {
mac = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, path);
} catch (Throwable e) {
if (mac == null || !mac.isPresent()) {
return false;
}
+ if (this.expectedPhyLocatorIps != null && !this.expectedPhyLocatorIps.isEmpty()) {
+ RemoteMcastMacs remoteMcastMac = mac.get();
+ if (remoteMcastMac.getLocatorSet() == null || remoteMcastMac.getLocatorSet().isEmpty()) {
+ return false;
+ }
+ for (IpAddress ip : this.expectedPhyLocatorIps) {
+ boolean ipExists = ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(this.nodeId,
+ remoteMcastMac, ip);
+ if (!ipExists) {
+ LOG.trace("IP [{}] not found in RemoteMcastMacs for node [{}]", String.valueOf(ip.getValue()),
+ this.nodeId.getValue());
+ return false;
+ }
+ }
+ }
return true;
}
*/
@Override
protected void add(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs mcastMac) {
- LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier,
- mcastMac);
+ LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier, mcastMac);
+ // No isDataPresentInOpDs check is done as assuming all the expected phy
+ // locator ips will be available during add
if (executeTask.compareAndSet(true, false)) {
runTask();
}
void runTask() {
try {
- DataStoreJobCoordinator jobCoordinator = DataStoreJobCoordinator.getInstance();
- String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), ElanConstants.UNKNOWN_DMAC);
- jobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+
+ String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), nodeId.getValue());
+ dataStoreJobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
} catch (Exception e) {
LOG.error("Failed to handle remote mcast mac - add: {}", e);
} finally {
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
import org.opendaylight.vpnservice.datastoreutils.AsyncClusteredDataChangeListenerBase;
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.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
private ListenerRegistration<DataChangeListener> listenerRegistration;
private final DataBroker broker;
- private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private ElanInstanceManager elanInstanceManager;
- public L2GatewayConnectionListener(final DataBroker db, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager) {
+ public L2GatewayConnectionListener(final DataBroker db, ElanInstanceManager elanInstanceManager) {
super(L2gatewayConnection.class, L2GatewayConnectionListener.class);
broker = db;
- this.entityOwnershipService = entityOwnershipService;
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
this.elanInstanceManager = elanInstanceManager;
registerListener(db);
}
@Override
protected void add(final InstanceIdentifier<L2gatewayConnection> identifier, final L2gatewayConnection input) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Adding L2gatewayConnection : key: " + identifier + ", value=" + input);
+ LOG.trace("Adding L2gatewayConnection: {}", input);
}
// Get associated L2GwId from 'input'
// Create logical switch in each of the L2GwDevices part of L2Gw
// Logical switch name is network UUID
// Add L2GwDevices to ELAN
- L2GatewayConnectionUtils.addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
- elanInstanceManager, input);
+ L2GatewayConnectionUtils.addL2GatewayConnection(input);
}
@Override
protected void remove(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection input) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Removing L2gatewayConnection : key: " + identifier + ", value=" + input);
+ LOG.trace("Removing L2gatewayConnection: {}", input);
}
- L2GatewayConnectionUtils.deleteL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer,
- elanInstanceManager, input);
+ L2GatewayConnectionUtils.deleteL2GatewayConnection(input);
}
@Override
protected void update(InstanceIdentifier<L2gatewayConnection> identifier, L2gatewayConnection original,
L2gatewayConnection update) {
if (LOG.isTraceEnabled()) {
- LOG.trace("Updating L2gatewayConnection : key: " + identifier + ", original value=" + original
- + ", update value=" + update);
+ LOG.trace("Updating L2gatewayConnection : original value={}, updated value={}", original, update);
}
}
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
import org.opendaylight.vpnservice.elan.internal.ElanInterfaceManager;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.HwvtepDeviceMcastMacUpdateJob;
import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSetBuilder;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.DesignatedSwitchesForExternalTunnels;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
-//import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev150129.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.DesignatedSwitchesForExternalTunnels;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.designated.switches._for.external.tunnels.DesignatedSwitchForTunnelKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
/** The elan interface manager. */
private static ElanInterfaceManager elanInterfaceManager;
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
/**
* Sets the broker.
*
* @return the listenable future
*/
public static ListenableFuture<Void> handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) {
- return updateMcastMacs(elanName, device, true/* updateThisDevice */);
+ return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */);
}
/**
SettableFuture<Void> future = SettableFuture.create();
future.set(null);
try {
- ConcurrentMap<String, L2GatewayDevice> mapL2gwDevices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
- if (mapL2gwDevices == null || mapL2gwDevices.isEmpty()) {
- LOG.trace("No L2GatewayDevices to configure RemoteMcastMac for elan {}", elanName);
- return future;
- }
- List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
-
- // TODO revisit
- L2GatewayDevice firstDevice = mapL2gwDevices.values().iterator().next();
- List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(firstDevice, dpns);
- List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(mapL2gwDevices);
-
WriteTransaction transaction = broker.newWriteOnlyTransaction();
- for (L2GatewayDevice device : mapL2gwDevices.values()) {
- updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+ for (L2GatewayDevice device : ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName).values()) {
+ prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
}
return transaction.submit();
} catch (Throwable e) {
return future;
}
+ public static void scheduleMcastMacUpdateJob(String elanName, L2GatewayDevice device) {
+ HwvtepDeviceMcastMacUpdateJob job = new HwvtepDeviceMcastMacUpdateJob(elanName,device);
+ dataStoreJobCoordinator.enqueueJob(job.getJobKey(), job);
+ }
+
/**
- * Update mcast macs.
+ * Update remote mcast mac on elan l2 gw device.
+ *
+ * @param elanName
+ * the elan name
+ * @param device
+ * the device
+ * @return the listenable future
+ */
+ public static ListenableFuture<Void> updateRemoteMcastMacOnElanL2GwDevice(String elanName, L2GatewayDevice device) {
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ prepareRemoteMcastMacUpdateOnDevice(transaction, elanName, device);
+ return transaction.submit();
+ }
+
+ public static void prepareRemoteMcastMacUpdateOnDevice(WriteTransaction transaction,String elanName,
+ L2GatewayDevice device) {
+ ConcurrentMap<String, L2GatewayDevice> elanL2gwDevices = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(elanName);
+ List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
+ List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
+ List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(elanL2gwDevices);
+ preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+ }
+
+ /**
+ * Update mcast macs for this elan.
+ * for all dpns in this elan recompute and update broadcast group
+ * for all l2gw devices in this elan recompute and update remote mcast mac entry
*
* @param elanName
* the elan name
* the update this device
* @return the listenable future
*/
- public static ListenableFuture<Void> updateMcastMacs(String elanName, L2GatewayDevice device,
- boolean updateThisDevice) {
+ public static ListenableFuture<Void> updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device,
+ boolean updateThisDevice) {
SettableFuture<Void> ft = SettableFuture.create();
ft.set(null);
ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName);
- elanInterfaceManager.updateElanBroadcastGroup(elanInstance);
+ elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance);
List<DpnInterfaces> dpns = ElanUtils.getInvolvedDpnsInElan(elanName);
ConcurrentMap<String, L2GatewayDevice> devices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
List<IpAddress> dpnsTepIps = getAllTepIpsOfDpns(device, dpns);
List<IpAddress> l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices);
WriteTransaction transaction = broker.newWriteOnlyTransaction();
if (updateThisDevice) {
- updateRemoteMcastMac(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
+ preapareRemoteMcastMacEntry(transaction, elanName, device, dpnsTepIps, l2GwDevicesTepIps);
}
// TODO: Need to revisit below logic as logical switches might not be
- // created to configure RemoteMcastMac entry
+ // present to configure RemoteMcastMac entry
for (L2GatewayDevice otherDevice : devices.values()) {
if (!otherDevice.getDeviceName().equals(device.getDeviceName())) {
- updateRemoteMcastMac(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
+ preapareRemoteMcastMacEntry(transaction, elanName, otherDevice, dpnsTepIps, l2GwDevicesTepIps);
}
}
return transaction.submit();
* the l2 gw devices tep ips
* @return the write transaction
*/
- private static WriteTransaction updateRemoteMcastMac(WriteTransaction transaction, String elanName,
- L2GatewayDevice device, List<IpAddress> dpnsTepIps, List<IpAddress> l2GwDevicesTepIps) {
+ private static void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName,
+ L2GatewayDevice device, List<IpAddress> dpnsTepIps,
+ List<IpAddress> l2GwDevicesTepIps) {
NodeId nodeId = new NodeId(device.getHwvtepNodeId());
String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName);
- ArrayList<IpAddress> otherTepIps = new ArrayList<>(l2GwDevicesTepIps);
- otherTepIps.remove(device.getTunnelIp());
-
- if (!dpnsTepIps.isEmpty()) {
- otherTepIps.addAll(dpnsTepIps);
- } else {
+ ArrayList<IpAddress> remoteTepIps = new ArrayList<>(l2GwDevicesTepIps);
+ remoteTepIps.remove(device.getTunnelIp());
+ remoteTepIps.addAll(dpnsTepIps);
+ if (dpnsTepIps.isEmpty()) {
// If no dpns in elan, configure dhcp designated switch Tep Ip as a
// physical locator in l2 gw device
IpAddress dhcpDesignatedSwitchTepIp = getTepIpOfDesignatedSwitchForExternalTunnel(device, elanName);
if (dhcpDesignatedSwitchTepIp != null) {
- otherTepIps.add(dhcpDesignatedSwitchTepIp);
+ remoteTepIps.add(dhcpDesignatedSwitchTepIp);
HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
.createHwvtepPhysicalLocatorAugmentation(String.valueOf(dhcpDesignatedSwitchTepIp.getValue()));
}
}
- putRemoteMcastMac(transaction, nodeId, logicalSwitchName, otherTepIps);
+ putRemoteMcastMac(transaction, nodeId, logicalSwitchName, remoteTepIps);
LOG.info("Adding RemoteMcastMac for node: {} with physical locators: {}", device.getHwvtepNodeId(),
- otherTepIps);
- return transaction;
+ remoteTepIps);
}
/**
/**
* Gets all the tep ips of dpns.
*
- * @param device
+ * @param l2GwDevice
* the device
* @param dpns
* the dpns
- * @param devices
- * the devices
* @return the all tep ips of dpns and devices
*/
private static List<IpAddress> getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List<DpnInterfaces> dpns) {
*/
public static List<ListenableFuture<Void>> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance,
L2GatewayDevice l2GatewayDevice) {
- ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacs(elanInstance.getElanInstanceName(),
+ ListenableFuture<Void> updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(),
l2GatewayDevice, false/* updateThisDevice */);
ListenableFuture<Void> deleteRemoteMcastMacFuture = deleteRemoteMcastMac(
new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName());
public static IpAddress getTepIpOfDesignatedSwitchForExternalTunnel(L2GatewayDevice l2GwDevice,
String elanInstanceName) {
IpAddress tepIp = null;
- // TODO: Uncomment after DHCP changes are merged
-/* DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
+ DesignatedSwitchForTunnel desgSwitch = getDesignatedSwitchForExternalTunnel(l2GwDevice.getTunnelIp(),
elanInstanceName);
if (desgSwitch != null) {
tepIp = ElanL2GatewayUtils.getSourceDpnTepIp(BigInteger.valueOf(desgSwitch.getDpId()),
new NodeId(l2GwDevice.getHwvtepNodeId()));
- }*/
+ }
return tepIp;
}
* the elan instance name
* @return the designated switch for external tunnel
*/
- // TODO: Uncomment after DHCP changes are merged
-/* public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
+ public static DesignatedSwitchForTunnel getDesignatedSwitchForExternalTunnel(IpAddress tunnelIp,
String elanInstanceName) {
InstanceIdentifier<DesignatedSwitchForTunnel> instanceIdentifier = InstanceIdentifier
.builder(DesignatedSwitchesForExternalTunnels.class)
return designatedSwitchForTunnelOptional.get();
}
return null;
- }*/
+ }
}
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.elanmanager.utils.ElanL2GwCacheUtils;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.DeleteL2GwDeviceMacsFromElanJob;
import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.LogicalSwitchDeletedJob;
+import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepPhysicalLocatorListener;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanConstants;
import org.opendaylight.vpnservice.elan.utils.ElanUtils;
import org.opendaylight.vpnservice.interfacemgr.IfmUtil;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.vpnservice.utils.SystemPropertyReader;
-import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepLogicalSwitchRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepNodeName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorRef;
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.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteUcastMacs;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.locator.set.attributes.LocatorSet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan._interface.forwarding.entries.ElanInterfaceMac;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.dpn.interfaces.elan.dpn.interfaces.list.DpnInterfaces;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.forwarding.entries.MacEntry;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.AddL2GwDeviceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
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.binding.data.codec.api.BindingNormalizedNodeSerializer;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.commons.lang3.tuple.ImmutablePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.SettableFuture;
/**
* It gathers a set of utility methods that handle ELAN configuration in external Devices (where external means
*
*/
public class ElanL2GatewayUtils {
-
- private static DataBroker broker;
- private static ItmRpcService itmRpcService;
+ private static DataBroker broker;
+ private static ItmRpcService itmRpcService;
+ private static DataStoreJobCoordinator dataStoreJobCoordinator;
+ private static Timer LogicalSwitchDeleteJobTimer = new Timer();
+ private static final int LOGICAL_SWITCH_DELETE_DELAY = 120000;
+ private static ConcurrentMap<Pair<NodeId, String>, TimerTask> LogicalSwitchDeletedTasks =
+ new ConcurrentHashMap<Pair<NodeId, String>, TimerTask>();
private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class);
}
/**
- * Installs the given MAC as a remote mac in all external devices (as of
- * now, TORs) that participate in the given Elan.
+ * Sets DataStoreJobCoordinator
*
- * @param elanInstance
- * Elan to which the interface belongs to
- * @param dpId
- * Id of the DPN where the macs are located. Needed for selecting
- * the right tunnel
- * @param macAddresses
- * the mac addresses
+ * @param dsJobCoordinator
+ * the new dataStoreJobCoordinator
*/
- public static void installMacsInElanExternalDevices(ElanInstance elanInstance, BigInteger dpId,
- List<PhysAddress> macAddresses) {
- String logicalSwitchName = getElanFromLogicalSwitch(elanInstance.getElanInstanceName());
- ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
- for (L2GatewayDevice externalDevice : elanDevices.values()) {
- NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
- IpAddress dpnTepIp = getSourceDpnTepIp(dpId, nodeId);
- LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
- if (dpnTepIp == null) {
- LOG.error("TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
- continue;
- }
- installMacsInExternalDeviceAsRemoteUcastMacs(externalDevice.getHwvtepNodeId(), macAddresses,
- logicalSwitchName, dpnTepIp);
- }
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator dsJobCoordinator) {
+ dataStoreJobCoordinator = dsJobCoordinator;
}
/**
- * Installs a list of Mac Addresses as remote Ucast address in an external
- * device using the hwvtep-southbound.
- *
- * @param deviceNodeId
- * NodeId if the ExternalDevice where the macs must be installed
- * in.
- * @param macAddresses
- * List of Mac addresses to be installed in the external device.
- * @param logicalSwitchName
- * the logical switch name
- * @param remoteVtepIp
- * VTEP's IP in this CSS used for the tunnel with external
- * device.
- */
- private static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String deviceNodeId,
- List<PhysAddress> macAddresses, String logicalSwitchName, IpAddress remoteVtepIp) {
- NodeId nodeId = new NodeId(deviceNodeId);
- HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
- .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue()));
- List<RemoteUcastMacs> macs = new ArrayList<RemoteUcastMacs>();
- for (PhysAddress mac : macAddresses) {
- // TODO: Query ARP cache to get IP address corresponding to
- // the MAC
- IpAddress ipAddress = null;
- macs.add(HwvtepSouthboundUtils.createRemoteUcastMac(nodeId, mac.getValue(), ipAddress, logicalSwitchName,
- phyLocatorAug));
- }
- return HwvtepUtils.addRemoteUcastMacs(broker, nodeId, macs);
- }
-
- /**
- * Install macs in external device as remote ucast macs.
- *
+ * Installs dpn macs in external device.
+ * first it checks if the physical locator towards this dpn tep is present or not
+ * if the physical locator is present go ahead and add the ucast macs
+ * otherwise update the mcast mac entry to include this dpn tep ip
+ * and schedule the job to put ucast macs once the physical locator is programmed in device
* @param elanName
* the elan name
* @param lstElanInterfaceNames
* the dpn id
* @param externalNodeId
* the external node id
- * @return the listenable future
*/
- public static ListenableFuture<Void> installMacsInExternalDeviceAsRemoteUcastMacs(String elanName,
- Set<String> lstElanInterfaceNames, BigInteger dpnId, NodeId externalNodeId) {
- SettableFuture<Void> future = SettableFuture.create();
- future.set(null);
- if (lstElanInterfaceNames == null || lstElanInterfaceNames.isEmpty()) {
- return future;
+ public static void installDpnMacsInL2gwDevice(String elanName, Set<String> lstElanInterfaceNames,
+ BigInteger dpnId, NodeId externalNodeId) {
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+ externalNodeId.getValue());
+ if (elanL2GwDevice == null) {
+ LOG.debug("L2 gw device not found in elan cache for device name {}", externalNodeId);
+ return;
}
-
IpAddress dpnTepIp = getSourceDpnTepIp(dpnId, externalNodeId);
if (dpnTepIp == null) {
- return future;
+ LOG.warn("Could not install dpn macs in l2gw device , dpnTepIp not found dpn : {} , nodeid : {}",
+ dpnId, externalNodeId);
+ return;
}
- WriteTransaction transaction = broker.newWriteOnlyTransaction();
- HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepUtils.getPhysicalLocator(broker,
- LogicalDatastoreType.CONFIGURATION, externalNodeId, dpnTepIp);
- if (phyLocatorAug == null) {
- phyLocatorAug = HwvtepSouthboundUtils
- .createHwvtepPhysicalLocatorAugmentation(String.valueOf(dpnTepIp.getValue()));
- HwvtepUtils.putPhysicalLocator(transaction, externalNodeId, phyLocatorAug);
+ String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+ RemoteMcastMacs remoteMcastMac = readRemoteMcastMac(externalNodeId, logicalSwitchName,
+ LogicalDatastoreType.OPERATIONAL);
+ boolean phyLocAlreadyExists = checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(externalNodeId, remoteMcastMac,
+ dpnTepIp);
+ LOG.debug("phyLocAlreadyExists = {} for locator [{}] in remote mcast entry for elan [{}], nodeId [{}]",
+ phyLocAlreadyExists, String.valueOf(dpnTepIp.getValue()), elanName, externalNodeId.getValue());
+ List<PhysAddress> staticMacs = null;
+ staticMacs = getElanDpnMacsFromInterfaces(lstElanInterfaceNames);
+
+ if (phyLocAlreadyExists) {
+ scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+ return;
}
+ ElanL2GatewayMulticastUtils.scheduleMcastMacUpdateJob(elanName, elanL2GwDevice);
+ scheduleAddDpnMacsInExtDevice(elanName, dpnId, staticMacs, elanL2GwDevice);
+ }
- String logicalSwitchName = getLogicalSwitchFromElan(elanName);
+ /**
+ * gets the macs addresses for elan interfaces
+ *
+ * @param lstElanInterfaceNames
+ * the lst elan interface names
+ * @return the list
+ */
+ private static List<PhysAddress> getElanDpnMacsFromInterfaces(Set<String> lstElanInterfaceNames) {
+ List<PhysAddress> result = new ArrayList<>();
for (String interfaceName : lstElanInterfaceNames) {
ElanInterfaceMac elanInterfaceMac = ElanUtils.getElanInterfaceMacByInterfaceName(interfaceName);
if (elanInterfaceMac != null && elanInterfaceMac.getMacEntry() != null) {
for (MacEntry macEntry : elanInterfaceMac.getMacEntry()) {
- // TODO: Query ARP cache to get IP address corresponding to
- // the MAC
- IpAddress ipAddress = null;
- RemoteUcastMacs mac = HwvtepSouthboundUtils.createRemoteUcastMac(externalNodeId,
- macEntry.getMacAddress().getValue(), ipAddress, logicalSwitchName, phyLocatorAug);
- HwvtepUtils.putRemoteUcastMac(transaction, externalNodeId, mac);
+ result.add(macEntry.getMacAddress());
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Check if phy locator already exists in remote mcast entry.
+ *
+ * @param nodeId
+ * the node id
+ * @param remoteMcastMac
+ * the remote mcast mac
+ * @param expectedPhyLocatorIp
+ * the expected phy locator ip
+ * @return true, if successful
+ */
+ public static boolean checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(NodeId nodeId,
+ RemoteMcastMacs remoteMcastMac, IpAddress expectedPhyLocatorIp) {
+ if (remoteMcastMac != null) {
+ HwvtepPhysicalLocatorAugmentation expectedPhyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(expectedPhyLocatorIp.getValue()));
+ HwvtepPhysicalLocatorRef expectedPhyLocRef = new HwvtepPhysicalLocatorRef(
+ HwvtepSouthboundUtils.createPhysicalLocatorInstanceIdentifier(nodeId, expectedPhyLocatorAug));
+ if (remoteMcastMac.getLocatorSet() != null) {
+ for (LocatorSet locatorSet : remoteMcastMac.getLocatorSet()) {
+ if (locatorSet.getLocatorRef().equals(expectedPhyLocRef)) {
+ LOG.trace("matched phyLocRef: {}", expectedPhyLocRef);
+ return true;
+ }
}
}
}
- LOG.debug("Installing macs in external device [{}] for dpn [{}], elan [{}], no of interfaces [{}]",
- externalNodeId.getValue(), dpnId, elanName, lstElanInterfaceNames.size());
- return transaction.submit();
+ return false;
+ }
+
+ /**
+ * Gets the remote mcast mac.
+ *
+ * @param nodeId
+ * the node id
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param datastoreType
+ * the datastore type
+ * @return the remote mcast mac
+ */
+ public static RemoteMcastMacs readRemoteMcastMac(NodeId nodeId, String logicalSwitchName,
+ LogicalDatastoreType datastoreType) {
+ InstanceIdentifier<LogicalSwitches> logicalSwitch = HwvtepSouthboundUtils
+ .createLogicalSwitchesInstanceIdentifier(nodeId, new HwvtepNodeName(logicalSwitchName));
+ RemoteMcastMacsKey remoteMcastMacsKey = new RemoteMcastMacsKey(new HwvtepLogicalSwitchRef(logicalSwitch),
+ new MacAddress(ElanConstants.UNKNOWN_DMAC));
+ RemoteMcastMacs remoteMcastMac = HwvtepUtils.getRemoteMcastMac(broker, datastoreType, nodeId,
+ remoteMcastMacsKey);
+ return remoteMcastMac;
}
/**
*/
public static void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List<PhysAddress> macAddresses) {
ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName());
+ .getInvolvedL2GwDevices(elanInstance.getElanInstanceName());
for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) {
removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(),
elanInstance.getElanInstanceName(), macAddresses);
* @param elan
* the elan
*/
- public static void installL2gwDeviceLocalMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
- String elanName = elan.getElanInstanceName();
- L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName,
+ public static void installL2gwDeviceMacsInDpn(BigInteger dpnId, NodeId l2gwDeviceNodeId, ElanInstance elan) {
+ L2GatewayDevice l2gwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elan.getElanInstanceName(),
l2gwDeviceNodeId.getValue());
if (l2gwDevice == null) {
LOG.debug("L2 gw device not found in elan cache for device name {}", l2gwDeviceNodeId.getValue());
return;
}
+ installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+ }
+
+ /**
+ * Install dmac flows on dpn.
+ *
+ * @param dpnId
+ * the dpn id
+ * @param l2gwDevice
+ * the l2gw device
+ * @param elan
+ * the elan
+ */
+ public static void installDmacFlowsOnDpn(BigInteger dpnId, L2GatewayDevice l2gwDevice, ElanInstance elan) {
+ String elanName = elan.getElanInstanceName();
+
List<LocalUcastMacs> l2gwDeviceLocalMacs = l2gwDevice.getUcastLocalMacs();
if (l2gwDeviceLocalMacs != null && !l2gwDeviceLocalMacs.isEmpty()) {
for (LocalUcastMacs localUcastMac : l2gwDeviceLocalMacs) {
- ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDeviceNodeId.getValue(), elan.getElanTag(),
+ //TODO batch these ops
+ ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, l2gwDevice.getHwvtepNodeId(), elan.getElanTag(),
elan.getVni(), localUcastMac.getMacEntryKey().getValue(), elanName);
}
+ LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
+ l2gwDevice.getHwvtepNodeId(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
}
- LOG.debug("Installing L2gw device [{}] local macs [size: {}] in dpn [{}] for elan [{}]",
- l2gwDeviceNodeId.getValue(), l2gwDeviceLocalMacs.size(), dpnId, elanName);
}
- public static void installL2GwUcastMacInElan(EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
- L2GatewayDevice extL2GwDevice, final String macToBeAdded) {
+ /**
+ * Install elan l2gw devices local macs in dpn.
+ *
+ * @param dpnId
+ * the dpn id
+ * @param elan
+ * the elan
+ */
+ public static void installElanL2gwDevicesLocalMacsInDpn(BigInteger dpnId, ElanInstance elan) {
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(elan.getElanInstanceName());
+ if (elanL2GwDevicesFromCache != null) {
+ for (L2GatewayDevice l2gwDevice : elanL2GwDevicesFromCache.values()) {
+ installDmacFlowsOnDpn(dpnId, l2gwDevice, elan);
+ }
+ } else {
+ LOG.debug("No Elan l2 gateway devices in cache for [{}] ", elan.getElanInstanceName());
+ }
+ }
+
+ public static void installL2GwUcastMacInElan(final ElanInstance elan,
+ final L2GatewayDevice extL2GwDevice, final String macToBeAdded) {
final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
final String elanInstanceName = elan.getElanInstanceName();
// 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<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
- for (DpnInterfaces elanDpn : elanDpns) {
- final BigInteger dpnId = elanDpn.getDpId();
- final String nodeId = getNodeIdFromDpnId(dpnId);
-
- ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
- Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("Installing DMAC flows in {} connected to cluster node owner", dpnId.toString());
-
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- return ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId,
- elan.getElanTag(), elan.getVni(), macToBeAdded, elanInstanceName);
+ final List<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
+ if (elanDpns != null && elanDpns.size() > 0) {
+ String jobKey = elan.getElanInstanceName() + ":" + macToBeAdded;
+ ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+ "install l2gw mcas in dmac table",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ List<ListenableFuture<Void>> fts = Lists.newArrayList();
+ for (DpnInterfaces elanDpn : elanDpns) {
+ //TODO batch the below call
+ fts.addAll(ElanUtils.installDmacFlowsToExternalRemoteMac(elanDpn.getDpId(),
+ extDeviceNodeId, elan.getElanTag(), elan.getVni(), macToBeAdded,
+ elanInstanceName));
}
- }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
- } else {
- LOG.info("Install DMAC flows is not executed on the cluster node as this is not owner " +
- "for the DPN {}", dpnId.toString());
- }
- }
-
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to install DMAC flows", error);
- }
- });
+ return fts;
+ }
+ });
}
-
final IpAddress extL2GwDeviceTepIp = extL2GwDevice.getTunnelIp();
final List<PhysAddress> macList = new ArrayList<PhysAddress>();
macList.add(new PhysAddress(macToBeAdded));
- ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
- ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
- for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
- if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
- final String hwvtepId = otherDevice.getHwvtepNodeId();
- InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
- ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
- Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ String jobKey = "hwvtep:"+elan.getElanInstanceName() + ":" + macToBeAdded;
+ ElanClusterUtils.runOnlyInLeaderNode(jobKey,
+ "install remote ucast macs in l2gw device",
+ new Callable<List<ListenableFuture<Void>>>() {
@Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("Adding DMAC entry in {} connected to cluster node owner", hwvtepId);
+ public List<ListenableFuture<Void>> call() throws Exception {
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
+ ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInstanceName);
+
+ List<ListenableFuture<Void>> fts = Lists.newArrayList();
+ for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
+ if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId)
+ && !areMLAGDevices(extL2GwDevice, otherDevice)) {
+ final String hwvtepId = otherDevice.getHwvtepNodeId();
+ InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(
+ new NodeId(hwvtepId));
+ final String logicalSwitchName = elanInstanceName;
+
+ ListenableFuture<Void> ft = HwvtepUtils.installUcastMacs(
+ broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
+ //TODO batch the above call
+ Futures.addCallback(ft, new FutureCallback<Void>() {
+ @Override
+ public void onSuccess(Void noarg) {
+ LOG.trace("Successful in initiating ucast_remote_macs addition" +
+ "related to {} in {}", logicalSwitchName, hwvtepId);
+ }
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
- ListenableFuture<Void> installFuture = installMacsInExternalDeviceAsRemoteUcastMacs(
- hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp);
-
- Futures.addCallback(installFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void noarg) {
- if (LOG.isTraceEnabled()) {
- LOG.trace("Successful in initiating ucast_remote_macs addition" +
- "related to {} in {}", logicalSwitchName, hwvtepId);
- }
- }
-
- @Override
- public void onFailure(Throwable error) {
- LOG.error(String.format("Failed adding ucast_remote_macs related to " +
- "%s in %s", logicalSwitchName, hwvtepId), error);
- }
- });
-
- return Lists.newArrayList(installFuture);
- }
- }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
- } else {
- LOG.info("DMAC entry addition is not executed on the cluster node as this is not owner for " +
- "the Hwvtep {}", hwvtepId);
+ @Override
+ public void onFailure(Throwable error) {
+ LOG.error(String.format("Failed adding ucast_remote_macs related to " +
+ "%s in %s", logicalSwitchName, hwvtepId), error);
+ };
+ });
+ fts.add(ft);
+ }
}
- }
+ return fts;
+ }});
+ }
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to install DMAC entry", error);
- }
- });
+ /**
+ * Un install l2 gw ucast mac from elan.
+ *
+ * @param elan
+ * the elan
+ * @param l2GwDevice
+ * the l2 gw device
+ * @param macAddresses
+ * the mac addresses
+ */
+ public static void unInstallL2GwUcastMacFromElan(final ElanInstance elan, final L2GatewayDevice l2GwDevice,
+ final List<MacAddress> macAddresses) {
+ if (macAddresses == null || macAddresses.isEmpty()) {
+ return;
+ }
+ final String elanName = elan.getElanInstanceName();
+
+ // 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(jobKey, "delete l2gw macs from dmac table",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> fts = Lists.newArrayList();
+ for (DpnInterfaces elanDpn : elanDpns) {
+ BigInteger dpnId = elanDpn.getDpId();
+ // never batch deletes
+ fts.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
+ l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+ }
+ return fts;
+ }
+ });
}
}
- }
- public static void unInstallL2GwUcastMacFromElan(EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elan,
- L2GatewayDevice extL2GwDevice, final LocalUcastMacs macToBeRemoved) {
- final String extDeviceNodeId = extL2GwDevice.getHwvtepNodeId();
- final String elanInstanceName = elan.getElanInstanceName();
+ DeleteL2GwDeviceMacsFromElanJob job = new DeleteL2GwDeviceMacsFromElanJob(broker, elanName, l2GwDevice,
+ macAddresses);
+ ElanClusterUtils.runOnlyInLeaderNode(job.getJobKey(), "delete remote ucast macs in l2gw devices", job);
+ }
- // 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<DpnInterfaces> elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName);
- for (DpnInterfaces elanDpn : elanDpns) {
- final BigInteger dpnId = elanDpn.getDpId();
- final String nodeId = getNodeIdFromDpnId(dpnId);
-
- ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId);
- Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("Uninstalling DMAC flows from {} connected to cluster node owner",
- dpnId.toString());
+ /**
+ * Delete elan l2 gateway devices ucast local macs from dpn.
+ *
+ * @param elanName
+ * the elan name
+ * @param dpnId
+ * the dpn id
+ */
+ public static void deleteElanL2GwDevicesUcastLocalMacsFromDpn(final String elanName, final BigInteger dpnId) {
+ ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanName);
+ if (elanL2GwDevices == null || elanL2GwDevices.isEmpty()) {
+ LOG.trace("No L2 gateway devices in Elan [{}] cache.", elanName);
+ return;
+ }
+ final ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
+ if (elan == null) {
+ LOG.error("Could not find Elan by name: {}", elanName);
+ return;
+ }
+ LOG.info("Deleting Elan [{}] L2GatewayDevices UcastLocalMacs from Dpn [{}]", elanName, dpnId);
+
+ final Long elanTag = elan.getElanTag();
+ for (final L2GatewayDevice l2GwDevice : elanL2GwDevices.values()) {
+ List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GwDevice);
+ if (localMacs != null && !localMacs.isEmpty()) {
+ for (final MacAddress mac : localMacs) {
+ String jobKey = elanName + ":" + mac.getValue();
+ ElanClusterUtils.runOnlyInLeaderNode(jobKey, "delete l2gw macs from dmac table",
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() {
+ List<ListenableFuture<Void>> futures = Lists.newArrayList();
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- dataStoreCoordinator.enqueueJob(nodeId, new Callable<List<ListenableFuture<Void>>>() {
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- return ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), dpnId,
- extDeviceNodeId, macToBeRemoved.getMacEntryKey().getValue());
- }
- }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
- } else {
- LOG.info("Uninstall DMAC flows is not executed on the cluster node as this is not owner " +
- "for the DPN {}", dpnId.toString());
- }
+ futures.addAll(ElanUtils.deleteDmacFlowsToExternalMac(elanTag, dpnId,
+ l2GwDevice.getHwvtepNodeId(), mac.getValue()));
+ return futures;
+ }
+ });
}
+ }
+ }
+ }
+ /**
+ * Gets the l2 gw device local macs.
+ *
+ * @param l2gwDevice
+ * the l2gw device
+ * @return the l2 gw device local macs
+ */
+ public static List<MacAddress> getL2GwDeviceLocalMacs(L2GatewayDevice l2gwDevice) {
+ List<MacAddress> macs = new ArrayList<>();
+ if (l2gwDevice == null) {
+ return macs;
+ }
+ List<LocalUcastMacs> lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs();
+ if (lstUcastLocalMacs != null && !lstUcastLocalMacs.isEmpty()) {
+ macs = Lists.transform(lstUcastLocalMacs, new Function<LocalUcastMacs, MacAddress>() {
@Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to uninstall DMAC flows", error);
+ public MacAddress apply(LocalUcastMacs localUcastMac) {
+ return (localUcastMac != null) ? localUcastMac.getMacEntryKey() : null;
}
});
}
-
- ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices =
- ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName);
- for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
- if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) {
- final String hwvtepId = otherDevice.getHwvtepNodeId();
- final NodeId hwvtepNodeId = new NodeId(hwvtepId);
- InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(hwvtepNodeId);
- ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
- Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("Removing DMAC entry from {} connected to cluster node owner", hwvtepId);
-
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- dataStoreCoordinator.enqueueJob(hwvtepId, new Callable<List<ListenableFuture<Void>>>() {
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName);
- ListenableFuture<Void> uninstallFuture = HwvtepUtils.deleteRemoteUcastMac(broker,
- hwvtepNodeId, logicalSwitchName, macToBeRemoved.getMacEntryKey());
-
- Futures.addCallback(uninstallFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void noarg) {
- if (LOG.isTraceEnabled()) {
- LOG.trace("Successful in initiating ucast_remote_macs deletion " +
- "related to {} in {}", logicalSwitchName, hwvtepId);
- }
- }
-
- @Override
- public void onFailure(Throwable error) {
- LOG.error(String.format("Failed removing ucast_remote_macs related " +
- "to %s in %s", logicalSwitchName, hwvtepId), error);
- }
- });
-
- return Lists.newArrayList(uninstallFuture);
- }
- }, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
- } else {
- LOG.info("DMAC entry removal is not executed on the cluster node as this is not owner for " +
- "the Hwvtep {}", hwvtepId);
- }
- }
-
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to uninstall DMAC entry", error);
- }
- });
- }
- }
+ return macs;
}
/**
List<MacAddress> lstL2GatewayDeviceMacs = new ArrayList<>();
ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
if (elanL2GwDevicesFromCache != null) {
for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
if (!otherDevice.getHwvtepNodeId().equals(l2GwDeviceToBeExcluded.getHwvtepNodeId())) {
String logicalSwitchName = getLogicalSwitchFromElan(elanName);
NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
- List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(elanName,
+ List<RemoteUcastMacs> lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName,
l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
- List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesAsRemoteUcastMacs(elanName,
+ List<RemoteUcastMacs> lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName,
l2GatewayDevice, hwVtepNodeId, logicalSwitchName);
List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs);
* the logical switch name
* @return the l2 gateway devices macs as remote ucast macs
*/
- public static List<RemoteUcastMacs> getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(String elanName,
- L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+ public static List<RemoteUcastMacs> getOtherDevicesMacs(String elanName,
+ L2GatewayDevice l2GatewayDeviceToBeConfigured,
+ NodeId hwVtepNodeId, String logicalSwitchName) {
List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
ConcurrentMap<String, L2GatewayDevice> elanL2GwDevicesFromCache = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
+ .getInvolvedL2GwDevices(elanName);
if (elanL2GwDevicesFromCache != null) {
for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) {
* the logical switch name
* @return the elan mac table entries as remote ucast macs
*/
- public static List<RemoteUcastMacs> getElanMacTableEntriesAsRemoteUcastMacs(String elanName,
- L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) {
+ public static List<RemoteUcastMacs> getElanMacTableEntriesMacs(String elanName,
+ L2GatewayDevice l2GatewayDeviceToBeConfigured,
+ NodeId hwVtepNodeId, String logicalSwitchName) {
List<RemoteUcastMacs> lstRemoteUcastMacs = new ArrayList<RemoteUcastMacs>();
MacTable macTable = ElanUtils.getElanMacTable(elanName);
* @return the external tunnel interface name
*/
public static String getExternalTunnelInterfaceName(String sourceNode, String dstNode) {
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
String tunnelInterfaceName = null;
try {
Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output = itmRpcService
.getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
- .setSourceNode(sourceNode).setDestinationNode(dstNode).build());
+ .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build());
RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = output.get();
if (rpcResult.isSuccessful()) {
* @return the l2 gateway connection job key
*/
public static String getL2GatewayConnectionJobKey(String nodeId, String logicalSwitchName) {
- return new StringBuilder(nodeId).append(logicalSwitchName).toString();
+ return logicalSwitchName;
}
public static InstanceIdentifier<Interface> getInterfaceIdentifier(InterfaceKey interfaceKey) {
* the elan name
* @return the listenable future
*/
- public static List<ListenableFuture<Void>> deleteL2GatewayDeviceUcastLocalMacsFromElan(
- L2GatewayDevice l2GatewayDevice, String elanName) {
- List<ListenableFuture<Void>> futures = new ArrayList<>();
+ public static List<ListenableFuture<Void>> deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice,
+ String elanName) {
+ LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(), elanName);
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
ElanInstance elan = ElanUtils.getElanInstanceByName(elanName);
if (elan == null) {
LOG.error("Could not find Elan by name: {}", elanName);
return futures;
}
- List<LocalUcastMacs> lstLocalUcastMacs = l2GatewayDevice.getUcastLocalMacs();
- if (lstLocalUcastMacs != null) {
- for (LocalUcastMacs localUcastMac : lstLocalUcastMacs) {
- List<DpnInterfaces> dpnInterfaces = ElanUtils.getInvolvedDpnsInElan(elanName);
- if (dpnInterfaces != null) {
- // TODO: Need to check if it can be optimized
- for (DpnInterfaces elanDpn : dpnInterfaces) {
- ElanUtils.deleteDmacFlowsToExternalMac(elan.getElanTag(), elanDpn.getDpId(),
- l2GatewayDevice.getHwvtepNodeId(), localUcastMac.getMacEntryKey().getValue());
- }
- }
- }
-
- List<MacAddress> lstMac = Lists.transform(lstLocalUcastMacs, new Function<LocalUcastMacs, MacAddress>() {
- @Override
- public MacAddress apply(LocalUcastMacs mac) {
- return (mac != null) ? mac.getMacEntryKey() : null;
- }
- });
-
- ConcurrentMap<String, L2GatewayDevice> elanL2GwDevices = ElanL2GwCacheUtils
- .getAllElanL2GatewayDevicesFromCache(elanName);
- for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) {
- if (!otherDevice.getHwvtepNodeId().equals(l2GatewayDevice.getHwvtepNodeId())) {
- futures.add(HwvtepUtils.deleteRemoteUcastMacs(broker, new NodeId(otherDevice.getHwvtepNodeId()),
- elanName, lstMac));
- }
- }
- }
+ List<MacAddress> localMacs = getL2GwDeviceLocalMacs(l2GatewayDevice);
+ unInstallL2GwUcastMacFromElan(elan, l2GatewayDevice, localMacs);
return futures;
}
return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString();
}
+ public static void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId,
+ List<PhysAddress> staticMacAddresses) {
+ ConcurrentMap<String, L2GatewayDevice> elanDevices = ElanL2GwCacheUtils
+ .getInvolvedL2GwDevices(elanName);
+ for (final L2GatewayDevice externalDevice : elanDevices.values()) {
+ scheduleAddDpnMacsInExtDevice(elanName, dpId, staticMacAddresses, externalDevice);
+ }
+ }
+
+ public static void scheduleAddDpnMacsInExtDevice(final String elanName, BigInteger dpId,
+ final List<PhysAddress> staticMacAddresses,
+ final L2GatewayDevice externalDevice) {
+ NodeId nodeId = new NodeId(externalDevice.getHwvtepNodeId());
+ final IpAddress dpnTepIp = ElanL2GatewayUtils.getSourceDpnTepIp(dpId, nodeId);
+ LOG.trace("Dpn Tep IP: {} for dpnId: {} and nodeId: {}", dpnTepIp, dpId, nodeId);
+ if (dpnTepIp == null) {
+ LOG.error("could not install dpn mac in l2gw TEP IP not found for dpnId {} and nodeId {}", dpId, nodeId);
+ return;
+ }
+ TerminationPointKey tpKey = HwvtepSouthboundUtils.getTerminationPointKey(
+ dpnTepIp.getIpv4Address().getValue());
+ InstanceIdentifier<TerminationPoint> tpPath = HwvtepSouthboundUtils.createTerminationPointId
+ (nodeId, tpKey);
+
+ HwvtepPhysicalLocatorListener.runJobAfterPhysicalLocatorIsAvialable(tpPath, new Runnable() {
+ @Override
+ public void run() {
+ HwvtepUtils.installUcastMacs(broker,
+ externalDevice.getHwvtepNodeId(), staticMacAddresses,
+ elanName, dpnTepIp);
+ }
+ });
+ }
+
+ public static void scheduleDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+ TimerTask logicalSwitchDeleteTask = new TimerTask() {
+ @Override
+ public void run() {
+ LogicalSwitchDeletedJob logicalSwitchDeletedJob = new LogicalSwitchDeletedJob(broker, hwvtepNodeId,
+ lsName);
+ ElanL2GatewayUtils.dataStoreJobCoordinator.enqueueJob(logicalSwitchDeletedJob.getJobKey(),
+ logicalSwitchDeletedJob, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ }
+ };
+ Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+ LogicalSwitchDeletedTasks.putIfAbsent(nodeIdLogicalSwitchNamePair, logicalSwitchDeleteTask);
+ LogicalSwitchDeleteJobTimer.schedule(logicalSwitchDeleteTask, LOGICAL_SWITCH_DELETE_DELAY);
+ }
+
+ public static void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) {
+ Pair<NodeId, String> nodeIdLogicalSwitchNamePair = new ImmutablePair<NodeId, String>(hwvtepNodeId, lsName);
+ TimerTask logicalSwitchDeleteTask = LogicalSwitchDeletedTasks.get(nodeIdLogicalSwitchNamePair);
+ if (logicalSwitchDeleteTask != null) {
+ LOG.debug("Delete logical switch {} action on node {} cancelled", lsName, hwvtepNodeId);
+ logicalSwitchDeleteTask.cancel();
+ LogicalSwitchDeletedTasks.remove(nodeIdLogicalSwitchNamePair);
+ }
+ }
}
package org.opendaylight.vpnservice.elan.l2gw.utils;
-import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Callable;
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.elanmanager.utils.ElanL2GwCacheUtils;
import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
import org.opendaylight.vpnservice.elan.internal.ElanInstanceManager;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.AssociateHwvtepToElanJob;
+import org.opendaylight.vpnservice.elan.l2gw.jobs.DisAssociateHwvtepFromElanJob;
import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepLogicalSwitchListener;
-import org.opendaylight.vpnservice.elan.l2gw.listeners.HwvtepRemoteMcastMacListener;
-import org.opendaylight.vpnservice.elan.utils.ElanUtils;
+import org.opendaylight.vpnservice.elan.utils.ElanClusterUtils;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
-import org.opendaylight.vpnservice.utils.SystemPropertyReader;
-import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
-import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundUtils;
import org.opendaylight.vpnservice.utils.hwvtep.HwvtepUtils;
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.neutron.l2gateways.rev150712.l2gateway.attributes.Devices;
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.HwvtepNodeName;
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.opendaylight.vpnservice.elan.rev150602.elan.instances.ElanInstance;
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.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
public class L2GatewayConnectionUtils {
private static final Logger LOG = LoggerFactory.getLogger(L2GatewayConnectionUtils.class);
+ private static DataBroker broker;
+ private static ElanInstanceManager elanInstanceManager;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
+ public static void setBroker(DataBroker broker) {
+ L2GatewayConnectionUtils.broker = broker;
+ }
+
+ public static void setElanInstanceManager(ElanInstanceManager elanInstanceManager) {
+ L2GatewayConnectionUtils.elanInstanceManager = elanInstanceManager;
+ }
+
public static boolean isGatewayAssociatedToL2Device(L2GatewayDevice l2GwDevice) {
return (l2GwDevice.getL2GatewayIds().size() > 0);
}
return null;
}
- public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
- L2gatewayConnection input) {
- addL2GatewayConnection(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstanceManager,
- input, null);
+ public static void addL2GatewayConnection(L2gatewayConnection input) {
+ addL2GatewayConnection(input, null/*deviceName*/);
}
- public static void addL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
- L2gatewayConnection input, String l2GwDeviceName) {
+ public static void addL2GatewayConnection(L2gatewayConnection input, String l2GwDeviceName) {
+ LOG.info("Adding L2gateway Connection with ID: {}", input.getKey().getUuid());
+
Uuid networkUuid = input.getNetworkId();
ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
if (elanInstance == null || elanInstance.getVni() == null) {
if (l2Gateway == null) {
LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
} else {
- associateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
- l2Gateway, input.getSegmentId(), l2GwDeviceName);
+ associateHwvtepsToElan(elanInstance, l2Gateway, input, l2GwDeviceName);
}
}
}
- public static void deleteL2GatewayConnection(DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, ElanInstanceManager elanInstanceManager,
- L2gatewayConnection input) {
+ public static void deleteL2GatewayConnection(L2gatewayConnection input) {
+ LOG.info("Deleting L2gateway Connection with ID: {}", input.getKey().getUuid());
+
Uuid networkUuid = input.getNetworkId();
ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(networkUuid.getValue());
if (elanInstance == null) {
if (l2Gateway == null) {
LOG.error("L2Gateway with id {} is not present", l2GatewayId.getValue());
} else {
- disAssociateHwvtepsToElan(broker, entityOwnershipService, bindingNormalizedNodeSerializer, elanInstance,
- l2Gateway, input.getSegmentId());
+ disAssociateHwvtepsFromElan(elanInstance, l2Gateway, input);
}
}
}
- private static void disAssociateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
- L2gateway l2Gateway, final Integer defaultVlan) {
- final String elanName = elanInstance.getElanInstanceName();
+ private static void disAssociateHwvtepsFromElan(ElanInstance elanInstance, L2gateway l2Gateway,
+ L2gatewayConnection input) {
+ String elanName = elanInstance.getElanInstanceName();
+ Integer defaultVlan = input.getSegmentId();
List<Devices> l2Devices = l2Gateway.getDevices();
- for (final Devices l2Device : l2Devices) {
- final String l2DeviceName = l2Device.getDeviceName();
- final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+ for (Devices l2Device : l2Devices) {
+ String l2DeviceName = l2Device.getDeviceName();
+ L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
if (isL2GwDeviceConnected(l2GatewayDevice)) {//TODO handle delete while device is offline
// Delete L2 Gateway device from 'ElanL2GwDevice' cache
- ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, l2GatewayDevice.getHwvtepNodeId());
-
- final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
- InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
- ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
- Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("L2 Gateway device delete is triggered for {} connected to cluster owner node",
- l2DeviceName);
-
- // Create DataStoreJobCoordinator jobs to create Logical
- // switches on all physical switches
- // which are part of L2 Gateway
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- DisAssociateHwvtepFromElan disAssociateHwvtepToElan = new DisAssociateHwvtepFromElan(broker,
- l2GatewayDevice, elanInstance, l2Device, defaultVlan);
- String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
- dataStoreCoordinator.enqueueJob(jobKey, disAssociateHwvtepToElan,
- SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
- } else {
- LOG.info("L2 Gateway device delete is not triggered on the cluster node as this is not " +
- "owner for {}", l2DeviceName);
- }
- }
-
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to trigger L2 Gateway device delete action", error);
- }
- });
+ String hwvtepNodeId = l2GatewayDevice.getHwvtepNodeId();
+ boolean isLastL2GwConnDeleted = false;
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+ if (isLastL2GwConnBeingDeleted(elanL2GwDevice)) {
+ LOG.debug("Elan L2Gw Conn cache removed for id {}", hwvtepNodeId);
+ ElanL2GwCacheUtils.removeL2GatewayDeviceFromCache(elanName, hwvtepNodeId);
+ isLastL2GwConnDeleted = true;
+ } else {
+ 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);
+ }
+
+ DisAssociateHwvtepFromElanJob disAssociateHwvtepToElanJob = new DisAssociateHwvtepFromElanJob(broker,
+ elanL2GwDevice, elanInstance, l2Device, defaultVlan, isLastL2GwConnDeleted);
+ ElanClusterUtils.runOnlyInLeaderNode(disAssociateHwvtepToElanJob.getJobKey(),
+ "remove l2gw connection job ",
+ disAssociateHwvtepToElanJob);
} else {
- LOG.error("could not handle connection delete L2 Gateway device with id {} is not present",
- l2DeviceName);
+ LOG.info("L2GwConn delete is not handled for device with id {} as it's not connected", l2DeviceName);
}
}
}
- private static void associateHwvtepsToElan(final DataBroker broker, EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer, final ElanInstance elanInstance,
- L2gateway l2Gateway, final Integer defaultVlan, String l2GwDeviceName) {
- final String elanName = elanInstance.getElanInstanceName();
+ private static void associateHwvtepsToElan(ElanInstance elanInstance,
+ L2gateway l2Gateway, L2gatewayConnection input, String l2GwDeviceName) {
+ String elanName = elanInstance.getElanInstanceName();
+ Integer defaultVlan = input.getSegmentId();
+ Uuid l2GwConnId = input.getKey().getUuid();
List<Devices> l2Devices = l2Gateway.getDevices();
- for (final Devices l2Device : l2Devices) {
- final String l2DeviceName = l2Device.getDeviceName();
+
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Associating ELAN {} with L2Gw Conn Id {} having below L2Gw devices {}", elanName, l2GwConnId,
+ l2Devices);
+ }
+
+ for (Devices l2Device : l2Devices) {
+ String l2DeviceName = l2Device.getDeviceName();
// L2gateway can have more than one L2 Gw devices. Configure Logical Switch, VLAN mappings,...
// only on the switch which has come up just now and exclude all other devices from
// preprovisioning/re-provisioning
if (l2GwDeviceName != null && !l2GwDeviceName.equals(l2DeviceName)) {
+ LOG.debug("Associating Hwvtep to ELAN is not been processed for {}; as only {} got connected now!",
+ l2DeviceName, l2GwDeviceName);
continue;
}
- final L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
+ L2GatewayDevice l2GatewayDevice = L2GatewayCacheUtils.getL2DeviceFromCache(l2DeviceName);
if (isL2GwDeviceConnected(l2GatewayDevice)) {
+ NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
+
+ // Delete pending delete logical switch task if scheduled
+ ElanL2GatewayUtils.cancelDeleteLogicalSwitch(hwvtepNodeId,
+ ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName));
+
// Add L2 Gateway device to 'ElanL2GwDevice' cache
- final boolean createLogicalSwitch;
+ boolean createLogicalSwitch;
LogicalSwitches logicalSwitch = HwvtepUtils.getLogicalSwitch(broker, LogicalDatastoreType.OPERATIONAL,
- new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanName);
+ hwvtepNodeId, elanName);
if (logicalSwitch == null) {
- final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
- l2GatewayDevice, elanName, l2Device, defaultVlan);
+ HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
+ l2GatewayDevice, elanName, l2Device, defaultVlan, l2GwConnId);
hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
createLogicalSwitch = true;
} else {
- addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice);
+ addL2DeviceToElanL2GwCache(elanName, l2GatewayDevice, l2GwConnId);
createLogicalSwitch = false;
}
- final String hwvtepId = l2GatewayDevice.getHwvtepNodeId();
- InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
- ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
- Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
- @Override
- public void onSuccess(Boolean isOwner) {
- if (isOwner) {
- LOG.info("Creating Logical switch on {} connected to cluster owner node", l2DeviceName);
-
- // Create DataStoreJobCoordinator jobs to create Logical
- // switches on all physical switches
- // which are part of L2 Gateway
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
- AssociateHwvtepToElan associateHwvtepToElan = new AssociateHwvtepToElan(broker,
- l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
- String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(hwvtepId, elanName);
- dataStoreCoordinator.enqueueJob(jobKey, associateHwvtepToElan,
- SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
- } else {
- LOG.info("Logical switch creation is not triggered on the cluster node as this is not " +
- "owner for {}", l2DeviceName);
- }
- }
-
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed to trigger Logical switch creation action", error);
- }
- });
- } else {
- LOG.error("L2 Gateway device with id {} is not present", l2DeviceName);
- }
- }
- }
-
- public static void addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice) {
- L2GatewayDevice elanL2GwDevice = new L2GatewayDevice();
- elanL2GwDevice.setHwvtepNodeId(l2GatewayDevice.getHwvtepNodeId());
- elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
- elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
- ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
- }
-
- private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
- return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
- }
-
- private static class AssociateHwvtepToElan implements Callable<List<ListenableFuture<Void>>> {
- DataBroker broker;
- L2GatewayDevice l2GatewayDevice;
- ElanInstance elanInstance;
- Devices l2Device;
- Integer defaultVlan;
- boolean createLogicalSwitch;
-
- public AssociateHwvtepToElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
- Devices l2Device, Integer defaultVlan, boolean createLogicalSwitch) {
- this.broker = broker;
- this.l2GatewayDevice = l2GatewayDevice;
- this.elanInstance = elanInstance;
- this.l2Device = l2Device;
- this.defaultVlan = defaultVlan;
- this.createLogicalSwitch = createLogicalSwitch;
- }
-
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- List<ListenableFuture<Void>> futures = new ArrayList<>();
+ AssociateHwvtepToElanJob associateHwvtepToElanJob = new AssociateHwvtepToElanJob(broker,
+ l2GatewayDevice, elanInstance, l2Device, defaultVlan, createLogicalSwitch);
- final String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
+ ElanClusterUtils.runOnlyInLeaderNode( associateHwvtepToElanJob.getJobKey() ,
+ "create logical switch in hwvtep topo",
+ associateHwvtepToElanJob);
- // Create Logical Switch if it's not created already in
- // the device
- if (createLogicalSwitch) {
- ListenableFuture<Void> lsCreateFuture = createLogicalSwitch(l2GatewayDevice, elanInstance, l2Device);
- futures.add(lsCreateFuture);
} else {
- // Logical switch is already created; do the rest of
- // configuration
- futures.add(ElanL2GatewayUtils.updateVlanBindingsInL2GatewayDevice(
- new NodeId(l2GatewayDevice.getHwvtepNodeId()), logicalSwitchName, l2Device, defaultVlan));
- futures.add(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceAdd(logicalSwitchName, l2GatewayDevice));
- HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(),
- logicalSwitchName, l2GatewayDevice,
- new Callable<List<ListenableFuture<Void>>>() {
-
- @Override
- public List<ListenableFuture<Void>> call() {
- List<ListenableFuture<Void>> futures = new ArrayList<>();
- futures.add(ElanL2GatewayUtils.installElanMacsInL2GatewayDevice(
- logicalSwitchName, l2GatewayDevice));
- return futures;
- }}
- );
+ LOG.info("L2GwConn create is not handled for device with id {} as it's not connected", l2DeviceName);
}
-
- return futures;
}
+ }
- private ListenableFuture<Void> createLogicalSwitch(L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
- Devices l2Device) {
- final String logicalSwitchName = ElanL2GatewayUtils
- .getLogicalSwitchFromElan(elanInstance.getElanInstanceName());
- String segmentationId = elanInstance.getVni().toString();
-
- // Register for Logical switch update in opearational DS
- final HwvtepLogicalSwitchListener hwVTEPLogicalSwitchListener = new HwvtepLogicalSwitchListener(
- l2GatewayDevice, logicalSwitchName, l2Device, defaultVlan);
- hwVTEPLogicalSwitchListener.registerListener(LogicalDatastoreType.OPERATIONAL, broker);
-
- NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
- InstanceIdentifier<LogicalSwitches> path = HwvtepSouthboundUtils
- .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName));
- LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName,
- elanInstance.getDescription(), segmentationId);
-
- ListenableFuture<Void> lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch);
- Futures.addCallback(lsCreateFuture, new FutureCallback<Void>() {
- @Override
- public void onSuccess(Void noarg) {
- // Listener will be closed after all configuration completed
- // on hwvtep by
- // listener itself
- if (LOG.isTraceEnabled()) {
- LOG.trace("Successful in initiating logical switch {} creation", logicalSwitchName);
- }
- }
+ public static L2GatewayDevice addL2DeviceToElanL2GwCache(String elanName, L2GatewayDevice l2GatewayDevice,
+ Uuid l2GwConnId) {
+ String l2gwDeviceNodeId = l2GatewayDevice.getHwvtepNodeId();
+ L2GatewayDevice elanL2GwDevice = ElanL2GwCacheUtils.getL2GatewayDeviceFromCache(elanName, l2gwDeviceNodeId);
+ if (elanL2GwDevice == null) {
+ elanL2GwDevice = new L2GatewayDevice();
+ elanL2GwDevice.setHwvtepNodeId(l2gwDeviceNodeId);
+ elanL2GwDevice.setDeviceName(l2GatewayDevice.getDeviceName());
+ elanL2GwDevice.setTunnelIps(l2GatewayDevice.getTunnelIps());
+ ElanL2GwCacheUtils.addL2GatewayDeviceToCache(elanName, elanL2GwDevice);
+ LOG.debug("Elan L2GwConn cache created for hwvtep id {}", l2gwDeviceNodeId);
+ } else {
+ LOG.debug("Elan L2GwConn cache already exists for hwvtep id {}; updating L2GwConn id {} to it",
+ l2gwDeviceNodeId, l2GwConnId);
+ }
+ elanL2GwDevice.addL2GatewayId(l2GwConnId);
- @Override
- public void onFailure(Throwable error) {
- LOG.error("Failed logical switch {} creation", logicalSwitchName, error);
- try {
- hwVTEPLogicalSwitchListener.close();
- } catch (final Exception e) {
- LOG.error("Error when cleaning up DataChangeListener.", e);
- }
- }
- });
- return lsCreateFuture;
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Elan L2GwConn cache updated with below details: {}", elanL2GwDevice);
}
+ return elanL2GwDevice;
}
- private static class DisAssociateHwvtepFromElan implements Callable<List<ListenableFuture<Void>>> {
- DataBroker broker;
- L2GatewayDevice l2GatewayDevice;
- ElanInstance elanInstance;
- Devices l2Device;
- Integer defaultVlan;
-
- public DisAssociateHwvtepFromElan(DataBroker broker, L2GatewayDevice l2GatewayDevice, ElanInstance elanInstance,
- Devices l2Device, Integer defaultVlan) {
- this.broker = broker;
- this.l2GatewayDevice = l2GatewayDevice;
- this.elanInstance = elanInstance;
- this.l2Device = l2Device;
- this.defaultVlan = defaultVlan;
- }
+ private static boolean isL2GwDeviceConnected(L2GatewayDevice l2GwDevice) {
+ return (l2GwDevice != null && l2GwDevice.getHwvtepNodeId() != null && l2GwDevice.isConnected());
+ }
- @Override
- public List<ListenableFuture<Void>> call() throws Exception {
- List<ListenableFuture<Void>> futures = new ArrayList<>();
-
- // Remove remote MACs and vlan mappings from physical port
- // Once all above configurations are deleted, delete logical
- // switch
- NodeId hwvtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
- String elanName = elanInstance.getElanInstanceName();
- futures.add(ElanL2GatewayUtils.deleteElanMacsFromL2GatewayDevice(l2GatewayDevice, elanName));
- futures.addAll(ElanL2GatewayMulticastUtils.handleMcastForElanL2GwDeviceDelete(elanInstance,
- l2GatewayDevice));
- futures.addAll(ElanL2GatewayUtils.deleteL2GatewayDeviceUcastLocalMacsFromElan(l2GatewayDevice, elanName));
- futures.add(ElanL2GatewayUtils.deleteVlanBindingsFromL2GatewayDevice(hwvtepNodeId, l2Device, defaultVlan));
- Thread.sleep(30000);
- futures.add(HwvtepUtils.deleteLogicalSwitch(this.broker, hwvtepNodeId, elanName));
-
- return futures;
- }
+ protected static boolean isLastL2GwConnBeingDeleted(L2GatewayDevice l2GwDevice) {
+ return (l2GwDevice.getL2GatewayIds().size() == 1);
}
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.elan.utils;
+
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.clustering.ClusteringUtils;
+import org.opendaylight.vpnservice.utils.hwvtep.HwvtepSouthboundConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public class ElanClusterUtils {
+ private static final Logger logger = LoggerFactory.getLogger(ElanClusterUtils.class);
+
+ private static EntityOwnershipService eos;
+
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
+ public static void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+ eos = entityOwnershipService;
+ }
+
+ public static void runOnlyInLeaderNode(Runnable job) {
+ runOnlyInLeaderNode(job, "");
+ }
+
+ public static void runOnlyInLeaderNode(final Runnable job, final String jobDescription) {
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ job.run();
+ } else {
+ logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+ }
+ }
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Failed to identity cluster owner ", error);
+ }
+ });
+ }
+
+ public static void runOnlyInLeaderNode(String jobKey, Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+ runOnlyInLeaderNode(jobKey, "", dataStoreJob);
+ }
+
+ public static void runOnlyInLeaderNode(final String jobKey, final String jobDescription,
+ final Callable<List<ListenableFuture<Void>>> dataStoreJob) {
+ ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
+ eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
+ Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean isOwner) {
+ if (isOwner) {
+ logger.trace("scheduling job {} ", jobDescription);
+ dataStoreJobCoordinator.enqueueJob(jobKey, dataStoreJob,
+ SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
+ } else {
+ logger.trace("job is not run as i m not cluster owner desc :{} ", jobDescription);
+ }
+ }
+ @Override
+ public void onFailure(Throwable error) {
+ logger.error("Failed to identity cluster owner for job "+jobDescription, error);
+ }
+ });
+ }
+}
public static final String L2GATEWAY_DS_JOB_NAME = "L2GW";
public static final String UNKNOWN_DMAC = "00:00:00:00:00:00";
+ public static final int JOB_MAX_RETRIES = 3;
}
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import org.apache.commons.lang3.StringUtils;
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.vpnservice.mdsalutil.MetaDataUtil;
import org.opendaylight.vpnservice.mdsalutil.NwConstants;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
+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;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007.IfIndexesInterfaceMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterface;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.meta.rev151007._if.indexes._interface.map.IfIndexInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeGre;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeVxlan;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnelKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.CreateTerminatingServiceActionsInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.RemoveTerminatingServiceActionsInputBuilder;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ElanUtils {
- private static final ArrayList EMPTY_LIST = new ArrayList();
-
private static OdlInterfaceRpcService interfaceMgrRpcService;
private static ItmRpcService itmRpcService;
synchronized (macAddress) {
logger.info("Acquired lock for mac : " + macAddress + ". Proceeding with install operation.");
setupKnownSmacFlow(elanInfo, interfaceInfo, macTimeout, macAddress, mdsalMgr);
- setupTermDmacFlows(interfaceInfo, mdsalMgr);
setupOrigDmacFlows(elanInfo, interfaceInfo, macAddress, mdsalMgr, dataBroker);
}
}
* @param interfaceInfo
* @param mdsalApiManager
*/
- private static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
+ public static void setupTermDmacFlows(InterfaceInfo interfaceInfo, IMdsalApiManager mdsalApiManager) {
BigInteger dpId = interfaceInfo.getDpId();
int lportTag = interfaceInfo.getInterfaceTag();
Flow flow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
public static List<DpnInterfaces> getInvolvedDpnsInElan(String elanName) {
List<DpnInterfaces> dpns = ElanInstanceManager.getElanInstanceManager().getElanDPNByName(elanName);
if (dpns == null) {
- return EMPTY_LIST;
+ return Collections.emptyList();
}
return dpns;
}
}
mdsalMgr.removeFlow(srcdpId, MDSALUtil.buildFlow(ElanConstants.ELAN_DMAC_TABLE,
getKnownDynamicmacFlowRef(ElanConstants.ELAN_DMAC_TABLE, srcdpId, ifTag, macAddress, elanTag)));
- RemoveTerminatingServiceActionsInput removeTerminatingServiceActionsInput = new RemoveTerminatingServiceActionsInputBuilder().setServiceId(interfaceInfo.getInterfaceTag()).setDpnId(srcdpId).build();
- itmRpcService.removeTerminatingServiceActions(removeTerminatingServiceActionsInput);
if (logger.isDebugEnabled()) {
logger.debug("All the required flows deleted for elan:{}, logical Interface port:{} and mac address:{} on dpn:{}", elanInstanceName, interfaceInfo.getPortName(), macAddress, srcdpId);
}
* @return the list
*/
public static List<Action> buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) {
- List<Action> result = EMPTY_LIST;
+ List<Action> result = Collections.emptyList();
if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) {
GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder()
.setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build();
* @return the external itm egress action
*/
public static List<Action> getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) {
- List<Action> result = EMPTY_LIST;
+ List<Action> result = Collections.emptyList();
GetExternalTunnelInterfaceNameInput input = new GetExternalTunnelInterfaceNameInputBuilder()
- .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).build();
+ .setDestinationNode(torNode.getValue()).setSourceNode(srcDpnId.toString()).setTunnelType(TunnelTypeVxlan.class).build();
Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> output =
itmRpcService.getExternalTunnelInterfaceName(input);
try {
*/
public static List<Action> getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId,
long serviceTag) {
- List<Action> result = EMPTY_LIST;
+ List<Action> result = Collections.emptyList();
logger.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}",
sourceDpnId, destinationDpnId, serviceTag);
-
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder()
- .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).build();
+ .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build();
Future<RpcResult<GetTunnelInterfaceNameOutput>> output = itmRpcService.getTunnelInterfaceName(input);
try {
if (output.get().isSuccessful()) {
return null;
}
+ /**
+ * Gets the external tunnel.
+ *
+ * @param sourceDevice
+ * the source device
+ * @param destinationDevice
+ * the destination device
+ * @param datastoreType
+ * the datastore type
+ * @return the external tunnel
+ */
+ public static ExternalTunnel getExternalTunnel(String sourceDevice, String destinationDevice,
+ LogicalDatastoreType datastoreType) {
+ ExternalTunnel externalTunnel = null;
+ Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class ;
+ InstanceIdentifier<ExternalTunnel> iid = InstanceIdentifier.builder(ExternalTunnelList.class)
+ .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build();
+ Optional<ExternalTunnel> tunnelList = read(dataBroker, datastoreType, iid);
+ if (tunnelList.isPresent()) {
+ externalTunnel = tunnelList.get();
+ }
+ return externalTunnel;
+ }
+
+ /**
+ * Gets the external tunnel.
+ *
+ * @param interfaceName
+ * the interface name
+ * @param datastoreType
+ * the datastore type
+ * @return the external tunnel
+ */
+ public static ExternalTunnel getExternalTunnel(String interfaceName, LogicalDatastoreType datastoreType) {
+ ExternalTunnel externalTunnel = null;
+ List<ExternalTunnel> externalTunnels = getAllExternalTunnels(datastoreType);
+ for (ExternalTunnel tunnel : externalTunnels) {
+ if (StringUtils.equalsIgnoreCase(interfaceName, tunnel.getTunnelInterfaceName())) {
+ externalTunnel = tunnel;
+ break;
+ }
+ }
+ return externalTunnel;
+ }
+
+ /**
+ * Gets the all external tunnels.
+ *
+ * @return the all external tunnels
+ */
+ public static List<ExternalTunnel> getAllExternalTunnels(LogicalDatastoreType datastoreType) {
+ List<ExternalTunnel> result = null;
+ InstanceIdentifier<ExternalTunnelList> iid = InstanceIdentifier.builder(ExternalTunnelList.class).build();
+ Optional<ExternalTunnelList> tunnelList = read(dataBroker, datastoreType, iid);
+ if (tunnelList.isPresent()) {
+ result = tunnelList.get().getExternalTunnel();
+ }
+ if (result == null) {
+ result = Collections.emptyList();
+ }
+ return result;
+ }
+
/**
* Installs a Flow in a DPN's DMAC table. The Flow is for a MAC that is
* connected remotely in another CSS and accessible through an internal
return dpId;
}
+ /**
+ * Checks if is interface operational.
+ *
+ * @param interfaceName
+ * the interface name
+ * @param dataBroker
+ * the data broker
+ * @return true, if is interface operational
+ */
+ public static boolean isInterfaceOperational(String interfaceName, DataBroker dataBroker) {
+ if (StringUtils.isBlank(interfaceName)) {
+ return false;
+ }
+ Interface ifState = getInterfaceStateFromOperDS(interfaceName, dataBroker);
+ if (ifState == null) {
+ return false;
+ }
+ return ((ifState.getOperStatus() == OperStatus.Up) && (ifState.getAdminStatus() == AdminStatus.Up));
+ }
+
+ /**
+ * Gets the interface state from operational ds.
+ *
+ * @param interfaceName
+ * the interface name
+ * @param dataBroker
+ * the data broker
+ * @return the interface state from oper ds
+ */
+ public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
+ String interfaceName, DataBroker dataBroker) {
+ InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = createInterfaceStateInstanceIdentifier(
+ interfaceName);
+ Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil
+ .read(dataBroker, LogicalDatastoreType.OPERATIONAL, ifStateId);
+ if (ifStateOptional.isPresent()) {
+ return ifStateOptional.get();
+ }
+ return null;
+ }
+
+ /**
+ * Creates the interface state instance identifier.
+ *
+ * @param interfaceName
+ * the interface name
+ * @return the instance identifier
+ */
+ public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
+ String interfaceName) {
+ InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder = InstanceIdentifier
+ .builder(InterfacesState.class)
+ .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
+ new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
+ interfaceName));
+ return idBuilder.build();
+ }
+
}
provider.setItmManager(getItmmanagerDependency());
provider.setIdManager(idManager);
provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
- provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
getBrokerDependency().registerProvider(provider);
return provider;
}
}
}
}
- container binding-normalized-node-serializer {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity md-sal-binding:binding-normalized-node-serializer;
- }
- }
- }
}
}
}
\ No newline at end of file
public class ClusteringUtils {
+ static DataStoreJobCoordinator dataStoreJobCoordinator;
+
+ static DataStoreJobCoordinator getDataStoreJobCoordinator() {
+ if (dataStoreJobCoordinator == null) {
+ dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
+ }
+ return dataStoreJobCoordinator;
+ }
+ public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) {
+ dataStoreJobCoordinator = ds;
+ }
+
public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
String entityType, String nodeId) {
return checkNodeEntityOwner(entityOwnershipService, new Entity(entityType, nodeId),
public static ListenableFuture<Boolean> checkNodeEntityOwner(EntityOwnershipService entityOwnershipService,
Entity entity, long sleepBetweenRetries, int maxRetries) {
SettableFuture<Boolean> checkNodeEntityfuture = SettableFuture.create();
- DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
CheckEntityOwnerTask checkEntityOwnerTask = new CheckEntityOwnerTask(entityOwnershipService, entity,
checkNodeEntityfuture, sleepBetweenRetries, maxRetries);
- dataStoreCoordinator.enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
+ getDataStoreJobCoordinator().enqueueJob(entityOwnershipService.toString(), checkEntityOwnerTask);
return checkNodeEntityfuture;
}
--- /dev/null
+/*
+ * Copyright (c) 2016 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.vpnservice.utils.clustering;
+
+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.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+import org.opendaylight.controller.md.sal.common.api.clustering.*;
+import org.opendaylight.vpnservice.datastoreutils.DataStoreJobCoordinator;
+import org.opendaylight.vpnservice.utils.SystemPropertyReader;
+import org.opendaylight.vpnservice.utils.cache.CacheUtil;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+
+public class EntityOwnerUtils {
+ public static final String ENTITY_OWNER_CACHE = "entity.owner.cache";
+ private static final Logger LOG = LoggerFactory.getLogger(EntityOwnerUtils.class);
+
+ static {
+ createEntityOwnerCache();
+ }
+ private static void createEntityOwnerCache() {
+ if (CacheUtil.getCache(ENTITY_OWNER_CACHE) == null) {
+ CacheUtil.createCache(ENTITY_OWNER_CACHE);
+ }
+ }
+
+ private static String getEntity(String entityType, String entityName) {
+ return entityType;
+ }
+
+ private static void updateEntityOwner(String entityType, String entityName, Boolean isOwner) {
+ ConcurrentMap<String, Boolean> entityOwnerCache =
+ (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+ String entity = getEntity(entityType, entityName);
+ if (entityOwnerCache != null) {
+ LOG.trace("updating entity owner "+isOwner+ " "+entity );
+ entityOwnerCache.put(entity, isOwner);
+ }
+ }
+
+ public static boolean amIEntityOwner(String entityType, String entityName) {
+ ConcurrentMap<String, Boolean> entityOwnerCache =
+ (ConcurrentMap<String, Boolean>) CacheUtil.getCache(ENTITY_OWNER_CACHE);
+ String entity = getEntity(entityType, entityName);
+ boolean ret = false;
+ if (entityOwnerCache != null) {
+ if (entityOwnerCache.get(entity) != null) {
+ ret = entityOwnerCache.get(entity);
+ }
+ } else {
+ LOG.error("entity owner cache null");
+ }
+ LOG.trace("get entity owner result {} for type {}" ,ret ,entity);
+ return ret;
+ }
+
+ /**
+ * Registers the entityName for ownership for given entityType
+ * adds a local listener which takes care of updating the cached entity status
+ * @param entityOwnershipService
+ * @param entityType
+ * @param entityName
+ * @param listener also adds this listener for ownership events if provided
+ * @throws CandidateAlreadyRegisteredException
+ */
+ public static void registerEntityCandidateForOwnerShip (
+ EntityOwnershipService entityOwnershipService,
+ String entityType, String entityName, EntityOwnershipListener listener)
+ throws CandidateAlreadyRegisteredException {
+ LOG.info("registering for entity ownership for type "+entityType);
+ Entity candidateEntity = new Entity(entityType, entityName);
+ EntityOwnershipCandidateRegistration candidateRegistration = entityOwnershipService.registerCandidate(
+ candidateEntity);
+ EntityOwnershipListenerRegistration listenerRegistration = entityOwnershipService.registerListener(entityType,
+ entityOwnershipListener);
+ if (listener != null) {
+ entityOwnershipService.registerListener(entityType, listener);
+ }
+ LOG.info("registered for entity ownership for type "+entityType);
+ //TODO track registrations for closing
+ }
+
+ private static Listener entityOwnershipListener = new Listener();
+ static class Listener implements EntityOwnershipListener {
+
+ @Override
+ public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+ String entityType = ownershipChange.getEntity().getType();
+ String entityName = ownershipChange.getEntity().getId().toString();
+ LOG.info("entity ownership changed for "+entityType);
+ if (ownershipChange.hasOwner() && ownershipChange.isOwner()) {
+ LOG.info("entity ownership change became owner for type "+entityType);
+ updateEntityOwner(entityType, entityName, Boolean.TRUE);
+ } else {
+ LOG.info("entity ownership lost ownership for type "+entityType);
+ updateEntityOwner(entityType, entityName, Boolean.FALSE);
+ }
+ }
+ }
+}
\ No newline at end of file
public static final Object PSWITCH_URI_PREFIX = "physicalswitch";
public static final ImmutableBiMap<Class<? extends EncapsulationTypeBase>, String> ENCAPS_TYPE_MAP = new ImmutableBiMap.Builder<Class<? extends EncapsulationTypeBase>, String>()
.put(EncapsulationTypeVxlanOverIpv4.class, "vxlan_over_ipv4").build();
-
+ public static final String ELAN_ENTITY_TYPE = "elan";
+ public static final String ELAN_ENTITY_NAME = "elan";
+ public static final String TEP_PREFIX = "vxlan_over_ipv4:";
}
.child(Node.class, new NodeKey(nodeId));
}
+
+ public static InstanceIdentifier<TerminationPoint> createTerminationPointId(NodeId nodeId,
+ TerminationPointKey tpKey) {
+ return createInstanceIdentifier(nodeId).child(TerminationPoint.class, tpKey);
+ }
/**
* Creates the logical switches instance identifier.
*
return vbBuilder.build();
}
+ public static TerminationPointKey getTerminationPointKey(String ipAddress) {
+ TerminationPointKey tpKey = null;
+ String tpKeyStr = getTerminationPointKeyString(ipAddress);
+ if(tpKeyStr != null) {
+ tpKey = new TerminationPointKey(new TpId(tpKeyStr));
+ }
+ return tpKey;
+ }
+ public static String getTerminationPointKeyString(String ipAddress) {
+ String tpKeyStr = null;
+ if(ipAddress != null) {
+ tpKeyStr = new StringBuilder(HwvtepSouthboundConstants.TEP_PREFIX).
+ append(ipAddress).toString();
+ }
+ return tpKeyStr;
+ }
+
}
package org.opendaylight.vpnservice.utils.hwvtep;
+import java.util.ArrayList;
import java.util.List;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
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.yang.types.rev130715.MacAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
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.HwvtepNodeName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalLocatorAugmentation;
public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, NodeId nodeId,
LogicalSwitches logicalSwitch) {
WriteTransaction transaction = broker.newWriteOnlyTransaction();
- putLogicalSwitch(transaction, nodeId, logicalSwitch);
+ putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
return transaction.submit();
}
+ public static ListenableFuture<Void> addLogicalSwitch(DataBroker broker, LogicalDatastoreType logicalDatastoreType,
+ NodeId nodeId,
+ LogicalSwitches logicalSwitch) {
+ WriteTransaction transaction = broker.newWriteOnlyTransaction();
+ putLogicalSwitch(transaction,logicalDatastoreType, nodeId, logicalSwitch);
+ return transaction.submit();
+ }
/**
* Put the logical switches in the transaction.
*
final List<LogicalSwitches> lstSwitches) {
if (lstSwitches != null) {
for (LogicalSwitches logicalSwitch : lstSwitches) {
- putLogicalSwitch(transaction, nodeId, logicalSwitch);
+ putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch);
}
}
}
* @param logicalSwitch
* the logical switch
*/
- public static void putLogicalSwitch(final WriteTransaction transaction, final NodeId nodeId,
- final LogicalSwitches logicalSwitch) {
+ public static void putLogicalSwitch(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+ final NodeId nodeId, final LogicalSwitches logicalSwitch) {
InstanceIdentifier<LogicalSwitches> iid = HwvtepSouthboundUtils.createLogicalSwitchesInstanceIdentifier(nodeId,
logicalSwitch.getHwvtepNodeName());
- transaction.put(LogicalDatastoreType.CONFIGURATION, iid, logicalSwitch, true);
+ transaction.put(logicalDatastoreType, iid, logicalSwitch, true);
}
/**
transaction.put(LogicalDatastoreType.CONFIGURATION, iid, remoteMcastMac, true);
}
+ public static void putRemoteMcastMac(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType,
+ final NodeId nodeId,
+ RemoteMcastMacs remoteMcastMac) {
+ InstanceIdentifier<RemoteMcastMacs> iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
+ remoteMcastMac.getKey());
+ transaction.put(logicalDatastoreType, iid, remoteMcastMac, true);
+ }
/**
* Gets the remote mcast mac.
*
}
return null;
}
+
+ /**
+ * Installs a list of Mac Addresses as remote Ucast address in an external
+ * device using the hwvtep-southbound.
+ *
+ * @param deviceNodeId
+ * NodeId if the ExternalDevice where the macs must be installed
+ * in.
+ * @param macAddresses
+ * List of Mac addresses to be installed in the external device.
+ * @param logicalSwitchName
+ * the logical switch name
+ * @param remoteVtepIp
+ * VTEP's IP in this CSS used for the tunnel with external
+ * device.
+ */
+ public static ListenableFuture<Void> installUcastMacs(DataBroker broker,
+ String deviceNodeId, List<PhysAddress> macAddresses,
+ String logicalSwitchName, IpAddress remoteVtepIp) {
+ NodeId nodeId = new NodeId(deviceNodeId);
+ HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils
+ .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue()));
+ List<RemoteUcastMacs> macs = new ArrayList<RemoteUcastMacs>();
+ for (PhysAddress mac : macAddresses) {
+ // TODO: Query ARP cache to get IP address corresponding to
+ // the MAC
+ IpAddress ipAddress = null;
+ macs.add(HwvtepSouthboundUtils.createRemoteUcastMac(nodeId, mac.getValue(), ipAddress, logicalSwitchName,
+ phyLocatorAug));
+ }
+ return HwvtepUtils.addRemoteUcastMacs(broker, nodeId, macs);
+ }
+
}
</type>
<name>mdsalutil-service</name>
</mdsalutil>
- <entity-ownership-service>
- <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
- <name>entity-ownership-service</name>
- </entity-ownership-service>
- <binding-normalized-node-serializer>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-normalized-node-serializer</type>
- <name>runtime-mapping-singleton</name>
- </binding-normalized-node-serializer>
<notification-publish-service>
<type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-publish-service</type>
<name>binding-notification-publish-adapter</name>
<type xmlns:bindingimpl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">bindingimpl:binding-new-notification-service</type>
<name>binding-notification-adapter</name>
</notification-service>
+ <entity-ownership-service>
+ <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
+ <name>entity-ownership-service</name>
+ </entity-ownership-service>
</module>
</modules>
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
import org.opendaylight.vpnservice.neutronvpn.interfaces.INeutronVpnManager;
import org.opendaylight.vpnservice.neutronvpn.l2gw.L2GatewayProvider;
private NeutronPortChangeListener portListener;
private RpcProviderRegistry rpcProviderRegistry;
private L2GatewayProvider l2GatewayProvider;
- private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
private NotificationPublishService notificationPublishService;
private NotificationService notificationService;
+ private EntityOwnershipService entityOwnershipService;
public NeutronvpnProvider(RpcProviderRegistry rpcRegistry,NotificationPublishService notificationPublishService,
NotificationService notificationService) {
this.entityOwnershipService = entityOwnershipService;
}
- public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
- }
-
@Override
public void onSessionInitiated(ProviderContext session) {
try {
portListener = new NeutronPortChangeListener(dbx, nvManager,notificationPublishService,notificationService);
portListener.setLockManager(lockManager);
nvManager.setLockManager(lockManager);
- l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService,
- bindingNormalizedNodeSerializer);
+ l2GatewayProvider = new L2GatewayProvider(dbx, rpcProviderRegistry, entityOwnershipService);
LOG.info("NeutronvpnProvider Session Initiated");
} catch (Exception e) {
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcResult;
private final DataBroker broker;
private ItmRpcService itmRpcService;
private EntityOwnershipService entityOwnershipService;
- private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer;
public L2GatewayListener(final DataBroker db, RpcProviderRegistry rpcRegistry,
- EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ EntityOwnershipService entityOwnershipService) {
super(L2gateway.class, L2GatewayListener.class);
broker = db;
this.entityOwnershipService = entityOwnershipService;
- this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer;
itmRpcService = rpcRegistry.getRpcService(ItmRpcService.class);
registerListener(db);
}
final String hwvtepId = l2GwDevice.getHwvtepNodeId();
InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
@Override
final String hwvtepId = l2GwDevice.getHwvtepNodeId();
InstanceIdentifier<Node> iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId));
ListenableFuture<Boolean> checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(
- entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE,
- bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid));
+ entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE,
+ HwvtepSouthboundConstants.ELAN_ENTITY_NAME);
final List<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
Futures.addCallback(checkEntityOwnerFuture, new FutureCallback<Boolean>() {
@Override
import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
import org.opendaylight.vpnservice.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
-import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private L2GatewayListener l2GatewayListener;
public L2GatewayProvider(DataBroker broker, RpcProviderRegistry rpcRegistry,
- EntityOwnershipService entityOwnershipService,
- BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) {
+ EntityOwnershipService entityOwnershipService) {
L2GatewayCacheUtils.createL2DeviceCache();
- l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService,
- bindingNormalizedNodeSerializer);
+ l2GatewayListener = new L2GatewayListener(broker, rpcRegistry, entityOwnershipService);
LOG.info("L2GatewayProvider Initialized");
}
provider.setMdsalManager(getMdsalutilDependency());
provider.setLockManager(lockManagerService);
provider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
- provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency());
getBrokerDependency().registerProvider(provider);
return provider;
}
}
}
}
- container entity-ownership-service {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity eos:entity-ownership-service;
- }
- }
- }
-
- container binding-normalized-node-serializer {
- uses config:service-ref {
- refine type {
- mandatory true;
- config:required-identity md-sal-binding:binding-normalized-node-serializer;
- }
- }
- }
-
container notification-publish-service {
uses config:service-ref {
refine type {
mandatory true;
config:required-identity md-sal-binding-impl:binding-new-notification-service;
}
+ }
+ }
+
+ container entity-ownership-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity eos:entity-ownership-service;
+ }
}
}
}