Bug-2827: role switch proposal 95/16495/1
authorMartin Bobak <mbobak@cisco.com>
Mon, 1 Dec 2014 13:36:16 +0000 (14:36 +0100)
committerMichal Rehak <mirehak@cisco.com>
Fri, 13 Mar 2015 18:10:37 +0000 (19:10 +0100)
- 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)
- worked-in configSubsystem change

Change-Id: I942d4b0e297543324c5fa0495f078834bee44899
Signed-off-by: Michal Rehak <mirehak@cisco.com>
Signed-off-by: Martin Bobak <mbobak@cisco.com>
26 files changed:
features/pom.xml
features/src/main/resources/features.xml
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/IMessageDispatchService.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionContext.java
openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/md/core/session/SessionManager.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OFRpcTaskUtil.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/sal/OpenflowPluginProvider.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImpl.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManager.java [new file with mode: 0644]
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFSessionUtil.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushException.java [new file with mode: 0644]
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/RolePushTask.java [new file with mode: 0644]
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionContextOFImpl.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/core/session/SessionManagerOFImpl.java
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtil.java [new file with mode: 0644]
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/RpcResultUtil.java [new file with mode: 0644]
openflowplugin/src/main/java/org/opendaylight/openflowplugin/openflow/md/util/TaskUtil.java [new file with mode: 0644]
openflowplugin/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/openflow/common/config/impl/rev140326/ConfigurableOpenFlowProviderModule.java
openflowplugin/src/main/yang/openflow-plugin-cfg-impl.yang
openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/HandshakeManagerImplTest.java
openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/RpcResultsUtil.java [deleted file]
openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/MessageDispatchServiceImplTest.java
openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/session/OFRoleManagerTest.java [new file with mode: 0644]
openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/core/translator/PacketInV10TranslatorTest.java
openflowplugin/src/test/java/org/opendaylight/openflowplugin/openflow/md/util/RoleUtilTest.java [new file with mode: 0644]
pom.xml

index 3eb0df4d696a3cf7e10bdc6a68b06359508c2567..4721d60586f39b1b59305eb8631aef3d60be6094 100644 (file)
@@ -99,8 +99,8 @@
       <classifier>config</classifier>
       <type>xml</type>
     </dependency>
-    
-    
+
+
     <dependency>
       <groupId>org.opendaylight.dlux</groupId>
       <artifactId>features-dlux</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-netconf-connector</artifactId>
