com.h3c.of.sw

## Class MockOpenflowSwitch

- java.lang.Object
- - com.h3c.of.sw.MockOpenflowSwitch

- All Implemented Interfaces:
    Comparable<MockOpenflowSwitch>

      public class MockOpenflowSwitch
      extends Object
      implements Comparable<MockOpenflowSwitch>

  Represents a mock switch that talks OpenFlow; useful for OpenFlow Controller and Application unit testing.

  The mock switch is configured via a text-based definition file. Blank lines and lines beginning with "#" are considered comments and thus ignored by the parser. The remaining lines take the form:

       keyword: set of parameters

  Long parameter lists may be extended over multiple lines by the use of trailing backslashes:

       keyword: this parameter list is too long \
                to comfortably fit \
                on a single line

  Specific keywords may also be indexable, by which we mean that entries may take the form:

       keyword[i]: parameters

  where i is a zero-based index.

  In addition to the defined set of keywords, a set of arbitrary custom properties may also be defined. These properties are minimally parsed, and made available via `SwitchDefn.getCustomProps()`. This allows for subclasses of `MockOpenflowSwitch` to use the definition file as a source of their own specialized configuration. For example:

           public class MySwitch extends MockOpenflowSwitch {
               public MySwitch(String defnPath) {
                   super(defnPath);
                   configure();
               }
               private void configure() {
                   for (SwitchDefn.CustomProp prop: getDefn().getCustomProps()) {
                       String name = prop.name();
                       String params = prop.value();
                       // ... do something with the property
                   }
               }
           }

  An example definition file might look like this:

       ## Simple OpenFlow 1.0 Mock Switch (4 ports) Definition file

       ### Define the switch's reported datapath ID
       dpid: 42/0016b9:006502

       ### Define the switch's HELLO message
       #   LAZY = wait for controller's HELLO msg; EAGER = send HELLO immediately
       #   space-separated list of versions (for bitmap)
       #   optional LEGACY token suppresses the version-bitmap hello-element
       hello: LAZY V_1_0 LEGACY

       ### Define the switch's base configuration
       controller: 127.0.0.1 6633
       buffers: 256
       tables: 12
       capabilities: FLOW_STATS TABLE_STATS PORT_STATS IP_REASM QUEUE_STATS

       ### 1.0 switch supported actions
       supportedActions: OUTPUT SET_VLAN_VID STRIP_VLAN \
                         SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST

       ### Number of ports on this switch (256 max)
       portCount: 4
       ### MAC address of each port (last byte is 0..portCount-1)
       portMac: 00:16:b9:0a:01:*

       ### Default port config and features - these values will be used to
       #   configure each port that is not overridden with an indexed entry.
       portConfig:
       portFeature: RATE_100MB_FD COPPER

       ### Specific port overrides (index must be 0..3 for this 4-port switch)
       portConfig[1]: PORT_DOWN
       portConfig[3]: NO_FLOOD NO_FWD

       ### Description strings for MP/DESC reply
       descMfr:    Acme Switch Co.
       descHw:     Coyote WB10
       descSw:     OF-Sneaky 1.0
       descSerial: WB-11937-TAF
       descDp:     WB10 at top of Mesa, Top Shelf

       ### Define some custom properties...
       [custom]
       foo: value for FOO
       bar: value for BAR

  Note that everything after the [custom] line is interpreted as a custom property.

  Some code to instantiate and activate a mock switch:

           MockOpenflowSwitch sw = new MockOpenflowSwitch("path/to/switch.def");
           DataPathId dpid = sw.getDpid();
           // when we are ready for the switch to connect to the controller...
           sw.activate();

  Right out of the box, a mock openflow switch will perform the handshake and version negotiation with the controller, (including consuming Error/HELLO_FAILED messages). It will also respond to Multipart/PORT_DESC requests (v1.3 only) and Multipart/DESC requests from the controller. All other messages from the controller are passed to `msgRx(OpenflowMessage)` which has the default behavior of throwing a runtime exception announcing that an "unexpected message" was received from the controller.

  For the mock switch to do anything more useful than handshake and provide a description of itself, this class must be subclassed and the `msgRx(OpenflowMessage)` method overridden. For example, to program the mock switch to respond to a Multipart/AGGREGATE request, one might use code like this:

           @Override
           protected void msgRx(OpenflowMessage msg) {
               switch (msg.getType()) {
                   case: MULTIPART_REQUEST:
                       if (!handleMpRequest((OfmMultipartRequest) msg)
                           super.msgRx(msg);
                       break;
                   default:
                       super.msgRx(msg);
                       break;
               }
           }

           private boolean handleMpRequest(OfmMultipartRequest request) {
               switch (request.getMultipartType()) {
                   case AGGREGATE:
                       send(createMpAggregateReply(request));
                       return true;
               }
               // message was not handled
               return false;
           }

           private OpenflowMessage createMpAggregateReply(OpenflowMessage req) {
               OfmMutableMultipartReply reply = (OfmMutableMultipartReply)
                   MessageFactory.create(req, MessageType.MULTIPART_REPLY);
               MBodyMutableAggregate agg = (MBodyMutableAggregate)
                   MpBodyFactory.createReplyBody(MultipartType.AGGREGATE);
               // Note: not advocating "magic" constants - for instruction only...
               agg.packetCount(1000).byteCount(3057).flowCount(42);
               reply.body((MultipartBody) agg.toImmutable());
               return reply.toImmutable();
           }

  See Also:
    `MockSwitchBank`

- - ### Nested Class Summary

    Nested Classes
    Modifier and Type | Class and Description
    --- | ---
    `static class` | `MockOpenflowSwitch.HelloMode` Designates the alternative ways to respond to handshaking.

  - ### Field Summary

    Fields
    Modifier and Type | Field and Description
    --- | ---
    `protected DataPathId` | `dpid`
    `protected static String` | `E_PROG_ERR`
    `protected ProtocolVersion` | `negotiated` The protocol version that we negotiated with the controller.

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `MockOpenflowSwitch(String path, boolean showOutput)` Constructs a mock-switch configured from the specified text-based definition file.

  - ### Method Summary

    Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `activate()` Instructs the mock-switch to connect to the controller.
    `protected int` | `auxId()` Returns the auxiliary connection ID to be returned in the features reply.
    `void` | `cache(MessageType messageType, OpenflowMessage msg)` The command processor has asked us to cache this outgoing message for validation later.
    `int` | `compareTo(MockOpenflowSwitch o)`
    `OpenflowMessage` | `createMpPortDescReply(OpenflowMessage request)` Creates a multipart PORT_DESC reply from the configured data.
    `protected PipelineFactory` | `createPipelineFactory()` Returns the channel pipeline factory to use for this mock switch.
    `protected List<Port>` | `createPorts(ProtocolVersion pv)` Creates ports based on the `feature configuration` information, using the protocol version specified in the `hello configuration`.
    `protected SwMessageHandler` | `createSwMessageHandler()` Returns the message handler to use for this mock switch.
    `void` | `deactivate()` Instruct the mock-switch to disconnect from the controller.
    `boolean` | `equals(Object o)`
    `List<String>` | `failedAssertions()` Returns any failed assertions that were collected during the lifetime of the mock switch.
    `SwitchDefn` | `getDefn()` Returns the switch definition.
    `DataPathId` | `getDpid()` Convenience method that returns the datapath ID as configured in the switch definition.
    `String` | `getKeystoreName()` Returns the keystore name.
    `String` | `getKeystorePass()` Returns the keystore password.
    `Port` | `getPort(int portNum)` Returns the specified port.
    `boolean` | `handleMultipartRequest(OfmMultipartRequest request)` Called by the message handler when a multipart request comes in.
    `int` | `hashCode()`
    `void` | `helloFailed(OfmError err)` The controller has told us that our hello has failed.
    `boolean` | `isActive()` Returns true if this switch is connected to the controller; false otherwise.
    `boolean` | `isHandshakeCompleted()` Returns true of the handshake concluded without or with error.
    `protected void` | `msgRx(OpenflowMessage msg)` Invoked when a message is received from the controller.
    `void` | `reconcileEcho(OfmEchoReply msg)` Check in our cache for the EchoRequest we sent, and validate against the EchoReply just received from the controller.
    `protected void` | `send(OpenflowMessage msg)` Sends the specified openflow message to the controller.
    `protected void` | `sendError(ErrorType et, ErrorCode ec, OpenflowMessage m)` Send an error message back to the controller.
    `protected void` | `sendHelloError(ECodeHelloFailed ec, String message)` Send a hello-failed error message back to the controller.
    `void` | `setHelloMode(MockOpenflowSwitch.HelloMode mode)` Sets the hello mode for this switch.
    `void` | `setInternalMsgLatch(CountDownLatch latch)` A countdown latch can be set that will count down for every message handled by the SwMessageHandler, including internal messages such as HELLO, FEATURES_REQUEST and ECHO_REPLY.
    `void` | `setPortState(int portNum, CmdPortStatus.State state)` Sets the "state" of the specified port.
    `void` | `setSecure(String keyStoreName, String keyStorePass)` Sets the switch to secure mode (uses TLS connection) using the given (combined truststore/keystore) keystore parameters.
    `void` | `showOutput(boolean show)` Sets the flag to determine whether we output stuff.
    `protected void` | `stowAndThrow(String error)` Stows the error string in the failed assertions list, and throws an IllegalStateException.
    `String` | `toDebugString()` Returns a multi-line string representation of this mock switch.
    `String` | `toString()`
    `void` | `waitForHandshake(boolean successExpected)` A blocking call that returns once the handshake with the controller has completed.

    - ### Methods inherited from class java.lang.Object

      `clone, finalize, getClass, notify, notifyAll, wait, wait, wait`

- - ### Field Detail

    - #### E_PROG_ERR

          protected static final String E_PROG_ERR

    - #### dpid

          protected DataPathId dpid

    - #### negotiated

          protected ProtocolVersion negotiated

      The protocol version that we negotiated with the controller.

  - ### Constructor Detail

    - #### MockOpenflowSwitch

          public MockOpenflowSwitch(String path,
                            boolean showOutput)

      Constructs a mock-switch configured from the specified text-based definition file.
      Parameters:
        `path` - the switch definition file path
        `showOutput` - true if output is enabled

  - ### Method Detail

    - #### showOutput

          public void showOutput(boolean show)

      Sets the flag to determine whether we output stuff.
      Parameters:
        `show` - true to show output; false to suppress output

    - #### setSecure

          public void setSecure(String keyStoreName,
                       String keyStorePass)

      Sets the switch to secure mode (uses TLS connection) using the given (combined truststore/keystore) keystore parameters.
      Parameters:
        `keyStoreName` - the keystore filename with relative path
        `keyStorePass` - the keystore password

    - #### getKeystoreName

          public String getKeystoreName()

      Returns the keystore name.
      Returns:
        the keystore name

    - #### getKeystorePass

          public String getKeystorePass()

      Returns the keystore password.
      Returns:
        the keystore password

    - #### getDefn

          public SwitchDefn getDefn()

      Returns the switch definition.
      Returns:
        the switch definition

    - #### getDpid

          public DataPathId getDpid()

      Convenience method that returns the datapath ID as configured in the switch definition.
      Returns:
        the configured datapath id

    - #### activate

          public void activate()

      Instructs the mock-switch to connect to the controller.

    - #### createSwMessageHandler

          protected SwMessageHandler createSwMessageHandler()

      Returns the message handler to use for this mock switch.
      Returns:
        the message handler

    - #### createPipelineFactory

          protected PipelineFactory createPipelineFactory()

      Returns the channel pipeline factory to use for this mock switch. This default implementation returns a standard pipeline factory that encodes and decodes openflow messages.
      Returns:
        the pipeline factory

    - #### deactivate

          public void deactivate()

      Instruct the mock-switch to disconnect from the controller.

    - #### toString

          public String toString()

      Overrides:
        `toString` in class `Object`

    - #### toDebugString

          public String toDebugString()

      Returns a multi-line string representation of this mock switch.
      Returns:
        a multi-line string representation

    - #### isActive

          public boolean isActive()

      Returns true if this switch is connected to the controller; false otherwise.
      Returns:
        true if connected to the controller

    - #### setPortState

          public void setPortState(int portNum,
                          CmdPortStatus.State state)

      Sets the "state" of the specified port.
      Parameters:
        `portNum` - the port number (1-based)
        `state` - the state to which the port should be set

    - #### getPort

          public Port getPort(int portNum)

      Returns the specified port.
      Parameters:
        `portNum` - the port number (1-based)
      Returns:
        the port

    - #### isHandshakeCompleted

          public boolean isHandshakeCompleted()

      Returns true of the handshake concluded without or with error.
      Returns:
        true if handshake transpired

    - #### waitForHandshake

          public void waitForHandshake(boolean successExpected)

      A blocking call that returns once the handshake with the controller has completed. If success is expected, and the handshake does not complete successfully, an exception is thrown. Conversely, an exception is thrown if success is not expected and the switch does not issue an error response.
      Parameters:
        `successExpected` - true if expecting a successful handshake

    - #### helloFailed

          public void helloFailed(OfmError err)

      The controller has told us that our hello has failed.
      Parameters:
        `err` - the error message from the controller

    - #### reconcileEcho

          public void reconcileEcho(OfmEchoReply msg)

      Check in our cache for the EchoRequest we sent, and validate against the EchoReply just received from the controller.
      Parameters:
        `msg` - the echo reply message

    - #### setInternalMsgLatch

          public void setInternalMsgLatch(CountDownLatch latch)

      A countdown latch can be set that will count down for every message handled by the SwMessageHandler, including internal messages such as HELLO, FEATURES_REQUEST and ECHO_REPLY.
      Parameters:
        `latch` - the count down latch

    - #### cache

          public void cache(MessageType messageType,
                   OpenflowMessage msg)

      The command processor has asked us to cache this outgoing message for validation later.
      Parameters:
        `messageType` - the message type used as a key
        `msg` - the message to cache

    - #### stowAndThrow

          protected void stowAndThrow(String error)

      Stows the error string in the failed assertions list, and throws an IllegalStateException.
      Parameters:
        `error` - the error message

    - #### failedAssertions

          public List<String> failedAssertions()

      Returns any failed assertions that were collected during the lifetime of the mock switch.
      Returns:
        the list of failed assertions

    - #### sendError

          protected void sendError(ErrorType et,
                       ErrorCode ec,
                       OpenflowMessage m)

      Send an error message back to the controller.
      Parameters:
        `et` - error type
        `ec` - error code
        `m` - the message that was the cause of the error

    - #### sendHelloError

          protected void sendHelloError(ECodeHelloFailed ec,
                            String message)

      Send a hello-failed error message back to the controller.
      Parameters:
        `ec` - the error code
        `message` - the message string

    - #### auxId

          protected int auxId()

      Returns the auxiliary connection ID to be returned in the features reply. This default implementation returns 0, i.e. the main connection.
      Returns:
        the auxiliary ID

    - #### createPorts

          protected List<Port> createPorts(ProtocolVersion pv)

      Creates ports based on the `feature configuration` information, using the protocol version specified in the `hello configuration`.
      Parameters:
        `pv` - the protocol version for this switch
      Returns:
        the list of (mock) ports that this (mock) switch reports

    - #### createMpPortDescReply

          public OpenflowMessage createMpPortDescReply(OpenflowMessage request)

      Creates a multipart PORT_DESC reply from the configured data. The request has to be passed in so we can replicate the transaction ID.
      Parameters:
        `request` - the request message
      Returns:
        the multipart PORT_DESC reply
      Throws:
        `VersionMismatchException` - if the negotiated version is <1.3

    - #### handleMultipartRequest

          public boolean handleMultipartRequest(OfmMultipartRequest request)

      Called by the message handler when a multipart request comes in. If it is of type `DESC` or `PORT_DESC` we will handle it internally; otherwise we tell the handler to pass it through `msgRx(OpenflowMessage)`.
      Parameters:
        `request` - the inbound request
      Returns:
        true, if we handled the message; false otherwise

    - #### send

          protected void send(OpenflowMessage msg)

      Sends the specified openflow message to the controller.
      Parameters:
        `msg` - the message to send.
      Throws:
        `NullPointerException` - if msg is null
        `IllegalArgumentException` - if the message is mutable

    - #### msgRx

          protected void msgRx(OpenflowMessage msg)

      Invoked when a message is received from the controller.

      More precisely, messages that are not:

      - Type HELLO
      - Type ERROR with subtype HELLO_FAILED
      - Type FEATURES_REQUEST
      - Type SET_CONFIG
      - Type MULTIPART_REQUEST with subtype DESC
      - Type MULTIPART_REQUEST with subtype PORT_DESC

      The above messages are handled internally and do not get passed to this method.

      This default implementation throws a runtime exception. It is expected that subclasses will override this method to handle the messages arriving from the controller, to provide the required mock-switch behavior.

      Parameters:
        `msg` - the message from the controller

    - #### equals

          public boolean equals(Object o)

      Overrides:
        `equals` in class `Object`

    - #### hashCode

          public int hashCode()

      Overrides:
        `hashCode` in class `Object`

    - #### compareTo

          public int compareTo(MockOpenflowSwitch o)

      Specified by:
        `compareTo` in interface `Comparable<MockOpenflowSwitch>`

    - #### setHelloMode

          public void setHelloMode(MockOpenflowSwitch.HelloMode mode)

      Sets the hello mode for this switch.
      Parameters:
        `mode` - the mode

Copyright © 2014. All Rights Reserved.