X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=openflowplugin-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fimpl%2Flifecycle%2FContextChainImpl.java;h=b5894b5705b4e7fb51e8c17e51f6bea412b420dd;hb=2e76db6b47cf358727f267fe74a1b0b2a6d4d001;hp=dfc6d67c0558418a1c9907424a6049f44ed4e225;hpb=c373ae004e9e04a40ea9c3a7d7476fdf47faee09;p=openflowplugin.git 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 dfc6d67c05..b5894b5705 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 @@ -7,51 +7,207 @@ */ package org.opendaylight.openflowplugin.impl.lifecycle; -import java.util.HashSet; +import com.google.common.base.Function; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import io.netty.util.internal.ConcurrentSet; +import java.util.ArrayList; +import java.util.List; import java.util.Set; -import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChain; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.ContextChainState; +import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainMastershipState; +import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainState; +import org.opendaylight.openflowplugin.api.openflow.lifecycle.LifecycleService; +import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext; +import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ContextChainImpl implements ContextChain { - private Set contexts = new HashSet<>(); - private final ContextChainState contextChainState; - private ConnectionContext primaryConnectionContext; + private static final Logger LOG = LoggerFactory.getLogger(ContextChainImpl.class); - public ContextChainImpl(final ContextChainState contextChainState) { - this.contextChainState = contextChainState; + private Set contexts = new ConcurrentSet<>(); + private StatisticsContext statisticsContext; + private DeviceContext deviceContext; + private RpcContext rpcContext; + private LifecycleService lifecycleService; + private DeviceInfo deviceInfo; + private ConnectionContext primaryConnection; + private Set auxiliaryConnections = new ConcurrentSet<>(); + + private volatile ContextChainState contextChainState; + + private AtomicBoolean masterStateOnDevice; + private AtomicBoolean initialGathering; + private AtomicBoolean initialSubmitting; + private AtomicBoolean registryFilling; + + ContextChainImpl(final ConnectionContext connectionContext) { + this.primaryConnection = connectionContext; + this.contextChainState = ContextChainState.UNDEFINED; + this.masterStateOnDevice = new AtomicBoolean(false); + this.initialGathering = new AtomicBoolean(false); + this.initialSubmitting = new AtomicBoolean(false); + this.registryFilling = new AtomicBoolean(false); + this.deviceInfo = connectionContext.getDeviceInfo(); } @Override - public boolean isReady() { - return false; + public void addContext(final T context) { + if (context instanceof StatisticsContext) { + this.statisticsContext = (StatisticsContext) context; + } else { + if (context instanceof DeviceContext) { + this.deviceContext = (DeviceContext) context; + } else { + if (context instanceof RpcContext) { + this.rpcContext = (RpcContext) context; + } + } + } + contexts.add(context); } @Override - public void addContext(final T context) { + public void addLifecycleService(final LifecycleService lifecycleService) { + this.lifecycleService = lifecycleService; + } + @Override + public ListenableFuture stopChain() { + //TODO: stopClusterServices change parameter + final List> futureList = new ArrayList<>(); + futureList.add(statisticsContext.stopClusterServices()); + futureList.add(rpcContext.stopClusterServices()); + futureList.add(deviceContext.stopClusterServices()); + this.unMasterMe(); + return Futures.transform(Futures.successfulAsList(futureList), new Function, Void>() { + @Nullable + @Override + public Void apply(@Nullable List input) { + LOG.info("Closed clustering MASTER services for node {}", deviceContext.getDeviceInfo().getLOGValue()); + return null; + } + }); + } + + private void unMasterMe() { + this.registryFilling.set(false); + this.initialSubmitting.set(false); + this.initialGathering.set(false); + this.masterStateOnDevice.set(false); } @Override - public Future stopChain() { - return null; + public void close() { + this.auxiliaryConnections.forEach(connectionContext -> connectionContext.closeConnection(false)); + if (this.primaryConnection.getConnectionState() != ConnectionContext.CONNECTION_STATE.RIP) { + this.primaryConnection.closeConnection(true); + } + lifecycleService.close(); + deviceContext.close(); + rpcContext.close(); + statisticsContext.close(); } @Override - public Future startChain() { - return null; + public void makeContextChainStateSlave() { + this.unMasterMe(); + this.contextChainState = ContextChainState.WORKING_SLAVE; } @Override - public void close() { + public ListenableFuture connectionDropped() { + if (this.contextChainState == ContextChainState.WORKING_MASTER) { + return this.stopChain(); + } + this.unMasterMe(); + return Futures.immediateFuture(null); + } + + @Override + public void registerServices(final ClusterSingletonServiceProvider clusterSingletonServiceProvider) { + this.lifecycleService.registerService( + clusterSingletonServiceProvider, + this.deviceContext); + } + + @Override + public void makeDeviceSlave() { + this.unMasterMe(); + this.lifecycleService.makeDeviceSlave(this.deviceContext); + } + + @Override + public boolean isMastered(@Nonnull ContextChainMastershipState mastershipState) { + switch (mastershipState) { + case INITIAL_SUBMIT: + LOG.debug("Device {}, initial submit OK.", deviceInfo.getLOGValue()); + this.initialSubmitting.set(true); + break; + case MASTER_ON_DEVICE: + LOG.debug("Device {}, master state OK.", deviceInfo.getLOGValue()); + this.masterStateOnDevice.set(true); + break; + case INITIAL_GATHERING: + LOG.debug("Device {}, initial gathering OK.", deviceInfo.getLOGValue()); + this.initialGathering.set(true); + break; + //Flow registry fill is not mandatory to work as a master + case INITIAL_FLOW_REGISTRY_FILL: + LOG.debug("Device {}, initial registry filling OK.", deviceInfo.getLOGValue()); + this.registryFilling.set(true); + case CHECK: + default: + } + final boolean result = + this.initialGathering.get() && + this.masterStateOnDevice.get() && + this.initialSubmitting.get(); + if (result && mastershipState != ContextChainMastershipState.CHECK) { + LOG.info("Device {} is able to work as master{}", + deviceInfo.getLOGValue(), + this.registryFilling.get() ? " WITHOUT flow registry !!!" : "."); + contextChainState = ContextChainState.WORKING_MASTER; + } + return result; + } + + @Override + public boolean hasState() { + return contextChainState == ContextChainState.WORKING_MASTER + || contextChainState == ContextChainState.WORKING_SLAVE; + } + + @Override + public boolean addAuxiliaryConnection(@Nonnull ConnectionContext connectionContext) { + if (this.primaryConnection.getConnectionState() != ConnectionContext.CONNECTION_STATE.RIP) { + this.auxiliaryConnections.add(connectionContext); + return true; + } else { + return false; + } } @Override - public void changePrimaryConnection(final ConnectionContext connectionContext) { - this.primaryConnectionContext = connectionContext; + public boolean auxiliaryConnectionDropped(@Nonnull ConnectionContext connectionContext) { + if (this.auxiliaryConnections.isEmpty()) { + return false; + } + if (!this.auxiliaryConnections.contains(connectionContext)) { + return false; + } + this.auxiliaryConnections.remove(connectionContext); + return true; } }