+      <version>${netconf.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
 
     <!-- bundle dependencies -->
     <dependency>
index 1b6549ab696fcefc602ff7bf256de885b5aca4e9..095db24319e41cacddd7a22410e05cf95bb6c273 100644 (file)
@@ -8,6 +8,7 @@
     <repository>mvn:org.opendaylight.openflowjava/features-openflowjava/${openflowjava.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.dlux/features-dlux/${dlux.version}/xml/features</repository>
     <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
+    <!-- repository>mvn:org.opendaylight.controller/features-netconf-connector/${netconf.version}/xml/features</repository -->
 
     <feature name='odl-openflowplugin-all' description="OpenDaylight :: Openflow Plugin :: All" version='${project.version}'>
         <feature version="${project.version}">odl-openflowplugin-southbound</feature>
@@ -33,7 +34,7 @@
         <feature version="${project.version}">odl-openflowplugin-app-config-pusher</feature>
         <feature version="${project.version}">odl-openflowplugin-app-lldp-speaker</feature>
     </feature>
-    
+
     <feature name='odl-openflowplugin-nsf-services' version='${project.version}'
         description="OpenDaylight :: OpenflowPlugin :: NSF :: Services">
         <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
@@ -46,7 +47,7 @@
         <bundle>mvn:org.opendaylight.controller/liblldp/${sal.api.version}</bundle>
         <configfile finalname="${config.configfile.directory}/${config.statistics.manager.configfile}">mvn:org.opendaylight.openflowplugin.applications/statistics-manager-config/${project.version}/xml/config</configfile>
     </feature>
-    
+
     <feature name='odl-openflowplugin-nsf-model' version='${project.version}'
         description="OpenDaylight :: OpenflowPlugin :: NSF :: Model">
         <!-- general models -->
@@ -58,8 +59,9 @@
         <bundle>mvn:org.opendaylight.openflowplugin.model/model-flow-statistics/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.openflowplugin.model/model-flow-service/${project.version}</bundle>
     </feature>
-    
+
     <feature name='odl-openflowplugin-flow-services-rest' description="OpenDaylight :: Openflow Plugin :: Flow Services :: REST" version='${project.version}'>
+        <!-- feature version="${netconf.version}">odl-netconf-connector-ssh</feature -->
         <feature version="${project.version}">odl-openflowplugin-flow-services</feature>
         <feature version="${mdsal.version}">odl-restconf</feature>
     </feature>
@@ -69,7 +71,7 @@
         <feature version="${mdsal.version}">odl-mdsal-apidocs</feature>
         <feature version="${mdsal.version}">odl-mdsal-xsql</feature>
     </feature>
-    
+
     <!-- CBENCH TESTING -->
     <feature name='odl-openflowplugin-drop-test' description="OpenDaylight :: Openflow Plugin :: Drop Test" version='${project.version}'>
         <feature version="${project.version}">odl-openflowplugin-flow-services</feature>
index 601265d2a1de801d39ebeb431290b8f96fc1f121..0b3d74a6980422bbd8a45588a82f1d387f7ee862 100644 (file)
@@ -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
      *
index 2fe1ff0d03627c7aea83b40ab421f465c5a5d7ad..eec52194be693942f4898e8ae575c0129e2999cb 100644 (file)
@@ -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<Long, PortGrouping> 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<Long> 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<ModelDrivenSwitch> 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();
 }
index d82bd7cef7bf23dac1ae51ac1be8f2d9c5f397df..9b45a1a87aff27f419a1cad72c6e83dd054154ba 100644 (file)
@@ -134,4 +134,8 @@ public interface SessionManager extends AutoCloseable {
      */
     MessageSpy<DataContainer> getMessageSpy();
 
+    /**
+     * @return collection of current sessions
+     */
+    Collection<SessionContext> getAllSessions();
 }
index 58211395291518639a7d9efe428e19e289c83a1f..73171cbfb508ffb15ebfa76dd077b26133785185 100644 (file)
@@ -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<RpcError> errors = null;
         if (Objects.firstNonNull(isBarrier, Boolean.FALSE)) {
             RpcInputOutputTuple<BarrierInput, ListenableFuture<RpcResult<BarrierOutput>>> sendBarrierRpc =
-                    sendBarrier(taskContext.getSession(), cookie, taskContext.getMessageService());
+                    TaskUtil.sendBarrier(taskContext.getSession(), cookie, taskContext.getMessageService());
             Future<RpcResult<BarrierOutput>> barrierFuture = sendBarrierRpc.getOutput();
             try {
                 RpcResult<BarrierOutput> 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<BarrierInput, ListenableFuture<RpcResult<BarrierOutput>>> sendBarrier(SessionContext session,
-            SwitchConnectionDistinguisher cookie, IMessageDispatchService messageService) {
-        BarrierInput barrierInput = MessageFactory.createBarrier(
-                session.getFeatures().getVersion(), session.getNextXid());
-        Future<RpcResult<BarrierOutput>> barrierResult = messageService.barrier(barrierInput, cookie);
-        ListenableFuture<RpcResult<BarrierOutput>> 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<RpcResult<T>> apply(final RpcResult<T> input) throws Exception {
                     if (input.isSuccessful()) {
-                        RpcInputOutputTuple<BarrierInput, ListenableFuture<RpcResult<BarrierOutput>>> sendBarrierRpc = sendBarrier(
+                        RpcInputOutputTuple<BarrierInput, ListenableFuture<RpcResult<BarrierOutput>>> sendBarrierRpc = TaskUtil.sendBarrier(
                                 task.getSession(), task.getCookie(), task.getMessageService());
                         ListenableFuture<RpcResult<T>> barrierTxResult = Futures.transform(
                                 sendBarrierRpc.getOutput(),
index 3ca9a2676d0afa0ca0687797b64e40d4c1ebcef8..33b65a4bc26cb28f6ab156f627ac8c54119854c5 100644 (file)
@@ -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;
+            }
+        }
+    }
 }
index 12888bf41c603f7e0e370146ccb631a7f4d586c8..5faabb495788c15a8ae8a77d6c85177861c140b8 100644 (file)
@@ -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 <T> SettableFuture<RpcResult<T>> getRpcErrorFuture(ConnectionException e) {
-        List<RpcError> rpcErrorList = getConnectionErrorAsRpcErrors(e);
-        SettableFuture<RpcResult<T>> futureWithError = SettableFuture.create();
-        futureWithError.set(Rpcs.<T>getRpcResult(false, rpcErrorList));
-        return futureWithError;
-    }
-
-    private List<RpcError> getConnectionErrorAsRpcErrors(ConnectionException e) {
-        List<RpcError> 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<RpcResult<Void>> 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<UpdateFlowOutput> rpcResult = Rpcs.getRpcResult(
-                                inputArg.isSuccessful(), result, inputArg.getErrors());
+                        RpcResult<UpdateFlowOutput> rpcResult = RpcResultBuilder
+                                .<UpdateFlowOutput>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<UpdateGroupOutput> rpcResult = Rpcs.getRpcResult(
-                                inputArg.isSuccessful(), result, inputArg.getErrors());
+                        RpcResult<UpdateGroupOutput> rpcResult = RpcResultBuilder
+                                .<UpdateGroupOutput>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<UpdateMeterOutput> rpcResult = Rpcs.getRpcResult(
-                                inputArg.isSuccessful(), result, inputArg.getErrors());
+                        RpcResult<UpdateMeterOutput> rpcResult = RpcResultBuilder
+                                .<UpdateMeterOutput>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<UpdatePortOutput> rpcResult = Rpcs.getRpcResult(
-                                inputArg.isSuccessful(), result, inputArg.getErrors());
+                        RpcResult<UpdatePortOutput> rpcResult = RpcResultBuilder
+                                .<UpdatePortOutput>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 (file)
index 0000000..a7bce0e
--- /dev/null
@@ -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<RolePushTask> 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<RolePushTask>() {
+            @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<Runnable>(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<Boolean> rolePushResult = broadcastPool.submit(task);
+            CheckedFuture<Boolean, RolePushException> 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();
+    }
+}
index 763804ee033961688d44af7f804a35789a19e52a..d7d0e6761effc9f8d59e0613f634264d24208500 100644 (file)
@@ -182,4 +182,11 @@ public abstract class OFSessionUtil {
         return getSessionManager().getExtensionConverterProvider();
     }
 
+    /**
+     * @return collection of all sessions
+     */
+    public static Collection<SessionContext> 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 (file)
index 0000000..faa981c
--- /dev/null
@@ -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 (file)
index 0000000..feb663c
--- /dev/null
@@ -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:<br/>
+ * <ul>
+ * <li>here we read generationId from device and</li>
+ * <li>push role request with incremented generationId</li>
+ * <li>{@link #call()} returns true if role request was successful</li>
+ * </ul>
+ */
+final class RolePushTask implements Callable<Boolean> {
+
+    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<RpcResult<RoleRequestOutput>> roleReply = RoleUtil.sendRoleChangeRequest(session, role, generationId);
+        // flush election result with barrier
+        BarrierInput barrierInput = MessageFactory.createBarrier(
+                session.getFeatures().getVersion(), session.getNextXid());
+        Future<RpcResult<BarrierOutput>> 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
index 3749756ff04ff7d4b5ce5720a427f2a53f22d960..899e1f66c5874d5fb61ff94b7d15fc758a7da6d9 100644 (file)
@@ -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<Long, Boolean> portBandwidth;
     private CompositeObjectRegistration<ModelDrivenSwitch> providerRegistration;
     private int seed;
-    
+    private ControllerRole roleOnDevice = ControllerRole.OFPCRROLEEQUAL;
+
 
     /**
      * default ctor
@@ -81,7 +84,7 @@ public class SessionContextOFImpl implements SessionContext {
     public Set<Entry<SwitchConnectionDistinguisher, ConnectionConductor>> 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<Long, PortGrouping> getPhysicalPorts() {
         return this.physicalPorts;
     }
-    
+
     @Override
     public Map<Long, Boolean> getPortsBandwidth() {
         return this.portBandwidth;
@@ -207,23 +210,23 @@ public class SessionContextOFImpl implements SessionContext {
         }
         return result;
     }
-    
+
     @Override
     public void setProviderRegistration(
             CompositeObjectRegistration<ModelDrivenSwitch> providerRegistration) {
                 this.providerRegistration = providerRegistration;
     }
-    
+
     @Override
     public CompositeObjectRegistration<ModelDrivenSwitch> 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;
+    }
 }
index 5af0b5f81976672d4ef92715651cc239d391be54..be2982195ddba55029832e745234a0a632ab0472 100644 (file)
@@ -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<SessionListener> 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<SessionContext> 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 (file)
index 0000000..d4ea43c
--- /dev/null
@@ -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<Exception, RolePushException> exceptionFunction = new Function<Exception, RolePushException>() {
+        @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<RpcResult<RoleRequestOutput>> sendRoleChangeRequest(SessionContext sessionContext, OfpRole ofpRole, BigInteger generationId) {
+        RoleRequestInputBuilder ruleRequestInputBld = RoleUtil.createRoleRequestInput(sessionContext, ofpRole, generationId);
+        Future<RpcResult<RoleRequestOutput>> roleReply = sessionContext.getPrimaryConductor().getConnectionAdapter()
+                .roleRequest(ruleRequestInputBld.build());
+        return roleReply;
+    }
+
+    /**
+     * @param sessionContext
+     * @return generationId from future RpcResult
+     */
+    public static Future<BigInteger> readGenerationIdFromDevice(SessionContext sessionContext) {
+        Future<BigInteger> generationIdFuture = null;
+        Future<RpcResult<RoleRequestOutput>> roleReply = sendRoleChangeRequest(sessionContext, OfpRole.NOCHANGE, BigInteger.ZERO);
+        generationIdFuture = Futures.transform(
+                JdkFutureAdapters.listenInPoolThread(roleReply),
+                new Function<RpcResult<RoleRequestOutput>, BigInteger>() {
+                    @Override
+                    public BigInteger apply(RpcResult<RoleRequestOutput> 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<Boolean, RolePushException> makeCheckedRuleRequestFxResult(
+            ListenableFuture<Boolean> 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 (file)
index 0000000..43f8c4f
--- /dev/null
@@ -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 <T> SettableFuture<RpcResult<T>> getRpcErrorFuture(ConnectionException e) {
+        List<RpcError> rpcErrorList = wrapConnectionErrorIntoRpcErrors(e);
+        SettableFuture<RpcResult<T>> futureWithError = SettableFuture.create();
+        futureWithError.set(RpcResultBuilder.<T>failed().withRpcErrors(rpcErrorList).build());
+        return futureWithError;
+    }
+
+    private static List<RpcError> wrapConnectionErrorIntoRpcErrors(ConnectionException e) {
+        List<RpcError> 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 (file)
index 0000000..df01952
--- /dev/null
@@ -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<BarrierInput, ListenableFuture<RpcResult<BarrierOutput>>> sendBarrier(SessionContext session,
+                                                                                                            SwitchConnectionDistinguisher cookie, IMessageDispatchService messageService) {
+        BarrierInput barrierInput = MessageFactory.createBarrier(
+                session.getFeatures().getVersion(), session.getNextXid());
+        Future<RpcResult<BarrierOutput>> barrierResult = messageService.barrier(barrierInput, cookie);
+        ListenableFuture<RpcResult<BarrierOutput>> output = JdkFutureAdapters.listenInPoolThread(barrierResult);
+
+        return new RpcInputOutputTuple<>(barrierInput, output);
+    }
+
+
+}
index d518391baf761737ae82f6261bbef6f33883dcc9..fbc87643b57460967695d5eee5baccd98911b2f1 100644 (file)
@@ -9,8 +9,12 @@
 */
 package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.common.config.impl.rev140326;
 
+import javax.management.ObjectName;
+
 import org.opendaylight.openflowplugin.openflow.md.core.sal.OpenflowPluginProvider;
 
+import com.google.common.base.MoreObjects;
+
 /**
 *
 */
@@ -48,7 +52,31 @@ 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 &= dependencyResolver.canReuseDependency(
+                getBindingAwareBroker(), bindingAwareBrokerJmxAttribute);
+        for (ObjectName ofSwitchProvider : getOpenflowSwitchConnectionProvider()) {
+            noChangeExceptRole &= dependencyResolver.canReuseDependency(
+                    ofSwitchProvider, openflowSwitchConnectionProviderJmxAttribute); 
+        }
+        return noChangeExceptRole;
+    }
+
+    @Override
+    public AutoCloseable reuseInstance(AutoCloseable oldInstance) {
+        OpenflowPluginProvider recycled = (OpenflowPluginProvider) super.reuseInstance(oldInstance);
+        // change role if different
+        recycled.fireRoleChange(MoreObjects.firstNonNull(getRole(), getRole()));
+
+        return recycled;
+    }
 }
index 3ac7acc27264158842ceb8496883fb0429449986..ed459ece7e87ba3adb2f6583bceb9b77d4767f87 100644 (file)
@@ -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 {
index a5a76498a50b6516f83e6013c9d41a9f59f2d637..3dbebfb7c007f450e2f5417ba40193b97e5516e0 100644 (file)
@@ -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 (file)
index d1d6c35..0000000
+++ /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 <T> RpcResult<T> createRpcResult(boolean success, T result, Collection<RpcError> errorsArg) {
-        Collection<RpcError> errors = errorsArg;
-        if (errors == null) {
-            errors = Collections.emptyList();
-        }
-        return Rpcs.getRpcResult(success, result, errors);
-    }
-
-}
index 09a532ababb8337b5ee5e259acd6782594255c1d..bb20b31aa1bd5b6d216b3d5f8325de5e47b2246b 100644 (file)
@@ -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<SwitchConnectionDistinguisher, ConnectionConductor>();
+        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 (file)
index 0000000..d2ea001
--- /dev/null
@@ -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)}.
+     * <br/>
+     * 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)}.
+     * <br/>
+     * 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)}.
+     * <br/>
+     * 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<RoleRequestInput> roleRequestCaptor = ArgumentCaptor.forClass(RoleRequestInput.class);
+        Mockito.verify(connectionAdapter, Mockito.times(2)).roleRequest(roleRequestCaptor.capture());
+
+        List<RoleRequestInput> 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());
+    }
+}
index 570e511da95892cca1e15e18c0c3f509af2b90e1..043811a68cf16800f6dabe72f2c2e264b9687fec 100644 (file)
@@ -17,7 +17,6 @@ import java.util.Collection;
 import java.util.HashMap;\r
 import java.util.List;\r
 import java.util.Map;\r
-\r
 import org.junit.Assert;\r
 import org.junit.Before;\r
 import org.junit.Test;\r
@@ -48,10 +47,10 @@ import org.slf4j.LoggerFactory;
  * Created by Jakub Toth jatoth@cisco.com on 3/10/14.\r
  */\r
 @RunWith(MockitoJUnitRunner.class)\r
-public class PacketInV10TranslatorTest{\r
+public class PacketInV10TranslatorTest {\r
     private static final Logger LOG = LoggerFactory\r
             .getLogger(PacketInV10TranslatorTest.class);\r
-    \r
+\r
     @Mock\r
     private SessionContext sc;\r
     @Mock\r
@@ -61,7 +60,7 @@ public class PacketInV10TranslatorTest{
 \r
     private SwitchConnectionDistinguisher cookie;\r
     private byte[] data;\r
-    \r
+\r
     /**\r
      * Initializes mocks\r
      */\r
@@ -72,11 +71,11 @@ public class PacketInV10TranslatorTest{
         when(sc.getFeatures()).thenReturn(features);\r
         when(features.getDatapathId()).thenReturn(new BigInteger("42"));\r
         OpenflowPortsUtil.init();\r
-        \r
+\r
         cookie = settingCookie();\r
         data = messageData();\r
     }\r
-    \r
+\r
     /**\r
      * test\r
      * {@link PacketInV10Translator#translate(SwitchConnectionDistinguisher, SessionContext, OfHeader)}\r
@@ -84,7 +83,7 @@ public class PacketInV10TranslatorTest{
      * MD-SAL model, supports OF-1.0\r
      */\r
     @Test\r
-    public void testTranslateWithAllNullParam(){\r
+    public void testTranslateWithAllNullParam() {\r
         SwitchConnectionDistinguisher cookieNull = null;\r
         SessionContext sessionContext = null;\r
         OfHeader msg = null;\r
@@ -106,8 +105,8 @@ public class PacketInV10TranslatorTest{
      * supports OF-1.0\r
      */\r
     @Test\r
-    public void testTranslateDPIDNull(){\r
-        SessionContextOFImpl sessionContextOFImpl = new SessionContextOFImpl();\r
+    public void testTranslateDPIDNull() {\r
+        SessionContext sessionContextOFImpl = new SessionContextOFImpl();\r
 \r
         PacketInMessage message = createPacketInMessage(data, null);\r
 \r
@@ -127,7 +126,7 @@ public class PacketInV10TranslatorTest{
      * supports OF-1.0\r
      */\r
     @Test\r
-    public void testTranslateInPortNull(){\r
+    public void testTranslateInPortNull() {\r
         BigInteger datapathId = dataPathId();\r
 \r
         GetFeaturesOutputBuilder featuresBuilder = new GetFeaturesOutputBuilder();\r
@@ -152,11 +151,11 @@ public class PacketInV10TranslatorTest{
      * test\r
      * {@link PacketInV10Translator#translate(SwitchConnectionDistinguisher, SessionContext, OfHeader)}\r
      * - translates packetIn from OF-API model to MD-SAL model, supports OF-1.0\r
-     * \r
+     *\r
      * @throws IOException\r
      */\r
     @Test\r
-    public void testTranslate(){\r
+    public void testTranslate() {\r
         BigInteger datapathId = dataPathId();\r
 \r
         PacketInMessage message = createPacketInMessage(data, 5);\r
@@ -170,7 +169,7 @@ public class PacketInV10TranslatorTest{
         OpenflowPortsUtil.init();\r
         List<DataObject> salPacketIn = packetInV10Translator.translate(cookie,\r
                 sessionContextOFImpl, message);\r
-        \r
+\r
         //TODO: rewrite to object and involve object comparison in Assert\r
         String expectedString = "[PacketReceived [_ingress=NodeConnectorRef [_value=KeyedInstanceIdentifier"\r
                 + "{targetType=interface org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector,"\r
@@ -193,12 +192,12 @@ public class PacketInV10TranslatorTest{
 \r
     /**\r
      * create datapathID\r
-     * \r
+     *\r
      * @return BigInteger\r
      */\r
-    private static BigInteger dataPathId(){\r
+    private static BigInteger dataPathId() {\r
         byte[] datapathIdByte = new byte[EncodeConstants.SIZE_OF_LONG_IN_BYTES];\r
-        for(int i = 0; i < datapathIdByte.length; i++){\r
+        for (int i = 0; i < datapathIdByte.length; i++) {\r
             datapathIdByte[i] = 1;\r
         }\r
         return new BigInteger(1, datapathIdByte);\r
@@ -206,23 +205,23 @@ public class PacketInV10TranslatorTest{
 \r
     /**\r
      * generate message from string to byte[]\r
-     * \r
+     *\r
      * @return byte[]\r
      */\r
-    private static byte[] messageData(){\r
+    private static byte[] messageData() {\r
         String string = new String("sendOutputMsg_TEST");\r
         return string.getBytes();\r
     }\r
 \r
     /**\r
      * create PacketInMessage with setting Version, InPort, Data, Reason\r
-     * \r
+     *\r
      * @param data\r
      * @param port\r
      * @return PacketInMessage\r
      */\r
     private static PacketInMessage createPacketInMessage(final byte[] data,\r
-            final java.lang.Integer port){\r
+                                                         final java.lang.Integer port) {\r
         PacketInReason reason = PacketInReason.OFPRACTION;\r
         return new PacketInMessageBuilder()\r
                 .setVersion((short) EncodeConstants.OF10_VERSION_ID)\r
@@ -232,10 +231,10 @@ public class PacketInV10TranslatorTest{
 \r
     /**\r
      * create cookie\r
-     * \r
+     *\r
      * @return SwitchConnectionDistinguisher\r
      */\r
-    private static SwitchConnectionDistinguisher settingCookie(){\r
+    private static SwitchConnectionDistinguisher settingCookie() {\r
         SwitchConnectionCookieOFImpl key = new SwitchConnectionCookieOFImpl();\r
         key.setAuxiliaryId((short) 1);\r
         key.init(42);\r
@@ -244,24 +243,24 @@ public class PacketInV10TranslatorTest{
 \r
     /**\r
      * create GetFeatureOutput\r
-     * \r
+     *\r
      * @param datapathId\r
      * @return GetFeaturesOutput\r
      */\r
-    private static GetFeaturesOutput createGetFeatureOutput(final BigInteger datapathId){\r
+    private static GetFeaturesOutput createGetFeatureOutput(final BigInteger datapathId) {\r
         return new GetFeaturesOutputBuilder().setDatapathId(datapathId)\r
                 .setVersion((short) 0x01).build();\r
     }\r
 \r
     /**\r
      * init connectionConductor\r
-     * \r
+     *\r
      * @param connectionConductor\r
      * @param featuresOutput\r
      */\r
     private static void initConnectionConductor(\r
             final ConnectionConductorImpl connectionConductor,\r
-            final GetFeaturesOutput featuresOutput){\r
+            final GetFeaturesOutput featuresOutput) {\r
         TranslatorKey paramK = new TranslatorKey(1, PacketInMessage.class.getSimpleName());\r
         Collection<IMDMessageTranslator<OfHeader, List<DataObject>>> coll = new ArrayList<>();\r
         coll.add(new PacketInV10Translator());\r
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 (file)
index 0000000..e46c040
--- /dev/null
@@ -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<RpcResult<RoleRequestOutput>> roleRequestOutputFx = RoleUtil.sendRoleChangeRequest(session, OfpRole.BECOMEMASTER, generationId);
+        Assert.assertNotNull(roleRequestOutputFx);
+        
+        ArgumentCaptor<RoleRequestInput> 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.<Boolean>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.<Boolean>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 6a2eaac8db3b5d1ca4267bf033b94962596a73cb..aa6d6462d9bda190b343a73ae57d395c54f46930 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,7 @@
     <properties>
       <project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
       <mdsal.version>1.2.0-SNAPSHOT</mdsal.version>
+      <netconf.version>1.2.0-SNAPSHOT</netconf.version>
       <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
       <openflowjava.version>0.6.0-SNAPSHOT</openflowjava.version>
       <openflowplugin.model.version>${project.version}</openflowplugin.model.version>
             <artifactId>yang-binding</artifactId>
             <version>${yang.binding.version}</version>
         </dependency>
-       <dependency>
-           <groupId>org.opendaylight.yangtools</groupId>
-           <artifactId>yang-common</artifactId>
-            <version>${yang.binding.version}</version>
-       </dependency>
-       <dependency>
-           <groupId>org.opendaylight.yangtools.model</groupId>
-            <artifactId>ietf-inet-types</artifactId>
-           <version>${ietf-inet-types.version}</version>
+        <dependency>
+          <groupId>org.opendaylight.yangtools</groupId>
+          <artifactId>yang-common</artifactId>
+          <version>${yang.binding.version}</version>
+          <scope>import</scope>
+          <type>pom</type>
         </dependency>
         <dependency>
-            <groupId>org.opendaylight.yangtools.model</groupId>
-            <artifactId>ietf-yang-types</artifactId>
-           <version>${ietf-yang-types.version}</version>
+          <groupId>org.opendaylight.yangtools.model</groupId>
+          <artifactId>ietf-inet-types</artifactId>
+          <version>${ietf-inet-types.version}</version>
+        </dependency>
+        <dependency>
+          <groupId>org.opendaylight.yangtools.model</groupId>
+          <artifactId>ietf-yang-types</artifactId>
+          <version>${ietf-yang-types.version}</version>
         </dependency>
         <dependency>
             <groupId>org.opendaylight.yangtools.model</groupId>