From 391a84bf97e3f2ffa550ef50276748a9145f2579 Mon Sep 17 00:00:00 2001 From: Jozef Bacigal Date: Wed, 14 Dec 2016 17:15:24 +0100 Subject: [PATCH] Disconnection improvements. Change-Id: I547bf7fab3604e8b7dad8ce8964528b3cbc05998 Signed-off-by: Jozef Bacigal --- .../api/openflow/OFPContext.java | 8 ++ .../connection/ConnectionManager.java | 9 +- .../api/openflow/device/DeviceContext.java | 2 + .../api/openflow/device/DeviceManager.java | 1 - .../api/openflow/lifecycle/ContextChain.java | 14 +-- .../lifecycle/ContextChainHolder.java | 6 +- .../impl/OpenFlowPluginProviderImpl.java | 9 +- .../connection/ConnectionManagerImpl.java | 8 ++ .../connection/OutboundQueueProviderImpl.java | 7 +- .../impl/device/DeviceContextImpl.java | 73 +++++++++------- .../impl/device/DeviceManagerImpl.java | 7 -- .../lifecycle/ContextChainHolderImpl.java | 86 ++++++++++++++++--- .../impl/lifecycle/ContextChainImpl.java | 24 ++++-- .../impl/rpc/RpcContextImpl.java | 13 +-- .../statistics/StatisticsContextImpl.java | 4 +- .../impl/device/DeviceContextImplTest.java | 1 - .../impl/device/DeviceManagerImplTest.java | 8 -- 17 files changed, 187 insertions(+), 93 deletions(-) diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java index 7d1ad0555e..4752cf38bb 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/OFPContext.java @@ -60,6 +60,14 @@ public interface OFPContext extends AutoCloseable, ClusterLifecycleSupervisor, C new RejectedExecutionException(MESSAGE)); } + /** + * About to stop services in cluster not master anymore or going down. + * @return Future most of services need time to be closed. + */ + default ListenableFuture stopClusterServices() { + return stopClusterServices(false); + } + /** * Get cluster singleton service identifier. * @return cluster singleton service identifier. diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/connection/ConnectionManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/connection/ConnectionManager.java index e0660cbfc3..7356f5b034 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/connection/ConnectionManager.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/connection/ConnectionManager.java @@ -10,6 +10,7 @@ package org.opendaylight.openflowplugin.api.openflow.connection; import org.opendaylight.openflowjava.protocol.api.connection.SwitchConnectionHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler; /** * Connection manager manages connections with devices. @@ -23,7 +24,13 @@ public interface ConnectionManager extends SwitchConnectionHandler { * device is connected. * @param deviceConnectedHandler device connected handler */ - void setDeviceConnectedHandler(DeviceConnectedHandler deviceConnectedHandler); + void setDeviceConnectedHandler(final DeviceConnectedHandler deviceConnectedHandler); + + /** + * Method registers handler responsible handling device disconnected event + * @param deviceDisconnectedHandler device disconnected handler + */ + void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler); /** * Setter for echo reply timeout. diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceContext.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceContext.java index 4f0cf4ef68..3206a89ad7 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceContext.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceContext.java @@ -142,6 +142,8 @@ public interface DeviceContext extends */ void setSalRoleService(@Nonnull final SalRoleService salRoleService); + void masterSuccessful(); + /** * Make device slave. * @return listenable future from sal role service diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java index 49999edbac..b429744e29 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/device/DeviceManager.java @@ -24,7 +24,6 @@ import org.opendaylight.openflowplugin.api.openflow.translator.TranslatorLibrari */ public interface DeviceManager extends OFPManager, - DeviceConnectedHandler, DeviceDisconnectedHandler, TranslatorLibrarian { diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChain.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChain.java index 64c1c28217..1894468e79 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChain.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChain.java @@ -8,12 +8,11 @@ package org.opendaylight.openflowplugin.api.openflow.lifecycle; import com.google.common.util.concurrent.ListenableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.openflowplugin.api.openflow.OFPContext; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; +import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.ContextChainState; /** @@ -38,14 +37,15 @@ public interface ContextChain extends AutoCloseable { /** * Stop the working contexts, but not release them * @return Future + * @param connectionDropped */ - Future stopChain(); + ListenableFuture stopChain(boolean connectionDropped); /** * Start the contexts, if some context is missing or cant be started returns failed future * @return Future */ - Future startChain(); + ListenableFuture startChain(); @Override void close(); @@ -56,7 +56,7 @@ public interface ContextChain extends AutoCloseable { */ void changePrimaryConnection(final ConnectionContext connectionContext); - ListenableFuture connectionDropped() throws ExecutionException, InterruptedException; + ListenableFuture connectionDropped(); ContextChainState getContextChainState(); @@ -67,4 +67,8 @@ public interface ContextChain extends AutoCloseable { void registerServices(@NonNull final ClusterSingletonServiceProvider clusterSingletonServiceProvider); void makeDeviceSlave(); + + void closePrimaryConnection(); + + DeviceContext provideDeviceContext(); } diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainHolder.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainHolder.java index b7de4ccaab..196f7ff0d6 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainHolder.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainHolder.java @@ -13,11 +13,15 @@ import org.opendaylight.openflowplugin.api.openflow.OFPManager; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler; /** * Generic interface for context chain holder, hold all created context chains. */ -public interface ContextChainHolder extends DeviceConnectedHandler, MastershipChangeListener { +public interface ContextChainHolder extends + DeviceConnectedHandler, + MastershipChangeListener, + DeviceDisconnectedHandler { void addManager(final T manager); ContextChain createContextChain(final ConnectionContext connectionContext); diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java index fc7ddf8113..aa65b4b841 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/OpenFlowPluginProviderImpl.java @@ -274,18 +274,11 @@ public class OpenFlowPluginProviderImpl implements OpenFlowPluginProvider, OpenF statisticsManager = new StatisticsManagerImpl(rpcProviderRegistry, isStatisticsPollingOn, hashedWheelTimer, convertorManager,basicTimerDelay,maximumTimerDelay); - /* Initialization Phase ordering - OFP Device Context suite */ - // CM -> DM -> SM -> RPC -> Role -> DM // Device connection handler moved from device manager to context holder connectionManager.setDeviceConnectedHandler(contextChainHolder); - deviceManager.setDeviceInitializationPhaseHandler(statisticsManager); - statisticsManager.setDeviceInitializationPhaseHandler(rpcManager); - rpcManager.setDeviceInitializationPhaseHandler(deviceManager); /* Termination Phase ordering - OFP Device Context suite */ - deviceManager.setDeviceTerminationPhaseHandler(rpcManager); - rpcManager.setDeviceTerminationPhaseHandler(statisticsManager); - statisticsManager.setDeviceTerminationPhaseHandler(deviceManager); + connectionManager.setDeviceDisconnectedHandler(contextChainHolder); rpcManager.setStatisticsRpcEnabled(isStatisticsRpcEnabled); diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/ConnectionManagerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/ConnectionManagerImpl.java index d954f0b24e..8e6f3c8e26 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/ConnectionManagerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/ConnectionManagerImpl.java @@ -16,6 +16,7 @@ import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionManager; import org.opendaylight.openflowplugin.api.openflow.connection.HandshakeContext; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceConnectedHandler; +import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceDisconnectedHandler; import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeListener; import org.opendaylight.openflowplugin.api.openflow.md.core.HandshakeManager; @@ -40,6 +41,7 @@ public class ConnectionManagerImpl implements ConnectionManager { private DeviceConnectedHandler deviceConnectedHandler; private long echoReplyTimeout; private final ThreadPoolExecutor threadPool; + private DeviceDisconnectedHandler deviceDisconnectedHandler; public ConnectionManagerImpl(long echoReplyTimeout, final ThreadPoolExecutor threadPool) { this.echoReplyTimeout = echoReplyTimeout; @@ -50,6 +52,7 @@ public class ConnectionManagerImpl implements ConnectionManager { public void onSwitchConnected(final ConnectionAdapter connectionAdapter) { LOG.trace("prepare connection context"); final ConnectionContext connectionContext = new ConnectionContextImpl(connectionAdapter); + connectionContext.setDeviceDisconnectedHandler(this.deviceDisconnectedHandler); HandshakeListener handshakeListener = new HandshakeListenerImpl(connectionContext, deviceConnectedHandler); final HandshakeManager handshakeManager = createHandshakeManager(connectionAdapter, handshakeListener); @@ -102,6 +105,11 @@ public class ConnectionManagerImpl implements ConnectionManager { this.deviceConnectedHandler = deviceConnectedHandler; } + @Override + public void setDeviceDisconnectedHandler(final DeviceDisconnectedHandler deviceDisconnectedHandler) { + this.deviceDisconnectedHandler = deviceDisconnectedHandler; + } + public void setEchoReplyTimeout(long echoReplyTimeout){ this.echoReplyTimeout = echoReplyTimeout; } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/OutboundQueueProviderImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/OutboundQueueProviderImpl.java index ac1a084fda..e86a9e9897 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/OutboundQueueProviderImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/connection/OutboundQueueProviderImpl.java @@ -40,13 +40,18 @@ public class OutboundQueueProviderImpl implements OutboundQueueProvider { @Override public synchronized void onConnectionQueueChanged(final OutboundQueue queue) { - LOG.debug("Replacing queue {} with {}", outboundQueue, queue); + if (LOG.isDebugEnabled()) { + LOG.debug("Replacing queue {} with {}", outboundQueue, queue); + } outboundQueue = queue; notifyAll(); } @Override public Long reserveEntry() { + if (LOG.isDebugEnabled()) { + LOG.debug("Reserve entry with queue: {} in this {} implementation", outboundQueue, this); + } for (;;) { OutboundQueue queue = outboundQueue; if (queue == null) { diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java index 44d67f18d6..c07b67aa91 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java @@ -141,11 +141,14 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi // Timeout in seconds after what we will give up on propagating role private static final int SET_ROLE_TIMEOUT = 10; + private static final int LOW_WATERMARK = 1000; + private static final int HIGH_WATERMARK = 2000; + private boolean initialized; private SalRoleService salRoleService = null; private final HashedWheelTimer hashedWheelTimer; - private ConnectionContext primaryConnectionContext; + private volatile ConnectionContext primaryConnectionContext; private final DeviceState deviceState; private final DataBroker dataBroker; private final Map auxiliaryConnectionContexts; @@ -153,7 +156,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi private DeviceFlowRegistry deviceFlowRegistry; private DeviceGroupRegistry deviceGroupRegistry; private DeviceMeterRegistry deviceMeterRegistry; - private final PacketInRateLimiter packetInLimiter; + private PacketInRateLimiter packetInLimiter; private final MessageSpy messageSpy; private final ItemLifeCycleKeeper flowLifeCycleKeeper; private NotificationPublishService notificationPublishService; @@ -166,7 +169,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi private ExtensionConverterProvider extensionConverterProvider; private boolean skipTableFeatures; private boolean switchFeaturesMandatory; - private final DeviceInfo deviceInfo; + private DeviceInfo deviceInfo; private final ConvertorExecutor convertorExecutor; private volatile CONTEXT_STATE state; private ClusterInitializationPhaseHandler clusterInitializationPhaseHandler; @@ -174,6 +177,8 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi private final DeviceInitializerProvider deviceInitializerProvider; private final boolean useSingleLayerSerialization; private Boolean isAddNotificationSent = false; + private OutboundQueueProvider outboundQueueProvider; + private boolean wasOnceMaster; DeviceContextImpl( @Nonnull final ConnectionContext primaryConnectionContext, @@ -188,6 +193,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi final DeviceInitializerProvider deviceInitializerProvider) { this.primaryConnectionContext = primaryConnectionContext; + this.outboundQueueProvider = (OutboundQueueProvider) primaryConnectionContext.getOutboundQueueProvider(); this.deviceInfo = primaryConnectionContext.getDeviceInfo(); this.hashedWheelTimer = hashedWheelTimer; this.deviceInitializerProvider = deviceInitializerProvider; @@ -198,7 +204,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi this.messageSpy = Preconditions.checkNotNull(messageSpy); this.packetInLimiter = new PacketInRateLimiter(primaryConnectionContext.getConnectionAdapter(), - /*initial*/ 1000, /*initial*/2000, this.messageSpy, REJECTED_DRAIN_FACTOR); + /*initial*/ LOW_WATERMARK, /*initial*/HIGH_WATERMARK, this.messageSpy, REJECTED_DRAIN_FACTOR); this.translatorLibrary = translatorLibrary; this.portStatusTranslator = translatorLibrary.lookupTranslator( @@ -216,6 +222,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi this.skipTableFeatures = skipTableFeatures; this.useSingleLayerSerialization = useSingleLayerSerialization; this.initialized = false; + this.wasOnceMaster = false; } @Override @@ -515,7 +522,9 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi public void onPublished() { Verify.verify(CONTEXT_STATE.INITIALIZATION.equals(getState())); this.state = CONTEXT_STATE.WORKING; - primaryConnectionContext.getConnectionAdapter().setPacketInFiltering(false); + synchronized (primaryConnectionContext) { + primaryConnectionContext.getConnectionAdapter().setPacketInFiltering(false); + } for (final ConnectionContext switchAuxConnectionContext : auxiliaryConnectionContexts.values()) { switchAuxConnectionContext.getConnectionAdapter().setPacketInFiltering(false); } @@ -596,31 +605,36 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi } @Override - public void replaceConnection(final ConnectionContext connectionContext) { + public synchronized void replaceConnection(final ConnectionContext connectionContext) { + + primaryConnectionContext = null; + deviceInfo = null; + packetInLimiter = null; + + primaryConnectionContext = connectionContext; + deviceInfo = primaryConnectionContext.getDeviceInfo(); - connectionContext.getConnectionAdapter().setPacketInFiltering(true); + packetInLimiter = new PacketInRateLimiter(primaryConnectionContext.getConnectionAdapter(), + /*initial*/ LOW_WATERMARK, /*initial*/HIGH_WATERMARK, messageSpy, REJECTED_DRAIN_FACTOR); - final OutboundQueueProvider outboundQueueProvider - = new OutboundQueueProviderImpl(connectionContext.getDeviceInfo().getVersion()); + primaryConnectionContext.setOutboundQueueProvider(outboundQueueProvider); - connectionContext.setOutboundQueueProvider(outboundQueueProvider); final OutboundQueueHandlerRegistration outboundQueueHandlerRegistration = - connectionContext.getConnectionAdapter().registerOutboundQueueHandler( + primaryConnectionContext.getConnectionAdapter().registerOutboundQueueHandler( outboundQueueProvider, - this.myManager.getBarrierCountLimit(), - this.myManager.getBarrierIntervalNanos()); - connectionContext.setOutboundQueueHandleRegistration(outboundQueueHandlerRegistration); + myManager.getBarrierCountLimit(), + myManager.getBarrierIntervalNanos()); - this.salRoleService = new SalRoleServiceImpl(this, this); + primaryConnectionContext.setOutboundQueueHandleRegistration(outboundQueueHandlerRegistration); final OpenflowProtocolListenerFullImpl messageListener = new OpenflowProtocolListenerFullImpl( - connectionContext.getConnectionAdapter(), this); + primaryConnectionContext.getConnectionAdapter(), this); - connectionContext.getConnectionAdapter().setMessageListener(messageListener); + primaryConnectionContext.getConnectionAdapter().setMessageListener(messageListener); LOG.info("ConnectionEvent: Connection on device:{}, NodeId:{} switched.", - connectionContext.getConnectionAdapter().getRemoteAddress(), - connectionContext.getDeviceInfo().getNodeId()); + primaryConnectionContext.getConnectionAdapter().getRemoteAddress(), + primaryConnectionContext.getDeviceInfo().getNodeId()); } @@ -661,15 +675,9 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi } }); - return Futures.transform(deactivateTxManagerFuture, (AsyncFunction) aVoid -> { - // Add fallback to remove device from operational DS if setting slave fails - return Futures.withFallback(makeSlaveFuture, t -> - myManager.removeDeviceFromOperationalDS(deviceInfo)); - }); - } else { - return Futures.transform(deactivateTxManagerFuture, (AsyncFunction) aVoid -> - myManager.removeDeviceFromOperationalDS(deviceInfo)); } + + return deactivateTxManagerFuture; } @Override @@ -722,13 +730,12 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi } @Override - public boolean onContextInstantiateService(final MastershipChangeListener mastershipChangeListener) { + public void masterSuccessful(){ + this.wasOnceMaster = true; + } - if (getPrimaryConnectionContext().getConnectionState().equals(ConnectionContext.CONNECTION_STATE.RIP)) { - LOG.warn("Connection on device {} was interrupted, will stop starting master services.", - deviceInfo.getLOGValue()); - return false; - } + @Override + public boolean onContextInstantiateService(final MastershipChangeListener mastershipChangeListener) { LOG.info("Starting device context cluster services for node {}", deviceInfo.getLOGValue()); diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java index 1c4428aca6..b267d115f5 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImpl.java @@ -77,7 +77,6 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi private final DeviceInitializerProvider deviceInitializerProvider; private final ConvertorExecutor convertorExecutor; private TranslatorLibrary translatorLibrary; - private DeviceInitializationPhaseHandler deviceInitPhaseHandler; private DeviceTerminationPhaseHandler deviceTerminPhaseHandler; private final ConcurrentMap deviceContexts = new ConcurrentHashMap<>(); @@ -140,7 +139,6 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi @Override public void setDeviceInitializationPhaseHandler(final DeviceInitializationPhaseHandler handler) { - this.deviceInitPhaseHandler = handler; } @Override @@ -152,11 +150,6 @@ public class DeviceManagerImpl implements DeviceManager, ExtensionConverterProvi lifecycleService.registerDeviceRemovedHandler(this); } - @Override - public ConnectionStatus deviceConnected(@CheckForNull final ConnectionContext connectionContext) throws Exception { - return ConnectionStatus.MAY_CONTINUE; - } - @Override public TranslatorLibrary oook() { return translatorLibrary; diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java index 8fe1a89dd0..5cde6fc507 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java @@ -13,8 +13,10 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import javax.annotation.Nonnull; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import javax.annotation.Nullable; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.openflowplugin.api.openflow.OFPManager; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; @@ -31,8 +33,6 @@ import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.ContextChainState; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.openflow.provider.config.ContextChainConfig; -import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput; -import org.opendaylight.yangtools.yang.common.RpcResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -134,15 +134,21 @@ public class ContextChainHolderImpl implements ContextChainHolder { ContextChain chain = contextChainMap.get(deviceInfo); if (Objects.nonNull(chain)) { chain.close(); + try { + deviceManager.removeDeviceFromOperationalDS(deviceInfo).checkedGet(5L, TimeUnit.SECONDS); + } catch (TimeoutException | TransactionCommitFailedException e) { + LOG.warn("Not able to remove device {} from DS", deviceInfo.getLOGValue()); + } } } @Override public void pairConnection(final ConnectionContext connectionContext) { DeviceInfo deviceInfo = connectionContext.getDeviceInfo(); - latestConnections.put(deviceInfo, connectionContext); - if (checkChainContext(deviceInfo)) { - contextChainMap.get(deviceInfo).changePrimaryConnection(connectionContext); + ContextChain contextChain = contextChainMap.get(deviceInfo); + if (Objects.nonNull(contextChain)) { + contextChain.changePrimaryConnection(connectionContext); + contextChain.makeDeviceSlave(); } } @@ -175,7 +181,7 @@ public class ContextChainHolderImpl implements ContextChainHolder { if (Objects.nonNull(contextChain)) { LOG.warn("Not able to set MASTER role on device {}", deviceInfo.getLOGValue()); if (contextChain.getContextChainState().equals(ContextChainState.INITIALIZED)) { - contextChain.getPrimaryConnectionContext().closeConnection(false); + contextChain.closePrimaryConnection(); } else { contextChain.sleepTheChainAndDropConnection(); } @@ -196,7 +202,8 @@ public class ContextChainHolderImpl implements ContextChainHolder { LOG.info("Device {} has not finish initial gathering yet.", deviceInfo.getLOGValue()); } - contextChain.startChain(); + Futures.addCallback(contextChain.startChain(), + new StartStopChainCallback(contextChain.provideDeviceContext(), false)); } } } @@ -205,11 +212,13 @@ public class ContextChainHolderImpl implements ContextChainHolder { public void onSlaveRoleAcquired(final DeviceInfo deviceInfo) { ContextChain contextChain = contextChainMap.get(deviceInfo); if (Objects.nonNull(contextChain)) { - if (contextChain.getContextChainState().equals(ContextChainState.INITIALIZED)) { - contextChain.registerServices(this.singletonServicesProvider); - } else { - contextChain.stopChain(); - } +// if (contextChain.getContextChainState().equals(ContextChainState.INITIALIZED)) { +// contextChain.registerServices(this.singletonServicesProvider); +// } else { +// Futures.addCallback(contextChain.stopChain(false), +// new StartStopChainCallback(contextChain.provideDeviceContext(), true)); +// } + contextChain.registerServices(this.singletonServicesProvider); } } @@ -221,6 +230,26 @@ public class ContextChainHolderImpl implements ContextChainHolder { } } + @Override + public void onDeviceDisconnected(final ConnectionContext connectionContext) { + + if (Objects.isNull(connectionContext.getDeviceInfo())) { + LOG.info("Non existing device info. Cannot close context chain."); + } else { + LOG.info("Device {} disconnected.", connectionContext.getDeviceInfo().getLOGValue()); + ContextChain chain = contextChainMap.get(connectionContext.getDeviceInfo()); + if (Objects.isNull(chain)) { + if (LOG.isDebugEnabled()) { + LOG.debug("There was no context chain created yet for the disconnected device {}", + connectionContext.getDeviceInfo().getLOGValue()); + } + } else { + Futures.addCallback(chain.connectionDropped(), + new StartStopChainCallback(null, true)); + } + } + } + private boolean checkAllManagers() { return Objects.nonNull(deviceManager) && Objects.nonNull(rpcManager) && Objects.nonNull(statisticsManager); } @@ -229,4 +258,35 @@ public class ContextChainHolderImpl implements ContextChainHolder { return contextChainMap.containsKey(deviceInfo); } + private class StartStopChainCallback implements FutureCallback { + + private final String deviceInfo; + private final String stop; + private final String stopped; + private final boolean start; + private final DeviceContext deviceContext; + + StartStopChainCallback(final DeviceContext deviceContext, final boolean stop) { + + this.deviceInfo = Objects.nonNull(deviceContext) ? deviceContext.getDeviceInfo().getLOGValue() : "null"; + this.stop = stop ? "stop" : "start"; + this.stopped = stop ? "stopped" : "started"; + this.start = !stop; + this.deviceContext = deviceContext; + } + + @Override + public void onSuccess(@Nullable Void aVoid) { + LOG.info("Context chain for device {} successfully {}", deviceInfo, stopped); +// if (start && Objects.nonNull(deviceContext)) { +// deviceContext.masterSuccessful(); +// } + } + + @Override + public void onFailure(Throwable throwable) { + LOG.warn("Not able to {} the context chain for device {}", stop, deviceInfo); + } + } + } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java index 886e3b03f5..c43e759e77 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java @@ -71,12 +71,12 @@ public class ContextChainImpl implements ContextChain { } @Override - public ListenableFuture stopChain() { + public ListenableFuture stopChain(boolean connectionDropped) { //TODO: stopClusterServices change parameter final List> futureList = new ArrayList<>(); - futureList.add(statisticsContext.stopClusterServices(true)); - futureList.add(rpcContext.stopClusterServices(false)); - futureList.add(deviceContext.stopClusterServices(false)); + futureList.add(statisticsContext.stopClusterServices()); + futureList.add(rpcContext.stopClusterServices()); + futureList.add(deviceContext.stopClusterServices(connectionDropped)); return Futures.transform(Futures.successfulAsList(futureList), new Function, Void>() { @Nullable @@ -113,10 +113,11 @@ public class ContextChainImpl implements ContextChain { @Override public void changePrimaryConnection(final ConnectionContext connectionContext) { + this.primaryConnectionContext = connectionContext; + this.contextChainState = ContextChainState.INITIALIZED; for (OFPContext context : contexts) { context.replaceConnection(connectionContext); } - this.primaryConnectionContext = connectionContext; } @Override @@ -129,7 +130,7 @@ public class ContextChainImpl implements ContextChain { ContextChainState oldState = this.contextChainState; this.contextChainState = ContextChainState.SLEEPING; if (oldState.equals(ContextChainState.WORKINGMASTER)) { - return this.stopChain(); + return this.stopChain(true); } return Futures.immediateFuture(null); } @@ -142,7 +143,7 @@ public class ContextChainImpl implements ContextChain { @Override public void sleepTheChainAndDropConnection() { this.contextChainState = ContextChainState.SLEEPING; - this.primaryConnectionContext.closeConnection(false); + this.primaryConnectionContext.closeConnection(true); } @Override @@ -160,4 +161,13 @@ public class ContextChainImpl implements ContextChain { this.lifecycleService.makeDeviceSlave(this.deviceContext); } + @Override + public void closePrimaryConnection() { + this.primaryConnectionContext.closeConnection(true); + } + + @Override + public DeviceContext provideDeviceContext() { + return this.deviceContext; + } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java index c188c65a8e..2820bd4012 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/rpc/RpcContextImpl.java @@ -87,12 +87,15 @@ class RpcContextImpl implements RpcContext { @Override public void registerRpcServiceImplementation(final Class serviceClass, final S serviceInstance) { - LOG.trace("Try to register service {} for device {}.", serviceClass, nodeInstanceIdentifier); if (! rpcRegistrations.containsKey(serviceClass)) { final RoutedRpcRegistration routedRpcReg = rpcProviderRegistry.addRoutedRpcImplementation(serviceClass, serviceInstance); routedRpcReg.registerPath(NodeContext.class, nodeInstanceIdentifier); rpcRegistrations.put(serviceClass, routedRpcReg); - LOG.debug("Registration of service {} for device {}.", serviceClass.getSimpleName(), nodeInstanceIdentifier.getKey().getId().getValue()); + if (LOG.isDebugEnabled()) { + LOG.debug("Registration of service {} for device {}.", + serviceClass.getSimpleName(), + nodeInstanceIdentifier.getKey().getId().getValue()); + } } } @@ -116,7 +119,7 @@ class RpcContextImpl implements RpcContext { } } else { try { - stopClusterServices(true).get(); + stopClusterServices().get(); } catch (Exception e) { LOG.debug("Failed to close RpcContext for node {} with exception: ", getDeviceInfo().getLOGValue(), e); } @@ -189,8 +192,8 @@ class RpcContextImpl implements RpcContext { } @Override - public ListenableFuture stopClusterServices(boolean connectionInterrupted) { - if (CONTEXT_STATE.TERMINATION.equals(getState())) { + public ListenableFuture stopClusterServices() { + if (CONTEXT_STATE.TERMINATION.equals(this.state)) { return Futures.immediateCancelledFuture(); } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java index 5a608d1aa1..d955274769 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/statistics/StatisticsContextImpl.java @@ -458,8 +458,8 @@ class StatisticsContextImpl implements StatisticsContext { } @Override - public ListenableFuture stopClusterServices(boolean connectionInterrupted) { - if (CONTEXT_STATE.TERMINATION.equals(getState())) { + public ListenableFuture stopClusterServices() { + if (CONTEXT_STATE.TERMINATION.equals(this.state)) { return Futures.immediateCancelledFuture(); } diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImplTest.java index 08243d9f5a..b5364e4559 100644 --- a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImplTest.java +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImplTest.java @@ -29,7 +29,6 @@ import io.netty.util.Timeout; import java.math.BigInteger; import java.net.InetSocketAddress; import java.util.concurrent.atomic.AtomicLong; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImplTest.java index e4bd778066..c46d13946e 100644 --- a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImplTest.java +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/device/DeviceManagerImplTest.java @@ -10,7 +10,6 @@ package org.opendaylight.openflowplugin.impl.device; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -21,14 +20,11 @@ import com.google.common.util.concurrent.Futures; import io.netty.util.HashedWheelTimer; import java.lang.reflect.Field; import java.math.BigInteger; -import java.util.Collections; import java.util.concurrent.ConcurrentHashMap; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.InOrder; import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; @@ -48,16 +44,13 @@ import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueueHandle import org.opendaylight.openflowplugin.api.OFConstants; import org.opendaylight.openflowplugin.api.openflow.OFPContext; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; -import org.opendaylight.openflowplugin.api.openflow.connection.OutboundQueueProvider; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.DeviceState; -import org.opendaylight.openflowplugin.api.openflow.device.MessageTranslator; import org.opendaylight.openflowplugin.api.openflow.device.TranslatorLibrary; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceTerminationPhaseHandler; import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; -import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey; import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency; import org.opendaylight.openflowplugin.impl.device.initialization.DeviceInitializerProviderFactory; import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor; @@ -69,7 +62,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev13 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; -import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.features.reply.PhyPortBuilder; import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier; @RunWith(MockitoJUnitRunner.class) -- 2.36.6