1. Created a Role manager and RoleContext which would get invoked as part of the device init phase
2. Introduced dependency to EntityOwnership service , to get the ownership (implemented in controller)
4. RoleManager requests ownership from EntityOwnership and on notification makes a role change call SalRoleService
5. SalRoleService makes a role change to the device
6. Tests
Change-Id: Ie443d519be985b867d5c6f9ce8473fbd6cdf4dca
Signed-off-by: Kamal Rameshan <kramesha@cisco.com>
Signed-off-by: Moiz Raja <moraja@cisco.com>
<feature version="${project.version}">odl-openflowplugin-nsf-services-li</feature>
<feature version="${openflowjava.version}">odl-openflowjava-protocol</feature>
<bundle>mvn:org.opendaylight.openflowplugin/openflowplugin-common/{{VERSION}}</bundle>
+ <bundle>mvn:org.opendaylight.openflowplugin/openflowplugin-api/{{VERSION}}</bundle>
<!-- TODO : remove dependency on openflowplugin in the future -->
<bundle>mvn:org.opendaylight.openflowplugin/openflowplugin/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.openflowplugin/openflowplugin-impl/{{VERSION}}</bundle>
- <bundle>mvn:org.opendaylight.openflowplugin/openflowplugin-api/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.openflowplugin/openflowplugin-extension-api/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.controller/liblldp/{{VERSION}}</bundle>
<configfile finalname="etc/opendaylight/karaf/42-openflowplugin-Li.xml">mvn:org.opendaylight.openflowplugin/openflowplugin-controller-config/{{VERSION}}/xml/config-Li</configfile>
<groupId>org.opendaylight.openflowjava</groupId>
<artifactId>openflow-protocol-spi</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-api</artifactId>
+ </dependency>
</dependencies>
</project>
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.RpcProviderRegistry;
import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
void setIsStatisticsPollingOff(final boolean isStatisticsPollingOff);
+ void setEntityOwnershipService(EntityOwnershipService entityOwnershipService);
+
}
import org.opendaylight.openflowplugin.api.openflow.registry.flow.DeviceFlowRegistry;
import org.opendaylight.openflowplugin.api.openflow.registry.group.DeviceGroupRegistry;
import org.opendaylight.openflowplugin.api.openflow.registry.meter.DeviceMeterRegistry;
+import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReply;
import org.opendaylight.yangtools.yang.binding.DataObject;
* @return registry point for item life cycle sources of device
*/
ItemLifeCycleRegistry getItemLifeCycleSourceRegistry();
+
+ void setRpcContext(RpcContext rpcContext);
+
+ RpcContext getRpcContext();
+
+ /**
+ * Callback when confirmed that device is disconnected from cluster
+ */
+ void onDeviceDisconnectedFromCluster();
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
/**
void setDeviceSynchronized(boolean deviceSynchronized);
+ void setRole(OfpRole ofpRole);
+
+ OfpRole getRole();
+
}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.api.openflow.role;
+
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
+
+/**
+ * Created by kramesha on 9/19/15.
+ */
+public interface RoleChangeListener extends AutoCloseable {
+ /**
+ * Gets called by the EntityOwnershipCandidate after role change received from EntityOwnershipService
+ * @param oldRole
+ * @param newRole
+ */
+ void onRoleChanged(OfpRole oldRole, OfpRole newRole);
+
+ Entity getEntity();
+
+ void onDeviceDisconnectedFromCluster();
+
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.api.openflow.role;
+
+import com.google.common.util.concurrent.FutureCallback;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceContextClosedHandler;
+
+/**
+ * Created by kramesha on 9/12/15.
+ */
+public interface RoleContext extends RoleChangeListener, DeviceContextClosedHandler, RequestContextStack {
+
+ void facilitateRoleChange(FutureCallback<Boolean> futureCallback);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.api.openflow.role;
+
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializator;
+
+/**
+ * Created by kramesha on 8/31/15.
+ */
+public interface RoleManager extends DeviceInitializator, DeviceInitializationPhaseHandler, AutoCloseable {
+ public static final String ENTITY_TYPE = "openflow";
+}
* <p>
* Created by Martin Bobak <mbobak@cisco.com> on 25.2.2015.
*/
-public interface RpcManager extends DeviceInitializator, DeviceInitializationPhaseHandler {
+public interface RpcManager extends DeviceInitializator, DeviceInitializationPhaseHandler, AutoCloseable {
}
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-new-notification-publish-service</type>
<name>binding-notification-publish-adapter</name>
</notification-publish-adapter>
+ <entity-ownership-service>
+ <type xmlns:entity-ownership="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:entity-ownership-service">entity-ownership:entity-ownership-service</type>
+ <name>entity-ownership-service</name>
+ </entity-ownership-service>
<rpc-requests-quota>20000</rpc-requests-quota>
<switch-features-mandatory>false</switch-features-mandatory>
<global-notification-quota>64000</global-notification-quota>
<groupId>org.opendaylight.openflowjava</groupId>
<artifactId>openflowjava-util</artifactId>
</dependency>
-
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-api</artifactId>
+ </dependency>
</dependencies>
</project>
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.RpcProviderRegistry;
import org.opendaylight.openflowjava.protocol.spi.connection.SwitchConnectionProvider;
import org.opendaylight.openflowplugin.api.openflow.OpenFlowPluginProvider;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionManager;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
+import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
import org.opendaylight.openflowplugin.api.openflow.rpc.RpcManager;
import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager;
import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency;
import org.opendaylight.openflowplugin.extension.api.OpenFlowPluginExtensionRegistratorProvider;
import org.opendaylight.openflowplugin.impl.connection.ConnectionManagerImpl;
import org.opendaylight.openflowplugin.impl.device.DeviceManagerImpl;
+import org.opendaylight.openflowplugin.impl.role.RoleManagerImpl;
import org.opendaylight.openflowplugin.impl.rpc.RpcManagerImpl;
import org.opendaylight.openflowplugin.impl.statistics.StatisticsManagerImpl;
import org.opendaylight.openflowplugin.impl.statistics.ofpspecific.MessageIntelligenceAgencyImpl;
private final int rpcRequestsQuota;
private final long globalNotificationQuota;
private DeviceManager deviceManager;
+ private RoleManager roleManager;
private RpcManager rpcManager;
private RpcProviderRegistry rpcProviderRegistry;
private StatisticsManager statisticsManager;
private ConnectionManager connectionManager;
private NotificationService notificationProviderService;
private NotificationPublishService notificationPublishService;
+ private EntityOwnershipService entityOwnershipService;
private ExtensionConverterManager extensionConverterManager;
return switchFeaturesMandatory;
}
+ @Override
+ public void setEntityOwnershipService(EntityOwnershipService entityOwnershipService) {
+ this.entityOwnershipService = entityOwnershipService;
+ }
+
public void setSwitchFeaturesMandatory(final boolean switchFeaturesMandatory) {
this.switchFeaturesMandatory = switchFeaturesMandatory;
}
registerMXBean(messageIntelligenceAgency);
deviceManager = new DeviceManagerImpl(dataBroker, messageIntelligenceAgency, switchFeaturesMandatory, globalNotificationQuota);
+ roleManager = new RoleManagerImpl(rpcProviderRegistry, entityOwnershipService);
statisticsManager = new StatisticsManagerImpl(rpcProviderRegistry, isStatisticsPollingOff);
rpcManager = new RpcManagerImpl(rpcProviderRegistry, rpcRequestsQuota);
+ // CM -> DM -> Role -> SM -> RPC -> DM
connectionManager.setDeviceConnectedHandler(deviceManager);
- deviceManager.setDeviceInitializationPhaseHandler(statisticsManager);
- deviceManager.setNotificationService(this.notificationProviderService);
- deviceManager.setNotificationPublishService(this.notificationPublishService);
+ deviceManager.setDeviceInitializationPhaseHandler(roleManager);
+ roleManager.setDeviceInitializationPhaseHandler(statisticsManager);
statisticsManager.setDeviceInitializationPhaseHandler(rpcManager);
rpcManager.setDeviceInitializationPhaseHandler(deviceManager);
+ deviceManager.setNotificationService(this.notificationProviderService);
+ deviceManager.setNotificationPublishService(this.notificationPublishService);
+
TranslatorLibraryUtil.setBasicTranslatorLibrary(deviceManager);
deviceManager.initialize();
@Override
public void close() throws Exception {
//TODO: close all contexts, switchConnections (, managers)
+ rpcManager.close();
+ statisticsManager.close();
+ roleManager.close();
}
}
import org.opendaylight.openflowplugin.api.openflow.registry.group.DeviceGroupRegistry;
import org.opendaylight.openflowplugin.api.openflow.registry.meter.DeviceMeterRegistry;
import org.opendaylight.openflowplugin.api.openflow.rpc.ItemLifeCycleKeeper;
+import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
import org.opendaylight.openflowplugin.api.openflow.rpc.listener.ItemLifecycleListener;
import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
import org.opendaylight.openflowplugin.impl.common.ItemLifeCycleSourceImpl;
private final TranslatorLibrary translatorLibrary;
private Map<Long, NodeConnectorRef> nodeConnectorCache;
private ItemLifeCycleRegistry itemLifeCycleSourceRegistry;
-
+ private RpcContext rpcContext;
@VisibleForTesting
DeviceContextImpl(@Nonnull final ConnectionContext primaryConnectionContext,
transactionChainManager.initialSubmitWriteTransaction();
}
+ /**
+ * This method is called fron
+ */
+ void cancelTransaction() {
+ transactionChainManager.cancelWriteTransaction();
+ }
+
@Override
public Long getReservedXid() {
return outboundQueueProvider.reserveEntry();
deviceContextClosedHandler.onDeviceContextClosed(this);
}
+ LOG.info("Closing transaction chain manager without cleaning inventory operational");
+ transactionChainManager.closeWithoutCleanup();
+ }
+
+ @Override
+ public void onDeviceDisconnectedFromCluster() {
+ LOG.info("Removing device from operational and closing transaction Manager for device:{}", getDeviceState().getNodeId());
transactionChainManager.close();
}
public ItemLifeCycleRegistry getItemLifeCycleSourceRegistry() {
return itemLifeCycleSourceRegistry;
}
+
+ @Override
+ public void setRpcContext(RpcContext rpcContext) {
+ this.rpcContext = rpcContext;
+ }
+
+ @Override
+ public RpcContext getRpcContext() {
+ return rpcContext;
+ }
+
+
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsData;
import org.opendaylight.yang.gen.v1.urn.opendaylight.port.statistics.rev131214.FlowCapableNodeConnectorStatisticsDataBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.table.features.TableFeatures;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
// final phase - we have to add new Device to MD-SAL DataStore
Preconditions.checkNotNull(deviceContext);
try {
- ((DeviceContextImpl) deviceContext).initialSubmitTransaction();
- deviceContext.onPublished();
+
+ if (deviceContext.getDeviceState().getRole() != OfpRole.BECOMESLAVE) {
+ ((DeviceContextImpl) deviceContext).initialSubmitTransaction();
+ deviceContext.onPublished();
+ } else {
+ ((DeviceContextImpl) deviceContext).cancelTransaction();
+ }
+
} catch (final Exception e) {
LOG.warn("Node {} can not be add to OPERATIONAL DataStore yet because {} ", deviceContext.getDeviceState().getNodeId(), e.getMessage());
LOG.trace("Problem with add node {} to OPERATIONAL DataStore", deviceContext.getDeviceState().getNodeId(), e);
DeviceTransactionChainManagerProvider.TransactionChainManagerRegistration transactionChainManagerRegistration = deviceTransactionChainManagerProvider.provideTransactionChainManager(connectionContext);
TransactionChainManager transactionChainManager = transactionChainManagerRegistration.getTransactionChainManager();
- //this actually is new registration for currently processed connection context
if (transactionChainManagerRegistration.ownedByInvokingConnectionContext()) {
+ //this actually is new registration for currently processed connection context
initializeDeviceContext(connectionContext, transactionChainManager);
}
- //this means there already exists connection described by same NodeId and it is not current connection contexts' registration
else if (TransactionChainManager.TransactionChainManagerStatus.WORKING.equals(transactionChainManager.getTransactionChainManagerStatus())) {
+ //this means there already exists connection described by same NodeId and it is not current connection contexts' registration
+ LOG.info("In deviceConnected, ownedByInvokingConnectionContext is false and TransactionChainManagerStatus.WORKING. Closing connection to device to start again.");
connectionContext.closeConnection(false);
}
- //previous connection is shutting down, we will try to register handler listening on new transaction chain ready
else if (!transactionChainManager.attemptToRegisterHandler(readyForNewTransactionChainHandler)) {
+ //previous connection is shutting down, we will try to register handler listening on new transaction chain ready
// new connection wil be closed if handler registration fails
+ LOG.info("In deviceConnected, ownedByInvokingConnectionContext is false, TransactionChainManagerStatus is not shutting down or readyForNewTransactionChainHandler is null. " +
+ "Closing connection to device to start again.");
connectionContext.closeConnection(false);
}
}
void deviceCtxLevelUp(final DeviceContext deviceContext) {
deviceContext.getDeviceState().setValid(true);
- deviceInitPhaseHandler.onDeviceContextLevelUp(deviceContext);
LOG.trace("Device context level up called.");
+ deviceInitPhaseHandler.onDeviceContextLevelUp(deviceContext);
}
static void chainTableTrunkWriteOF10(final DeviceContext deviceContext, final ListenableFuture<List<RpcResult<List<MultipartReply>>>> deviceFeaturesFuture) {
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
/**
private boolean tableStatisticsAvailable;
private boolean portStatisticsAvailable;
private boolean queueStatisticsAvailable;
+ private volatile OfpRole role;
public DeviceStateImpl(@CheckForNull final FeaturesReply featuresReply, @Nonnull final NodeId nodeId) {
Preconditions.checkArgument(featuresReply != null);
deviceSynchronized = _deviceSynchronized;
}
+ @Override
+ public OfpRole getRole() {
+ return role;
+ }
+
+ @Override
+ public void setRole(OfpRole role) {
+ this.role = role;
+ }
}
return true;
}
+ public void cancelWriteTransaction() {
+ // there is no cancel txn in ping-pong broker. So we need to drop the chain and recreate it.
+ // since the chain is created per device, there won't be any other txns other than ones we created.
+ recreateTxChain();
+ }
+
<T extends DataObject> void addDeleteOperationTotTxChain(final LogicalDatastoreType store,
final InstanceIdentifier<T> path) {
final WriteTransaction writeTx = getTransactionSafely();
}
}
+
private WriteTransaction getTransactionSafely() {
if (wTx == null && !TransactionChainManagerStatus.SHUTTING_DOWN.equals(transactionChainManagerStatus)) {
synchronized (txLock) {
}
private void notifyReadyForNewTransactionChainAndCloseFactory() {
+ if(managerRegistration == null){
+ LOG.warn("managerRegistration is null");
+ return;
+ }
synchronized (this) {
try {
LOG.debug("Closing registration in manager.");
LOG.debug("Transaction chain factory closed.");
}
+ public void closeWithoutCleanup() {
+ LOG.debug("closing txChainManager without cleanup of node {} from operational DS.", nodeII);
+ synchronized (txLock) {
+ this.transactionChainManagerStatus = TransactionChainManagerStatus.SHUTTING_DOWN;
+ notifyReadyForNewTransactionChainAndCloseFactory();
+ wTx = null;
+ }
+ }
+
public enum TransactionChainManagerStatus {
WORKING, SHUTTING_DOWN;
}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.impl.role;
+
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.openflowplugin.api.openflow.role.RoleChangeListener;
+import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by kramesha on 9/14/15.
+ */
+public class OpenflowOwnershipListener implements EntityOwnershipListener, AutoCloseable {
+
+ private static final Logger LOG = LoggerFactory.getLogger(OpenflowOwnershipListener.class);
+
+ private EntityOwnershipService entityOwnershipService;
+ private EntityOwnershipListenerRegistration entityOwnershipListenerRegistration;
+ private Map<Entity, RoleChangeListener> roleChangeListenerMap = new ConcurrentHashMap<>();
+ private final Map<Entity, Boolean> ownershipMap = new ConcurrentHashMap<>();
+ private final ExecutorService roleChangeExecutor = Executors.newSingleThreadExecutor();
+
+ public OpenflowOwnershipListener(EntityOwnershipService entityOwnershipService) {
+ this.entityOwnershipService = entityOwnershipService;
+ }
+
+ public void init() {
+ entityOwnershipListenerRegistration = entityOwnershipService.registerListener(RoleManager.ENTITY_TYPE, this);
+ }
+
+ @Override
+ public void ownershipChanged(EntityOwnershipChange ownershipChange) {
+ LOG.debug("Received EntityOwnershipChange:{}", ownershipChange);
+
+ RoleChangeListener roleChangeListener = roleChangeListenerMap.get(ownershipChange.getEntity());
+
+ ownershipMap.put(ownershipChange.getEntity(), ownershipChange.isOwner());
+
+ if (roleChangeListener != null) {
+ LOG.debug("Found local entity:{}", ownershipChange.getEntity());
+
+ // if this was the master and entity does not have a master
+ if (ownershipChange.wasOwner() && !ownershipChange.isOwner() && !ownershipChange.hasOwner()) {
+ // possible the last node to be disconnected from device.
+ // eligible for the device to get deleted from inventory.
+ LOG.debug("Initiate removal from operational. Possibly the last node to be disconnected for :{}. ", ownershipChange);
+ ownershipMap.remove(ownershipChange.getEntity());
+ roleChangeListener.onDeviceDisconnectedFromCluster();
+
+ } else {
+ OfpRole newRole = ownershipChange.isOwner() ? OfpRole.BECOMEMASTER : OfpRole.BECOMESLAVE;
+ OfpRole oldRole = ownershipChange.wasOwner() ? OfpRole.BECOMEMASTER : OfpRole.BECOMESLAVE;
+ // send even if they are same. we do the check for duplicates in SalRoleService and maintain a lastKnownRole
+ roleChangeListener.onRoleChanged(oldRole, newRole);
+ }
+ }
+ }
+
+ public void registerRoleChangeListener(final RoleChangeListener roleChangeListener) {
+ roleChangeListenerMap.put(roleChangeListener.getEntity(), roleChangeListener);
+
+ final Entity entity = roleChangeListener.getEntity();
+ final OpenflowOwnershipListener self = this;
+
+ if(this.hasOwner(entity)) {
+ LOG.debug("An owner exist for entity {}", entity);
+ roleChangeExecutor.submit(new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ if(self.isOwner(entity)){
+ LOG.debug("Ownership is here for entity {} becoming master", entity);
+ roleChangeListener.onRoleChanged(OfpRole.BECOMEMASTER, OfpRole.BECOMEMASTER);
+ } else {
+ LOG.debug("Ownership is NOT here for entity {} becoming alave", entity);
+ roleChangeListener.onRoleChanged(OfpRole.BECOMESLAVE, OfpRole.BECOMESLAVE);
+
+ }
+
+ return null;
+ }
+ });
+ }
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (entityOwnershipListenerRegistration != null) {
+ entityOwnershipListenerRegistration.close();
+ }
+ }
+
+ private boolean hasOwner(Entity entity){
+ return ownershipMap.containsKey(entity);
+ }
+
+ private boolean isOwner(Entity entity){
+ if(hasOwner(entity)){
+ Boolean isOwner = ownershipMap.get(entity);
+ if(isOwner != null) {
+ return isOwner.booleanValue();
+ }
+ }
+
+ return false;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.impl.role;
+
+/**
+ * Created by kramesha on 8/21/15.
+ */
+public class RoleChangeException extends Exception {
+ private static final long serialVersionUID = -615991366447313972L;
+
+ /**
+ * default ctor
+ *
+ * @param message
+ */
+ public RoleChangeException(String message) {
+ super(message);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public RoleChangeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.impl.role;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import java.util.concurrent.Future;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
+import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
+import org.opendaylight.openflowplugin.impl.rpc.AbstractRequestContext;
+import org.opendaylight.openflowplugin.impl.services.SalRoleServiceImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
+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;
+
+/**
+ * Created by kramesha on 9/12/15.
+ */
+public class RoleContextImpl implements RoleContext {
+ private static final Logger LOG = LoggerFactory.getLogger(RoleContextImpl.class);
+
+ private EntityOwnershipService entityOwnershipService;
+ private EntityOwnershipCandidateRegistration entityOwnershipCandidateRegistration;
+ private final RpcProviderRegistry rpcProviderRegistry;
+ private DeviceContext deviceContext;
+ private Entity entity;
+ private OpenflowOwnershipListener openflowOwnershipListener;
+ private SalRoleService salRoleService;
+ private FutureCallback<Boolean> roleChangeCallback;
+
+
+ public RoleContextImpl(DeviceContext deviceContext, RpcProviderRegistry rpcProviderRegistry,
+ EntityOwnershipService entityOwnershipService, OpenflowOwnershipListener openflowOwnershipListener) {
+ this.entityOwnershipService = entityOwnershipService;
+ this.rpcProviderRegistry = rpcProviderRegistry;
+ this.deviceContext = deviceContext;
+ entity = new Entity(RoleManager.ENTITY_TYPE, deviceContext.getPrimaryConnectionContext().getNodeId().getValue());
+
+ this.openflowOwnershipListener = openflowOwnershipListener;
+ salRoleService = new SalRoleServiceImpl(this, deviceContext);
+
+ //make a call to entity ownership service and listen for notifications from the service
+ requestOpenflowEntityOwnership();
+ }
+
+ @Override
+ public void facilitateRoleChange(FutureCallback<Boolean> roleChangeCallback) {
+ this.roleChangeCallback = roleChangeCallback;
+ if (!isDeviceConnected()) {
+ throw new IllegalStateException(
+ "Device is disconnected. Giving up on Role Change:" + deviceContext.getDeviceState().getNodeId());
+ }
+ }
+
+ private void requestOpenflowEntityOwnership() {
+
+ LOG.debug("requestOpenflowEntityOwnership for entity {}", entity);
+ try {
+ entityOwnershipCandidateRegistration = entityOwnershipService.registerCandidate(entity);
+
+ // The role change listener must be registered after registering a candidate
+ openflowOwnershipListener.registerRoleChangeListener(this);
+ LOG.info("RoleContextImpl : Candidate registered with ownership service for device :{}", deviceContext.getPrimaryConnectionContext().getNodeId().getValue());
+ } catch (CandidateAlreadyRegisteredException e) {
+ // we can log and move for this error, as listener is present and role changes will be served.
+ LOG.error("Candidate - Entity already registered with Openflow candidate ", entity, e );
+ }
+ }
+
+ @Override
+ public void onRoleChanged(final OfpRole oldRole, final OfpRole newRole) {
+
+ // called notification thread from md-sal
+
+ LOG.debug("Role change received from ownership listener from {} to {} for device:{}", oldRole, newRole,
+ deviceContext.getPrimaryConnectionContext().getNodeId());
+
+ final SetRoleInput setRoleInput = (new SetRoleInputBuilder())
+ .setControllerRole(newRole)
+ .setNode(new NodeRef(deviceContext.getDeviceState().getNodeInstanceIdentifier()))
+ .build();
+
+ Future<RpcResult<SetRoleOutput>> setRoleOutputFuture = salRoleService.setRole(setRoleInput);
+
+ Futures.addCallback(JdkFutureAdapters.listenInPoolThread(setRoleOutputFuture), new FutureCallback<RpcResult<SetRoleOutput>>() {
+ @Override
+ public void onSuccess(RpcResult<SetRoleOutput> setRoleOutputRpcResult) {
+ LOG.debug("Rolechange {} successful made on switch :{}", newRole,
+ deviceContext.getPrimaryConnectionContext().getNodeId());
+ deviceContext.getDeviceState().setRole(newRole);
+ if (roleChangeCallback != null) {
+ roleChangeCallback.onSuccess(true);
+ }
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("Error in setRole {} for device {} ", newRole,
+ deviceContext.getPrimaryConnectionContext().getNodeId(), throwable);
+ if (roleChangeCallback != null) {
+ roleChangeCallback.onFailure(throwable);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void close() throws Exception {
+ if (entityOwnershipCandidateRegistration != null) {
+ LOG.debug("Closing EntityOwnershipCandidateRegistration for {}", entity);
+ LOG.error("Who called this close?????", new Throwable());
+ entityOwnershipCandidateRegistration.close();
+ }
+ }
+
+ @Override
+ public void onDeviceContextClosed(DeviceContext deviceContext) {
+ try {
+ LOG.debug("onDeviceContextClosed called");
+ this.close();
+ } catch (Exception e) {
+ LOG.error("Exception in onDeviceContextClosed of RoleContext", e);
+ }
+ }
+
+ @Override
+ public Entity getEntity() {
+ return entity;
+ }
+
+ @Override
+ public void onDeviceDisconnectedFromCluster() {
+ LOG.debug("Called onDeviceDisconnectedFromCluster in DeviceContext for entity:{}", entity);
+ deviceContext.onDeviceDisconnectedFromCluster();
+ }
+
+ private boolean isDeviceConnected() {
+ return ConnectionContext.CONNECTION_STATE.WORKING.equals(
+ deviceContext.getPrimaryConnectionContext().getConnectionState());
+ }
+
+ @Nullable
+ @Override
+ public <T> RequestContext<T> createRequestContext() {
+ final AbstractRequestContext<T> ret = new AbstractRequestContext<T>(deviceContext.getReservedXid()) {
+ @Override
+ public void close() {
+ }
+ };
+ return ret;
+ }
+
+ @VisibleForTesting
+ public void setSalRoleService(SalRoleService salRoleService) {
+ this.salRoleService = salRoleService;
+ }
+}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.impl.role;
+
+import com.google.common.util.concurrent.FutureCallback;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.annotation.CheckForNull;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
+import org.opendaylight.openflowplugin.api.openflow.role.RoleContext;
+import org.opendaylight.openflowplugin.api.openflow.role.RoleManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Gets invoked from RpcManagerInitial, registers a candidate with EntityOwnershipService.
+ * On receipt of the ownership notification, makes an rpc call to SalRoleSevice.
+ *
+ * Hands over to StatisticsManager at the end.
+ */
+public class RoleManagerImpl implements RoleManager {
+ private static final Logger LOG = LoggerFactory.getLogger(RoleManagerImpl.class);
+
+ private DeviceInitializationPhaseHandler deviceInitializationPhaseHandler;
+ private EntityOwnershipService entityOwnershipService;
+ private final RpcProviderRegistry rpcProviderRegistry;
+ private final ConcurrentHashMap<DeviceContext, RoleContext> contexts = new ConcurrentHashMap<>();
+ private final OpenflowOwnershipListener openflowOwnershipListener;
+
+ public RoleManagerImpl(RpcProviderRegistry rpcProviderRegistry, EntityOwnershipService entityOwnershipService) {
+ this.entityOwnershipService = entityOwnershipService;
+ this.rpcProviderRegistry = rpcProviderRegistry;
+ this.openflowOwnershipListener = new OpenflowOwnershipListener(entityOwnershipService);
+ LOG.debug("Registering OpenflowOwnershipListener listening to all entity ownership changes");
+ openflowOwnershipListener.init();
+ }
+
+ @Override
+ public void setDeviceInitializationPhaseHandler(DeviceInitializationPhaseHandler handler) {
+ deviceInitializationPhaseHandler = handler;
+ }
+
+ @Override
+ public void onDeviceContextLevelUp(@CheckForNull final DeviceContext deviceContext) {
+ LOG.debug("RoleManager called for device:{}", deviceContext.getPrimaryConnectionContext().getNodeId());
+ if (deviceContext.getDeviceState().getFeatures().getVersion() < OFConstants.OFP_VERSION_1_3) {
+ // Roles are not supported before OF1.3, so move forward.
+ deviceInitializationPhaseHandler.onDeviceContextLevelUp(deviceContext);
+ }
+
+ RoleContext roleContext = new RoleContextImpl(deviceContext, rpcProviderRegistry, entityOwnershipService, openflowOwnershipListener);
+ contexts.put(deviceContext, roleContext);
+ LOG.debug("Created role context");
+
+ // if the device context gets closed (mostly on connection close), we would need to cleanup
+ deviceContext.addDeviceContextClosedHandler(roleContext);
+
+ roleContext.facilitateRoleChange(new FutureCallback<Boolean>() {
+ @Override
+ public void onSuccess(Boolean aBoolean) {
+ LOG.debug("roleChangeFuture success for device:{}. Moving to StatisticsManager", deviceContext.getDeviceState().getNodeId());
+ deviceInitializationPhaseHandler.onDeviceContextLevelUp(deviceContext);
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("RoleChange on device {} was not successful after several attempts. " +
+ "Closing the device Context, reconnect the device and start over",
+ deviceContext.getPrimaryConnectionContext().getNodeId().getValue(), throwable);
+// try {
+// deviceContext.close();
+// } catch (Exception e) {
+// LOG.warn("Error closing device context for device:{}",
+// deviceContext.getPrimaryConnectionContext().getNodeId().getValue(), e);
+// }
+ }
+ });
+ }
+
+ @Override
+ public void close() throws Exception {
+ for (Map.Entry<DeviceContext, RoleContext> roleContextEntry : contexts.entrySet()) {
+ roleContextEntry.getValue().close();
+ }
+ this.openflowOwnershipListener.close();
+ }
+}
import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
import org.opendaylight.openflowplugin.api.openflow.rpc.RpcManager;
import org.opendaylight.openflowplugin.impl.util.MdSalRegistratorUtils;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class RpcManagerImpl implements RpcManager {
+ private static final Logger LOG = LoggerFactory.getLogger(RpcManagerImpl.class);
private final RpcProviderRegistry rpcProviderRegistry;
private DeviceInitializationPhaseHandler deviceInitPhaseHandler;
private final int maxRequestsQuota;
@Override
public void onDeviceContextLevelUp(final DeviceContext deviceContext) {
+ LOG.debug("deviceContext.getDeviceState().getRole():"+deviceContext.getDeviceState().getRole());
+ if (deviceContext.getDeviceState().getRole() == OfpRole.BECOMESLAVE) {
+ // if slave, we dont poll for statistics and jump to rpc initialization
+ deviceInitPhaseHandler.onDeviceContextLevelUp(deviceContext);
+ return;
+ }
+
final RpcContext rpcContext = new RpcContextImpl(deviceContext.getMessageSpy(), rpcProviderRegistry, deviceContext, maxRequestsQuota);
deviceContext.addDeviceContextClosedHandler(rpcContext);
MdSalRegistratorUtils.registerServices(rpcContext, deviceContext);
// finish device initialization cycle back to DeviceManager
deviceInitPhaseHandler.onDeviceContextLevelUp(deviceContext);
}
+
+ @Override
+ public void close() throws Exception {
+
+ }
}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.impl.services;
+
+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;
+import java.math.BigInteger;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.impl.role.RoleChangeException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev150304.TransactionId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ControllerRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutputBuilder;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by kramesha on 8/24/15.
+ */
+public class RoleService extends AbstractSimpleService<RoleRequestInputBuilder, RoleRequestOutput> {
+ private static final Logger LOG = LoggerFactory.getLogger(RoleService.class);
+
+ private final DeviceContext deviceContext;
+
+ protected RoleService(final RequestContextStack requestContextStack, final DeviceContext deviceContext, final Class<RoleRequestOutput> clazz) {
+ super(requestContextStack, deviceContext, clazz);
+ this.deviceContext = deviceContext;
+ }
+
+ @Override
+ protected OfHeader buildRequest(Xid xid, RoleRequestInputBuilder input) {
+ input.setXid(xid.getValue());
+ return input.build();
+ }
+
+ public Future<BigInteger> getGenerationIdFromDevice(Short version) throws RoleChangeException {
+ final NodeId nodeId = deviceContext.getPrimaryConnectionContext().getNodeId();
+ LOG.info("getGenerationIdFromDevice called for device:{}", nodeId.getValue());
+
+ // send a dummy no-change role request to get the generation-id of the switch
+ final RoleRequestInputBuilder roleRequestInputBuilder = new RoleRequestInputBuilder();
+ roleRequestInputBuilder.setRole(toOFJavaRole(OfpRole.NOCHANGE));
+ roleRequestInputBuilder.setVersion(version);
+ roleRequestInputBuilder.setGenerationId(BigInteger.ZERO);
+
+ final SettableFuture<BigInteger> finalFuture = SettableFuture.create();
+ ListenableFuture<RpcResult<RoleRequestOutput>> genIdListenableFuture = handleServiceCall(roleRequestInputBuilder);
+ Futures.addCallback(genIdListenableFuture, new FutureCallback<RpcResult<RoleRequestOutput>>() {
+ @Override
+ public void onSuccess(RpcResult<RoleRequestOutput> roleRequestOutputRpcResult) {
+ if (roleRequestOutputRpcResult.isSuccessful()) {
+ RoleRequestOutput roleRequestOutput = roleRequestOutputRpcResult.getResult();
+ if (roleRequestOutput != null) {
+ LOG.debug("roleRequestOutput.getGenerationId()={}", roleRequestOutput.getGenerationId());
+ finalFuture.set(roleRequestOutput.getGenerationId());
+ } else {
+ LOG.info("roleRequestOutput is null in getGenerationIdFromDevice");
+ finalFuture.setException(new RoleChangeException("Exception in getting generationId for device:" + nodeId.getValue()));
+ }
+
+ } else {
+ LOG.error("getGenerationIdFromDevice RPC error " +
+ roleRequestOutputRpcResult.getErrors().iterator().next().getInfo());
+
+ }
+
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.info("onFailure - getGenerationIdFromDevice RPC error {}", throwable);
+ finalFuture.setException(new ExecutionException(throwable));
+ }
+ });
+ return finalFuture;
+ }
+
+
+ public Future<SetRoleOutput> submitRoleChange(final OfpRole ofpRole, final Short version, final BigInteger generationId) {
+ LOG.info("submitRoleChange called for device:{}, role:{}",
+ deviceContext.getPrimaryConnectionContext().getNodeId(), ofpRole);
+ RoleRequestInputBuilder roleRequestInputBuilder = new RoleRequestInputBuilder();
+ roleRequestInputBuilder.setRole(toOFJavaRole(ofpRole));
+ roleRequestInputBuilder.setVersion(version);
+ roleRequestInputBuilder.setGenerationId(generationId);
+
+ ListenableFuture<RpcResult<RoleRequestOutput>> roleListenableFuture = handleServiceCall(roleRequestInputBuilder);
+
+ final SettableFuture<SetRoleOutput> finalFuture = SettableFuture.create();
+ Futures.addCallback(roleListenableFuture, new FutureCallback<RpcResult<RoleRequestOutput>>() {
+ @Override
+ public void onSuccess(RpcResult<RoleRequestOutput> roleRequestOutputRpcResult) {
+ LOG.info("submitRoleChange onSuccess for device:{}, role:{}",
+ deviceContext.getPrimaryConnectionContext().getNodeId(), ofpRole);
+ RoleRequestOutput roleRequestOutput = roleRequestOutputRpcResult.getResult();
+ SetRoleOutputBuilder setRoleOutputBuilder = new SetRoleOutputBuilder();
+ setRoleOutputBuilder.setTransactionId(new TransactionId(BigInteger.valueOf(roleRequestOutput.getXid())));
+ finalFuture.set(setRoleOutputBuilder.build());
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.error("submitRoleChange onFailure for device:{}, role:{}",
+ deviceContext.getPrimaryConnectionContext().getNodeId(), ofpRole, throwable);
+ finalFuture.set(null);
+ }
+ });
+ return finalFuture;
+ }
+
+ private static ControllerRole toOFJavaRole(OfpRole role) {
+ ControllerRole ofJavaRole = null;
+ switch (role) {
+ case BECOMEMASTER:
+ ofJavaRole = ControllerRole.OFPCRROLEMASTER;
+ break;
+ case BECOMESLAVE:
+ ofJavaRole = ControllerRole.OFPCRROLESLAVE;
+ break;
+ case NOCHANGE:
+ ofJavaRole = ControllerRole.OFPCRROLENOCHANGE;
+ break;
+ default:
+ // no intention
+ LOG.warn("given role is not supported by protocol roles: {}", role);
+ break;
+ }
+ return ofJavaRole;
+ }
+
+
+}
*/
package org.opendaylight.openflowplugin.impl.services;
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.SettableFuture;
+import java.math.BigInteger;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.impl.role.RoleChangeException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
-public class SalRoleServiceImpl extends AbstractSimpleService<SetRoleInputBuilder, SetRoleOutput> implements SalRoleService {
+public class SalRoleServiceImpl extends AbstractSimpleService<SetRoleInput, SetRoleOutput> implements SalRoleService {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SalRoleServiceImpl.class);
+
+ private static final BigInteger MAX_GENERATION_ID = new BigInteger("ffffffffffffffff", 16);
+
+ private static final int MAX_RETRIES = 42;
+
+ private final DeviceContext deviceContext;
+ private final RoleService roleService;
+ private final AtomicReference<OfpRole> lastKnownRoleRef = new AtomicReference<>(OfpRole.NOCHANGE);
+ private final ListeningExecutorService listeningExecutorService;
+ private final NodeId nodeId;
+ private final Short version;
public SalRoleServiceImpl(final RequestContextStack requestContextStack, final DeviceContext deviceContext) {
super(requestContextStack, deviceContext, SetRoleOutput.class);
+ this.deviceContext = deviceContext;
+ this.roleService = new RoleService(requestContextStack, deviceContext, RoleRequestOutput.class);
+ nodeId = deviceContext.getPrimaryConnectionContext().getNodeId();
+ version = deviceContext.getPrimaryConnectionContext().getFeatures().getVersion();
+ listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
+
}
@Override
- protected OfHeader buildRequest(Xid xid, SetRoleInputBuilder input) {
+ protected OfHeader buildRequest(Xid xid, SetRoleInput input) {
return null;
}
+ public static BigInteger getNextGenerationId(BigInteger generationId) {
+ BigInteger nextGenerationId = null;
+ if (generationId.compareTo(MAX_GENERATION_ID) < 0) {
+ nextGenerationId = generationId.add(BigInteger.ONE);
+ } else {
+ nextGenerationId = BigInteger.ZERO;
+ }
+
+ return nextGenerationId;
+ }
+
+
@Override
- public Future<RpcResult<SetRoleOutput>> setRole(SetRoleInput input) {
+ public Future<RpcResult<SetRoleOutput>> setRole(final SetRoleInput input) {
+ LOG.info("SetRole called with input:{}", input);
+ OfpRole lastKnownRole = lastKnownRoleRef.get();
+
+ // compare with last known role and set if different. If they are same, then return.
+ if (lastKnownRoleRef.compareAndSet(input.getControllerRole(), input.getControllerRole())) {
+ LOG.info("Role to be set is same as the last known role for the device:{}. Hence ignoring.", input.getControllerRole());
+ SettableFuture<RpcResult<SetRoleOutput>> resultFuture = SettableFuture.create();
+ resultFuture.set(RpcResultBuilder.<SetRoleOutput>success().build());
+ return resultFuture;
+ }
+
+ final SettableFuture<RpcResult<SetRoleOutput>> resultFuture = SettableFuture.create();
+
+ RoleChangeTask roleChangeTask = new RoleChangeTask(nodeId, input.getControllerRole(), version, roleService);
+
+ do {
+ ListenableFuture<RpcResult<SetRoleOutput>> deviceCheck = deviceConnectionCheck();
+ if (deviceCheck != null) {
+ LOG.info("Device {} is disconnected or state is not valid. Giving up on role change", input.getNode());
+ return deviceCheck;
+ }
+
+ ListenableFuture<SetRoleOutput> taskFuture = listeningExecutorService.submit(roleChangeTask);
+ LOG.info("RoleChangeTask submitted for execution");
+ CheckedFuture<SetRoleOutput, RoleChangeException> taskFutureChecked = makeCheckedFuture(taskFuture);
+ try {
+ SetRoleOutput setRoleOutput = taskFutureChecked.checkedGet(10, TimeUnit.SECONDS);
+ LOG.info("setRoleOutput received after roleChangeTask execution:{}", setRoleOutput);
+ resultFuture.set(RpcResultBuilder.<SetRoleOutput>success().withResult(setRoleOutput).build());
+ lastKnownRoleRef.set(input.getControllerRole());
+ return resultFuture;
+
+ } catch (TimeoutException | RoleChangeException e) {
+ roleChangeTask.incrementRetryCounter();
+ LOG.info("Exception in setRole(), will retry:" + (MAX_RETRIES - roleChangeTask.getRetryCounter()) + " times.", e);
+ }
+
+ } while (roleChangeTask.getRetryCounter() < MAX_RETRIES);
+
+ resultFuture.setException(new RoleChangeException("Set Role failed after " + MAX_RETRIES + "tries on device " + input.getNode().getValue()));
+
+ return resultFuture;
+ }
+
+ private ListenableFuture<RpcResult<SetRoleOutput>> deviceConnectionCheck() {
+ if (!ConnectionContext.CONNECTION_STATE.WORKING.equals(deviceContext.getPrimaryConnectionContext().getConnectionState())) {
+ ListenableFuture<RpcResult<SetRoleOutput>> resultingFuture = SettableFuture.create();
+ switch (deviceContext.getPrimaryConnectionContext().getConnectionState()) {
+ case RIP:
+ final String errMsg = String.format("Device connection doesn't exist anymore. Primary connection status : %s",
+ deviceContext.getPrimaryConnectionContext().getConnectionState());
+ resultingFuture = Futures.immediateFailedFuture(new Throwable(errMsg));
+ break;
+ default:
+ resultingFuture = Futures.immediateCheckedFuture(RpcResultBuilder.<SetRoleOutput>failed().build());
+ break;
+ }
+ return resultingFuture;
+ }
return null;
}
+
+ class RoleChangeTask implements Callable<SetRoleOutput> {
+
+ private final NodeId nodeId;
+ private final OfpRole ofpRole;
+ private final Short version;
+ private final RoleService roleService;
+ private int retryCounter = 0;
+
+ public RoleChangeTask(NodeId nodeId, OfpRole ofpRole, Short version, RoleService roleService) {
+ this.nodeId = nodeId;
+ this.ofpRole = ofpRole;
+ this.version = version;
+ this.roleService = roleService;
+ }
+
+ @Override
+ public SetRoleOutput call() throws RoleChangeException {
+ LOG.info("RoleChangeTask called on device:{} OFPRole:{}", this.nodeId.getValue(), ofpRole);
+
+ // we cannot move ahead without having the generation id, so block the thread till we get it.
+ BigInteger generationId = null;
+ SetRoleOutput setRoleOutput = null;
+
+ try {
+ generationId = this.roleService.getGenerationIdFromDevice(version).get(10, TimeUnit.SECONDS);
+ LOG.info("RoleChangeTask, GenerationIdFromDevice from device is {}", generationId);
+
+ } catch (Exception e ) {
+ LOG.info("Exception in getting generationId for device:{}. Ex:{}" + this.nodeId.getValue(), e);
+ throw new RoleChangeException("Exception in getting generationId for device:"+ this.nodeId.getValue(), e);
+ }
+
+
+ LOG.info("GenerationId received from device:{} is {}", nodeId.getValue(), generationId);
+
+ final BigInteger nextGenerationId = getNextGenerationId(generationId);
+
+ LOG.info("nextGenerationId received from device:{} is {}", nodeId.getValue(), nextGenerationId);
+
+ try {
+ setRoleOutput = roleService.submitRoleChange(ofpRole, version, nextGenerationId).get(10 , TimeUnit.SECONDS);
+ LOG.info("setRoleOutput after submitRoleChange:{}", setRoleOutput);
+
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ LOG.error("Exception in making role change for device", e);
+ throw new RoleChangeException("Exception in making role change for device:" + nodeId.getValue());
+ }
+
+ return setRoleOutput;
+
+ }
+
+ public void incrementRetryCounter() {
+ this.retryCounter = retryCounter + 1;
+ }
+
+ public int getRetryCounter() {
+ return retryCounter;
+ }
+ }
+
+ public static CheckedFuture<SetRoleOutput, RoleChangeException> makeCheckedFuture(ListenableFuture<SetRoleOutput> rolePushResult) {
+ return Futures.makeChecked(rolePushResult,
+ new Function<Exception, RoleChangeException>() {
+ @Override
+ public RoleChangeException apply(Exception input) {
+ RoleChangeException output = null;
+ if (input instanceof ExecutionException) {
+ if (input.getCause() instanceof RoleChangeException) {
+ output = (RoleChangeException) input.getCause();
+ }
+ }
+
+ if (output == null) {
+ output = new RoleChangeException(input.getMessage(), input);
+ }
+
+ return output;
+ }
+ });
+ }
}
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Override
public void onDeviceContextLevelUp(final DeviceContext deviceContext) {
+ LOG.debug("deviceContext.getDeviceState().getRole():"+deviceContext.getDeviceState().getRole());
+ if (deviceContext.getDeviceState().getRole() == OfpRole.BECOMESLAVE) {
+ // if slave, we dont poll for statistics and jump to rpc initialization
+ deviceInitPhaseHandler.onDeviceContextLevelUp(deviceContext);
+ return;
+ }
if (null == hashedWheelTimer) {
LOG.trace("This is first device that delivered timer. Starting statistics polling immediately.");
import org.opendaylight.openflowplugin.impl.services.SalFlowServiceImpl;
import org.opendaylight.openflowplugin.impl.services.SalGroupServiceImpl;
import org.opendaylight.openflowplugin.impl.services.SalMeterServiceImpl;
-import org.opendaylight.openflowplugin.impl.services.SalRoleServiceImpl;
import org.opendaylight.openflowplugin.impl.services.SalTableServiceImpl;
import org.opendaylight.openflowplugin.impl.statistics.services.OpendaylightFlowStatisticsServiceImpl;
import org.opendaylight.yang.gen.v1.urn.opendaylight.echo.service.rev150305.SalEchoService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.module.config.rev141015.NodeConfigService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.table.service.rev131026.SalTableService;
public class MdSalRegistratorUtils {
throw new IllegalStateException();
}
+
public static void registerServices(final RpcContext rpcContext, final DeviceContext deviceContext) {
rpcContext.registerRpcServiceImplementation(SalFlowService.class, new SalFlowServiceImpl(rpcContext, deviceContext));
rpcContext.registerRpcServiceImplementation(SalEchoService.class, new SalEchoServiceImpl(rpcContext, deviceContext));
rpcContext.registerRpcServiceImplementation(PacketProcessingService.class, new PacketProcessingServiceImpl(rpcContext, deviceContext));
rpcContext.registerRpcServiceImplementation(NodeConfigService.class, new NodeConfigServiceImpl(rpcContext, deviceContext));
rpcContext.registerRpcServiceImplementation(OpendaylightFlowStatisticsService.class, new OpendaylightFlowStatisticsServiceImpl(rpcContext, deviceContext));
- rpcContext.registerRpcServiceImplementation(SalRoleService.class, new SalRoleServiceImpl(rpcContext, deviceContext));
}
}
openflowPluginProvider.setNotificationPublishService(getNotificationPublishAdapterDependency());
openflowPluginProvider.setSwitchFeaturesMandatory(getSwitchFeaturesMandatory());
openflowPluginProvider.setIsStatisticsPollingOff(getIsStatisticsPollingOff());
+ openflowPluginProvider.setEntityOwnershipService(getEntityOwnershipServiceDependency());
openflowPluginProvider.initialize();
return openflowPluginProvider;
import opendaylight-md-sal-binding { prefix md-sal-binding; revision-date 2013-10-28;}
import opendaylight-sal-binding-broker-impl { prefix sal-broker; revision-date 2013-10-28;}
import openflowplugin-extension-registry {prefix ofp-ext-reg; revision-date 2015-04-25;}
+ import opendaylight-entity-ownership-service { prefix ownership-service; revision-date 2015-08-10;}
description
"openflow-plugin-impl";
}
}
}
+ container entity-ownership-service {
+ uses config:service-ref {
+ refine type {
+ mandatory true;
+ config:required-identity ownership-service:entity-ownership-service;
+ }
+ }
+ }
list openflow-switch-connection-provider {
uses config:service-ref {
refine type {
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortConfig;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortConfigV10;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.PortStateV10;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.features.reply.PhyPort;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
assertEquals(apf.isPause(), npf.isPause());
assertEquals(apf.isPauseAsym(), npf.isPauseAsym());
}
+
+ static InstanceIdentifier<NodeConnector> createNodeConnectorId(String nodeKey, String nodeConnectorKey) {
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, new NodeKey(new NodeId(nodeKey)))
+ .child(NodeConnector.class, new NodeConnectorKey(new NodeConnectorId(nodeConnectorKey)))
+ .build();
+ }
+
+ @Test
+ public void testDummy() {
+ InstanceIdentifier<NodeConnector> id = createNodeConnectorId("openflow:1", "openflow:1:1");
+ InstanceIdentifier<Node> nodeId = id.firstIdentifierOf(Node.class);
+ System.out.println(nodeId);
+ }
}
deviceContext.close();
verify(connectionContext).closeConnection(eq(false));
verify(deviceState).setValid(eq(false));
- verify(txChainManager).close();
+ verify(txChainManager).closeWithoutCleanup();
verify(mockedAuxiliaryConnectionContext).closeConnection(eq(false));
}
Assert.assertEquals(0, deviceContext.getDeviceGroupRegistry().getAllGroupIds().size());
Assert.assertEquals(0, deviceContext.getDeviceMeterRegistry().getAllMeterIds().size());
- Mockito.verify(txChainManager).close();
+ Mockito.verify(txChainManager).closeWithoutCleanup();
}
}
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.MultipartReplyTableFeaturesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.multipart.reply.table.features.TableFeatures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.reply.multipart.reply.body.multipart.reply.table.features._case.multipart.reply.table.features.TableFeaturesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
public void onDeviceContextLevelUp(boolean withException) {
DeviceManagerImpl deviceManager = prepareDeviceManager(withException);
+ DeviceState mockedDeviceState = mock(DeviceState.class);
+ when(mockedDeviceContext.getDeviceState()).thenReturn(mockedDeviceState);
+ when(mockedDeviceState.getRole()).thenReturn(OfpRole.BECOMEMASTER);
if (withException) {
doThrow(new IllegalStateException("dummy")).when(mockedDeviceContext).initialSubmitTransaction();
- DeviceState mockedDeviceState = mock(DeviceState.class);
- when(mockedDeviceContext.getDeviceState()).thenReturn(mockedDeviceState);
}
deviceManager.onDeviceContextLevelUp(mockedDeviceContext);
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.impl.role;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.google.common.util.concurrent.SettableFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Matchers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
+import org.opendaylight.openflowplugin.impl.util.DeviceStateUtil;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * Created by kramesha on 9/1/15.
+ */
+public class RoleContextImplTest {
+
+ @Mock
+ private EntityOwnershipService entityOwnershipService;
+
+ @Mock
+ private OpenflowOwnershipListener openflowOwnershipListener;
+
+ @Mock
+ private RpcProviderRegistry rpcProviderRegistry;
+
+ @Mock
+ private DeviceContext deviceContext;
+
+ @Mock
+ private ConnectionContext connectionContext;
+
+ @Mock
+ private DeviceState deviceState;
+
+ @Mock
+ private SalRoleService salRoleService;
+
+ @Mock
+ private GetFeaturesOutput getFeaturesOutput;
+
+ @Mock
+ private FeaturesReply featuresReply;
+
+ private NodeId nodeId = NodeId.getDefaultInstance("openflow:1");
+ private KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier = DeviceStateUtil.createNodeInstanceIdentifier(nodeId);
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(deviceContext.getPrimaryConnectionContext()).thenReturn(connectionContext);
+ when(deviceContext.getDeviceState()).thenReturn(deviceState);
+ when(connectionContext.getNodeId()).thenReturn(nodeId);
+ when(deviceState.getNodeInstanceIdentifier()).thenReturn(instanceIdentifier);
+ when(rpcProviderRegistry.getRpcService(SalRoleService.class)).thenReturn(salRoleService);
+ when(deviceState.getFeatures()).thenReturn(getFeaturesOutput);
+ when(getFeaturesOutput.getVersion()).thenReturn(OFConstants.OFP_VERSION_1_3);
+ when(deviceContext.getPrimaryConnectionContext().getFeatures()).thenReturn(featuresReply);
+ }
+
+ @Test
+ public void testOnRoleChanged() {
+ OfpRole newRole = OfpRole.BECOMEMASTER;
+
+ SettableFuture<RpcResult<SetRoleOutput>> future = SettableFuture.create();
+ future.set(RpcResultBuilder.<SetRoleOutput>success().build());
+ when(salRoleService.setRole(Matchers.argThat(new SetRoleInputMatcher(newRole, instanceIdentifier))))
+ .thenReturn(future);
+
+ RoleContextImpl roleContext = new RoleContextImpl(deviceContext, rpcProviderRegistry, entityOwnershipService, openflowOwnershipListener);
+ roleContext.setSalRoleService(salRoleService);
+
+ roleContext.onRoleChanged(OfpRole.BECOMESLAVE, newRole);
+
+ verify(deviceState).setRole(newRole);
+ }
+
+
+ private class SetRoleInputMatcher extends ArgumentMatcher<SetRoleInput> {
+
+ private OfpRole ofpRole;
+ private NodeRef nodeRef;
+ public SetRoleInputMatcher(OfpRole ofpRole, KeyedInstanceIdentifier<Node, NodeKey> instanceIdentifier) {
+ this.ofpRole = ofpRole;
+ nodeRef = new NodeRef(instanceIdentifier);
+
+ }
+
+ @Override
+ public boolean matches(Object o) {
+ SetRoleInput input = (SetRoleInput) o;
+ if (input.getControllerRole() == ofpRole &&
+ input.getNode().equals(nodeRef)) {
+ return true;
+ }
+ return false;
+ }
+ }
+}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.when;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Matchers;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
private DeviceContext deviceContext;
@Mock
private MessageSpy messageSpy;
- @Mock
- private SalFlowService salFlowServiceInstance;
- @Mock
- BindingAwareBroker.RoutedRpcRegistration<SalFlowService> routedRpcRegistration;
private KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier;
when(deviceState.getNodeInstanceIdentifier()).thenReturn(nodeInstanceIdentifier);
when(deviceContext.getDeviceState()).thenReturn(deviceState);
- when(mockedRpcProviderRegistry.addRoutedRpcImplementation(
- Matchers.<Class<SalFlowService>>any(), Matchers.any(SalFlowService.class)))
- .thenReturn(routedRpcRegistration);
}
@Test
- public void testCreateRequestContext() throws Exception {
- try (final RpcContext rpcContext = new RpcContextImpl(messageSpy, mockedRpcProviderRegistry, deviceContext, 1)) {
- RequestContext<?> requestContext1 = rpcContext.createRequestContext();
- assertNotNull(requestContext1);
+ public void invokeRpcTest() {
- // quota exceeded
- RequestContext<?> requestContext2 = rpcContext.createRequestContext();
- assertNull(requestContext2);
-
- requestContext1.close();
- RequestContext<?> requestContext3 = rpcContext.createRequestContext();
- assertNotNull(requestContext3);
- }
- }
-
- @Test
- public void testRegisterRpcServiceImplementation() throws Exception {
- try (final RpcContext rpcContext = new RpcContextImpl(messageSpy, mockedRpcProviderRegistry, deviceContext, 10)) {
- rpcContext.registerRpcServiceImplementation(SalFlowService.class, salFlowServiceInstance);
- Mockito.verify(routedRpcRegistration).registerPath(NodeContext.class, nodeInstanceIdentifier);
- }
}
@Test
- public void testClose() throws Exception {
- try (final RpcContext rpcContext = new RpcContextImpl(messageSpy, mockedRpcProviderRegistry, deviceContext, 10)) {
- rpcContext.registerRpcServiceImplementation(SalFlowService.class, salFlowServiceInstance);
- rpcContext.close();
- Mockito.verify(routedRpcRegistration).unregisterPath(NodeContext.class, nodeInstanceIdentifier);
- Mockito.verify(routedRpcRegistration).close();
+ public void testStoreOrFail() throws Exception {
+ try (final RpcContext rpcContext = new RpcContextImpl(messageSpy, mockedRpcProviderRegistry, deviceContext, 100)) {
+ RequestContext<?> requestContext = rpcContext.createRequestContext();
+ assertNotNull(requestContext);
}
}
@Test
- public void testOnDeviceContextClosed() throws Exception {
- try (final RpcContext rpcContext = new RpcContextImpl(messageSpy, mockedRpcProviderRegistry, deviceContext, 10)) {
- rpcContext.registerRpcServiceImplementation(SalFlowService.class, salFlowServiceInstance);
- rpcContext.onDeviceContextClosed(deviceContext);
- Mockito.verify(routedRpcRegistration).unregisterPath(NodeContext.class, nodeInstanceIdentifier);
- Mockito.verify(routedRpcRegistration).close();
+ public void testStoreOrFailThatFails() throws Exception {
+ try (final RpcContext rpcContext = new RpcContextImpl(messageSpy, mockedRpcProviderRegistry, deviceContext, 0)) {
+ RequestContext<?> requestContext = rpcContext.createRequestContext();
+ assertNull(requestContext);
}
}
}
*/
package org.opendaylight.openflowplugin.impl.rpc;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
-
-import org.junit.Before;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import java.math.BigInteger;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.junit.Ignore;
import org.junit.Test;
-import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
-import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
-import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceInitializationPhaseHandler;
-import org.opendaylight.openflowplugin.api.openflow.registry.ItemLifeCycleRegistry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContext;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
+import org.opendaylight.openflowplugin.impl.services.SalFlowServiceImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutputBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
-@RunWith(MockitoJUnitRunner.class)
public class RpcManagerImplTest {
- private static final int AWAITED_NUM_OF_CALL_ADD_ROUTED_RPC = 10;
+ private static final int AWAITED_NUM_OF_CALL_ADD_ROUTED_RPC = 12;
- private RpcManagerImpl rpcManager;
- @Mock
- private ProviderContext rpcProviderRegistry;
- @Mock
- private DeviceContext deviceContext;
- @Mock
- private DeviceInitializationPhaseHandler deviceINitializationPhaseHandler;
- @Mock
- private ConnectionContext connectionContext;
- @Mock
- private BindingAwareBroker.RoutedRpcRegistration<RpcService> routedRpcRegistration;
- @Mock
- private DeviceState deviceState;
+
+ final ProviderContext mockedProviderContext = mock(ProviderContext.class);
+ final RpcManagerImpl rpcManager = new RpcManagerImpl(mockedProviderContext, 500);
+ final DeviceContext mockedDeviceContext = mock(DeviceContext.class);
@Mock
- private ItemLifeCycleRegistry itemLifeCycleRegistry;
-
- private KeyedInstanceIdentifier<Node, NodeKey> nodePath;
-
- @Before
- public void setUp() {
- nodePath = KeyedInstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(new NodeId("openflow-junit:1")));
- rpcManager = new RpcManagerImpl(rpcProviderRegistry, 5);
- rpcManager.setDeviceInitializationPhaseHandler(deviceINitializationPhaseHandler);
- FeaturesReply features = new GetFeaturesOutputBuilder()
- .setVersion(OFConstants.OFP_VERSION_1_3)
- .build();
- Mockito.when(connectionContext.getFeatures()).thenReturn(features);
- Mockito.when(deviceContext.getPrimaryConnectionContext()).thenReturn(connectionContext);
- Mockito.when(deviceContext.getDeviceState()).thenReturn(deviceState);
- Mockito.when(deviceContext.getItemLifeCycleSourceRegistry()).thenReturn(itemLifeCycleRegistry);
- Mockito.when(deviceState.getNodeInstanceIdentifier()).thenReturn(nodePath);
+ private MessageSpy messageSpy;
+
+ @Ignore
+ @Test
+ public void deviceConnectedTest() {
+
+ rpcManager.onDeviceContextLevelUp(mockedDeviceContext);
+
+ verify(mockedProviderContext, times(AWAITED_NUM_OF_CALL_ADD_ROUTED_RPC)).addRoutedRpcImplementation(
+ Matchers.any(Class.class), Matchers.any(RpcService.class));
}
+
+ /**
+ * Tests behavior of RpcContextImpl when calling rpc from MD-SAL
+ */
+ @Ignore
@Test
- public void testOnDeviceContextLevelUp() {
+ public void invokeRpcTestExistsCapacityTest() throws InterruptedException, ExecutionException {
+ final ConnectionContext mockedConnectionContext = mock(ConnectionContext.class);
+ final FeaturesReply mockedFeatures = mock(FeaturesReply.class);
+ final BigInteger dummyDatapathId = BigInteger.ONE;
+ final Short dummyVersion = 1;
+ final ConnectionAdapter mockedConnectionAdapter = mock(ConnectionAdapter.class);
+
+ when(mockedFeatures.getDatapathId()).thenReturn(dummyDatapathId);
+ when(mockedFeatures.getVersion()).thenReturn(dummyVersion);
+ when(mockedConnectionContext.getFeatures()).thenReturn(mockedFeatures);
+ when(mockedConnectionContext.getConnectionAdapter()).thenReturn(mockedConnectionAdapter);
+ when(mockedDeviceContext.getPrimaryConnectionContext()).thenReturn(mockedConnectionContext);
+ final Xid mockedXid = mock(Xid.class);
+ final Long dummyXid = 1l;
+ when(mockedXid.getValue()).thenReturn(dummyXid);
+ when(mockedDeviceContext.getReservedXid()).thenReturn(dummyXid);
- Mockito.when(rpcProviderRegistry.addRoutedRpcImplementation(
- Matchers.<Class<RpcService>>any(), Matchers.any(RpcService.class)))
- .thenReturn(routedRpcRegistration);
+ invokeRpcTestExistsCapacity(10, true);
+ invokeRpcTestExistsCapacity(0, false);
+ }
+
+ private void invokeRpcTestExistsCapacity(final int capacity, final boolean result) throws InterruptedException,
+ ExecutionException {
+ // TODO: how to invoke service remotely?
+ NodeId nodeId = new NodeId("openflow:1");
+ KeyedInstanceIdentifier<Node, NodeKey> nodeInstanceIdentifier = InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(nodeId));
+ final RpcContextImpl rpcContext = new RpcContextImpl(messageSpy, mockedProviderContext, mockedDeviceContext, capacity);
+ when(mockedProviderContext.getRpcService(SalFlowService.class)).thenReturn(new SalFlowServiceImpl(rpcContext, mockedDeviceContext));
+
+ final SalFlowService salFlowService = mockedProviderContext.getRpcService(SalFlowService.class);
+ final Future<RpcResult<AddFlowOutput>> addedFlow = salFlowService.addFlow(prepareTestingAddFlow());
+ }
- rpcManager.onDeviceContextLevelUp(deviceContext);
+ /**
+ * @return
+ */
+ private static AddFlowInput prepareTestingAddFlow() {
+ final AddFlowInputBuilder builder = new AddFlowInputBuilder();
+ builder.setFlowName("dummy flow");
+ builder.setHardTimeout(10000);
- Mockito.verify(rpcProviderRegistry, times(AWAITED_NUM_OF_CALL_ADD_ROUTED_RPC)).addRoutedRpcImplementation(
- Matchers.<Class<RpcService>>any(), Matchers.any(RpcService.class));
- Mockito.verify(routedRpcRegistration, times(AWAITED_NUM_OF_CALL_ADD_ROUTED_RPC)).registerPath(
- NodeContext.class, nodePath);
- Mockito.verify(deviceINitializationPhaseHandler).onDeviceContextLevelUp(deviceContext);
+ return builder.build();
}
}
--- /dev/null
+/**
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.openflowplugin.impl.services;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.math.BigInteger;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
+import org.opendaylight.openflowjava.protocol.api.connection.OutboundQueue;
+import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContextStack;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.OfpRole;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SalRoleService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.role.service.rev150727.SetRoleOutput;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * Created by kramesha on 8/27/15.
+ */
+public class SalRoleServiceImplTest {
+
+ @Mock
+ private RequestContextStack mockRequestContextStack;
+
+ @Mock
+ private DeviceContext mockDeviceContext;
+
+ @Mock
+ private ConnectionAdapter mockConnectionAdapter;
+
+ @Mock
+ private FeaturesReply mockFeaturesReply;
+
+ @Mock
+ private ConnectionContext mockConnectionContext;
+
+ @Mock
+ private MessageSpy mockMessageSpy;
+
+ @Mock
+ private RequestContext<RoleRequestOutput> mockRequestContext;
+
+ @Mock
+ private OutboundQueue mockOutboundQueue;
+
+ private NodeId testNodeId = new NodeId(Uri.getDefaultInstance("openflow:1"));
+
+ private static short testVersion = 4;
+
+ private static long testXid = 100L;
+
+ private NodeRef nodeRef;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ Mockito.when(mockDeviceContext.getPrimaryConnectionContext()).thenReturn(mockConnectionContext);
+ Mockito.when(mockConnectionContext.getFeatures()).thenReturn(mockFeaturesReply);
+ Mockito.when(mockConnectionContext.getNodeId()).thenReturn(testNodeId);
+ Mockito.when(mockFeaturesReply.getVersion()).thenReturn(testVersion);
+ Mockito.when(mockDeviceContext.getMessageSpy()).thenReturn(mockMessageSpy);
+ Mockito.when(mockRequestContextStack.<RoleRequestOutput>createRequestContext()).thenReturn(mockRequestContext);
+ Mockito.when(mockRequestContext.getXid()).thenReturn(new Xid(testXid));
+ Mockito.when(mockConnectionContext.getOutboundQueueProvider()).thenReturn(mockOutboundQueue);
+ Mockito.when(mockDeviceContext.getPrimaryConnectionContext().getConnectionState()).thenReturn(ConnectionContext.CONNECTION_STATE.WORKING);
+
+ NodeKey key = new NodeKey(testNodeId);
+ InstanceIdentifier<Node> path = InstanceIdentifier.<Nodes>builder(Nodes.class)
+ .<Node, NodeKey>child(Node.class, key)
+ .build();
+ nodeRef = new NodeRef(path);
+
+ }
+
+ @Test
+ public void testSetRole() throws Exception {
+ RoleRequestOutput roleRequestOutput = (new RoleRequestOutputBuilder())
+ .setXid(testXid).setGenerationId(BigInteger.valueOf(1)).build();
+ ListenableFuture<RpcResult<RoleRequestOutput>> futureOutput =
+ RpcResultBuilder.<RoleRequestOutput>success().withResult(roleRequestOutput).buildFuture();
+
+ Mockito.when(mockRequestContext.getFuture()).thenReturn(futureOutput);
+
+
+ SalRoleService salRoleService = new SalRoleServiceImpl(mockRequestContextStack, mockDeviceContext);
+
+ SetRoleInput setRoleInput = new SetRoleInputBuilder()
+ .setControllerRole(OfpRole.BECOMESLAVE)
+ .setNode(nodeRef)
+ .build();
+
+ Future<RpcResult<SetRoleOutput>> future = salRoleService.setRole(setRoleInput);
+
+ RpcResult<SetRoleOutput> roleOutputRpcResult = future.get(5, TimeUnit.SECONDS);
+ assertNotNull("RpcResult from future cannot be null.", roleOutputRpcResult);
+ assertTrue("RpcResult from future is not successful.", roleOutputRpcResult.isSuccessful());
+
+ SetRoleOutput setRoleOutput = roleOutputRpcResult.getResult();
+ assertNotNull(setRoleOutput);
+ assertEquals(BigInteger.valueOf(testXid), setRoleOutput.getTransactionId().getValue());
+
+ }
+
+ @Test
+ public void testDuplicateRoles() throws Exception {
+ // set role to slave
+
+ RoleRequestOutput roleRequestOutput = (new RoleRequestOutputBuilder())
+ .setXid(testXid).setGenerationId(BigInteger.valueOf(1)).build();
+ ListenableFuture<RpcResult<RoleRequestOutput>> futureOutput =
+ RpcResultBuilder.<RoleRequestOutput>success().withResult(roleRequestOutput).buildFuture();
+
+ Mockito.when(mockRequestContext.getFuture()).thenReturn(futureOutput);
+
+ SalRoleService salRoleService = new SalRoleServiceImpl(mockRequestContextStack, mockDeviceContext);
+
+ SetRoleInput setRoleInput = new SetRoleInputBuilder()
+ .setControllerRole(OfpRole.BECOMESLAVE)
+ .setNode(nodeRef)
+ .build();
+
+ Future<RpcResult<SetRoleOutput>> future = salRoleService.setRole(setRoleInput);
+
+ RpcResult<SetRoleOutput> roleOutputRpcResult = future.get(5, TimeUnit.SECONDS);
+ assertNotNull("RpcResult from future cannot be null.", roleOutputRpcResult);
+ assertTrue("RpcResult from future is not successful.", roleOutputRpcResult.isSuccessful());
+
+ SetRoleOutput setRoleOutput = roleOutputRpcResult.getResult();
+ assertNotNull(setRoleOutput);
+ assertEquals(BigInteger.valueOf(testXid), setRoleOutput.getTransactionId().getValue());
+
+ // make another role change with the same role - slave
+ Future<RpcResult<SetRoleOutput>> future2 = salRoleService.setRole(setRoleInput);
+ RpcResult<SetRoleOutput> roleOutputRpcResult2 = future2.get(5, TimeUnit.SECONDS);
+ assertNotNull("RpcResult from future cannot be null.", roleOutputRpcResult2);
+ assertTrue("RpcResult from future for duplicate role is not successful.", roleOutputRpcResult2.isSuccessful());
+
+ }
+}
package org.opendaylight.openflowplugin.impl.util;
-import static org.mockito.Mockito.*;
-import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.math.BigInteger;
import org.junit.Test;
-
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext;
* Number of currently registrated services (can be changed) in {@link MdSalRegistratorUtils#registerServices
* (RpcContext, DeviceContext)}
*/
- private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 10;
+ private static final int NUMBER_OF_RPC_SERVICE_REGISTRATION = 9;
@Test
public void registerServiceTest() {