From d89e5915c691b50d173c44f9d09e3038838957a9 Mon Sep 17 00:00:00 2001 From: Shashidhar R Date: Tue, 3 May 2016 18:29:19 +0530 Subject: [PATCH] Updated L2Gw changes in "neutronvpn", "elanmanager" and "dhcpservice" modules - 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 --- .../dhcpservice/DhcpConfigListener.java | 10 +- .../DhcpDesignatedDpnListener.java | 8 +- .../DhcpExternalTunnelManager.java | 66 +- .../DhcpInterfaceEventListener.java | 10 - .../DhcpL2GatewayConnectionListener.java | 27 +- .../DhcpLogicalSwitchListener.java | 4 +- .../dhcpservice/DhcpServiceUtils.java | 4 +- .../dhcpservice/DhcpUCastMacListener.java | 10 +- .../elanmanager/utils/ElanL2GwCacheUtils.java | 15 +- elanmanager/elanmanager-impl/pom.xml | 18 +- .../src/main/config/default-config.xml | 4 - .../elan/cli/l2gw/L2GwUtilsCacheCli.java | 2 +- .../ElanDpnInterfaceClusteredListener.java | 146 ++++ .../elan/internal/ElanInstanceManager.java | 10 +- .../elan/internal/ElanInterfaceAddWorker.java | 53 ++ .../elan/internal/ElanInterfaceManager.java | 321 ++++---- .../internal/ElanInterfaceRemoveWorker.java | 50 ++ .../ElanInterfaceStateChangeListener.java | 62 +- .../ElanInterfaceStateClusteredListener.java | 103 +++ .../elan/internal/ElanPacketInHandler.java | 9 +- .../elan/internal/ElanServiceProvider.java | 33 +- .../l2gw/internal/ElanL2GatewayProvider.java | 43 +- .../l2gw/jobs/AssociateHwvtepToElanJob.java | 119 +++ .../jobs/DeleteL2GwDeviceMacsFromElanJob.java | 118 +++ .../jobs/DisAssociateHwvtepFromElanJob.java | 88 +++ .../jobs/HwvtepDeviceMcastMacUpdateJob.java | 43 ++ .../elan/l2gw/jobs/LogicalSwitchAddedJob.java | 99 +++ .../l2gw/jobs/LogicalSwitchDeletedJob.java | 64 ++ .../HwvtepLocalUcastMacListener.java | 38 +- .../HwvtepLogicalSwitchListener.java | 100 +-- .../l2gw/listeners/HwvtepNodeListener.java | 54 +- .../HwvtepPhysicalLocatorListener.java | 141 ++++ .../HwvtepRemoteMcastMacListener.java | 56 +- .../L2GatewayConnectionListener.java | 22 +- .../utils/ElanL2GatewayMulticastUtils.java | 119 +-- .../elan/l2gw/utils/ElanL2GatewayUtils.java | 718 ++++++++++-------- .../l2gw/utils/L2GatewayConnectionUtils.java | 368 +++------ .../elan/utils/ElanClusterUtils.java | 89 +++ .../vpnservice/elan/utils/ElanConstants.java | 1 + .../vpnservice/elan/utils/ElanUtils.java | 155 +++- .../impl/rev150216/ElanServiceImplModule.java | 1 - .../src/main/yang/elanservice-impl.yang | 8 - .../utils/clustering/ClusteringUtils.java | 15 +- .../utils/clustering/EntityOwnerUtils.java | 114 +++ .../hwvtep/HwvtepSouthboundConstants.java | 4 +- .../utils/hwvtep/HwvtepSouthboundUtils.java | 22 + .../vpnservice/utils/hwvtep/HwvtepUtils.java | 59 +- .../src/main/config/default-config.xml | 12 +- .../neutronvpn/NeutronvpnProvider.java | 13 +- .../neutronvpn/l2gw/L2GatewayListener.java | 14 +- .../neutronvpn/l2gw/L2GatewayProvider.java | 7 +- .../impl/rev150325/NeutronvpnImplModule.java | 1 - .../src/main/yang/neutronvpn-impl.yang | 27 +- 53 files changed, 2563 insertions(+), 1134 deletions(-) create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java create mode 100644 elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java create mode 100644 mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java index 2d187055..2fa8448a 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpConfigListener.java @@ -8,17 +8,15 @@ 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; diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java index 838cc468..27de14d7 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpDesignatedDpnListener.java @@ -64,10 +64,10 @@ public class DhcpDesignatedDpnListener extends AsyncClusteredDataChangeListenerB String elanInstanceName = update.getElanInstanceName(); dhcpExternalTunnelManager.removeFromLocalCache(BigInteger.valueOf(original.getDpId()), original.getTunnelRemoteIpAddress(), original.getElanInstanceName()); dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName); -/* List elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker); + List elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker); if (elanDpns == null || elanDpns.isEmpty()) { dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName); - }*/ + } } @Override @@ -76,10 +76,10 @@ public class DhcpDesignatedDpnListener extends AsyncClusteredDataChangeListenerB IpAddress tunnelRemoteIpAddress = add.getTunnelRemoteIpAddress(); String elanInstanceName = add.getElanInstanceName(); dhcpExternalTunnelManager.updateLocalCache(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName); -/* List elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker); + List elanDpns = DhcpServiceUtils.getDpnsForElan(elanInstanceName, broker); if (elanDpns == null || elanDpns.isEmpty()) { dhcpExternalTunnelManager.installRemoteMcastMac(designatedDpnId, tunnelRemoteIpAddress, elanInstanceName); - }*/ + } } @Override diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java index b51c8342..79e34826 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpExternalTunnelManager.java @@ -34,6 +34,7 @@ import org.opendaylight.vpnservice.neutronvpn.api.l2gw.L2GatewayDevice; 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; @@ -57,6 +58,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.dhcp.rev160428.d 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; @@ -336,9 +339,6 @@ public class DhcpExternalTunnelManager { designatedDpnId = dpn; } } - if (!elanDpnAvailableFlag) { - installRemoteMcastMac(designatedDpnId, device, elanInstanceName); - } writeDesignatedSwitchForExternalTunnel(designatedDpnId, tunnelIp, elanInstanceName); return designatedDpnId; } @@ -357,7 +357,8 @@ public class DhcpExternalTunnelManager { public void installDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) { final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId); ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - eos, MDSALUtil.NODE_PREFIX, nodeId); + eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, + HwvtepSouthboundConstants.ELAN_ENTITY_NAME); Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { @Override public void onSuccess(Boolean isOwner) { @@ -382,7 +383,8 @@ public class DhcpExternalTunnelManager { public void unInstallDhcpEntries(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) { final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId); ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - eos, MDSALUtil.NODE_PREFIX, nodeId); + eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, + HwvtepSouthboundConstants.ELAN_ENTITY_NAME); Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { @Override public void onSuccess(Boolean isOwner) { @@ -407,7 +409,8 @@ public class DhcpExternalTunnelManager { public void installDhcpDropAction(final BigInteger dpnId, final String vmMacAddress, EntityOwnershipService eos) { final String nodeId = DhcpServiceUtils.getNodeIdFromDpnId(dpnId); ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - eos, MDSALUtil.NODE_PREFIX, nodeId); + eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, + HwvtepSouthboundConstants.ELAN_ENTITY_NAME); Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { @Override public void onSuccess(Boolean isOwner) { @@ -511,10 +514,11 @@ public class DhcpExternalTunnelManager { public String getExternalTunnelInterfaceName(String sourceNode, String dstNode) { String tunnelInterfaceName = null; + Class tunType = TunnelTypeVxlan.class; try { Future> output = itmRpcService .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder() - .setSourceNode(sourceNode).setDestinationNode(dstNode).build()); + .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build()); RpcResult rpcResult = output.get(); if (rpcResult.isSuccessful()) { @@ -569,22 +573,42 @@ public class DhcpExternalTunnelManager { 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 checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner(entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, HwvtepSouthboundConstants.ELAN_ENTITY_NAME); + Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { + @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) { diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java index 199db913..3550156f 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpInterfaceEventListener.java @@ -23,7 +23,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.re 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; @@ -161,15 +160,6 @@ public class DhcpInterfaceEventListener extends AbstractDataChangeListener(dpId, update.getPhysAddress().getValue())); - } - } } @Override diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java index 6ba17767..7118c723 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpL2GatewayConnectionListener.java @@ -58,20 +58,13 @@ public class DhcpL2GatewayConnectionListener extends AsyncClusteredDataChangeLis .child(L2gateway.class, new L2gatewayKey(gatewayId)); Optional 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 l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class); - Optional l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier); - List 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 l2Devices = l2Gateway.get().getDevices(); @@ -88,6 +81,20 @@ public class DhcpL2GatewayConnectionListener extends AsyncClusteredDataChangeLis } } + private boolean isLastGatewayConnection(Uuid networkUuid) { + boolean isLastConnection = true; + InstanceIdentifier l2gatewayConnectionIdentifier = InstanceIdentifier.create(Neutron.class).child(L2gatewayConnections.class); + Optional l2GwConnection = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, l2gatewayConnectionIdentifier); + List l2GatewayConnectionList = l2GwConnection.get().getL2gatewayConnection(); + for (L2gatewayConnection l2gatewayConnection : l2GatewayConnectionList) { + if (networkUuid.equals(l2gatewayConnection.getNetworkId())) { + isLastConnection = false; + break; + } + } + return isLastConnection; + } + @Override protected void update(InstanceIdentifier identifier, L2gatewayConnection original, L2gatewayConnection update) { diff --git a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java index 5f466116..fef7085d 100644 --- a/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java +++ b/dhcpservice/dhcpservice-impl/src/main/java/org/opendaylight/vpnservice/dhcpservice/DhcpLogicalSwitchListener.java @@ -132,7 +132,7 @@ public class DhcpLogicalSwitchListener extends AbstractDataChangeListener> cachedMap = (ConcurrentMap>) CacheUtil.getCache( ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME); ConcurrentMap 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> cachedMap = (ConcurrentMap>) CacheUtil.getCache( ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME); ConcurrentMap deviceMap = cachedMap.get(elanName); if (deviceMap != null) { - return deviceMap.get(deviceName); + return deviceMap.get(l2gwDeviceNodeId); } else { return null; } } - public static ConcurrentMap getAllElanL2GatewayDevicesFromCache(String elanName) { + public static ConcurrentMap getInvolvedL2GwDevices(String elanName) { ConcurrentMap> cachedMap = (ConcurrentMap>) CacheUtil .getCache(ElanL2GwCacheUtils.L2GATEWAY_CONN_CACHE_NAME); ConcurrentMap result = cachedMap.get(elanName); diff --git a/elanmanager/elanmanager-impl/pom.xml b/elanmanager/elanmanager-impl/pom.xml index b7ea5772..2fa9b6c9 100644 --- a/elanmanager/elanmanager-impl/pom.xml +++ b/elanmanager/elanmanager-impl/pom.xml @@ -106,6 +106,22 @@ and is available at http://www.eclipse.org/legal/epl-v10.html ${powermock.version} test + + org.opendaylight.controller + sal-binding-broker-impl + test + + + org.opendaylight.controller + sal-binding-broker-impl + ${mdsal.version} + test + test-jar + + + org.slf4j + slf4j-simple + test + - diff --git a/elanmanager/elanmanager-impl/src/main/config/default-config.xml b/elanmanager/elanmanager-impl/src/main/config/default-config.xml index b34398e2..95ff8107 100644 --- a/elanmanager/elanmanager-impl/src/main/config/default-config.xml +++ b/elanmanager/elanmanager-impl/src/main/config/default-config.xml @@ -52,10 +52,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html entity-ownership:entity-ownership-service entity-ownership-service - - binding:binding-normalized-node-serializer - runtime-mapping-singleton - diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java index f9954043..d08347b7 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/cli/l2gw/L2GwUtilsCacheCli.java @@ -85,7 +85,7 @@ public class L2GwUtilsCacheCli extends OsgiCommandSupport { return; } ConcurrentMap elanDevices = ElanL2GwCacheUtils - .getAllElanL2GatewayDevicesFromCache(elanName); + .getInvolvedL2GwDevices(elanName); print(elanName, elanDevices); } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java new file mode 100644 index 00000000..3260581a --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanDpnInterfaceClusteredListener.java @@ -0,0 +1,146 @@ +/* + * 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 + implements AutoCloseable { + private DataBroker broker; + private ElanInterfaceManager elanInterfaceManager; + private ListenerRegistration 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 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 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>>() { + @Override + public List> call() throws Exception { + return Lists.newArrayList( + ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevices(elanName)); + } + }); + } + + @Override + protected void remove(InstanceIdentifier 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>>() { + @Override + public List> 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 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 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 identifier) { + return identifier.firstKeyOf(ElanDpnInterfacesList.class).getElanInstanceName(); + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java index 89f70711..f3332153 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInstanceManager.java @@ -13,6 +13,8 @@ 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.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; @@ -39,6 +41,7 @@ public class ElanInstanceManager extends AbstractDataChangeListener elanInstanceListenerRegistration; private IdManagerService idManager; private ElanInterfaceManager elanInterfaceManager; + private IInterfaceManager interfaceManager; private static final Logger logger = LoggerFactory.getLogger(ElanInstanceManager.class); @@ -63,6 +66,10 @@ public class ElanInstanceManager extends AbstractDataChangeListener elanInterfaceId = ElanUtils.getElanInterfaceConfigurationDataPathId(elanInterfaceName); - elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName); + InterfaceInfo interfaceInfo = interfaceManager.getInterfaceInfo(elanInterfaceName); + elanInterfaceManager.removeElanInterface(deletedElan, elanInterfaceName, interfaceInfo); ElanUtils.delete(broker, LogicalDatastoreType.CONFIGURATION, elanInterfaceId); } } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java new file mode 100644 index 00000000..b02e9e9f --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceAddWorker.java @@ -0,0 +1,53 @@ +/* + * 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>> { + 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> call() throws Exception { + List> futures = new ArrayList<>(); + dataChangeListener.addElanInterface(elanInterface, interfaceInfo, elanInstance); + return futures; + } + + + +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java index 1b422c5d..83ba8010 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceManager.java @@ -18,29 +18,24 @@ import java.util.concurrent.ConcurrentHashMap; 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; @@ -48,22 +43,18 @@ import org.opendaylight.vpnservice.mdsalutil.MatchFieldType; 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; @@ -88,6 +79,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.f 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; @@ -95,8 +88,6 @@ import org.slf4j.LoggerFactory; 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. @@ -183,20 +174,15 @@ public class ElanInterfaceManager extends AbstractDataChangeListener 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); @@ -228,6 +214,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener 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 = 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 identifier, ElanInterface original, ElanInterface update) { // updating the static-Mac Entries for the existing elanInterface @@ -374,7 +379,10 @@ public class ElanInterfaceManager extends AbstractDataChangeListener 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); } @@ -490,7 +498,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener getRemoteBCGroupBuckets(ElanInstance elanInfo, - InterfaceInfo interfaceInfo, int bucketId) { - BigInteger dpnId = interfaceInfo.getDpId(); + private List getRemoteBCGroupBuckets(ElanInstance elanInfo, BigInteger dpnId, int bucketId) { int elanTag = elanInfo.getElanTag().intValue(); List listBucketInfo = new ArrayList(); ElanDpnInterfacesList elanDpns = ElanUtils.getElanDpnInterfacesList(elanInfo.getElanInstanceName()); @@ -667,40 +674,6 @@ public class ElanInterfaceManager extends AbstractDataChangeListener elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName()); - if(elanDpns != null) { - for(DpnInterfaces dpnInterface : elanDpns) { - int bucketId = 0; - List remoteListBucket = new ArrayList(); - if(ElanUtils.isDpnPresent(dstDpId) && dpnInterface.getDpId().equals(dstDpId) && dpnInterface.getInterfaces() != null && !dpnInterface.getInterfaces().isEmpty()) { - try { - List 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 remoteListActionInfo = new ArrayList(); - 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 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. */ @@ -842,17 +815,19 @@ public class ElanInterfaceManager extends AbstractDataChangeListener listBucket = new ArrayList(); 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; } @@ -860,11 +835,11 @@ public class ElanInterfaceManager extends AbstractDataChangeListener listBucketInfoRemote = getRemoteBCGroupBuckets(elanInfo, interfaceInfo, bucketId); + List 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); } @@ -956,6 +931,7 @@ public class ElanInterfaceManager extends AbstractDataChangeListener elanInstancesMap = new HashSet<>(); if(dpnInterfaceLists == null) { return; } @@ -1212,17 +1188,16 @@ public class ElanInterfaceManager extends AbstractDataChangeListener 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); } } @@ -1231,6 +1206,93 @@ public class ElanInterfaceManager extends AbstractDataChangeListener 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(); @@ -1252,6 +1314,15 @@ public class ElanInterfaceManager extends AbstractDataChangeListener macAddresses = ElanUtils + .getElanInterfaceMacAddresses(interfaceInfo.getInterfaceName()); + if (macAddresses != null && !macAddresses.isEmpty()) { + ElanL2GatewayUtils.scheduleAddDpnMacInExtDevices(elanInstance.getElanInstanceName(), + dpId, macAddresses); + } + } } else { DpnInterfaces dpnInterfaces = ElanUtils.getElanInterfaceInfoByElanDpn(elanName, dpId); @@ -1296,81 +1367,21 @@ public class ElanInterfaceManager extends AbstractDataChangeListener dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo - .getElanInstanceName()); + public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo) { + List dpns = ElanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName()); if (dpns == null) { return; } for (DpnInterfaces dpn : dpns) { - bucketId = 0; - List listBucket = new ArrayList(); - 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 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 listBucket, int bucketId) { - int elanTag = elanInfo.getElanTag().intValue(); - ElanDpnInterfacesList elanDpns = ElanUtils - .getElanDpnInterfacesList(elanInfo.getElanInstanceName()); - if (elanDpns != null) { - List dpnInterfaceses = elanDpns.getDpnInterfaces(); - for (DpnInterfaces dpnInterface : dpnInterfaceses) { - if (ElanUtils.isDpnPresent(dpnInterface.getDpId()) - && dpnInterface.getDpId() != dpnId - && dpnInterface.getInterfaces() != null - && !dpnInterface.getInterfaces().isEmpty()) { - try { - List 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 elanL2GwDevicesBuckets = getRemoteBCGroupBucketsOfElanL2GwDevices(elanInfo, dpnId, bucketId); - listBucket.addAll(elanL2GwDevicesBuckets); } public static List getRemoteBCGroupBucketsOfElanL2GwDevices(ElanInstance elanInfo, BigInteger dpnId, int bucketId) { List listBucketInfo = new ArrayList(); ConcurrentMap map = ElanL2GwCacheUtils - .getAllElanL2GatewayDevicesFromCache(elanInfo.getElanInstanceName()); + .getInvolvedL2GwDevices(elanInfo.getElanInstanceName()); for (L2GatewayDevice device : map.values()) { String interfaceName = ElanL2GatewayUtils.getExternalTunnelInterfaceName(String.valueOf(dpnId), device.getHwvtepNodeId()); diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java new file mode 100644 index 00000000..1b3bf964 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceRemoveWorker.java @@ -0,0 +1,50 @@ +/* + * 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>> { + 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> call() throws Exception { + List> futures = new ArrayList<>(); + dataChangeListener.removeElanInterface(elanInfo, interfaceName, interfaceInfo); + return futures; + } + +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java index 80da7236..f74e4b88 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateChangeListener.java @@ -8,17 +8,20 @@ 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; @@ -32,9 +35,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.math.BigInteger; -import java.util.List; - public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener implements AutoCloseable { private DataBroker broker; private IInterfaceManager interfaceManager; @@ -67,24 +67,6 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener 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 identifier, Interface delIf) { logger.trace("Received interface {} Down event", delIf); @@ -100,34 +82,29 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener 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 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); - } - } } @@ -141,7 +118,8 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener 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()); } } } @@ -159,7 +137,7 @@ public class ElanInterfaceStateChangeListener extends AbstractDataChangeListener public InternalTunnel getTunnelState(String interfaceName) { InternalTunnel internalTunnel = null; TunnelList tunnelList = ElanUtils.buildInternalTunnel(broker); - if (tunnelList.getInternalTunnel() != null) { + if (tunnelList != null && tunnelList.getInternalTunnel() != null) { List internalTunnels = tunnelList.getInternalTunnel(); for (InternalTunnel tunnel : internalTunnels) { if (tunnel.getTunnelInterfaceName().equalsIgnoreCase(interfaceName)) { diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java new file mode 100644 index 00000000..3ce6b9fa --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanInterfaceStateClusteredListener.java @@ -0,0 +1,103 @@ +/* + * 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 implements AutoCloseable { + private DataBroker broker; + private ElanInterfaceManager elanInterfaceManager; + private ListenerRegistration 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 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 identifier, Interface delIf) { + } + + @Override + protected void update(InstanceIdentifier identifier, Interface original, final Interface update) { + add(identifier, update); + } + + @Override + protected void add(InstanceIdentifier 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); + } + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java index dbf83ddc..85ccf597 100755 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanPacketInHandler.java @@ -22,14 +22,11 @@ import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil; 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; @@ -40,9 +37,8 @@ import org.slf4j.Logger; 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 { @@ -134,7 +130,8 @@ 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); } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java index af817b85..6ad3df3b 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/internal/ElanServiceProvider.java @@ -22,9 +22,11 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; 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; @@ -59,7 +61,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev1512 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; @@ -79,6 +80,8 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService, private ElanPacketInHandler elanPacketInHandler; private ElanSmacFlowEventListener elanSmacFlowEventListener; private ElanInterfaceStateChangeListener elanInterfaceStateChangeListener; + private ElanInterfaceStateClusteredListener infStateChangeClusteredListener; + private ElanDpnInterfaceClusteredListener elanDpnInterfaceClusteredListener; private ElanNodeListener elanNodeListener; private NotificationService notificationService; private RpcProviderRegistry rpcProviderRegistry; @@ -88,9 +91,21 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService, 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; @@ -107,6 +122,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService, elanStatusMonitor.reportStatus("STARTING"); try { createIdPool(); + getDataStoreJobCoordinator(); broker = session.getSALService(DataBroker.class); ElanUtils.setDataBroker(broker); @@ -128,6 +144,7 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService, elanInstanceManager.setDataBroker(broker); elanInstanceManager.setIdManager(idManager); elanInstanceManager.setElanInterfaceManager(elanInterfaceManager); + elanInstanceManager.setInterfaceManager(interfaceManager); elanNodeListener = new ElanNodeListener(broker, mdsalManager); @@ -150,7 +167,11 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService, 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(); @@ -181,10 +202,6 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService, this.entityOwnershipService = entityOwnershipService; } - public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) { - this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer; - } - public IInterfaceManager getInterfaceManager() { return this.interfaceManager; } @@ -237,10 +254,6 @@ public class ElanServiceProvider implements BindingAwareProvider, IElanService, 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(); diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java index 76bdb6e8..65068970 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/internal/ElanL2GatewayProvider.java @@ -9,19 +9,26 @@ 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; @@ -34,7 +41,6 @@ public class ElanL2GatewayProvider implements AutoCloseable { private DataBroker broker; private EntityOwnershipService entityOwnershipService; - private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer; private ItmRpcService itmRpcService; private ElanInstanceManager elanInstanceManager; private ElanInterfaceManager elanInterfaceManager; @@ -42,6 +48,9 @@ public class ElanL2GatewayProvider implements AutoCloseable { private L2GatewayConnectionListener l2GwConnListener; private HwvtepNodeListener hwvtepNodeListener; private HwvtepLocalUcastMacListener torMacsListener; + private HwvtepPhysicalLocatorListener physicalLocatorListener; + + static DataStoreJobCoordinator dataStoreJobCoordinator; /** * Instantiates a new elan l2 gateway provider. @@ -52,11 +61,10 @@ public class ElanL2GatewayProvider implements AutoCloseable { 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"); @@ -69,18 +77,33 @@ public class ElanL2GatewayProvider implements AutoCloseable { 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"); + } } /* diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java new file mode 100644 index 00000000..946fb245 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/AssociateHwvtepToElanJob.java @@ -0,0 +1,119 @@ +/* + * 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>> { + 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> call() throws Exception { + List> 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 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 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 path = HwvtepSouthboundUtils + .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName)); + LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName, + elanInstance.getDescription(), segmentationId); + + ListenableFuture lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch); + Futures.addCallback(lsCreateFuture, new FutureCallback() { + @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; + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java new file mode 100644 index 00000000..96170f60 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DeleteL2GwDeviceMacsFromElanJob.java @@ -0,0 +1,118 @@ +/* + * 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>> { + + /** 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 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 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> 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 elanL2GwDevices = ElanL2GwCacheUtils + .getInvolvedL2GwDevices(this.elanName); + List> 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 uninstallFuture = HwvtepUtils.deleteRemoteUcastMacs(this.broker, + new NodeId(hwvtepId), logicalSwitchName, this.macAddresses); + Futures.addCallback(uninstallFuture, new FutureCallback() { + @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; + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java new file mode 100644 index 00000000..49e0c207 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/DisAssociateHwvtepFromElanJob.java @@ -0,0 +1,88 @@ +/* + * 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>> { + 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> 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> 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; + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java new file mode 100644 index 00000000..e94d6268 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/HwvtepDeviceMcastMacUpdateJob.java @@ -0,0 +1,43 @@ +/* + * 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>> { + 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> call() throws Exception { + LOG.info("running update mcast mac entry job for {} {}", + elanName, l2GatewayDevice.getHwvtepNodeId()); + return Lists.newArrayList( + ElanL2GatewayMulticastUtils.updateRemoteMcastMacOnElanL2GwDevice(elanName, l2GatewayDevice)); + } + +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java new file mode 100644 index 00000000..7ad1c45d --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchAddedJob.java @@ -0,0 +1,99 @@ +/* + * 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>> { + /** 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> call() throws Exception { + try { + LOG.debug("running logical switch added job for {} {}", logicalSwitchName, elanL2GwDevice.getHwvtepNodeId()); + List> 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 expectedPhyLocatorIps = Lists.newArrayList(); + HwvtepRemoteMcastMacListener list = new HwvtepRemoteMcastMacListener(ElanUtils.getDataBroker(), + logicalSwitchName, elanL2GwDevice, expectedPhyLocatorIps, + new Callable>>() { + @Override + public List> call() { + LOG.info("adding remote ucast macs for {} {}", logicalSwitchName, + elanL2GwDevice.getHwvtepNodeId()); + List> 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; + } + } + +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java new file mode 100644 index 00000000..f29e4095 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/jobs/LogicalSwitchDeletedJob.java @@ -0,0 +1,64 @@ +/* + * 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>> { + 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> call() throws Exception { + try { + LOG.debug("running logical switch deleted job for {} in {}", logicalSwitchName, hwvtepNodeId); + List> futures = new ArrayList<>(); + futures.add(HwvtepUtils.deleteLogicalSwitch(broker, hwvtepNodeId, logicalSwitchName)); + return futures; + } catch (Throwable e) { + LOG.error("failed to delete ls ", e); + return null; + } + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java index c2558fe5..d0e9e2e7 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLocalUcastMacListener.java @@ -7,29 +7,26 @@ */ 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). * @@ -42,19 +39,14 @@ public class HwvtepLocalUcastMacListener extends AsyncClusteredDataChangeListenerBase implements AutoCloseable { private DataBroker broker; - private EntityOwnershipService entityOwnershipService; - private BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer; private ListenerRegistration 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(); } @@ -103,8 +95,9 @@ public class HwvtepLocalUcastMacListener extends // 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 identifier, LocalUcastMacs original, @@ -136,8 +129,7 @@ public class HwvtepLocalUcastMacListener extends // Cache MAC for furthur processing later elanL2GwDevice.addUcastLocalMac(macAdded); - ElanL2GatewayUtils.installL2GwUcastMacInElan(entityOwnershipService, bindingNormalizedNodeSerializer, elan, - elanL2GwDevice, macAddress); + ElanL2GatewayUtils.installL2GwUcastMacInElan(elan, elanL2GwDevice, macAddress); } @Override diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java index 9edbd862..a0e4c668 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepLogicalSwitchListener.java @@ -7,22 +7,16 @@ */ 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; @@ -31,8 +25,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; 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. @@ -60,6 +52,15 @@ public class HwvtepLogicalSwitchListener /** 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. * @@ -71,15 +72,18 @@ public class HwvtepLogicalSwitchListener * 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; } /* @@ -162,12 +166,12 @@ public class HwvtepLogicalSwitchListener 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) { @@ -185,66 +189,4 @@ public class HwvtepLogicalSwitchListener } } - /** - * The Class LogicalSwitchAddedWorker. - */ - private class LogicalSwitchAddedWorker implements Callable>> { - /** 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> call() throws Exception { - try { - List> 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>>() { - - @Override - public List> call() { - List> 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 diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java index 3891246b..18418230 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepNodeListener.java @@ -12,7 +12,6 @@ import java.util.ArrayList; 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; @@ -39,7 +38,6 @@ import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology. 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; @@ -51,18 +49,13 @@ public class HwvtepNodeListener 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; } @@ -85,43 +78,63 @@ public class HwvtepNodeListener @Override protected void remove(InstanceIdentifier 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 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 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 = psAugmentation.getTunnelIps(); @@ -130,6 +143,11 @@ public class HwvtepNodeListener 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); @@ -139,15 +157,25 @@ public class HwvtepNodeListener List 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); } } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java new file mode 100644 index 00000000..04f63040 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepPhysicalLocatorListener.java @@ -0,0 +1,141 @@ +/* + * 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 implements AutoCloseable { + + private DataBroker broker; + private ListenerRegistration 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, List> waitingJobsList = new ConcurrentHashMap<>(); + static Map, Boolean> teps = new ConcurrentHashMap<>(); + + public static void runJobAfterPhysicalLocatorIsAvialable(InstanceIdentifier key, Runnable runnable) { + if (teps.get(key) != null) { + logger.debug("physical locator already available {} running job ", key); + runnable.run(); + return; + } + synchronized (HwvtepPhysicalLocatorListener.class) { + List 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 identifier, TerminationPoint del) { + logger.trace("physical locator removed {}", identifier); + teps.remove(identifier); + } + + @Override + protected void update(InstanceIdentifier identifier, TerminationPoint original, TerminationPoint update) { + logger.trace("physical locator available {}", identifier); + } + + @Override + protected void add(InstanceIdentifier identifier, TerminationPoint add) { + logger.trace("physical locator available {}", identifier); + teps.put(identifier, true); + List 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 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; + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java index 52046271..9f80390e 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/HwvtepRemoteMcastMacListener.java @@ -7,6 +7,7 @@ */ 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; @@ -23,9 +24,13 @@ 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.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; @@ -50,6 +55,8 @@ public class HwvtepRemoteMcastMacListener /** The node id. */ private NodeId nodeId; + private List expectedPhyLocatorIps; + DataBroker broker; String logicalSwitchName; @@ -57,37 +64,50 @@ public class HwvtepRemoteMcastMacListener AtomicBoolean executeTask = new AtomicBoolean(true); Callable>> 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>> task) throws Exception { + List expectedPhyLocatorIps, Callable>> 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 path) throws Exception { - Optional mac = null; + private boolean isDataPresentInOpDs(InstanceIdentifier path) throws Exception { + Optional mac = null; try { mac = ElanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, path); } catch (Throwable e) { @@ -95,6 +115,21 @@ public class HwvtepRemoteMcastMacListener 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; } @@ -175,8 +210,9 @@ public class HwvtepRemoteMcastMacListener */ @Override protected void add(InstanceIdentifier 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(); } @@ -184,9 +220,9 @@ public class HwvtepRemoteMcastMacListener 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 { diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java index 305bb1c0..ad6296a9 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/listeners/L2GatewayConnectionListener.java @@ -10,7 +10,6 @@ package org.opendaylight.vpnservice.elan.l2gw.listeners; 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; @@ -19,7 +18,6 @@ import org.opendaylight.vpnservice.elan.l2gw.utils.L2GatewayConnectionUtils; 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; @@ -31,16 +29,11 @@ public class L2GatewayConnectionListener extends AsyncClusteredDataChangeListene private ListenerRegistration 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); } @@ -74,33 +67,30 @@ public class L2GatewayConnectionListener extends AsyncClusteredDataChangeListene @Override protected void add(final InstanceIdentifier 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 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 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); } } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java index 498530ce..ca700aad 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java @@ -16,8 +16,10 @@ 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.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; @@ -36,9 +38,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hw 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; @@ -68,6 +70,12 @@ public class ElanL2GatewayMulticastUtils { /** The elan interface manager. */ private static ElanInterfaceManager elanInterfaceManager; + static DataStoreJobCoordinator dataStoreJobCoordinator; + + public static void setDataStoreJobCoordinator(DataStoreJobCoordinator ds) { + dataStoreJobCoordinator = ds; + } + /** * Sets the broker. * @@ -108,7 +116,7 @@ public class ElanL2GatewayMulticastUtils { * @return the listenable future */ public static ListenableFuture handleMcastForElanL2GwDeviceAdd(String elanName, L2GatewayDevice device) { - return updateMcastMacs(elanName, device, true/* updateThisDevice */); + return updateMcastMacsForAllElanDevices(elanName, device, true/* updateThisDevice */); } /** @@ -124,22 +132,9 @@ public class ElanL2GatewayMulticastUtils { SettableFuture future = SettableFuture.create(); future.set(null); try { - ConcurrentMap mapL2gwDevices = ElanL2GwCacheUtils - .getAllElanL2GatewayDevicesFromCache(elanName); - if (mapL2gwDevices == null || mapL2gwDevices.isEmpty()) { - LOG.trace("No L2GatewayDevices to configure RemoteMcastMac for elan {}", elanName); - return future; - } - List dpns = ElanUtils.getInvolvedDpnsInElan(elanName); - - // TODO revisit - L2GatewayDevice firstDevice = mapL2gwDevices.values().iterator().next(); - List dpnsTepIps = getAllTepIpsOfDpns(firstDevice, dpns); - List 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) { @@ -148,8 +143,40 @@ public class ElanL2GatewayMulticastUtils { 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 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 elanL2gwDevices = ElanL2GwCacheUtils + .getInvolvedL2GwDevices(elanName); + List dpns = ElanUtils.getInvolvedDpnsInElan(elanName); + List dpnsTepIps = getAllTepIpsOfDpns(device, dpns); + List 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 @@ -159,19 +186,19 @@ public class ElanL2GatewayMulticastUtils { * the update this device * @return the listenable future */ - public static ListenableFuture updateMcastMacs(String elanName, L2GatewayDevice device, - boolean updateThisDevice) { + public static ListenableFuture updateMcastMacsForAllElanDevices(String elanName, L2GatewayDevice device, + boolean updateThisDevice) { SettableFuture ft = SettableFuture.create(); ft.set(null); ElanInstance elanInstance = elanInstanceManager.getElanInstanceByName(elanName); - elanInterfaceManager.updateElanBroadcastGroup(elanInstance); + elanInterfaceManager.updateRemoteBroadcastGroupForAllElanDpns(elanInstance); List dpns = ElanUtils.getInvolvedDpnsInElan(elanName); ConcurrentMap devices = ElanL2GwCacheUtils - .getAllElanL2GatewayDevicesFromCache(elanName); + .getInvolvedL2GwDevices(elanName); List dpnsTepIps = getAllTepIpsOfDpns(device, dpns); List l2GwDevicesTepIps = getAllTepIpsOfL2GwDevices(devices); @@ -182,14 +209,14 @@ public class ElanL2GatewayMulticastUtils { 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(); @@ -211,22 +238,21 @@ public class ElanL2GatewayMulticastUtils { * the l2 gw devices tep ips * @return the write transaction */ - private static WriteTransaction updateRemoteMcastMac(WriteTransaction transaction, String elanName, - L2GatewayDevice device, List dpnsTepIps, List l2GwDevicesTepIps) { + private static void preapareRemoteMcastMacEntry(WriteTransaction transaction, String elanName, + L2GatewayDevice device, List dpnsTepIps, + List l2GwDevicesTepIps) { NodeId nodeId = new NodeId(device.getHwvtepNodeId()); String logicalSwitchName = ElanL2GatewayUtils.getLogicalSwitchFromElan(elanName); - ArrayList otherTepIps = new ArrayList<>(l2GwDevicesTepIps); - otherTepIps.remove(device.getTunnelIp()); - - if (!dpnsTepIps.isEmpty()) { - otherTepIps.addAll(dpnsTepIps); - } else { + ArrayList 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())); @@ -241,10 +267,9 @@ public class ElanL2GatewayMulticastUtils { } } - 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); } /** @@ -281,12 +306,10 @@ public class ElanL2GatewayMulticastUtils { /** * 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 getAllTepIpsOfDpns(L2GatewayDevice l2GwDevice, List dpns) { @@ -327,7 +350,7 @@ public class ElanL2GatewayMulticastUtils { */ public static List> handleMcastForElanL2GwDeviceDelete(ElanInstance elanInstance, L2GatewayDevice l2GatewayDevice) { - ListenableFuture updateMcastMacsFuture = updateMcastMacs(elanInstance.getElanInstanceName(), + ListenableFuture updateMcastMacsFuture = updateMcastMacsForAllElanDevices(elanInstance.getElanInstanceName(), l2GatewayDevice, false/* updateThisDevice */); ListenableFuture deleteRemoteMcastMacFuture = deleteRemoteMcastMac( new NodeId(l2GatewayDevice.getHwvtepNodeId()), elanInstance.getElanInstanceName()); @@ -374,13 +397,12 @@ public class ElanL2GatewayMulticastUtils { 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; } @@ -393,8 +415,7 @@ public class ElanL2GatewayMulticastUtils { * 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 instanceIdentifier = InstanceIdentifier .builder(DesignatedSwitchesForExternalTunnels.class) @@ -406,6 +427,6 @@ public class ElanL2GatewayMulticastUtils { return designatedSwitchForTunnelOptional.get(); } return null; - }*/ + } } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java index e695055f..4a18a9ae 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/ElanL2GatewayUtils.java @@ -13,23 +13,29 @@ import java.util.Collections; 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; @@ -40,10 +46,16 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces. 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; @@ -51,15 +63,20 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.elan.rev150602.e 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; @@ -69,7 +86,6 @@ 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; -import com.google.common.util.concurrent.SettableFuture; /** * It gathers a set of utility methods that handle ELAN configuration in external Devices (where external means @@ -81,9 +97,13 @@ import com.google.common.util.concurrent.SettableFuture; * */ 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, TimerTask> LogicalSwitchDeletedTasks = + new ConcurrentHashMap, TimerTask>(); private static final Logger LOG = LoggerFactory.getLogger(ElanL2GatewayUtils.class); @@ -108,69 +128,21 @@ public class ElanL2GatewayUtils { } /** - * 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 macAddresses) { - String logicalSwitchName = getElanFromLogicalSwitch(elanInstance.getElanInstanceName()); - ConcurrentMap 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 installMacsInExternalDeviceAsRemoteUcastMacs(String deviceNodeId, - List macAddresses, String logicalSwitchName, IpAddress remoteVtepIp) { - NodeId nodeId = new NodeId(deviceNodeId); - HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils - .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue())); - List macs = new ArrayList(); - 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 @@ -179,47 +151,110 @@ public class ElanL2GatewayUtils { * the dpn id * @param externalNodeId * the external node id - * @return the listenable future */ - public static ListenableFuture installMacsInExternalDeviceAsRemoteUcastMacs(String elanName, - Set lstElanInterfaceNames, BigInteger dpnId, NodeId externalNodeId) { - SettableFuture future = SettableFuture.create(); - future.set(null); - if (lstElanInterfaceNames == null || lstElanInterfaceNames.isEmpty()) { - return future; + public static void installDpnMacsInL2gwDevice(String elanName, Set 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 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 getElanDpnMacsFromInterfaces(Set lstElanInterfaceNames) { + List 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 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; } /** @@ -233,7 +268,7 @@ public class ElanL2GatewayUtils { */ public static void removeMacsFromElanExternalDevices(ElanInstance elanInstance, List macAddresses) { ConcurrentMap elanL2GwDevices = ElanL2GwCacheUtils - .getAllElanL2GatewayDevicesFromCache(elanInstance.getElanInstanceName()); + .getInvolvedL2GwDevices(elanInstance.getElanInstanceName()); for (L2GatewayDevice l2GatewayDevice : elanL2GwDevices.values()) { removeRemoteUcastMacsFromExternalDevice(l2GatewayDevice.getHwvtepNodeId(), elanInstance.getElanInstanceName(), macAddresses); @@ -291,228 +326,244 @@ public class ElanL2GatewayUtils { * @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 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 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 elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName); - for (DpnInterfaces elanDpn : elanDpns) { - final BigInteger dpnId = elanDpn.getDpId(); - final String nodeId = getNodeIdFromDpnId(dpnId); - - ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId); - Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { - @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>>() { - @Override - public List> call() throws Exception { - return ElanUtils.installDmacFlowsToExternalRemoteMac(dpnId, extDeviceNodeId, - elan.getElanTag(), elan.getVni(), macToBeAdded, elanInstanceName); + final List 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>>() { + @Override + public List> call() throws Exception { + List> 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 macList = new ArrayList(); macList.add(new PhysAddress(macToBeAdded)); - ConcurrentMap elanL2GwDevices = - ElanL2GwCacheUtils.getAllElanL2GatewayDevicesFromCache(elanInstanceName); - for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) { - if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) && !areMLAGDevices(extL2GwDevice, otherDevice)) { - final String hwvtepId = otherDevice.getHwvtepNodeId(); - InstanceIdentifier iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId)); - ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE, - bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid)); - Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { + String jobKey = "hwvtep:"+elan.getElanInstanceName() + ":" + macToBeAdded; + ElanClusterUtils.runOnlyInLeaderNode(jobKey, + "install remote ucast macs in l2gw device", + new Callable>>() { @Override - public void onSuccess(Boolean isOwner) { - if (isOwner) { - LOG.info("Adding DMAC entry in {} connected to cluster node owner", hwvtepId); + public List> call() throws Exception { + ConcurrentMap elanL2GwDevices = + ElanL2GwCacheUtils.getInvolvedL2GwDevices(elanInstanceName); + + List> fts = Lists.newArrayList(); + for (L2GatewayDevice otherDevice : elanL2GwDevices.values()) { + if (!otherDevice.getHwvtepNodeId().equals(extDeviceNodeId) + && !areMLAGDevices(extL2GwDevice, otherDevice)) { + final String hwvtepId = otherDevice.getHwvtepNodeId(); + InstanceIdentifier iid = HwvtepSouthboundUtils.createInstanceIdentifier( + new NodeId(hwvtepId)); + final String logicalSwitchName = elanInstanceName; + + ListenableFuture ft = HwvtepUtils.installUcastMacs( + broker, hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp); + //TODO batch the above call + Futures.addCallback(ft, new FutureCallback() { + @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>>() { - @Override - public List> call() throws Exception { - final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName); - ListenableFuture installFuture = installMacsInExternalDeviceAsRemoteUcastMacs( - hwvtepId, macList, logicalSwitchName, extL2GwDeviceTepIp); - - Futures.addCallback(installFuture, new FutureCallback() { - @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 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 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>>() { + @Override + public List> call() { + List> 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 elanDpns = ElanUtils.getInvolvedDpnsInElan(elanInstanceName); - for (DpnInterfaces elanDpn : elanDpns) { - final BigInteger dpnId = elanDpn.getDpId(); - final String nodeId = getNodeIdFromDpnId(dpnId); - - ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, MDSALUtil.NODE_PREFIX, nodeId); - Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { - @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 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 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>>() { + @Override + public List> call() { + List> futures = Lists.newArrayList(); - DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance(); - dataStoreCoordinator.enqueueJob(nodeId, new Callable>>() { - @Override - public List> 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 getL2GwDeviceLocalMacs(L2GatewayDevice l2gwDevice) { + List macs = new ArrayList<>(); + if (l2gwDevice == null) { + return macs; + } + List lstUcastLocalMacs = l2gwDevice.getUcastLocalMacs(); + if (lstUcastLocalMacs != null && !lstUcastLocalMacs.isEmpty()) { + macs = Lists.transform(lstUcastLocalMacs, new Function() { @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 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 iid = HwvtepSouthboundUtils.createInstanceIdentifier(hwvtepNodeId); - ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE, - bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid)); - Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { - @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>>() { - @Override - public List> call() throws Exception { - final String logicalSwitchName = getLogicalSwitchFromElan(elanInstanceName); - ListenableFuture uninstallFuture = HwvtepUtils.deleteRemoteUcastMac(broker, - hwvtepNodeId, logicalSwitchName, macToBeRemoved.getMacEntryKey()); - - Futures.addCallback(uninstallFuture, new FutureCallback() { - @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; } /** @@ -574,7 +625,7 @@ public class ElanL2GatewayUtils { List lstL2GatewayDeviceMacs = new ArrayList<>(); ConcurrentMap elanL2GwDevicesFromCache = ElanL2GwCacheUtils - .getAllElanL2GatewayDevicesFromCache(elanName); + .getInvolvedL2GwDevices(elanName); if (elanL2GwDevicesFromCache != null) { for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) { if (!otherDevice.getHwvtepNodeId().equals(l2GwDeviceToBeExcluded.getHwvtepNodeId())) { @@ -611,9 +662,9 @@ public class ElanL2GatewayUtils { String logicalSwitchName = getLogicalSwitchFromElan(elanName); NodeId hwVtepNodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId()); - List lstL2GatewayDevicesMacs = getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(elanName, + List lstL2GatewayDevicesMacs = getOtherDevicesMacs(elanName, l2GatewayDevice, hwVtepNodeId, logicalSwitchName); - List lstElanMacTableEntries = getElanMacTableEntriesAsRemoteUcastMacs(elanName, + List lstElanMacTableEntries = getElanMacTableEntriesMacs(elanName, l2GatewayDevice, hwVtepNodeId, logicalSwitchName); List lstRemoteUcastMacs = new ArrayList<>(lstL2GatewayDevicesMacs); @@ -639,11 +690,12 @@ public class ElanL2GatewayUtils { * the logical switch name * @return the l2 gateway devices macs as remote ucast macs */ - public static List getL2GatewayDevicesUcastLocalMacsAsRemoteUcastMacs(String elanName, - L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) { + public static List getOtherDevicesMacs(String elanName, + L2GatewayDevice l2GatewayDeviceToBeConfigured, + NodeId hwVtepNodeId, String logicalSwitchName) { List lstRemoteUcastMacs = new ArrayList(); ConcurrentMap elanL2GwDevicesFromCache = ElanL2GwCacheUtils - .getAllElanL2GatewayDevicesFromCache(elanName); + .getInvolvedL2GwDevices(elanName); if (elanL2GwDevicesFromCache != null) { for (L2GatewayDevice otherDevice : elanL2GwDevicesFromCache.values()) { @@ -699,8 +751,9 @@ public class ElanL2GatewayUtils { * the logical switch name * @return the elan mac table entries as remote ucast macs */ - public static List getElanMacTableEntriesAsRemoteUcastMacs(String elanName, - L2GatewayDevice l2GatewayDeviceToBeConfigured, NodeId hwVtepNodeId, String logicalSwitchName) { + public static List getElanMacTableEntriesMacs(String elanName, + L2GatewayDevice l2GatewayDeviceToBeConfigured, + NodeId hwVtepNodeId, String logicalSwitchName) { List lstRemoteUcastMacs = new ArrayList(); MacTable macTable = ElanUtils.getElanMacTable(elanName); @@ -744,11 +797,12 @@ public class ElanL2GatewayUtils { * @return the external tunnel interface name */ public static String getExternalTunnelInterfaceName(String sourceNode, String dstNode) { + Class tunType = TunnelTypeVxlan.class; String tunnelInterfaceName = null; try { Future> output = itmRpcService .getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder() - .setSourceNode(sourceNode).setDestinationNode(dstNode).build()); + .setSourceNode(sourceNode).setDestinationNode(dstNode).setTunnelType(tunType).build()); RpcResult rpcResult = output.get(); if (rpcResult.isSuccessful()) { @@ -913,7 +967,7 @@ public class ElanL2GatewayUtils { * @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 getInterfaceIdentifier(InterfaceKey interfaceKey) { @@ -944,45 +998,19 @@ public class ElanL2GatewayUtils { * the elan name * @return the listenable future */ - public static List> deleteL2GatewayDeviceUcastLocalMacsFromElan( - L2GatewayDevice l2GatewayDevice, String elanName) { - List> futures = new ArrayList<>(); + public static List> deleteL2GwDeviceUcastLocalMacsFromElan(L2GatewayDevice l2GatewayDevice, + String elanName) { + LOG.info("Deleting L2GatewayDevice [{}] UcastLocalMacs from elan [{}]", l2GatewayDevice.getHwvtepNodeId(), elanName); + List> futures = new ArrayList<>(); ElanInstance elan = ElanUtils.getElanInstanceByName(elanName); if (elan == null) { LOG.error("Could not find Elan by name: {}", elanName); return futures; } - List lstLocalUcastMacs = l2GatewayDevice.getUcastLocalMacs(); - if (lstLocalUcastMacs != null) { - for (LocalUcastMacs localUcastMac : lstLocalUcastMacs) { - List 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 lstMac = Lists.transform(lstLocalUcastMacs, new Function() { - @Override - public MacAddress apply(LocalUcastMacs mac) { - return (mac != null) ? mac.getMacEntryKey() : null; - } - }); - - ConcurrentMap 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 localMacs = getL2GwDeviceLocalMacs(l2GatewayDevice); + unInstallL2GwUcastMacFromElan(elan, l2GatewayDevice, localMacs); return futures; } @@ -1009,4 +1037,62 @@ public class ElanL2GatewayUtils { return MDSALUtil.NODE_PREFIX + MDSALUtil.SEPARATOR + dpnId.toString(); } + public static void scheduleAddDpnMacInExtDevices(String elanName, BigInteger dpId, + List staticMacAddresses) { + ConcurrentMap 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 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 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 nodeIdLogicalSwitchNamePair = new ImmutablePair(hwvtepNodeId, lsName); + LogicalSwitchDeletedTasks.putIfAbsent(nodeIdLogicalSwitchNamePair, logicalSwitchDeleteTask); + LogicalSwitchDeleteJobTimer.schedule(logicalSwitchDeleteTask, LOGICAL_SWITCH_DELETE_DELAY); + } + + public static void cancelDeleteLogicalSwitch(final NodeId hwvtepNodeId, final String lsName) { + Pair nodeIdLogicalSwitchNamePair = new ImmutablePair(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); + } + } } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java index be0012f4..688fd151 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/l2gw/utils/L2GatewayConnectionUtils.java @@ -8,26 +8,20 @@ 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; @@ -37,24 +31,35 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev15071 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); } @@ -90,16 +95,13 @@ public class L2GatewayConnectionUtils { 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) { @@ -110,15 +112,14 @@ public class L2GatewayConnectionUtils { 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) { @@ -129,269 +130,130 @@ public class L2GatewayConnectionUtils { 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 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 iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId)); - ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE, - bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid)); - Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { - @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 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 iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId)); - ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE, - bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid)); - Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { - @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>> { - 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> call() throws Exception { - List> 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 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>>() { - - @Override - public List> call() { - List> 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 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 path = HwvtepSouthboundUtils - .createLogicalSwitchesInstanceIdentifier(hwvtepNodeId, new HwvtepNodeName(logicalSwitchName)); - LogicalSwitches logicalSwitch = HwvtepSouthboundUtils.createLogicalSwitch(logicalSwitchName, - elanInstance.getDescription(), segmentationId); - - ListenableFuture lsCreateFuture = HwvtepUtils.addLogicalSwitch(broker, hwvtepNodeId, logicalSwitch); - Futures.addCallback(lsCreateFuture, new FutureCallback() { - @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>> { - 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> call() throws Exception { - List> 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); } } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java new file mode 100644 index 00000000..ee4f4d66 --- /dev/null +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanClusterUtils.java @@ -0,0 +1,89 @@ +/* + * 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 checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( + eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, + HwvtepSouthboundConstants.ELAN_ENTITY_NAME); + Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { + @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>> dataStoreJob) { + runOnlyInLeaderNode(jobKey, "", dataStoreJob); + } + + public static void runOnlyInLeaderNode(final String jobKey, final String jobDescription, + final Callable>> dataStoreJob) { + ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( + eos, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, + HwvtepSouthboundConstants.ELAN_ENTITY_NAME); + Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { + @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); + } + }); + } +} diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java index 51aff882..e317d145 100755 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanConstants.java @@ -33,4 +33,5 @@ public class ElanConstants { 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; } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java index e81a2759..c53bff81 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/vpnservice/elan/utils/ElanUtils.java @@ -9,10 +9,12 @@ package org.opendaylight.vpnservice.elan.utils; 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; @@ -33,6 +35,10 @@ import org.opendaylight.vpnservice.mdsalutil.MatchInfo; 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; @@ -90,13 +96,19 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150 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; @@ -110,6 +122,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev1512 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; @@ -122,8 +135,6 @@ import com.google.common.util.concurrent.ListenableFuture; public class ElanUtils { - private static final ArrayList EMPTY_LIST = new ArrayList(); - private static OdlInterfaceRpcService interfaceMgrRpcService; private static ItmRpcService itmRpcService; @@ -571,7 +582,6 @@ public class ElanUtils { 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); } } @@ -633,7 +643,7 @@ public class ElanUtils { * @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, @@ -788,7 +798,7 @@ public class ElanUtils { public static List getInvolvedDpnsInElan(String elanName) { List dpns = ElanInstanceManager.getElanInstanceManager().getElanDPNByName(elanName); if (dpns == null) { - return EMPTY_LIST; + return Collections.emptyList(); } return dpns; } @@ -932,8 +942,6 @@ public class ElanUtils { } 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); } @@ -1058,7 +1066,7 @@ public class ElanUtils { * @return the list */ public static List buildItmEgressActions(String tunnelIfaceName, Long tunnelKey) { - List result = EMPTY_LIST; + List result = Collections.emptyList(); if (tunnelIfaceName != null && !tunnelIfaceName.isEmpty()) { GetEgressActionsForInterfaceInput getEgressActInput = new GetEgressActionsForInterfaceInputBuilder() .setIntfName(tunnelIfaceName).setTunnelKey(tunnelKey).build(); @@ -1096,10 +1104,10 @@ public class ElanUtils { * @return the external itm egress action */ public static List getExternalItmEgressAction(BigInteger srcDpnId, NodeId torNode, long vni ) { - List result = EMPTY_LIST; + List 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> output = itmRpcService.getExternalTunnelInterfaceName(input); try { @@ -1136,13 +1144,13 @@ public class ElanUtils { */ public static List getInternalItmEgressAction(BigInteger sourceDpnId, BigInteger destinationDpnId, long serviceTag) { - List result = EMPTY_LIST; + List result = Collections.emptyList(); logger.debug("In getInternalItmEgressAction Action source {}, destination {}, elanTag {}", sourceDpnId, destinationDpnId, serviceTag); - + Class tunType = TunnelTypeVxlan.class; GetTunnelInterfaceNameInput input = new GetTunnelInterfaceNameInputBuilder() - .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).build(); + .setDestinationDpid(destinationDpnId).setSourceDpid(sourceDpnId).setTunnelType(tunType).build(); Future> output = itmRpcService.getTunnelInterfaceName(input); try { if (output.get().isSuccessful()) { @@ -1199,6 +1207,69 @@ public class ElanUtils { 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 tunType = TunnelTypeVxlan.class ; + InstanceIdentifier iid = InstanceIdentifier.builder(ExternalTunnelList.class) + .child(ExternalTunnel.class, new ExternalTunnelKey(destinationDevice, sourceDevice, tunType)).build(); + Optional 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 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 getAllExternalTunnels(LogicalDatastoreType datastoreType) { + List result = null; + InstanceIdentifier iid = InstanceIdentifier.builder(ExternalTunnelList.class).build(); + Optional 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 @@ -1464,5 +1535,63 @@ public class ElanUtils { 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 ifStateId = createInterfaceStateInstanceIdentifier( + interfaceName); + Optional 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 createInterfaceStateInstanceIdentifier( + String interfaceName) { + InstanceIdentifierBuilder 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(); + } + } diff --git a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java index 82b13ea4..6017e2d2 100644 --- a/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java +++ b/elanmanager/elanmanager-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/elanservice/impl/rev150216/ElanServiceImplModule.java @@ -40,7 +40,6 @@ public class ElanServiceImplModule extends org.opendaylight.yang.gen.v1.urn.open provider.setItmManager(getItmmanagerDependency()); provider.setIdManager(idManager); provider.setEntityOwnershipService(getEntityOwnershipServiceDependency()); - provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency()); getBrokerDependency().registerProvider(provider); return provider; } diff --git a/elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang b/elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang index 90ff1150..15df3ee7 100644 --- a/elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang +++ b/elanmanager/elanmanager-impl/src/main/yang/elanservice-impl.yang @@ -85,14 +85,6 @@ module elanservice-impl { } } } - 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 diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java index 311efac7..b73c4f58 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/ClusteringUtils.java @@ -27,6 +27,18 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; 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 checkNodeEntityOwner(EntityOwnershipService entityOwnershipService, String entityType, String nodeId) { return checkNodeEntityOwner(entityOwnershipService, new Entity(entityType, nodeId), @@ -42,10 +54,9 @@ public class ClusteringUtils { public static ListenableFuture checkNodeEntityOwner(EntityOwnershipService entityOwnershipService, Entity entity, long sleepBetweenRetries, int maxRetries) { SettableFuture 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; } diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java new file mode 100644 index 00000000..3d2d8708 --- /dev/null +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/clustering/EntityOwnerUtils.java @@ -0,0 +1,114 @@ +/* + * 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 entityOwnerCache = + (ConcurrentMap) 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 entityOwnerCache = + (ConcurrentMap) 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 diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java index 33eecd9a..ec4bc5c8 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundConstants.java @@ -21,5 +21,7 @@ public class HwvtepSouthboundConstants { public static final Object PSWITCH_URI_PREFIX = "physicalswitch"; public static final ImmutableBiMap, String> ENCAPS_TYPE_MAP = new ImmutableBiMap.Builder, 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:"; } diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java index c1dae6c4..cdb26525 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepSouthboundUtils.java @@ -82,6 +82,11 @@ public class HwvtepSouthboundUtils { .child(Node.class, new NodeKey(nodeId)); } + + public static InstanceIdentifier createTerminationPointId(NodeId nodeId, + TerminationPointKey tpKey) { + return createInstanceIdentifier(nodeId).child(TerminationPoint.class, tpKey); + } /** * Creates the logical switches instance identifier. * @@ -374,4 +379,21 @@ public class HwvtepSouthboundUtils { 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; + } + } diff --git a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java index 64756366..f4d6b447 100644 --- a/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java +++ b/mdsalutil/mdsalutil-api/src/main/java/org/opendaylight/vpnservice/utils/hwvtep/HwvtepUtils.java @@ -8,6 +8,7 @@ package org.opendaylight.vpnservice.utils.hwvtep; +import java.util.ArrayList; import java.util.List; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -16,6 +17,7 @@ import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; 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; @@ -64,10 +66,17 @@ public final class HwvtepUtils { public static ListenableFuture 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 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. * @@ -82,7 +91,7 @@ public final class HwvtepUtils { final List lstSwitches) { if (lstSwitches != null) { for (LogicalSwitches logicalSwitch : lstSwitches) { - putLogicalSwitch(transaction, nodeId, logicalSwitch); + putLogicalSwitch(transaction,LogicalDatastoreType.CONFIGURATION, nodeId, logicalSwitch); } } } @@ -97,11 +106,11 @@ public final class HwvtepUtils { * @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 iid = HwvtepSouthboundUtils.createLogicalSwitchesInstanceIdentifier(nodeId, logicalSwitch.getHwvtepNodeName()); - transaction.put(LogicalDatastoreType.CONFIGURATION, iid, logicalSwitch, true); + transaction.put(logicalDatastoreType, iid, logicalSwitch, true); } /** @@ -430,6 +439,13 @@ public final class HwvtepUtils { transaction.put(LogicalDatastoreType.CONFIGURATION, iid, remoteMcastMac, true); } + public static void putRemoteMcastMac(final WriteTransaction transaction,LogicalDatastoreType logicalDatastoreType, + final NodeId nodeId, + RemoteMcastMacs remoteMcastMac) { + InstanceIdentifier iid = HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId, + remoteMcastMac.getKey()); + transaction.put(logicalDatastoreType, iid, remoteMcastMac, true); + } /** * Gets the remote mcast mac. * @@ -605,4 +621,37 @@ public final class HwvtepUtils { } 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 installUcastMacs(DataBroker broker, + String deviceNodeId, List macAddresses, + String logicalSwitchName, IpAddress remoteVtepIp) { + NodeId nodeId = new NodeId(deviceNodeId); + HwvtepPhysicalLocatorAugmentation phyLocatorAug = HwvtepSouthboundUtils + .createHwvtepPhysicalLocatorAugmentation(String.valueOf(remoteVtepIp.getValue())); + List macs = new ArrayList(); + 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); + } + } diff --git a/neutronvpn/neutronvpn-impl/src/main/config/default-config.xml b/neutronvpn/neutronvpn-impl/src/main/config/default-config.xml index e8c777e8..2bda4dee 100644 --- a/neutronvpn/neutronvpn-impl/src/main/config/default-config.xml +++ b/neutronvpn/neutronvpn-impl/src/main/config/default-config.xml @@ -39,14 +39,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html mdsalutil-service - - entity-ownership:entity-ownership-service - entity-ownership-service - - - binding:binding-normalized-node-serializer - runtime-mapping-singleton - bindingimpl:binding-new-notification-publish-service binding-notification-publish-adapter @@ -55,6 +47,10 @@ and is available at http://www.eclipse.org/legal/epl-v10.html bindingimpl:binding-new-notification-service binding-notification-adapter + + entity-ownership:entity-ownership-service + entity-ownership-service + diff --git a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java index a374e1de..f9a4dcd2 100644 --- a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java +++ b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/NeutronvpnProvider.java @@ -10,12 +10,11 @@ package org.opendaylight.vpnservice.neutronvpn; 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; @@ -44,10 +43,9 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana 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) { @@ -76,10 +74,6 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana this.entityOwnershipService = entityOwnershipService; } - public void setBindingNormalizedNodeSerializer(BindingNormalizedNodeSerializer bindingNormalizedNodeSerializer) { - this.bindingNormalizedNodeSerializer = bindingNormalizedNodeSerializer; - } - @Override public void onSessionInitiated(ProviderContext session) { try { @@ -94,8 +88,7 @@ public class NeutronvpnProvider implements BindingAwareProvider, INeutronVpnMana 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) { diff --git a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java index f62d3f43..9ab16250 100644 --- a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java +++ b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayListener.java @@ -13,7 +13,6 @@ import java.util.concurrent.Callable; 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; @@ -54,15 +53,12 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId)); ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE, - bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid)); + entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, + HwvtepSouthboundConstants.ELAN_ENTITY_NAME); final List tunnelIps = l2GwDevice.getTunnelIps(); Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { @Override @@ -184,8 +180,8 @@ public class L2GatewayListener extends AsyncClusteredDataChangeListenerBase iid = HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(hwvtepId)); ListenableFuture checkEntityOwnerFuture = ClusteringUtils.checkNodeEntityOwner( - entityOwnershipService, HwvtepSouthboundConstants.HWVTEP_ENTITY_TYPE, - bindingNormalizedNodeSerializer.toYangInstanceIdentifier(iid)); + entityOwnershipService, HwvtepSouthboundConstants.ELAN_ENTITY_TYPE, + HwvtepSouthboundConstants.ELAN_ENTITY_NAME); final List tunnelIps = l2GwDevice.getTunnelIps(); Futures.addCallback(checkEntityOwnerFuture, new FutureCallback() { @Override diff --git a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java index 2da2a459..e0d5445b 100644 --- a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java +++ b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/vpnservice/neutronvpn/l2gw/L2GatewayProvider.java @@ -12,7 +12,6 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker; 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; @@ -22,11 +21,9 @@ public class L2GatewayProvider { 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"); } diff --git a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java index 90198d70..35087e85 100644 --- a/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java +++ b/neutronvpn/neutronvpn-impl/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/neutronvpn/impl/rev150325/NeutronvpnImplModule.java @@ -39,7 +39,6 @@ public class NeutronvpnImplModule extends org.opendaylight.yang.gen.v1.urn.opend provider.setMdsalManager(getMdsalutilDependency()); provider.setLockManager(lockManagerService); provider.setEntityOwnershipService(getEntityOwnershipServiceDependency()); - provider.setBindingNormalizedNodeSerializer(getBindingNormalizedNodeSerializerDependency()); getBrokerDependency().registerProvider(provider); return provider; } diff --git a/neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang b/neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang index 33a3b036..b1ef1420 100644 --- a/neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang +++ b/neutronvpn/neutronvpn-impl/src/main/yang/neutronvpn-impl.yang @@ -51,24 +51,6 @@ module neutronvpn-impl { } } } - 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 { @@ -83,6 +65,15 @@ module neutronvpn-impl { 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; + } } } } -- 2.36.6