From 9dd9664db32bd7fa972bd414fb4e02ec83ad8e83 Mon Sep 17 00:00:00 2001 From: Martin Bobak Date: Mon, 1 Dec 2014 14:36:16 +0100 Subject: [PATCH] Bug-2827: role switch proposal - stub for entry point where propagation of role change should start - logic for pushing role to device with failover - added tests - role change logic wired to openflowpluginprovider (change can by invoked via configsubsystem) - added max retry limit - comments worked in - rebased - comments worked in (whitespace, 1 method rename) Change-Id: I6f43401821310c22a1b8b42c280e67f01ec9ed8f Signed-off-by: Michal Rehak Signed-off-by: Martin Bobak --- features/pom.xml | 11 +- features/src/main/resources/features.xml | 10 +- .../core/session/IMessageDispatchService.java | 3 + .../md/core/session/SessionContext.java | 19 +- .../md/core/session/SessionManager.java | 4 + .../openflow/md/core/sal/OFRpcTaskUtil.java | 25 +-- .../md/core/sal/OpenflowPluginProvider.java | 42 ++++ .../session/MessageDispatchServiceImpl.java | 85 +++----- .../md/core/session/OFRoleManager.java | 109 ++++++++++ .../md/core/session/OFSessionUtil.java | 7 + .../md/core/session/RolePushException.java | 33 +++ .../md/core/session/RolePushTask.java | 127 ++++++++++++ .../md/core/session/SessionContextOFImpl.java | 44 ++-- .../md/core/session/SessionManagerOFImpl.java | 17 +- .../openflow/md/util/RoleUtil.java | 156 ++++++++++++++ .../openflow/md/util/RpcResultUtil.java | 52 +++++ .../openflow/md/util/TaskUtil.java | 47 +++++ .../ConfigurableOpenFlowProviderModule.java | 22 ++ .../main/yang/openflow-plugin-cfg-impl.yang | 19 ++ .../md/core/HandshakeManagerImplTest.java | 174 ++++++++-------- .../openflow/md/core/RpcResultsUtil.java | 35 ---- .../MessageDispatchServiceImplTest.java | 16 +- .../md/core/session/OFRoleManagerTest.java | 143 +++++++++++++ .../translator/PacketInV10TranslatorTest.java | 51 +++-- .../openflow/md/util/RoleUtilTest.java | 190 ++++++++++++++++++ pom.xml | 27 +-- 26 files changed, 1202 insertions(+), 266 deletions(-) create mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManager.java create mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushException.java create mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushTask.java create mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtil.java create mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RpcResultUtil.java create mode 100644 openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/TaskUtil.java delete mode 100644 openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/RpcResultsUtil.java create mode 100644 openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManagerTest.java create mode 100644 openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtilTest.java diff --git a/features/pom.xml b/features/pom.xml index 3eb0df4d69..4721d60586 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -99,8 +99,8 @@ config xml - - + + org.opendaylight.dlux features-dlux @@ -108,6 +108,13 @@ features xml + + org.opendaylight.controller + features-netconf-connector + ${netconf.version} + features + xml + diff --git a/features/src/main/resources/features.xml b/features/src/main/resources/features.xml index 1b6549ab69..095db24319 100644 --- a/features/src/main/resources/features.xml +++ b/features/src/main/resources/features.xml @@ -8,6 +8,7 @@ mvn:org.opendaylight.openflowjava/features-openflowjava/${openflowjava.version}/xml/features mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features + odl-openflowplugin-southbound @@ -33,7 +34,7 @@ odl-openflowplugin-app-config-pusher odl-openflowplugin-app-lldp-speaker - + odl-mdsal-broker @@ -46,7 +47,7 @@ mvn:org.opendaylight.controller/liblldp/${sal.api.version} mvn:org.opendaylight.openflowplugin.applications/statistics-manager-config/${project.version}/xml/config - + @@ -58,8 +59,9 @@ mvn:org.opendaylight.openflowplugin.model/model-flow-statistics/${project.version} mvn:org.opendaylight.openflowplugin.model/model-flow-service/${project.version} - + + odl-openflowplugin-flow-services odl-restconf @@ -69,7 +71,7 @@ odl-mdsal-apidocs odl-mdsal-xsql - + odl-openflowplugin-flow-services diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/IMessageDispatchService.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/IMessageDispatchService.java index 601265d2a1..0b3d74a698 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/IMessageDispatchService.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/IMessageDispatchService.java @@ -46,6 +46,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult; */ public interface IMessageDispatchService { + public static final String CONNECTION_ERROR_MESSAGE = "Session for the cookie is invalid. Reason: " + + "the switch has been recently disconnected OR inventory provides outdated information."; + /** * send barrier message to switch * diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionContext.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionContext.java index 2fe1ff0d03..eec52194be 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionContext.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionContext.java @@ -18,6 +18,7 @@ import org.opendaylight.openflowplugin.api.openflow.md.core.NotificationEnqueuer import org.opendaylight.openflowplugin.api.openflow.md.ModelDrivenSwitch; import org.opendaylight.openflowplugin.api.openflow.md.core.NotificationQueueWrapper; import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ControllerRole; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortGrouping; import org.opendaylight.yangtools.concepts.CompositeObjectRegistration; @@ -86,7 +87,7 @@ public interface SessionContext { * @return The Map of OFPhysicalPort */ Map getPhysicalPorts(); - + /** * Returns a map containing all bandwidths for all OFPorts of this switch. * @return The Map of bandwidths for all OFPorts @@ -98,7 +99,7 @@ public interface SessionContext { * @return The Set of port ID */ Set getPorts(); - + /** * Returns OFPhysicalPort of the specified portNumber of this switch. * @param portNumber The port ID @@ -156,14 +157,24 @@ public interface SessionContext { * @return provider composite registration */ CompositeObjectRegistration getProviderRegistration(); - + /** * @return seed value for random operations */ int getSeed(); - + /** * @return (wrapped) notification enqueue service - {@link NotificationQueueWrapper} */ NotificationEnqueuer getNotificationEnqueuer(); + + /** + * @param roleOnDevice + */ + void setRoleOnDevice(ControllerRole roleOnDevice); + + /** + * @return actual role + */ + ControllerRole getRoleOnDevice(); } diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionManager.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionManager.java index d82bd7cef7..9b45a1a87a 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionManager.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionManager.java @@ -134,4 +134,8 @@ public interface SessionManager extends AutoCloseable { */ MessageSpy getMessageSpy(); + /** + * @return collection of current sessions + */ + Collection getAllSessions(); } diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OFRpcTaskUtil.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OFRpcTaskUtil.java index 5821139529..73171cbfb5 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OFRpcTaskUtil.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OFRpcTaskUtil.java @@ -18,10 +18,8 @@ import org.opendaylight.openflowplugin.api.OFConstants; import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; import org.opendaylight.openflowplugin.api.openflow.md.core.sal.NotificationComposer; import org.opendaylight.openflowplugin.api.statistics.MessageSpy; -import org.opendaylight.openflowplugin.openflow.md.core.MessageFactory; -import org.opendaylight.openflowplugin.api.openflow.md.core.session.IMessageDispatchService; -import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; import org.opendaylight.openflowplugin.openflow.md.util.RpcInputOutputTuple; +import org.opendaylight.openflowplugin.openflow.md.util.TaskUtil; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionAware; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutput; @@ -40,7 +38,6 @@ import com.google.common.collect.Lists; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.JdkFutureAdapters; import com.google.common.util.concurrent.ListenableFuture; /** @@ -63,7 +60,7 @@ public abstract class OFRpcTaskUtil { Collection errors = null; if (Objects.firstNonNull(isBarrier, Boolean.FALSE)) { RpcInputOutputTuple>> sendBarrierRpc = - sendBarrier(taskContext.getSession(), cookie, taskContext.getMessageService()); + TaskUtil.sendBarrier(taskContext.getSession(), cookie, taskContext.getMessageService()); Future> barrierFuture = sendBarrierRpc.getOutput(); try { RpcResult barrierResult = barrierFuture.get( @@ -90,22 +87,6 @@ public abstract class OFRpcTaskUtil { return errors; } - /** - * @param session - * @param cookie - * @param messageService - * @return barrier response - */ - protected static RpcInputOutputTuple>> sendBarrier(SessionContext session, - SwitchConnectionDistinguisher cookie, IMessageDispatchService messageService) { - BarrierInput barrierInput = MessageFactory.createBarrier( - session.getFeatures().getVersion(), session.getNextXid()); - Future> barrierResult = messageService.barrier(barrierInput, cookie); - ListenableFuture> output = JdkFutureAdapters.listenInPoolThread(barrierResult); - - return new RpcInputOutputTuple<>(barrierInput, output); - } - /** * @param task of rpc * @param originalResult @@ -170,7 +151,7 @@ public abstract class OFRpcTaskUtil { @Override public ListenableFuture> apply(final RpcResult input) throws Exception { if (input.isSuccessful()) { - RpcInputOutputTuple>> sendBarrierRpc = sendBarrier( + RpcInputOutputTuple>> sendBarrierRpc = TaskUtil.sendBarrier( task.getSession(), task.getCookie(), task.getMessageService()); ListenableFuture> barrierTxResult = Futures.transform( sendBarrierRpc.getOutput(), diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java index 3ca9a2676d..33b65a4bc2 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java @@ -16,9 +16,12 @@ import org.opendaylight.openflowplugin.extension.api.ExtensionConverterRegistrat import org.opendaylight.openflowplugin.openflow.md.core.MDController; import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionConverterManager; import org.opendaylight.openflowplugin.openflow.md.core.extension.ExtensionConverterManagerImpl; +import org.opendaylight.openflowplugin.openflow.md.core.session.OFRoleManager; +import org.opendaylight.openflowplugin.openflow.md.core.session.OFSessionUtil; import org.opendaylight.openflowplugin.api.statistics.MessageCountDumper; import org.opendaylight.openflowplugin.api.statistics.MessageObservatory; import org.opendaylight.openflowplugin.statistics.MessageSpyCounterImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.osgi.framework.BundleContext; import org.slf4j.Logger; @@ -45,12 +48,17 @@ public class OpenflowPluginProvider implements BindingAwareProvider, AutoCloseab private ExtensionConverterManager extensionConverterManager; + private OfpRole role; + + private OFRoleManager roleManager; + /** * Initialization of services and msgSpy counter */ public void initialization() { messageCountProvider = new MessageSpyCounterImpl(); extensionConverterManager = new ExtensionConverterManagerImpl(); + roleManager = new OFRoleManager(OFSessionUtil.getSessionManager()); this.registerProvider(); } @@ -141,4 +149,38 @@ public class OpenflowPluginProvider implements BindingAwareProvider, AutoCloseab public ExtensionConverterRegistrator getExtensionConverterRegistrator() { return extensionConverterManager; } + + /** + * @param role of instance + */ + public void setRole(OfpRole role) { + this.role = role; + } + + /** + * @param newRole + */ + public void fireRoleChange(OfpRole newRole) { + if (!role.equals(newRole)) { + LOG.debug("my role was chaged from {} to {}", role, newRole); + role = newRole; + switch (role) { + case BECOMEMASTER: + //TODO: implement appropriate action + roleManager.manageRoleChange(role); + break; + case BECOMESLAVE: + //TODO: implement appropriate action + roleManager.manageRoleChange(role); + break; + case NOCHANGE: + //TODO: implement appropriate action + roleManager.manageRoleChange(role); + break; + default: + LOG.warn("role not supported: {}", role); + break; + } + } + } } diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImpl.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImpl.java index 12888bf41c..5faabb4957 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImpl.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImpl.java @@ -11,16 +11,14 @@ import com.google.common.base.Function; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.JdkFutureAdapters; import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; -import org.opendaylight.controller.sal.common.util.RpcErrors; -import org.opendaylight.controller.sal.common.util.Rpcs; + import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter; import org.opendaylight.openflowplugin.ConnectionException; -import org.opendaylight.openflowplugin.api.OFConstants; import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; import org.opendaylight.openflowplugin.api.openflow.md.core.session.IMessageDispatchService; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.openflow.md.util.RpcResultUtil; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; @@ -31,14 +29,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.Upd import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.*; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.service.rev131107.UpdatePortOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.port.service.rev131107.UpdatePortOutputBuilder; -import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.Future; /** @@ -49,9 +45,6 @@ import java.util.concurrent.Future; public class MessageDispatchServiceImpl implements IMessageDispatchService { private static final Logger LOG = LoggerFactory.getLogger(MessageDispatchServiceImpl.class); - private static final String CONNECTION_ERROR_MESSAGE = "Session for the cookie is invalid. Reason: " - + "the switch has been recently disconnected OR inventory provides outdated information."; - private SessionContext session; /** @@ -98,35 +91,16 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).barrier(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } - private SettableFuture> getRpcErrorFuture(ConnectionException e) { - List rpcErrorList = getConnectionErrorAsRpcErrors(e); - SettableFuture> futureWithError = SettableFuture.create(); - futureWithError.set(Rpcs.getRpcResult(false, rpcErrorList)); - return futureWithError; - } - - private List getConnectionErrorAsRpcErrors(ConnectionException e) { - List rpcErrorList = new ArrayList<>(); - rpcErrorList.add(RpcErrors.getRpcError(OFConstants.APPLICATION_TAG, - OFConstants.ERROR_TAG_TIMEOUT, - CONNECTION_ERROR_MESSAGE, - RpcError.ErrorSeverity.WARNING, - e.getMessage(), - RpcError.ErrorType.TRANSPORT, - e.getCause())); - return rpcErrorList; - } - @Override public Future> experimenter(ExperimenterInput input, SwitchConnectionDistinguisher cookie) { try { return getConnectionAdapter(cookie).experimenter(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -137,7 +111,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { response = getConnectionAdapter(cookie).flowMod(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } // appending xid @@ -152,8 +126,10 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { flowModOutput.setTransactionId(new TransactionId(bigIntXid)); UpdateFlowOutput result = flowModOutput.build(); - RpcResult rpcResult = Rpcs.getRpcResult( - inputArg.isSuccessful(), result, inputArg.getErrors()); + RpcResult rpcResult = RpcResultBuilder + .status(inputArg.isSuccessful()) + .withResult(result).withRpcErrors(inputArg.getErrors()) + .build(); return rpcResult; } }); @@ -166,7 +142,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).getAsync(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -175,7 +151,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).getConfig(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -184,7 +160,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).getFeatures(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -194,7 +170,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).getQueueConfig(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -205,7 +181,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { response = getConnectionAdapter(cookie).groupMod(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } // appending xid @@ -220,8 +196,9 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { groupModOutput.setTransactionId(new TransactionId(bigIntXid)); UpdateGroupOutput result = groupModOutput.build(); - RpcResult rpcResult = Rpcs.getRpcResult( - inputArg.isSuccessful(), result, inputArg.getErrors()); + RpcResult rpcResult = RpcResultBuilder + .status(inputArg.isSuccessful()).withResult(result) + .withRpcErrors(inputArg.getErrors()).build(); return rpcResult; } }); @@ -236,7 +213,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { response = getConnectionAdapter(cookie).meterMod(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } // appending xid @@ -251,8 +228,9 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { meterModOutput.setTransactionId(new TransactionId(bigIntXid)); UpdateMeterOutput result = meterModOutput.build(); - RpcResult rpcResult = Rpcs.getRpcResult( - inputArg.isSuccessful(), result, inputArg.getErrors()); + RpcResult rpcResult = RpcResultBuilder + .status(inputArg.isSuccessful()).withResult(result) + .withRpcErrors(inputArg.getErrors()).build(); return rpcResult; } }); @@ -265,7 +243,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).multipartRequest(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -274,7 +252,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).packetOut(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -285,7 +263,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { response = getConnectionAdapter(cookie).portMod(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } // appending xid @@ -300,8 +278,9 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { portModOutput.setTransactionId(new TransactionId(bigIntXid)); UpdatePortOutput result = portModOutput.build(); - RpcResult rpcResult = Rpcs.getRpcResult( - inputArg.isSuccessful(), result, inputArg.getErrors()); + RpcResult rpcResult = RpcResultBuilder + .status(inputArg.isSuccessful()).withResult(result) + .withRpcErrors(inputArg.getErrors()).build(); return rpcResult; } }); @@ -314,7 +293,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).roleRequest(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -323,7 +302,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).setAsync(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -332,7 +311,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).setConfig(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } @@ -341,7 +320,7 @@ public class MessageDispatchServiceImpl implements IMessageDispatchService { try { return getConnectionAdapter(cookie).tableMod(input); } catch (ConnectionException e) { - return getRpcErrorFuture(e); + return RpcResultUtil.getRpcErrorFuture(e); } } } diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManager.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManager.java new file mode 100644 index 0000000000..a7bce0e6d2 --- /dev/null +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManager.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2014 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.openflow.md.core.session; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import java.math.BigInteger; +import java.util.Comparator; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionManager; +import org.opendaylight.openflowplugin.openflow.md.core.ThreadPoolLoggingExecutor; +import org.opendaylight.openflowplugin.openflow.md.util.RoleUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * manage OF-role propagation to devices + */ +public class OFRoleManager implements AutoCloseable { + + /** + * starting value of generationId + */ + public static final BigInteger MAX_GENERATION_ID = new BigInteger("ffffffffffffffff", 16); + + private static final Logger LOG = LoggerFactory.getLogger(OFRoleManager.class); + + private static final long TIMEOUT = 2000; + + private static final TimeUnit TIMEOUT_UNIT = TimeUnit.MILLISECONDS; + + private static final int RETRY_LIMIT = 42; + + private final ListeningExecutorService broadcastPool; + + private final BlockingQueue workQueue; + + private final SessionManager sessionManager; + + /** + * @param sessionManager + */ + public OFRoleManager(SessionManager sessionManager) { + Preconditions.checkNotNull("Session manager can not be empty.", sessionManager); + this.sessionManager = sessionManager; + workQueue = new PriorityBlockingQueue<>(500, new Comparator() { + @Override + public int compare(RolePushTask o1, RolePushTask o2) { + return Integer.compare(o1.getPriority(), o2.getPriority()); + } + }); + ThreadPoolLoggingExecutor delegate = new ThreadPoolLoggingExecutor( + 1, 1, 0, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(1), "ofRoleBroadcast"); + broadcastPool = MoreExecutors.listeningDecorator( + delegate); + } + + /** + * change role on each connected device + * + * @param role + */ + public void manageRoleChange(final OfpRole role) { + for (final SessionContext session : sessionManager.getAllSessions()) { + try { + workQueue.put(new RolePushTask(role, session)); + } catch (InterruptedException e) { + LOG.warn("Processing of role request failed while enqueueing role task: {}", e.getMessage()); + } + } + + while (!workQueue.isEmpty()) { + RolePushTask task = workQueue.poll(); + ListenableFuture rolePushResult = broadcastPool.submit(task); + CheckedFuture rolePushResultChecked = + RoleUtil.makeCheckedRuleRequestFxResult(rolePushResult); + try { + Boolean succeeded = rolePushResultChecked.checkedGet(TIMEOUT, TIMEOUT_UNIT); + if (!Objects.firstNonNull(succeeded, Boolean.FALSE)) { + if (task.getRetryCounter() < RETRY_LIMIT) { + workQueue.offer(task); + } + } + } catch (RolePushException | TimeoutException e) { + LOG.warn("failed to process role request: {}", e); + } + } + } + + @Override + public void close() throws Exception { + broadcastPool.shutdown(); + } +} diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFSessionUtil.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFSessionUtil.java index 763804ee03..d7d0e6761e 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFSessionUtil.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFSessionUtil.java @@ -182,4 +182,11 @@ public abstract class OFSessionUtil { return getSessionManager().getExtensionConverterProvider(); } + /** + * @return collection of all sessions + */ + public static Collection getAllSessions() { + return getSessionManager().getAllSessions(); + } + } diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushException.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushException.java new file mode 100644 index 0000000000..faa981c6ae --- /dev/null +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushException.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2014 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.openflow.md.core.session; + +/** + * covers role pushing issues + */ +public class RolePushException extends Exception { + + private static final long serialVersionUID = -615991366447313972L; + + /** + * default ctor + * + * @param message + */ + public RolePushException(String message) { + super(message); + } + + /** + * @param message + * @param cause + */ + public RolePushException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushTask.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushTask.java new file mode 100644 index 0000000000..feb663c838 --- /dev/null +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushTask.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2014 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.openflow.md.core.session; + +import com.google.common.base.Preconditions; +import java.math.BigInteger; +import java.util.concurrent.Callable; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.openflow.md.core.MessageFactory; +import org.opendaylight.openflowplugin.openflow.md.util.RoleUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * push role to device - basic step:
+ *
    + *
  • here we read generationId from device and
  • + *
  • push role request with incremented generationId
  • + *
  • {@link #call()} returns true if role request was successful
  • + *
+ */ +final class RolePushTask implements Callable { + + public static final Logger LOG = LoggerFactory + .getLogger(RolePushTask.class); + + public static final long TIMEOUT = 2000; + public static final TimeUnit TIMEOUT_UNIT = TimeUnit.MILLISECONDS; + private OfpRole role; + private SessionContext session; + private int priority; + private int retryCounter; + + /** + * @param role + * @param session + */ + public RolePushTask(OfpRole role, SessionContext session) { + Preconditions.checkNotNull("OfpRole can not be empty.", role); + Preconditions.checkNotNull("Session context can not be empty.", session); + this.role = role; + this.session = session; + } + + /** + * @return the retryCounter + */ + public int getRetryCounter() { + return retryCounter; + } + + /** + * @return the priority + */ + public int getPriority() { + return priority; + } + + /** + * @param priority the priority to set + */ + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public Boolean call() throws RolePushException { + if (!session.isValid()) { + String msg = "giving up role change: current session is invalid"; + LOG.debug(msg); + throw new RolePushException(msg); + } + + // adopt actual generationId from device (first shot failed and this is retry) + BigInteger generationId = null; + try { + generationId = RoleUtil.readGenerationIdFromDevice(session).get(TIMEOUT, TIMEOUT_UNIT); + } catch (Exception e) { + LOG.debug("generationId request failed: ", e); + } + + if (generationId == null) { + String msg = "giving up role change: current generationId can not be read"; + LOG.debug(msg); + throw new RolePushException(msg); + } + + generationId = RoleUtil.getNextGenerationId(generationId); + + // try to possess role on device + Future> roleReply = RoleUtil.sendRoleChangeRequest(session, role, generationId); + // flush election result with barrier + BarrierInput barrierInput = MessageFactory.createBarrier( + session.getFeatures().getVersion(), session.getNextXid()); + Future> barrierResult = session.getPrimaryConductor().getConnectionAdapter().barrier(barrierInput); + try { + barrierResult.get(TIMEOUT, TIMEOUT_UNIT); + } catch (Exception e) { + String msg = String.format("giving up role change: barrier after role change failed: %s", e.getMessage()); + LOG.warn(msg); + throw new RolePushException(msg); + } + // after barrier replied there must be election result or error + try { + roleReply.get(0, TimeUnit.MILLISECONDS); + } catch (Exception e) { + // no election result received - let's retry + retryCounter += 1; + return false; + } + + // here we expect that role on device is successfully possessed + return true; + } +} \ No newline at end of file diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionContextOFImpl.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionContextOFImpl.java index 3749756ff0..899e1f66c5 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionContextOFImpl.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionContextOFImpl.java @@ -8,6 +8,7 @@ package org.opendaylight.openflowplugin.openflow.md.core.session; +import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -18,13 +19,14 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; -import org.opendaylight.openflowplugin.api.openflow.md.core.session.IMessageDispatchService; -import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; -import org.opendaylight.openflowplugin.api.openflow.md.core.session.SwitchSessionKeyOF; import org.opendaylight.openflowplugin.api.openflow.md.ModelDrivenSwitch; import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; import org.opendaylight.openflowplugin.api.openflow.md.core.NotificationEnqueuer; import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.IMessageDispatchService; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SwitchSessionKeyOF; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ControllerRole; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortGrouping; import org.opendaylight.yangtools.concepts.CompositeObjectRegistration; @@ -46,7 +48,8 @@ public class SessionContextOFImpl implements SessionContext { private final Map portBandwidth; private CompositeObjectRegistration providerRegistration; private int seed; - + private ControllerRole roleOnDevice = ControllerRole.OFPCRROLEEQUAL; + /** * default ctor @@ -81,7 +84,7 @@ public class SessionContextOFImpl implements SessionContext { public Set> getAuxiliaryConductors() { return Collections.unmodifiableSet(auxiliaryConductors.entrySet()); } - + @Override public GetFeaturesOutput getFeatures() { return features; @@ -125,7 +128,7 @@ public class SessionContextOFImpl implements SessionContext { public void setSessionKey(SwitchSessionKeyOF sessionKey) { this.sessionKey = sessionKey; } - + /** * @param seed the seed to set */ @@ -152,7 +155,7 @@ public class SessionContextOFImpl implements SessionContext { public Map getPhysicalPorts() { return this.physicalPorts; } - + @Override public Map getPortsBandwidth() { return this.portBandwidth; @@ -207,23 +210,23 @@ public class SessionContextOFImpl implements SessionContext { } return result; } - + @Override public void setProviderRegistration( CompositeObjectRegistration providerRegistration) { this.providerRegistration = providerRegistration; } - + @Override public CompositeObjectRegistration getProviderRegistration() { return providerRegistration; } - + @Override public int getSeed() { return seed; } - + /** * @param notificationEnqueuer the notificationEnqueuer to set */ @@ -231,9 +234,26 @@ public class SessionContextOFImpl implements SessionContext { NotificationEnqueuer notificationEnqueuer) { this.notificationEnqueuer = notificationEnqueuer; } - + @Override public NotificationEnqueuer getNotificationEnqueuer() { return notificationEnqueuer; } + + /** + * @return the roleOnDevice + */ + @Override + public ControllerRole getRoleOnDevice() { + return roleOnDevice; + } + + /** + * @param roleOnDevice the roleOnDevice to set + */ + @Override + public void setRoleOnDevice(ControllerRole roleOnDevice) { + Preconditions.checkNotNull("Proposed controller role can not be empty.", roleOnDevice); + this.roleOnDevice = roleOnDevice; + } } diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionManagerOFImpl.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionManagerOFImpl.java index 5af0b5f819..be2982195d 100644 --- a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionManagerOFImpl.java +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionManagerOFImpl.java @@ -9,26 +9,24 @@ package org.opendaylight.openflowplugin.openflow.md.core.session; import com.google.common.util.concurrent.ListeningExecutorService; - import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; - import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; +import org.opendaylight.openflowplugin.api.openflow.md.core.IMDMessageTranslator; import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; import org.opendaylight.openflowplugin.api.openflow.md.core.TranslatorKey; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionListener; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SwitchSessionKeyOF; +import org.opendaylight.openflowplugin.api.openflow.md.queue.PopListener; import org.opendaylight.openflowplugin.api.statistics.MessageSpy; -import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; -import org.opendaylight.openflowplugin.api.openflow.md.core.IMDMessageTranslator; import org.opendaylight.openflowplugin.extension.api.core.extension.ExtensionConverterProvider; -import org.opendaylight.openflowplugin.api.openflow.md.queue.PopListener; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.util.ListenerRegistry; @@ -70,7 +68,7 @@ public class SessionManagerOFImpl implements ConjunctSessionManager { } /** - * close and release singleton instace + * close and release singleton instance */ public static void releaseInstance() { if (instance != null) { @@ -271,7 +269,7 @@ public class SessionManagerOFImpl implements ConjunctSessionManager { // TODO: handle timeouted shutdown rpcPool.shutdown(); } - + for (ListenerRegistration listenerRegistration : sessionListeners) { SessionListener listener = listenerRegistration.getInstance(); if (listener instanceof AutoCloseable) { @@ -317,4 +315,9 @@ public class SessionManagerOFImpl implements ConjunctSessionManager { public ExtensionConverterProvider getExtensionConverterProvider() { return extensionConverterProvider; } + + @Override + public Collection getAllSessions() { + return sessionLot.values(); + } } diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtil.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtil.java new file mode 100644 index 0000000000..d4ea43c120 --- /dev/null +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtil.java @@ -0,0 +1,156 @@ +/** + * Copyright (c) 2014 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.openflow.md.util; + +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.JdkFutureAdapters; +import com.google.common.util.concurrent.ListenableFuture; +import java.math.BigInteger; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.openflow.md.core.session.OFRoleManager; +import org.opendaylight.openflowplugin.openflow.md.core.session.RolePushException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ControllerRole; +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.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + */ +public final class RoleUtil { + + private static final Logger LOG = LoggerFactory.getLogger(RoleUtil.class); + private static final Function exceptionFunction = new Function() { + @Override + public RolePushException apply(Exception input) { + RolePushException output = null; + if (input instanceof ExecutionException) { + if (input.getCause() instanceof RolePushException) { + output = (RolePushException) input.getCause(); + } + } + + if (output == null) { + output = new RolePushException(input.getMessage(), input); + } + + return output; + } + }; + + private RoleUtil() { + throw new UnsupportedOperationException("RoleUtil is not expected to be instantiated."); + } + + /** + * @param role + * @return protocol role + */ + public 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; + } + + /** + * @param session + * @param role + * @param generationId + * @return input builder + */ + public static RoleRequestInputBuilder createRoleRequestInput( + final SessionContext session, OfpRole role, BigInteger generationId) { + + ControllerRole ofJavaRole = RoleUtil.toOFJavaRole(role); + + return new RoleRequestInputBuilder() + .setGenerationId(generationId) + .setRole(ofJavaRole) + .setVersion(session.getFeatures().getVersion()) + .setXid(session.getNextXid()); + } + + /** + * @param sessionContext + * @param ofpRole + * @param generationId + * @return roleRequest future result + */ + public static Future> sendRoleChangeRequest(SessionContext sessionContext, OfpRole ofpRole, BigInteger generationId) { + RoleRequestInputBuilder ruleRequestInputBld = RoleUtil.createRoleRequestInput(sessionContext, ofpRole, generationId); + Future> roleReply = sessionContext.getPrimaryConductor().getConnectionAdapter() + .roleRequest(ruleRequestInputBld.build()); + return roleReply; + } + + /** + * @param sessionContext + * @return generationId from future RpcResult + */ + public static Future readGenerationIdFromDevice(SessionContext sessionContext) { + Future generationIdFuture = null; + Future> roleReply = sendRoleChangeRequest(sessionContext, OfpRole.NOCHANGE, BigInteger.ZERO); + generationIdFuture = Futures.transform( + JdkFutureAdapters.listenInPoolThread(roleReply), + new Function, BigInteger>() { + @Override + public BigInteger apply(RpcResult input) { + return input.getResult().getGenerationId(); + } + }); + + return generationIdFuture; + } + + /** + * @param generationId + * @return next (incremented value) + */ + public static BigInteger getNextGenerationId(BigInteger generationId) { + BigInteger nextGenerationId = null; + if (generationId.compareTo(OFRoleManager.MAX_GENERATION_ID) < 0) { + nextGenerationId = generationId.add(BigInteger.ONE); + } else { + nextGenerationId = BigInteger.ZERO; + } + + return nextGenerationId; + } + + /** + * @param rolePushResult + * @return future which throws {@link RolePushException} + */ + public static CheckedFuture makeCheckedRuleRequestFxResult( + ListenableFuture rolePushResult) { + return Futures.makeChecked( + rolePushResult, exceptionFunction + ); + } +} diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RpcResultUtil.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RpcResultUtil.java new file mode 100644 index 0000000000..43f8c4f361 --- /dev/null +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RpcResultUtil.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014 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.openflow.md.util; + +import com.google.common.util.concurrent.SettableFuture; +import java.util.ArrayList; +import java.util.List; +import org.opendaylight.openflowplugin.ConnectionException; +import org.opendaylight.openflowplugin.api.OFConstants; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.IMessageDispatchService; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +/** + * + */ +public final class RpcResultUtil { + + private RpcResultUtil() { + throw new UnsupportedOperationException("RpcResultUtil is not expected to be instantiated."); + } + + /** + * @param e + * @return error wrapped inside {@link RpcResult} which is wrapped inside future + */ + public static SettableFuture> getRpcErrorFuture(ConnectionException e) { + List rpcErrorList = wrapConnectionErrorIntoRpcErrors(e); + SettableFuture> futureWithError = SettableFuture.create(); + futureWithError.set(RpcResultBuilder.failed().withRpcErrors(rpcErrorList).build()); + return futureWithError; + } + + private static List wrapConnectionErrorIntoRpcErrors(ConnectionException e) { + List rpcErrorList = new ArrayList<>(); + rpcErrorList.add(RpcResultBuilder.newError( + RpcError.ErrorType.TRANSPORT, + OFConstants.ERROR_TAG_TIMEOUT, + e.getMessage(), + OFConstants.APPLICATION_TAG, + IMessageDispatchService.CONNECTION_ERROR_MESSAGE, + e.getCause())); + return rpcErrorList; + } + +} diff --git a/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/TaskUtil.java b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/TaskUtil.java new file mode 100644 index 0000000000..df01952f49 --- /dev/null +++ b/openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/TaskUtil.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2014 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.openflow.md.util; + +import com.google.common.util.concurrent.JdkFutureAdapters; +import com.google.common.util.concurrent.ListenableFuture; +import java.util.concurrent.Future; +import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.IMessageDispatchService; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.openflow.md.core.MessageFactory; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutput; +import org.opendaylight.yangtools.yang.common.RpcResult; + +/** + * + */ +public final class TaskUtil { + + private TaskUtil() { + throw new AssertionError("TaskUtil is not expected to be instantiated."); + } + + /** + * @param session + * @param cookie + * @param messageService + * @return barrier response + */ + public static RpcInputOutputTuple>> sendBarrier(SessionContext session, + SwitchConnectionDistinguisher cookie, IMessageDispatchService messageService) { + BarrierInput barrierInput = MessageFactory.createBarrier( + session.getFeatures().getVersion(), session.getNextXid()); + Future> barrierResult = messageService.barrier(barrierInput, cookie); + ListenableFuture> output = JdkFutureAdapters.listenInPoolThread(barrierResult); + + return new RpcInputOutputTuple<>(barrierInput, output); + } + + +} diff --git a/openflowplugin/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/common/config/impl/rev140326/ConfigurableOpenFlowProviderModule.java b/openflowplugin/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/common/config/impl/rev140326/ConfigurableOpenFlowProviderModule.java index d518391baf..fdd9470ba7 100644 --- a/openflowplugin/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/common/config/impl/rev140326/ConfigurableOpenFlowProviderModule.java +++ b/openflowplugin/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/common/config/impl/rev140326/ConfigurableOpenFlowProviderModule.java @@ -11,6 +11,8 @@ package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflo import org.opendaylight.openflowplugin.openflow.md.core.sal.OpenflowPluginProvider; +import com.google.common.base.Objects; + /** * */ @@ -48,7 +50,27 @@ public final class ConfigurableOpenFlowProviderModule extends org.opendaylight.y pluginProvider = new OpenflowPluginProvider(); pluginProvider.setBroker(getBindingAwareBrokerDependency()); pluginProvider.setSwitchConnectionProviders(getOpenflowSwitchConnectionProviderDependency()); + pluginProvider.setRole(getRole()); pluginProvider.initialization(); return pluginProvider; } + + @Override + public boolean canReuseInstance( + AbstractConfigurableOpenFlowProviderModule oldModule) { + // we can reuse if only the role field changed + boolean noChangeExceptRole = true; + noChangeExceptRole &= getBindingAwareBrokerDependency().equals(oldModule.getBindingAwareBrokerDependency()); + noChangeExceptRole &= getOpenflowSwitchConnectionProviderDependency().equals(oldModule.getOpenflowSwitchConnectionProviderDependency()); + return noChangeExceptRole; + } + + @Override + public AutoCloseable reuseInstance(AutoCloseable oldInstance) { + OpenflowPluginProvider recycled = (OpenflowPluginProvider) super.reuseInstance(oldInstance); + // change role if different + recycled.fireRoleChange(Objects.firstNonNull(getRole(), getRole())); + + return recycled; + } } diff --git a/openflowplugin/src/main/yang/openflow-plugin-cfg-impl.yang b/openflowplugin/src/main/yang/openflow-plugin-cfg-impl.yang index 3ac7acc272..ed459ece7e 100644 --- a/openflowplugin/src/main/yang/openflow-plugin-cfg-impl.yang +++ b/openflowplugin/src/main/yang/openflow-plugin-cfg-impl.yang @@ -39,6 +39,21 @@ module openflow-provider-impl { config:java-name-prefix MsgSpyService; } + // role of OFPlugin instance + typedef ofp-role { + type enumeration { + enum NOCHANGE { + description "no change to role"; + } + enum BECOMEMASTER { + description "promote current role to MASTER"; + } + enum BECOMESLAVE { + description "demote current role to SLAVE"; + } + } + } + augment "/config:modules/config:module/config:configuration" { case openflow-provider-impl { when "/config:modules/config:module/config:type = 'openflow-provider-impl'"; @@ -59,6 +74,10 @@ module openflow-provider-impl { } } } + leaf role { + type ofp-role; + default "NOCHANGE"; + } } case msg-spy-service-impl { diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/HandshakeManagerImplTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/HandshakeManagerImplTest.java index a5a76498a5..3dbebfb7c0 100644 --- a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/HandshakeManagerImplTest.java +++ b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/HandshakeManagerImplTest.java @@ -20,7 +20,6 @@ import org.mockito.Matchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; -import org.opendaylight.controller.sal.common.util.Futures; import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter; import org.opendaylight.openflowplugin.api.OFConstants; import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; @@ -36,20 +35,22 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.Elements; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.hello.ElementsBuilder; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Futures; /** * testing handshake */ @RunWith(MockitoJUnitRunner.class) public class HandshakeManagerImplTest { - + private static final Logger LOG = LoggerFactory .getLogger(HandshakeManagerImplTest.class); - + private HandshakeManagerImpl handshakeManager; @Mock private ConnectionAdapter adapter; @@ -63,7 +64,7 @@ public class HandshakeManagerImplTest { private long helloXid = 42L; private int expectedErrors = 0; - + /** * invoked before every test method */ @@ -74,13 +75,14 @@ public class HandshakeManagerImplTest { handshakeManager.setErrorHandler(errorHandler); handshakeManager.setHandshakeListener(handshakeListener); handshakeManager.setUseVersionBitmap(false); - - resultFeatures = RpcResultsUtil.createRpcResult(true, new GetFeaturesOutputBuilder().build(), null); - + + resultFeatures = RpcResultBuilder.success(new GetFeaturesOutputBuilder().build()).build(); + Mockito.when(adapter.hello(Matchers.any(HelloInput.class))) - .thenReturn(Futures.immediateFuture(RpcResultsUtil.createRpcResult(true, (Void) null, null))); + .thenReturn(Futures.immediateFuture( + RpcResultBuilder.success((Void) null).build())); } - + /** * invoked after each test method */ @@ -93,7 +95,7 @@ public class HandshakeManagerImplTest { for (Throwable problem : errorCaptor.getAllValues()) { LOG.warn(problem.getMessage(), problem); } - + Mockito.verify(errorHandler, Mockito.times(expectedErrors)).handleException( Matchers.any(Throwable.class), Matchers.any(SessionContext.class)); } @@ -107,7 +109,7 @@ public class HandshakeManagerImplTest { {true, true, true, false, false, false}, {true, true, true, false, false} }; - + for (Boolean[] verasionList : versions) { ElementsBuilder elementsBuilder = new ElementsBuilder(); elementsBuilder.setVersionBitmap(Lists.newArrayList(verasionList)); @@ -145,7 +147,7 @@ public class HandshakeManagerImplTest { } //////// Version Negotiation Tests ////////////// - + /** * Test of version negotiation Where switch version = 1.0 * @@ -155,18 +157,18 @@ public class HandshakeManagerImplTest { public void testVersionNegotiation10() throws Exception { LOG.debug("testVersionNegotiation10"); Short version = OFConstants.OFP_VERSION_1_0; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull(resultFeatures.getResult(), version); } - + /** * Test of version negotiation Where switch version = 1.0 * @@ -176,13 +178,13 @@ public class HandshakeManagerImplTest { public void testVersionNegotiation10SwitchStarts() throws Exception { LOG.debug("testVersionNegotiation10-ss"); Short version = OFConstants.OFP_VERSION_1_0; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull(resultFeatures.getResult(), version); } @@ -196,14 +198,14 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation00"); expectedErrors = 1; Short version = (short) 0x00; - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener, Mockito.never()).onHandshakeSuccessfull( Matchers.any(GetFeaturesOutput.class), Matchers.anyShort()); } - + /** * Test of version negotiation Where switch version < 1.0 * Switch delivers first helloMessage with version 0x00 = negotiation unsuccessful @@ -214,12 +216,12 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation00-ss"); expectedErrors = 1; Short version = (short) 0x00; - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener, Mockito.never()).onHandshakeSuccessfull( Matchers.any(GetFeaturesOutput.class), Matchers.anyShort()); } @@ -234,20 +236,20 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation11"); Short version = (short) 0x02; Short expVersion = (short) 0x01; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(expVersion, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), expVersion); } - + /** * Test of version negotiation Where 1.0 < switch version < 1.3 * @@ -258,18 +260,18 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation11-ss"); Short version = (short) 0x02; Short expVersion = (short) 0x01; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(expVersion, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), expVersion); } @@ -283,17 +285,17 @@ public class HandshakeManagerImplTest { public void testVersionNegotiation13() throws Exception { LOG.debug("testVersionNegotiation13"); Short version = OFConstants.OFP_VERSION_1_3; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), version); } - + /** * Test of version negotiation Where switch version = 1.3 * @@ -303,15 +305,15 @@ public class HandshakeManagerImplTest { public void testVersionNegotiation13SwitchStarts() throws Exception { LOG.debug("testVersionNegotiation13-ss"); Short version = OFConstants.OFP_VERSION_1_3; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), version); } @@ -326,20 +328,20 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation15"); Short version = (short) 0x06; Short expVersion = OFConstants.OFP_VERSION_1_3; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(expVersion, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), expVersion); } - + /** * Test of version negotiation Where switch version >= 1.3 * @@ -350,16 +352,16 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation15-ss"); Short version = (short) 0x06; Short expVersion = OFConstants.OFP_VERSION_1_3; - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(expVersion, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), expVersion); } @@ -374,17 +376,17 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation15_MultipleCall"); Short version = (short) 0x06; expectedErrors = 1; - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener, Mockito.never()).onHandshakeSuccessfull( Matchers.any(GetFeaturesOutput.class), Matchers.anyShort()); } - + /** * Test of version negotiation Where switch version > 1.3 * @@ -395,15 +397,15 @@ public class HandshakeManagerImplTest { LOG.debug("testVersionNegotiation15_MultipleCall-ss"); Short version = (short) 0x06; expectedErrors = 1; - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + handshakeManager.setReceivedHello(createHelloMessage(version, helloXid).build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener, Mockito.never()).onHandshakeSuccessfull( Matchers.any(GetFeaturesOutput.class), Matchers.anyShort()); } @@ -421,17 +423,17 @@ public class HandshakeManagerImplTest { HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid); addVersionBitmap(Lists.newArrayList((short) 0x05, OFConstants.OFP_VERSION_1_0), helloMessage); - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.setReceivedHello(helloMessage.build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), version); } - + /** * Test of version negotiation Where bitmap version {0x05,0x01} * @@ -445,15 +447,15 @@ public class HandshakeManagerImplTest { HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid); addVersionBitmap(Lists.newArrayList((short) 0x05, OFConstants.OFP_VERSION_1_0), helloMessage); - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(helloMessage.build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), version); } @@ -471,17 +473,17 @@ public class HandshakeManagerImplTest { HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid); addVersionBitmap(Lists.newArrayList((short) 0x05, OFConstants.OFP_VERSION_1_3), helloMessage); - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.setReceivedHello(helloMessage.build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), version); } - + /** * Test of version negotiation Where bitmap version {0x05,0x04} * @@ -495,15 +497,15 @@ public class HandshakeManagerImplTest { HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid); addVersionBitmap(Lists.newArrayList((short) 0x05, OFConstants.OFP_VERSION_1_3), helloMessage); - + Mockito.when(adapter.getFeatures(Matchers.any(GetFeaturesInput.class))) .thenReturn(Futures.immediateFuture(resultFeatures)); - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(helloMessage.build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener).onHandshakeSuccessfull( resultFeatures.getResult(), version); } @@ -519,17 +521,17 @@ public class HandshakeManagerImplTest { Short version = (short) 0x05; expectedErrors = 1; handshakeManager.setUseVersionBitmap(true); - + HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid); addVersionBitmap(Lists.newArrayList((short) 0x05, (short) 0x02), helloMessage); - + handshakeManager.setReceivedHello(helloMessage.build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener, Mockito.never()).onHandshakeSuccessfull( Matchers.any(GetFeaturesOutput.class), Matchers.anyShort()); } - + /** * Test of version negotiation Where bitmap version {0x05,0x02} * @@ -541,15 +543,15 @@ public class HandshakeManagerImplTest { Short version = (short) 0x05; expectedErrors = 1; handshakeManager.setUseVersionBitmap(true); - + HelloMessageBuilder helloMessage = createHelloMessage(version, helloXid); addVersionBitmap(Lists.newArrayList((short) 0x05, (short) 0x02), helloMessage); - + handshakeManager.shake(); - + handshakeManager.setReceivedHello(helloMessage.build()); handshakeManager.shake(); - + Mockito.verify(handshakeListener, Mockito.never()).onHandshakeSuccessfull( Matchers.any(GetFeaturesOutput.class), Matchers.anyShort()); } @@ -563,7 +565,7 @@ public class HandshakeManagerImplTest { private static HelloMessageBuilder createHelloMessage(short ofpVersion10, long helloXid) { return new HelloMessageBuilder().setVersion(ofpVersion10).setXid(helloXid); } - + /** * @param versionOrder * @param helloBuilder diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/RpcResultsUtil.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/RpcResultsUtil.java deleted file mode 100644 index d1d6c351cd..0000000000 --- a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/RpcResultsUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2014 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.openflow.md.core; - -import java.util.Collection; -import java.util.Collections; -import org.opendaylight.controller.sal.common.util.Rpcs; -import org.opendaylight.yangtools.yang.common.RpcError; -import org.opendaylight.yangtools.yang.common.RpcResult; - -/** - * Created by Martin Bobak mbobak@cisco.com on 8/25/14. - */ -public class RpcResultsUtil { - - /** - * @param success - * @param result - * @param errors - * @return - */ - public static RpcResult createRpcResult(boolean success, T result, Collection errorsArg) { - Collection errors = errorsArg; - if (errors == null) { - errors = Collections.emptyList(); - } - return Rpcs.getRpcResult(success, result, errors); - } - -} diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImplTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImplTest.java index 09a532abab..bb20b31aa1 100644 --- a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImplTest.java +++ b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImplTest.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.junit.Assert; @@ -34,6 +33,7 @@ import org.opendaylight.openflowplugin.api.openflow.md.core.session.IMessageDisp import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; import org.opendaylight.openflowplugin.api.openflow.md.core.session.SwitchSessionKeyOF; import org.opendaylight.openflowplugin.api.openflow.md.queue.QueueProcessor; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ControllerRole; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutput; @@ -128,7 +128,7 @@ public class MessageDispatchServiceImplTest { * Test get async input with null cookie */ @Test - public void testGetAsync() throws ExecutionException, InterruptedException { + public void testGetAsync() { MockConnectionConductor conductor = new MockConnectionConductor(1); SwitchConnectionDistinguisher cookie = conductor.getAuxiliaryKey(); GetAsyncInputBuilder getAsyncInputBuilder = new GetAsyncInputBuilder(); @@ -328,7 +328,7 @@ class MockSessionContext implements SessionContext { MockSessionContext(int conductorNum) { conductor = new MockConnectionConductor(conductorNum); - map = new HashMap(); + map = new HashMap<>(); messageService = new MessageDispatchServiceImpl(this); sessionKey = new SwitchSessionKeyOF(); sessionKey.setDatapathId(new BigInteger("0")); @@ -476,6 +476,16 @@ class MockSessionContext implements SessionContext { public NotificationEnqueuer getNotificationEnqueuer() { return conductor; } + + @Override + public ControllerRole getRoleOnDevice() { + return null; + } + + @Override + public void setRoleOnDevice(ControllerRole roleOnDevice) { + // NOOP + } } class MockConnectionConductor implements ConnectionConductor, diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManagerTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManagerTest.java new file mode 100644 index 0000000000..d2ea001294 --- /dev/null +++ b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManagerTest.java @@ -0,0 +1,143 @@ +/** + * Copyright (c) 2014 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.openflow.md.core.session; + +import com.google.common.util.concurrent.Futures; +import java.math.BigInteger; +import java.util.Collections; +import java.util.List; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter; +import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionManager; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ControllerRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.BarrierOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestInput; +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.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +/** + * + */ +@RunWith(MockitoJUnitRunner.class) +public class OFRoleManagerTest { + + @Mock + private SessionManager sessionManager; + @Mock + private SessionContext session; + @Mock + private GetFeaturesOutput features; + @Mock + private ConnectionConductor primaryConductor; + @Mock + private ConnectionAdapter connectionAdapter; + + private OFRoleManager manager; + private RoleRequestOutput roleRequestOutput; + private BarrierOutput barrierOutput; + private BigInteger generationId = BigInteger.TEN; + + /** + * prepare values + */ + @Before + public void setUp() { + Mockito.when(session.getFeatures()).thenReturn(features); + Mockito.when(features.getVersion()).thenReturn(Short.valueOf((short) 42)); + Mockito.when(session.getNextXid()).thenReturn(84L); + Mockito.when(session.getPrimaryConductor()).thenReturn(primaryConductor); + Mockito.when(primaryConductor.getConnectionAdapter()).thenReturn(connectionAdapter); + roleRequestOutput = new RoleRequestOutputBuilder() + .setGenerationId(generationId) + .setRole(ControllerRole.OFPCRROLESLAVE) + .setVersion((short) 42) + .setXid(21L) + .build(); + barrierOutput = new BarrierOutputBuilder() + .setVersion((short) 42) + .setXid(1L) + .build(); + + manager = new OFRoleManager(sessionManager); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.core.session.OFRoleManager#manageRoleChange(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole)}. + *
+ * session lot is empty is invalid + */ + @Test + public void testManageRoleChangeFail1() { + manager.manageRoleChange(OfpRole.BECOMESLAVE); + Mockito.verify(connectionAdapter, Mockito.never()).roleRequest(Matchers.any(RoleRequestInput.class)); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.core.session.OFRoleManager#manageRoleChange(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole)}. + *
+ * available session is invalid + */ + @Test + public void testManageRoleChangeFail2() { + Mockito.when(sessionManager.getAllSessions()).thenReturn(Collections.singleton(session)); + manager.manageRoleChange(OfpRole.BECOMESLAVE); + Mockito.verify(connectionAdapter, Mockito.never()).roleRequest(Matchers.any(RoleRequestInput.class)); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.core.session.OFRoleManager#manageRoleChange(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole)}. + *
+ * device bound to valid session is not answering + */ + @Test + public void testManageRoleChangeFail3() { + Mockito.when(session.isValid()).thenReturn(true); + Mockito.when(sessionManager.getAllSessions()).thenReturn(Collections.singleton(session)); + manager.manageRoleChange(OfpRole.BECOMESLAVE); + Mockito.verify(connectionAdapter, Mockito.times(1)).roleRequest(Matchers.any(RoleRequestInput.class)); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.core.session.OFRoleManager#manageRoleChange(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole)}. + */ + @Test + public void testManageRoleChangeOK() { + Mockito.when(session.isValid()).thenReturn(true); + Mockito.when(sessionManager.getAllSessions()).thenReturn(Collections.singleton(session)); + Mockito.when(connectionAdapter.roleRequest(Matchers.any(RoleRequestInput.class))) + .thenReturn(Futures.immediateFuture(RpcResultBuilder.success(roleRequestOutput).build())); + Mockito.when(connectionAdapter.barrier(Matchers.any(BarrierInput.class))) + .thenReturn(Futures.immediateFuture(RpcResultBuilder.success(barrierOutput).build())); + + manager.manageRoleChange(OfpRole.BECOMESLAVE); + + ArgumentCaptor roleRequestCaptor = ArgumentCaptor.forClass(RoleRequestInput.class); + Mockito.verify(connectionAdapter, Mockito.times(2)).roleRequest(roleRequestCaptor.capture()); + + List values = roleRequestCaptor.getAllValues(); + Assert.assertEquals(ControllerRole.OFPCRROLENOCHANGE, values.get(0).getRole()); + Assert.assertEquals(0L, values.get(0).getGenerationId().longValue()); + Assert.assertEquals(ControllerRole.OFPCRROLESLAVE, values.get(1).getRole()); + Assert.assertEquals(11L, values.get(1).getGenerationId().longValue()); + } +} diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/translator/PacketInV10TranslatorTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/translator/PacketInV10TranslatorTest.java index 570e511da9..043811a68c 100644 --- a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/translator/PacketInV10TranslatorTest.java +++ b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/translator/PacketInV10TranslatorTest.java @@ -17,7 +17,6 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -48,10 +47,10 @@ import org.slf4j.LoggerFactory; * Created by Jakub Toth jatoth@cisco.com on 3/10/14. */ @RunWith(MockitoJUnitRunner.class) -public class PacketInV10TranslatorTest{ +public class PacketInV10TranslatorTest { private static final Logger LOG = LoggerFactory .getLogger(PacketInV10TranslatorTest.class); - + @Mock private SessionContext sc; @Mock @@ -61,7 +60,7 @@ public class PacketInV10TranslatorTest{ private SwitchConnectionDistinguisher cookie; private byte[] data; - + /** * Initializes mocks */ @@ -72,11 +71,11 @@ public class PacketInV10TranslatorTest{ when(sc.getFeatures()).thenReturn(features); when(features.getDatapathId()).thenReturn(new BigInteger("42")); OpenflowPortsUtil.init(); - + cookie = settingCookie(); data = messageData(); } - + /** * test * {@link PacketInV10Translator#translate(SwitchConnectionDistinguisher, SessionContext, OfHeader)} @@ -84,7 +83,7 @@ public class PacketInV10TranslatorTest{ * MD-SAL model, supports OF-1.0 */ @Test - public void testTranslateWithAllNullParam(){ + public void testTranslateWithAllNullParam() { SwitchConnectionDistinguisher cookieNull = null; SessionContext sessionContext = null; OfHeader msg = null; @@ -106,8 +105,8 @@ public class PacketInV10TranslatorTest{ * supports OF-1.0 */ @Test - public void testTranslateDPIDNull(){ - SessionContextOFImpl sessionContextOFImpl = new SessionContextOFImpl(); + public void testTranslateDPIDNull() { + SessionContext sessionContextOFImpl = new SessionContextOFImpl(); PacketInMessage message = createPacketInMessage(data, null); @@ -127,7 +126,7 @@ public class PacketInV10TranslatorTest{ * supports OF-1.0 */ @Test - public void testTranslateInPortNull(){ + public void testTranslateInPortNull() { BigInteger datapathId = dataPathId(); GetFeaturesOutputBuilder featuresBuilder = new GetFeaturesOutputBuilder(); @@ -152,11 +151,11 @@ public class PacketInV10TranslatorTest{ * test * {@link PacketInV10Translator#translate(SwitchConnectionDistinguisher, SessionContext, OfHeader)} * - translates packetIn from OF-API model to MD-SAL model, supports OF-1.0 - * + * * @throws IOException */ @Test - public void testTranslate(){ + public void testTranslate() { BigInteger datapathId = dataPathId(); PacketInMessage message = createPacketInMessage(data, 5); @@ -170,7 +169,7 @@ public class PacketInV10TranslatorTest{ OpenflowPortsUtil.init(); List salPacketIn = packetInV10Translator.translate(cookie, sessionContextOFImpl, message); - + //TODO: rewrite to object and involve object comparison in Assert String expectedString = "[PacketReceived [_ingress=NodeConnectorRef [_value=KeyedInstanceIdentifier" + "{targetType=interface org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector," @@ -193,12 +192,12 @@ public class PacketInV10TranslatorTest{ /** * create datapathID - * + * * @return BigInteger */ - private static BigInteger dataPathId(){ + private static BigInteger dataPathId() { byte[] datapathIdByte = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES]; - for(int i = 0; i < datapathIdByte.length; i++){ + for (int i = 0; i < datapathIdByte.length; i++) { datapathIdByte[i] = 1; } return new BigInteger(1, datapathIdByte); @@ -206,23 +205,23 @@ public class PacketInV10TranslatorTest{ /** * generate message from string to byte[] - * + * * @return byte[] */ - private static byte[] messageData(){ + private static byte[] messageData() { String string = new String("sendOutputMsg_TEST"); return string.getBytes(); } /** * create PacketInMessage with setting Version, InPort, Data, Reason - * + * * @param data * @param port * @return PacketInMessage */ private static PacketInMessage createPacketInMessage(final byte[] data, - final java.lang.Integer port){ + final java.lang.Integer port) { PacketInReason reason = PacketInReason.OFPRACTION; return new PacketInMessageBuilder() .setVersion((short) EncodeConstants.OF10_VERSION_ID) @@ -232,10 +231,10 @@ public class PacketInV10TranslatorTest{ /** * create cookie - * + * * @return SwitchConnectionDistinguisher */ - private static SwitchConnectionDistinguisher settingCookie(){ + private static SwitchConnectionDistinguisher settingCookie() { SwitchConnectionCookieOFImpl key = new SwitchConnectionCookieOFImpl(); key.setAuxiliaryId((short) 1); key.init(42); @@ -244,24 +243,24 @@ public class PacketInV10TranslatorTest{ /** * create GetFeatureOutput - * + * * @param datapathId * @return GetFeaturesOutput */ - private static GetFeaturesOutput createGetFeatureOutput(final BigInteger datapathId){ + private static GetFeaturesOutput createGetFeatureOutput(final BigInteger datapathId) { return new GetFeaturesOutputBuilder().setDatapathId(datapathId) .setVersion((short) 0x01).build(); } /** * init connectionConductor - * + * * @param connectionConductor * @param featuresOutput */ private static void initConnectionConductor( final ConnectionConductorImpl connectionConductor, - final GetFeaturesOutput featuresOutput){ + final GetFeaturesOutput featuresOutput) { TranslatorKey paramK = new TranslatorKey(1, PacketInMessage.class.getSimpleName()); Collection>> coll = new ArrayList<>(); coll.add(new PacketInV10Translator()); diff --git a/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtilTest.java b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtilTest.java new file mode 100644 index 0000000000..e46c040f43 --- /dev/null +++ b/openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtilTest.java @@ -0,0 +1,190 @@ +/** + * Copyright (c) 2014 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.openflow.md.util; + +import java.math.BigInteger; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter; +import org.opendaylight.openflowplugin.api.openflow.md.core.ConnectionConductor; +import org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext; +import org.opendaylight.openflowplugin.openflow.md.core.session.OFRoleManager; +import org.opendaylight.openflowplugin.openflow.md.core.session.RolePushException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.ControllerRole; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequest; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.RoleRequestInput; +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.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import com.google.common.util.concurrent.Futures; + +/** + * testing {@link RoleUtil} + */ +@RunWith(MockitoJUnitRunner.class) +public class RoleUtilTest { + + @Mock + private SessionContext session; + @Mock + private GetFeaturesOutput features; + @Mock + private ConnectionConductor primaryConductor; + @Mock + private ConnectionAdapter connectionAdapter; + + private final BigInteger generationId = BigInteger.TEN; + private RoleRequestOutput roleRequestOutput; + + /** + * prepare values + */ + @Before + public void setUp() { + Mockito.when(session.getFeatures()).thenReturn(features); + Mockito.when(features.getVersion()).thenReturn(Short.valueOf((short) 42)); + Mockito.when(session.getNextXid()).thenReturn(84L); + Mockito.when(session.getPrimaryConductor()).thenReturn(primaryConductor); + Mockito.when(primaryConductor.getConnectionAdapter()).thenReturn(connectionAdapter); + roleRequestOutput = new RoleRequestOutputBuilder() + .setGenerationId(generationId) + .setRole(ControllerRole.OFPCRROLESLAVE) + .setVersion((short) 42) + .setXid(21L) + .build(); + Mockito.when(connectionAdapter.roleRequest(Matchers.any(RoleRequestInput.class))) + .thenReturn(Futures.immediateFuture(RpcResultBuilder.success(roleRequestOutput).build())); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.util.RoleUtil#toOFJavaRole(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole)}. + */ + @Test + public void testToOFJavaRole() { + Assert.assertEquals(ControllerRole.OFPCRROLEMASTER, RoleUtil.toOFJavaRole(OfpRole.BECOMEMASTER)); + Assert.assertEquals(ControllerRole.OFPCRROLESLAVE, RoleUtil.toOFJavaRole(OfpRole.BECOMESLAVE)); + Assert.assertEquals(ControllerRole.OFPCRROLENOCHANGE, RoleUtil.toOFJavaRole(OfpRole.NOCHANGE)); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.util.RoleUtil#toOFJavaRole(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole)}. + */ + @Test(expected = NullPointerException.class) + public void testToOFJavaRoleNull() { + RoleUtil.toOFJavaRole(null); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.util.RoleUtil#createRoleRequestInput(org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole, java.math.BigInteger)}. + */ + @Test + public void testCreateRuleRequestInput() { + RoleRequestInput roleRequestInput = RoleUtil.createRoleRequestInput(session, OfpRole.BECOMEMASTER, generationId).build(); + Assert.assertEquals(generationId, roleRequestInput.getGenerationId()); + Assert.assertEquals(RoleRequestInput.class, roleRequestInput.getImplementedInterface()); + Assert.assertEquals(ControllerRole.OFPCRROLEMASTER, roleRequestInput.getRole()); + Assert.assertEquals(42, roleRequestInput.getVersion().intValue()); + Assert.assertEquals(84L, roleRequestInput.getXid().longValue()); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.util.RoleUtil#sendRoleChangeRequest(org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext, org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326.OfpRole, java.math.BigInteger)}. + * @throws Exception + */ + @Test + public void testSendRoleChangeRequest() throws Exception { + Future> roleRequestOutputFx = RoleUtil.sendRoleChangeRequest(session, OfpRole.BECOMEMASTER, generationId); + Assert.assertNotNull(roleRequestOutputFx); + + ArgumentCaptor roleRequestCaptor = ArgumentCaptor.forClass(RoleRequestInput.class); + Mockito.verify(connectionAdapter).roleRequest(roleRequestCaptor.capture()); + + RoleRequest roleRequestInput = roleRequestCaptor.getValue(); + Assert.assertEquals(generationId, roleRequestInput.getGenerationId()); + Assert.assertEquals(RoleRequestInput.class, roleRequestInput.getImplementedInterface()); + Assert.assertEquals(ControllerRole.OFPCRROLEMASTER, roleRequestInput.getRole()); + Assert.assertEquals(42, roleRequestInput.getVersion().intValue()); + Assert.assertEquals(84L, roleRequestInput.getXid().longValue()); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.util.RoleUtil#readGenerationIdFromDevice(org.opendaylight.openflowplugin.api.openflow.md.core.session.SessionContext)}. + * @throws Exception + */ + @Test + public void testReadGenerationIdFromDevice() throws Exception { + BigInteger generationIdFromDevice = RoleUtil.readGenerationIdFromDevice(session).get(); + Assert.assertEquals(generationId, generationIdFromDevice); + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.util.RoleUtil#getNextGenerationId(java.math.BigInteger)}. + */ + @Test + public void testGetNextGenerationId() { + BigInteger[] src = new BigInteger[] { + BigInteger.ZERO, + BigInteger.ONE, + OFRoleManager.MAX_GENERATION_ID.subtract(BigInteger.ONE), + OFRoleManager.MAX_GENERATION_ID + }; + + BigInteger[] out = new BigInteger[] { + BigInteger.ONE, + BigInteger.valueOf(2L), + OFRoleManager.MAX_GENERATION_ID, + BigInteger.ZERO + }; + + for (int i = 0; i < src.length; i++) { + BigInteger nextGenerationId = RoleUtil.getNextGenerationId(src[i]); + Assert.assertEquals(out[i], nextGenerationId); + } + } + + /** + * Test method for {@link org.opendaylight.openflowplugin.openflow.md.util.RoleUtil#makeCheckedRuleRequestFxResult(com.google.common.util.concurrent.ListenableFuture)}. + * @throws Exception + */ + @Test + public void testMakeCheckedRuleRequestFxResult() throws Exception { + String message = "me sooo naughty!"; + try { + RoleUtil.makeCheckedRuleRequestFxResult(Futures.immediateFailedFuture(new Exception(message))).checkedGet(); + } catch (Exception e) { + Assert.assertEquals(RolePushException.class, e.getClass()); + Assert.assertEquals(ExecutionException.class, e.getCause().getClass()); + Assert.assertEquals(Exception.class, e.getCause().getCause().getClass()); + Assert.assertNull(e.getCause().getCause().getCause()); + Assert.assertEquals(message, e.getCause().getCause().getMessage()); + } + + try { + RoleUtil.makeCheckedRuleRequestFxResult(Futures.immediateFailedFuture(new RolePushException(message))).checkedGet(); + } catch (Exception e) { + Assert.assertEquals(RolePushException.class, e.getClass()); + Assert.assertNull(e.getCause()); + Assert.assertEquals(message, e.getMessage()); + } + + } +} diff --git a/pom.xml b/pom.xml index 10034e0128..1dabc11abd 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,7 @@ utf-8 1.2.0-SNAPSHOT + 1.2.0-SNAPSHOT http://nexus.opendaylight.org/content 0.6.0-SNAPSHOT ${project.version} @@ -87,20 +88,22 @@ yang-binding ${yang.binding.version}
- - org.opendaylight.yangtools - yang-common - ${yang.binding.version} - - - org.opendaylight.yangtools.model - ietf-inet-types - ${ietf-inet-types.version} + + org.opendaylight.yangtools + yang-common + ${yang.binding.version} + import + pom - org.opendaylight.yangtools.model - ietf-yang-types - ${ietf-yang-types.version} + org.opendaylight.yangtools.model + ietf-inet-types + ${ietf-inet-types.version} + + + org.opendaylight.yangtools.model + ietf-yang-types + ${ietf-yang-types.version} org.opendaylight.yangtools.model -- 2.36.6