![]() |
ViewsOFTestTutorialFrom OpenFlow Wiki
IntroductionOFTest is a Python based OpenFlow switch test framework and collection of test cases. It is based on unittest which is included in the standard Python distribution. This document is meant to provide an introduction to the framework, discuss the basics of running tests and to provide examples of how to add tests. Other DocsThe following documents provide additional background on OFTest.
AssumptionsIt is assumed you're familiar with Python and specifically the unittest module (or at least are willing to refer to the doc at Python unittest doc). It's actually pretty straight forward:
Familiarity with the OpenFlow Switching protocol and switch/controller setup and interaction is also assumed. Architectural OverviewHere's an overview of the OFTest system architecture. Key Notes:
The OFTest framework provides a full object representation of OpenFlow messages and the abstractions from the OpenFlow protocol with which to build test scripts. Basics of unittest
At this point, you might want to jump down to the Examples below. Key Class Hierarchies and ComponentsOnce installed (see OFTestReadme) the components of OFTest are available via import of submodules of oftest. Typically, new tests will be written as subclasses of either the basic protocol test, SimpleProtocol, (for tests that require only communication with the switch over the controller interface) or the basic dataplane test, SimpleDataPlane which provides the dataplane object to send and receive packets to/from OpenFlow ports. SimpleProtocol and SimpleDataPlane are defined in tests/basic.py so normally that file is imported into your test file. SimpleProtocolThe essential object provided by inheritance from SimpleProtocol (and from SimpleDataPlane which is a subclass of SimpleProtocol) is self.controller. The setUp routine ensures a connection has been made to the SUT prior to returning. Thus, in runTest you can send messages across the control interface simply by invoking methods of this control object. These may be sent unacknowledged or done as transactions (which are based on the XID in the OpenFlow header): import basic class MyTest(basic.SimpleProtocol): ... # Inside your runTest: rv = self.controller.message_send(msg) # Unacknowledged response, pkt = self.controller.transact(request) # Transaction based on XID SimpleDataPlaneAs mentioned, SimpleDataPlane inherits from SimpleProtocol, so you get the controller object as well as the dataplane object, self.dataplane. Sending packets into the switch is done with the send member: import basic class MyDPTest(basic.SimpleDataPlane): ... # Inside your runTest: pkt = simple_tcp_packet() self.dataplane.send(port, str(pkt)) Packets can be received in the following ways:
(port, pkt, timestamp) = self.dataplane.poll()
(port, pkt, timestamp) = self.dataplane.poll(timeout=1)
self.dataplane.register(handler) For the calls to poll, you may specify a port number in which case only packets received on that port will be returned. (port, pkt, timestamp) = self.dataplane.poll(port_number=2, timeout=1) MessagesThe OpenFlow protocol is represented by a collection of objects inside the oftest.message module. In general, each message has its own class. All messages have a header member and data members specific to the message. Certain variable length data is treated specially and is described (TBD). Here are some examples: import oftest.message as message ... request = message.echo_request() request is now an echo_request object and can be sent via self.controller.transact for example. msg = message.packet_out() msg is now a packet_out object. msg.data holds the variable length packet data. msg.data = str(some_packet_data) This brings us to one of the important variable length data members, the action list. Each action type has its own class. The action list is also a class with an add method which takes an action object. import oftest.action as action ... act = action.action_output() # Create a new output action object act.port = egress_port # Set the action's parameter(s) msg.actions.add(act) # The packet out message has an action list member Another key data class is the match object. TBD: Fill this out. TBD: Add information about stats objects. PacketsOFTest uses Scapy for managing packet data, http://www.secdev.org/projects/scapy/, although you may not need to use it directly. In the example below, we use the function simple_tcp_packet from testutils to generate a packet. The the parse function packet_to_flow_match is called to generate a flow match based on the packet. from testutils import * import oftest.parse as parse import oftest.cstruct as ofp ... pkt = simple_tcp_packet() match = parse.packet_to_flow_match(pkt) match.wildcards &= ~ofp.OFPFW_IN_PORT This introduces the low level module oftest.cstruct, here referred to as ofp. This provides the base definitions from which OpenFlow messages are inherited and basic OpenFlow defines such as OFPFW_IN_PORT. Most enums defined in openflow.h are available in this module. DataPlaneOnlyOccasionally, it is convenient to be able to send a packet into a switch without connecting to the controller. The DataPlaneOnly class is the parent that allows you to do this. It instantiates a dataplane, but not a controller object. The classes PacketOnly and PacketOnlyTagged inherit from DataPlaneOnly and send packets into the switch. ExamplesLet's look at some example test cases. EchoThe Echo test case is very simple. It creates an Echo message object, tells the controller to run a transaction based on that message and then verifies that the proper response is received. This only requires the controller interface (not the dataplane interface) so we inherit from the SimpleProtocol test case.
Packet OutFor the packet out test, we generate a packet out message, put some data as the target egress packet and send the message to the controller. We then query the data ports as we expect a packet to egress from the switch. This is done for each OpenFlow port in the configuration.
Test UtilitiesThe file oftest/tests/testutils.py provides a good number of functions related to creating packets and flow messages. Here is a summary.
simple_tcp_packetThis function generates a TCP scapy packet. Default values are specified for the following fields: dl_dst='00:01:02:03:04:05' ip_src='192.168.0.1' dl_src='00:06:07:08:09:0a' ip_dst='192.168.0.2' dl_vlan_enable=False ip_tos=0 dl_vlan=0 tcp_sport=1234 dl_vlan_pcp=0 tcp_dport=80 dl_vlan_cfi=0 pktlen=100 pkt_action_setupThis routine takes a set of packet fields to modify. It creates three things:
Default values are coded into the routine, though you can pass in your own dictionaries for these. They must use the parameters names of the function simple_tcp_packet as keys (see above). flow_match_testThis routine runs a typical "set up flow mod, send packet, inspect received packet". You may set up the packet and actions for the flow mod using pkt_action_setup above. A port map must be passed in and all port pairs will be tested (although a maximum number of port-pair test runs may also be specified). delete_all_flowsClear the flow table. May not affect switch configuration that was put in place another configuration mechanism. clear_switchDelete all flows and set the port state of all ports no flood. receive_pkt_checkCheck that an expected packet was or was not received at port sets. Passing Parameters to TestsThere is a facility for passing test-specific parameters into tests that works as follows. On the command line, give the parameter --test-params="key1=17;key2=True" You can test for these parameters by importing testutils.py and using the function: my_key1 = testutils.test_param_get(self.config, 'key1') The config parameter is the global configuration structure copied into the base tests cases (and usually available in each test file). The routine returns None if the key was not assigned in the command line; otherwise it returns the value assigned (17 in this example). Note that any test may look at these parameters, so use some care in choosing your parameter keys. Currently the keys used are in pktact.py and control whether VLAN tagged packets are used and whether VLAN tag stripping should be included as an action. These parameters include:
Other Test ConventionsTBD:
TroubleshootingNormally, all debug output goes to the file oft.log in the current directory. You can force the output to appear on the terminal (and set the most verbose debug level) with these parameters added to the oft command: --verbose --log-file= |
Quick NavigationOpenFlow White PaperOpenFlow Demo Video![]() Watch the Demo that received the best demo award at SIGCOMM 2008. About OpenFlow OpenFlow is supported bythe Stanford Clean Slate Program. Wiki ToolsPersonal toolsProjects |