public class MockOpenflowSwitch extends Object implements Comparable<MockOpenflowSwitch>
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 parametersLong 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 lineSpecific keywords may also be indexable, by which we mean that entries may take the form:
keyword[i]: parameterswhere 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 BARNote 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/DESC requests,
Multipart/PORT_DESC requests (v1.3 only), and (minimally)
Multipart/TABLE_FEATURES requests (v1.3 only), 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/FLOW 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 FLOW: send(createMpFlowStatsReply(request)); return true; } // message was not handled return false; } private OpenflowMessage createMpFlowStatsReply(OpenflowMessage req) throws IncompleteStructureException { OfmMutableMultipartReply reply = (OfmMutableMultipartReply) MessageFactory.create(req, MessageType.MULTIPART_REPLY, MultipartType.FLOW); MBodyFlowStats.MutableArray array = (MBodyFlowStats.MutableArray) reply.getBody(); MBodyMutableFlowStats fs = (MBodyMutableFlowStats) MpBodyFactory.createReplyBodyElement(req.getVersion(), MultipartType.FLOW); // Note: not advocating "magic" constants - for instruction only... Match flowMatch = .... ; fs.tableId(TableId.valueOf(0)).match(flowMatch) .packetCount(1000).duration(30, 123000); // etc. array.addFlowStats(fs); // create and add further flow stats elements.. if required reply.body((MultipartBody) array.toImmutable()); return reply.toImmutable(); }
MockSwitchBank
Modifier and Type | Class and Description |
---|---|
static class |
MockOpenflowSwitch.HelloMode
Designates the alternative ways to respond to handshaking.
|
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 and Description |
---|
MockOpenflowSwitch(String path,
boolean showOutput)
Constructs a mock-switch configured from the specified
text-based definition file.
|
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) |
protected OpenflowMessage |
createMpDescReply(OpenflowMessage request)
Creates a multipart DESC reply from the configured data.
|
protected OpenflowMessage |
createMpPortDescReply(OpenflowMessage request)
Creates a multipart PORT_DESC reply from the configured data.
|
protected OpenflowMessage |
createMpTableFeaturesReply(OpenflowMessage request)
Creates a multipart TABLE_FEATURES reply (empty) to satisfy the basic
request from the controller (for 1.3 switches).
|
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.
|
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.
|
protected boolean |
sendMpDescReply(OfmMultipartRequest request)
Responds to multipart request for DESC.
|
protected boolean |
sendMpPortDescReply(OfmMultipartRequest request)
Responds to multipart request for PORT_DESC.
|
protected boolean |
sendMpTableFeaturesReply(OfmMultipartRequest request)
Responds to multipart request for TABLE_FEATURES.
|
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.
|
protected static final String E_PROG_ERR
protected DataPathId dpid
protected ProtocolVersion negotiated
public MockOpenflowSwitch(String path, boolean showOutput)
path
- the switch definition file pathshowOutput
- true if output is enabledpublic void showOutput(boolean show)
show
- true to show output; false to suppress outputpublic void setSecure(String keyStoreName, String keyStorePass)
keyStoreName
- the keystore filename with relative pathkeyStorePass
- the keystore passwordpublic String getKeystoreName()
public String getKeystorePass()
public SwitchDefn getDefn()
public DataPathId getDpid()
public void activate()
protected SwMessageHandler createSwMessageHandler()
protected PipelineFactory createPipelineFactory()
public void deactivate()
public String toDebugString()
public boolean isActive()
public void setPortState(int portNum, CmdPortStatus.State state)
portNum
- the port number (1-based)state
- the state to which the port should be setpublic Port getPort(int portNum)
portNum
- the port number (1-based)public void waitForHandshake(boolean successExpected)
successExpected
- true if expecting a successful handshakepublic void helloFailed(OfmError err)
err
- the error message from the controllerpublic void reconcileEcho(OfmEchoReply msg)
msg
- the echo reply messagepublic void setInternalMsgLatch(CountDownLatch latch)
latch
- the count down latchpublic void cache(MessageType messageType, OpenflowMessage msg)
messageType
- the message type used as a keymsg
- the message to cacheprotected void stowAndThrow(String error)
error
- the error messagepublic List<String> failedAssertions()
protected void sendError(ErrorType et, ErrorCode ec, OpenflowMessage m)
et
- error typeec
- error codem
- the message that was the cause of the errorprotected void sendHelloError(ECodeHelloFailed ec, String message)
ec
- the error codemessage
- the message stringprotected int auxId()
protected List<Port> createPorts(ProtocolVersion pv)
feature configuration
information, using the protocol version specified in the
hello configuration
.pv
- the protocol version for this switchprotected OpenflowMessage createMpPortDescReply(OpenflowMessage request)
request
- the request messageVersionMismatchException
- if the negotiated version is <1.3protected OpenflowMessage createMpDescReply(OpenflowMessage request)
request
- the request messageprotected OpenflowMessage createMpTableFeaturesReply(OpenflowMessage request)
request
- the request messageVersionMismatchException
- if the negotiated version is <1.3protected boolean sendMpTableFeaturesReply(OfmMultipartRequest request)
This default implementation sends a response created
via createMpTableFeaturesReply(com.hp.of.lib.msg.OpenflowMessage)
, and returns true to indicate
that the request was handled.
request
- the inbound requestprotected boolean sendMpPortDescReply(OfmMultipartRequest request)
This default implementation sends a response created
via createMpPortDescReply(com.hp.of.lib.msg.OpenflowMessage)
, and returns true to indicate
that the request was handled.
request
- the inbound requestprotected boolean sendMpDescReply(OfmMultipartRequest request)
This default implementation sends a response created
via createMpDescReply(com.hp.of.lib.msg.OpenflowMessage)
, and returns true to indicate
that the request was handled.
request
- the inbound requestpublic boolean handleMultipartRequest(OfmMultipartRequest request)
DESC
, PORT_DESC
, or
TABLE_FEATURES
we will handle it internally; otherwise we tell
the handler to pass it through msgRx(OpenflowMessage)
.
Note, however, that for each handled type, we call an overridable method:
sendMpDescReply(com.hp.of.lib.msg.OfmMultipartRequest)
sendMpPortDescReply(com.hp.of.lib.msg.OfmMultipartRequest)
sendMpTableFeaturesReply(com.hp.of.lib.msg.OfmMultipartRequest)
Alternatively, to route the request for one of the above multipart types
through msgRx(com.hp.of.lib.msg.OpenflowMessage)
instead, simply override the appropriate
"sendMp...Reply" method to return false:
protected boolean sendMpDescReply(OpenflowMessage request) { return false; }
request
- the inbound requestprotected void send(OpenflowMessage msg)
msg
- the message to send.NullPointerException
- if msg is nullIllegalArgumentException
- if the message is mutableprotected void msgRx(OpenflowMessage msg)
More precisely, messages that are not:
The above messages are handled internally and do not get passed
to this method. However, note that the default behavior for multipart
requests can be overridden; see handleMultipartRequest(com.hp.of.lib.msg.OfmMultipartRequest)
.
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.
msg
- the message from the controllerpublic int compareTo(MockOpenflowSwitch o)
compareTo
in interface Comparable<MockOpenflowSwitch>
public void setHelloMode(MockOpenflowSwitch.HelloMode mode)
mode
- the modeCopyright © 2015. All Rights Reserved.