Please Note: This website has been archived and is no longer maintained.
See the Open Networking Foundation for current OpenFlow-related information.


From OpenFlow Wiki

Jump to: navigation, search


Welcome to the OpenFlow tutorial!

OpenFlow is an open interface for remotely controlling the forwarding tables in network switches, routers, and access points. Upon this low-level primitive, researchers can build networks with new high-level properties. For example, OpenFlow enables more secure default-off networks, wireless networks with smooth handoffs, scalable data center networks, host mobility, more energy-efficient networks and new wide-area networks – to name a few.

This tutorial is your opportunity to gain hands-on experience with the platforms and debugging tools most useful for developing network control applications on OpenFlow.

Innovate in your network!

After completing this tutorial, please fill out the feedback form.



Tutorial flow hw.png

Following an introduction, you'll turn the provided hub controller into a controller-based learning switch, then a flow-accelerated learning switch, you'll test it with real hardware, and finally extend it to a firewall or router - you get to choose. Along the way, you'll learn the full suite of OpenFlow debugging tools. You will:

  • view flow tables with dpctl
  • dissect OpenFlow message with Wireshark
  • simulate a multi-switch, multi-host network with Mininet
  • benchmark your controller with cbench
  • control a slice of a real network using your controller and FlowVisor.

After the tutorial, you can apply what you've learned to physical networks based on software switches, NetFPGAs, or even hardware switches at line rate.

To get you started quickly, we provide a preconfigured virtual machine with the needed software.


You will need a computer with at least 1GB (preferably 2GB+) of RAM and at least 5GB of free hard disk space (more preferred). A faster processor may speed up the virtual machine boot time, and a larger screen may help to manage multiple terminal windows.

These instructions consider Linux, OS X, and Windows. Linux and OS X are preferred - there's less to install.

You will need administrative access to the machine.

The tutorial instructions require no prior knowledge of OpenFlow. The OpenFlow Learn More page is a concise introduction, and worth reading if you're not running this at a tutorial session.

Stuck? Found a bug? Questions?

Email [openflow-discuss - at -] if you're stuck, think you've found a bug, or just want to send some feedback.

If reporting a bug, try to include as many details about your setup as possible. Include your OS, virtualization software info, memory size, and the step you're on.

Install Required Software

At the Tutorial Only: Flash drives and DVDs are passed at the tutorial, and should include all of the software you will need. Please save the available wireless bandwidth for other traffic at the tutorial! If preparing for a tutorial, follow the instructions for web users below to pre-install the software.

Web Users + Tutorial Preparers: You will need to download these files individually.

The files include virtualization software, a SSH-capable terminal, an X server, and the VM image.

The tutorial image is distributed as a compressed VMware virtual disk image (.vmdk). Both VMware and VirtualBox enable you to run a virtual machine inside a physical machine, but they differ by the interface, features and price. They're both good choices, but we recommend VMware as it saves a few steps by setting up a transparent bridged network on the host. VirtualBox requires a few commands to set up networking, but is free for all platforms. VMware Player is free for Windows and Linux, but the Mac version (Fusion) and the more full-featured Windows and Linx version (Workstation) are not free. That's OK, you can use a free 30-day trial for the tutorial. For Mac, there are other choices, like Parallels Workstation. For Linux, there are plenty of other choices, including Qemu, KVM, and Xen.

The following instructions assume the use of VMware virtualization; if you insist on VirtualBox, please see the VirtualBox-specific instructions at the bottom of the page.

[At Tutorial Only] Copy Files From Flash Drive

All the files you might need should be on these flash drives and DVDs.

The first step is to create a folder on your computer, say 'oft', and start copying the relevant portions of the provided flash drive to this directory. This folder includes (the compressed virtual machine image), and a directories for each OS with installer files for required programs. Only copy the files needed for your platform that you haven't already installed. This may take a few minutes.

When you've copied the files, please pass a drive to your neighbor, and install the programs specific to your OS.

[Web Users + Tutorial Preparers] Download Files

You'll need to download the files corresponding to your OS, plus the tutorial VM.

Start now with downloading the compressed VM image. This will take awhile - it's on the order of 1GB in size.

Then move on to the other stuff:

OS Type OS Version Virtualization Software X Server Terminal
Windows 7 VMware Player or VMware workstation Xming PuTTY
Windows XP VMware Player or VMware workstation Xming PuTTY
Mac OS X 10.6 Snow Leopard VMware Fusion X11 (install from OS X main system DVD, preferred), or download XQuartz (built in)
Mac OS X 10.5 Leopard VMware Fusion X11 (install from OS X main system DVD, preferred), or download XQuartz (built in)
Mac OS X 10.4 Tiger VMware Fusion X11 (install from OS X main system DVD, preferred), or download XQuartz (built in)
Mac OS X 10.3 Panther VMware Fusion download Mac X11 server or download XQuartz (built in)
Linux Ubuntu 10.04 VMware player or VMware workstation X server already installed gnome terminal + SSH built in

You'll need to have each column item (X server, Virtualization software, and SSH terminal) installed for your platform, plus the VM image (

Setup Virtual Machine

Get Virtual Machine Disk Image

HOTI Tutorial Attendees: Copy the file from the DVD or flash drive.

Web users ONLY: download the VM from here (~700MB). Remember where you save this file, as you'll need it shortly. Warning This a large file, and the download will take awhile.

Unpack Virtual Machine Disk Image

The virtual machine image ships compressed. We'll need to unzip it first.

Warning This step will take awhile - the unpacked .vmdk file is around 2 GB.

OS X and Linux Users: from a terminal, unzip the virtual machine image:


Windows Users: unzip the image in Windows Explorer.

Start Virtual Machine

Double-click on the vmx file (not the vmdk), and it should open in VMware. Click the play button to start it. Do not change the kernel choice during boot.


If VMware asks if you'd like to install the VMware tools, decline, for now. VMware tools speed up the networking connection between the guest and host, enable copy/paste from the VM console, speed up graphics, and do a few other things. We don't need any of these, so decline. Feel free to install the VMware tools after the tutorial.

At the boot prompt, enter the username and password, which are both openflow. Note that the openflow user is a sudoer.

Choose Preferred Editor

Nano, Vim, Emacs, and Gedit come installed on the OpenFlowTutorial VM. Brief instructions for each:

Nano: You can immediately modify a file. When you're done, hit 'ctrl-x', then say 'Yes' to the prompt, to save and quit.

Vim: to modify a file, type 'i' to enter Insert mode, then use the arrow keys to navigate and edit. When you're done, hit 'esc', type ':wq', then press enter, to save and quit.

Emacs: you can immediately modify a file. When you're done, hit 'ctrl-x', 'ctrl-s', then hit 'ctrl-x', 'ctrl-c' to exit.

Gedit: a graphical text editor, no instructions needed.

Eclipse: Eclipse and its dependencies would require about 500MB extra space on the VM image, so it's not shipped by default. If you have Eclipse installed on the host VM, using the Remote Systems Explorer can be a convenient way to access and modify text files on the VM, with many of the advantages of Eclipse, such as syntax highlighting.

[Web Users Only] If you have another preferred text editor, feel free to install it now:

sudo apt-get install <editor>

Setup Network Access

The tutorial VM is shipped without a desktop environment, to reduce its size. All the exercises will be done through X forwarding, where programs display graphics through an X server running on the host OS.

To start up the X forwarding, you'll first need to find the guest IP address.


VMware sets up a bridge between the host and the guest by default, with external access through the host via NAT. No additional config should be necessary to contact the VM from the host, as well as access Internet resources from within the guest.


For VirtualBox, see the instructions at the bottom. For anything else, you'll need to consult its documentation.

Access VM via SSH

In this step, you'll verify that you can connect from the host PC (your laptop) to the guest VM (OpenFlowTutorial) via SSH.

First, from the virtual machine console - the one that appeared when you started up VMware - login as user openflow with password openflow , then enter:

$ ifconfig -a

to find ethenret interface. Let's suppose it is "eth1".

If there is no IP configured for eth1 (you can check this by running "ifconfig eth1"), type the following to get a DHCP lease from the host, and try "ifconfig again :

$ sudo dhclient eth1

Note this IP; you'll need it later. Next, log in, which will depend on your OS.

Mac OS X and Linux

Open a terminal ( in Mac, Gnome terminal in Ubuntu, etc). In that terminal, run:

$ ssh -Y openflow@[Guest IP Here]

Replace [Guest IP Here] with the IP you just noted.

Login with password openflow. Test the X11 forwarding by running on the local machine:

$ xterm

and a new terminal window should appear. If you have succeeded, you are done with the basic setup. Close the xterm. If you get a 'Display not set error', verify your X server installation from above.

Windows XP

Start Xming with X Forwarding enabled. To enable X-Forwarding, click puTTY->Connection->SSH->X11, then click on Forwarding->"Enable X11 Forwarding", as shown below:

Putty x11 fwding.PNG

Nothing exciting will happen after clicking OK, but you should see an icon on the right of the toolbar.

Open a terminal: click the Windows 'Start' button, 'run', then enter 'cmd'.

Change to the directory where you saved putty.

cd <dir>


putty.exe -X openflow@[Guest IP Here]

Replace [Guest IP Here] with the IP you just noted.

A new window will pop up; type in the password 'openflow'. Now, type:


A white terminal window should appear. If you have succeeded, you are done with the basic setup. Close the xterm.

Learn Development Tools

In this section, you'll bring up the development environment. In the process, you'll be introduced to tools that will later prove useful for turning the provided hub into a learning switch. You'll cover both general and OpenFlow-specific debugging tools.

Let's define some terminology, starting with terminal types:

  • VMware/VirtualBox console terminal: connects to OpenFlowTutorial. This is the one created when you started up the VM. You can't copy and paste from this tutorial page to the console terminal, so it's a bit of a pain. Minimize this NOW, if you haven't already done so. Once you've used it to set up networking, it won't be needed.
  • SSH terminal: connects to OpenFlowTutorial. Created by using putty on Windows or SSH on OS X / Linux, as described in the previous section. Copy and paste should work on this terminal.
  • xterm terminal: connects to a host in the virtual network. Created in the next section when you start up the virtual network. Will be labeled at the top with the name of the host.

The OpenFlowTutorial VM includes a number of OpenFlow-specific and general networking utilities pre-installed. Please read the short descriptions:

  • OpenFlow Controller: sits above the OpenFlow interface. The OpenFlow reference distribution includes a controller that acts as an Ethernet learning switch in combination with an OpenFlow switch. You'll run it and look at messages being sent. Then, in the next section, you'll write our own controller on top of NOX (a platform for writing controllers).
  • OpenFlow Switch: sits below the OpenFlow interface. The OpenFlow reference distribution includes a user-space software switch. Open vSwitch is another software but kernel-based switch, while there is a number of hardware switches available from Broadcom (Stanford Indigo release), HP, NEC, and others.
  • dpctl: command-line utility that sends quick OpenFlow messages, useful for viewing switch port and flow stats, plus manually inserting flow entries.
  • Wireshark: general (non-OF-specific) graphical utility for viewing packets. The OpenFlow reference distribution includes a Wireshark dissector, which parses OpenFlow messages sent to the OpenFlow default port (6633) in a conveniently readable way.
  • iperf: general command-line utility for testing the speed of a single TCP connection.
  • Mininet: network emulation platform. Mininet creates a virtual OpenFlow network - controller, switches, hosts, and links - on a single real or virtual machine. More Mininet details can be found at the Mininet web page.
  • cbench: utility for testing the flow setup rate of OpenFlow controllers.

From here on out, make sure to copy and paste as much as possible! For example, manually typing in ‘sudo dpctl show n1:0’ may look correct, but will cause a confusing error; the 'nl' is short for NetLink, not n-one.

Let's get started...

Start Network

The network you'll use for the first exercise includes 3 hosts and a switch:

Three switch layout simple.png

To create this network in the VM, in an SSH terminal, enter:

$ sudo mn --topo single,3 --mac --switch ovsk --controller remote

This tells Mininet to start up a 3-host, single-(openvSwitch-based)switch topology, set the MAC address of each host equal to its IP, and point to a remote controller which defaults to the localhost.

Here's what Mininet just did:

  • Created 3 virtual hosts, each with a separate IP address.
  • Created a single OpenFlow software switch in the kernel with 3 ports.
  • Connected each virtual host to the switch with a virtual ethernet cable.
  • Set the MAC address of each host equal to its IP.
  • Configure the OpenFlow switch to connect to a remote controller.

Mininet Brief Intro

Since you'll be working in Mininet for the whole tutorial, it's worth learning a few Mininet-specific commands:

NB: hereafter the following prompt means you'll run a command in Mininet console.


To see the list of nodes available, in the Mininet console, run:

mininet> nodes

To see a list of available commands, in the Mininet console, run:

mininet> help

To run a single command on a node, prepend the command with the name of the node. For example, to check the IP of a virtual host, in the Mininet console, run:

mininet> h2 ifconfig

The alternative - better for running interactive commands and watching debug output - is to spawn an xterm for one or more virtual hosts. In the Mininet console, run:

mininet> xterm h2 h3

You can close these windows now, as we'll run through most commands in the Mininet console.

If Mininet is not working correctly (or has crashed and needs to be restarted), try clearing any residual state or processes using (in ssh shell):

$ mn -c

and running Mininet again.

Mininet has loads of other commands and startup options to help with debugging, and this brief starter should be sufficient for the tutorial. If you're curious about other options, follow the Mininet Walkthrough after the main tutorial.

dpctl Example Usage

dpctl is a utility that comes with the OpenFlow reference distribution and enables visibility and control over a single switch's flow table. It is especially useful for debugging, by viewing flow state and flow counters. Most OpenFlow switches can start up with a passive listening port (in your current setup this is 6634), from which you can poll the switch, without having to add debugging code to the controller.

Create a second SSH window if you don't already have one, and in that shell (not in the mininet shell prompt), run:

$ dpctl show tcp:

The 'show' command connects to the switch and dumps out its port state and capabilities.

Here's a more useful command:

$ dpctl dump-flows tcp:

Since we haven't started any controller yet, the flow-table should be empty.

Ping Test

Now, go back to the mininet console and try to ping h3 from h2. In the Mininet console:

mininet> h2 ping -c3 h3

Note that the name of host h3 is automatically replaced when running commands in the Mininet console with its IP address (

Do you get any replies? Why? Why not?

As you saw before, switch flow table is empty. Besides that, there is no controller connected to the switch and therefore the switch doesn't know what to do with incoming traffic, leading to ping failure.

You'll use dpctl to manually install the necessary flows. In your SSH terminal:

$ dpctl add-flow tcp: in_port=1,actions=output:2
$ dpctl add-flow tcp: in_port=2,actions=output:1

This will forward packets coming at port 1 to port 2 and vice-verca. Verify by checking the flow-table

$ dpctl dump-flows tcp:

Run the ping command again. In your mininet console:

mininet> h2 ping -c3 h3

Do you get replies now? Check the flow-table again and look the statistics for each flow entry. Is this what you expected to see based on the ping traffic? NOTE: if you didn't see any ping replies coming through, it might be the case that the flow-entries expired before you start your ping test. When you do a "dpctl dump-flows" you can see an "idle_timeout" option for each entry, which defaults to 60s. This means that the flow will expire after 60secs if there is no incoming traffic. Run again respecting this limit, or install a flow-entry with longer timeout.

$ dpctl add-flow tcp: in_port=1,idle_timeout=120,actions=output:2

Start Wireshark

The VM image includes the OpenFlow Wireshark dissector pre-installed. Wireshark is extremely useful for watching OpenFlow protocol messages, as well as general debugging.

Start a new SSH terminal and connect to the VM w/X forwarding:

If you're using MAC OS X or Linux, enter:

$ ssh -X openflow@[guest ip address]

If you're using putty.exe, enter:

putty.exe -X openflow@[guest ip address]

Now open Wireshark:

$ sudo wireshark &

You'll propably get a warning message for using wireshark with root access. Press OK.

Click on Capture->Interfaces in the menu bar. Click on the Start button next to 'lo', the loopback interface. You may see some packets going by.

Now, set up a filter for OpenFlow control traffic, by typing 'of' in Filter box near the top:


Press the apply button to apply the filter to all recorded traffic.

Start Controller and view Startup messages in Wireshark

Now, with the Wireshark dissector listening, start the OpenFlow reference controller. In your SSH terminal:

controller ptcp:

This starts a simple controller that acts as a learning switch without installing any flow-entries.

You should see a bunch of messages displayed in Wireshark, from the Hello exchange onwards. As an example, click on the Features Reply message. Click on the triangle by the 'OpenFlow Protocol' line in the center section to expand the message fields. Click the triangle by Switch Features to display datapath capabilities - feel free to explore.

These messages include:

Message Type Description
Hello Controller->Switch following the TCP handshake, the controller sends its version number to the switch.
Hello Switch->Controller the switch replies with its supported version number.
Features Request Controller->Switch the controller asks to see which ports are available.
Set Config Controller->Switch in this case, the controller asks the switch to send flow expirations.
Features Reply Switch->Controller the switch replies with a list of ports, port speeds, and supported tables and actions.
Port Status Switch->Controller enables the switch to inform that controller of changes to port speeds or connectivity. Ignore this one, it appears to be a bug.

Since all messages are sent over localhost when using Mininet, determining the sender of a message can get confusing when there are lots of emulated switches. However, this won't be an issue, since we only have one switch. The controller is at the standard OpenFlow port (6633), while the switch is at some other user-level port.

View OpenFlow Messages for Ping

Now, we'll view messages generated in response to packets.

Before that update your wireshark filter to ignore the echo-request/reply messages (these are used to keep the connection between the switch and controller alive): Type the following in your wireshark filter, then press apply:

of && (of.type != 3) && (of.type != 2)

Run a ping to view the OpenFlow messages being used. In the Mininet console:

mininet> h2 ping -c1 h3

In the Wireshark window, you should see a number of new message types:

Message Type Description
Packet-In Switch->Controller a packet was received and it didn't match any entry in the switch's flow table, causing the packet to be sent to the controller.
Packet-Out Controller->Switch controller send a packet out one or more switch ports.
Flow-Mod Controller->Switch instructs a switch to add a particular flow to its flow table.
Flow-Expired Switch->Controller a flow timed out after a period of inactivity.

First, you see an ARP request miss the flow table, which generates a broadcast Packet-Out message. Next, the ARP response comes back; with both MAC addresses now known to the controller, it can push down a flow to the switch with a Flow-Mod message. The switch does then pushes flows for the ICMP packets. Subsequent ping requests go straight through the datapath, and should incur no extra messages; with the flows connecting h2 and h3 already pushed to the switch, there was no controller involvement.

Re-run the ping, again from the Mininet console (hitting up is sufficient - the Mininet console has a history buffer):

mininet> h2 ping -c1 h3

If the ping takes the same amount of time, run the ping once more; the flow entries may have timed out while reading the above text.

This is an example of using OpenFlow in a reactive mode, when flows are pushed down in response to individual packets.

Alternately, flows can be pushed down before packets, in a proactive mode, to avoid the round-trip times and flow insertion delays.

Benchmark Controller w/iperf

iperf is a command-line tool for checking speeds between two computers.

Here, you'll benchmark the reference controller; later, you'll compare this with the provided hub controller, and your flow-based switch (when you've implemented it).

In the mininet console run :

mininet> iperf

This Mininet command runs an iperf TCP server on one virtual host, then runs an iperf client on a second virtual host. Once connected, they blast packets between each other and report the results.

Now compare with the user-space switch. In the mininet console:

mininet> exit

Start the same Mininet with the user-space switch:

$ sudo mn --topo single,3 --mac --controller remote --switch user

Run one more iperf test with the reference controller:

mininet> iperf

See a difference? With the user-space switch, packets must cross from user-space to kernel-space and back on every hop, rather than staying in the kernel as they go through the switch. The user-space switch is easier to modify (no kernel oops'es to deal with), but slower for simulation.

Exit Mininet:

mininet> exit

Create Learning Switch

Now, let's move on building a networking application. We provide you with starter code for a hub controller. After getting yourself familiar with it, you'll modify the provided hub to act as an L2 learning switch. In this application, the switch will examine each packet and learn the source-port mapping. Thereafter, the source MAC address will be associated with the port. If the destination of the packet is already associated with some port, the packet will be sent to the given port, else it will be flooded on all ports of the switch.

Later, you'll turn this into a flow-based switch, where seeing a packet with a known source and dest causes a flow entry to get pushed down.

For this tutorial, you'll use the NOX platform for implementing your controller. We expect additional platforms to be available in the short future.

Controller Choice A: NOX w/Python

One option for the first exercise is to use NOX, a controller platform that allows you to write a controller on top, in Python, C++, or some combination of the two. From

NOX is an open-source platform that simplifies the creation of software for controlling or monitoring networks. Programs written within NOX (using either C++ or Python) have flow-level control of the network. This means that they can determine which flows are allowed on the network and the path they take.

For more details, see the NOX overview.

You do no need to install NOX - it comes ready to run on the VM.

We're not going to be using the reference controller anymore, which is running in the background (do 'ps -A | grep controller' if you're unsure).

The switches are all trying to connect to a controller, and will increase the period of their attempts to contact the controller, up to a maximum of 15 seconds. Since the OpenFlow switch has not connected yet, this delay may be anything between 0 and 15 seconds. If this is too long to wait, the switch can be configured to wait no more than N seconds using the --max-backoff parameter.

Make sure the reference controller used before is not running, so that NOX can use port 6633:

$ sudo killall controller

You can also restart Mininet to make sure that everything is "clean". From your Mininet console:

$ sudo mn --topo single,3 --mac --switch ovsk --controller remote

Go to the directory holding the built NOX executable (~/noxcore/build/src) in the other SSH window:

$ cd ~/noxcore/build/src

Then, in the same window, start the base Python hub code:

$ ./nox_core -v -i ptcp: pytutorial

This command told NOX to start the 'tutorial' application, to print verbose debug information, and to passively listen for new switch connections on the standard OpenFlow port (6633).

Wait until the application indicates that the OpenFlow switch has connected. When the switch connects, NOX will print something like this:

00039|nox|DBG:Registering switch with DPID = 1

Verify Hub Behavior with tcpdump

Now we verify that hosts can ping each other, and that all hosts see the exact same traffic - the behavior of a hub. To do this, we'll create xterms for each host, and view the traffic in each. In the Mininet console, start up three xterms:

mininet> xterm h2 h3 h4

Arrange each xterm so that they're all on the screen at once. This may require reducing the height of to fit a cramped laptop screen.

In the xterms for h3 and h4, run tcpdump, a utility to print the packets seen by a host:

$ sudo tcpdump -XX -n -i h3-eth0

and respectively:

$ sudo tcpdump -XX -n -i h4-eth0

In the xterm for h2, send a ping:

$ ping -c1

The ping packets are now going up to the controller, which then floods them out all interfaces except the sending one. You should see identical ARP and ICMP packets corresponding to the ping in both xterms running tcpdump.

Now, see what happens when a non-existent host doesn't reply. From h2 xterm:

$ ping -c1

You should see three unanswered ARP requests in the tcpdump xterms. If your code is off later, three unanswered ARP requests is a signal that you might be accidentally dropping packets.

You can close the xterms now.

Benchmark Hub Controller w/iperf

Here, you'll benchmark the provided hub.

First, verify reachability. Mininet should be running, along with the NOX tutorial in a second window. In the Mininet console, run:

mininet> pingall

This is just a sanity check for connectivity. Now, in the Mininet console, run:

mininet> iperf

Now, compare your number with the reference controller you saw before. How does that compare?

Open Hub Code and Begin

Go to your SSH terminal and stop the hub controller using Ctrl-C. The file you'll modify is ~/noxcore/src/nox/coreapps/tutorial/ Open this file in your favorite editor.

Most of the code will go in one function, learn_and_forward(). There isn't much code here, yet it's sufficient to make a complete hub, and an example of a minimal NOX app. You'll need to add roughly 10 lines to make a learning switch.

Each time you change and save this file, make sure to restart NOX, then use pings to verify hub or Ethernet learning switch behavior. Hosts that are not the destination should display no tcpdump traffic after the initial broadcast ARP request.

Learning Python

This section introduces Python, giving you just enough to be dangerous.


  • is a dynamic, interpreted language. There is no separate compilation step - just update your code and re-run it.
  • uses indentation rather than curly braces and semicolons to delimit code. Four spaces denote the body of a for loop, for example.
  • is dynamically typed. There is no need to pre-declare variables and types are automatically managed.
  • has built-in hash tables, called dictionaries, and vectors, called lists.
  • is object-oriented and introspective. You can easily print the members variables and functions of an object at runtime.

Common operations:

To initialize a dictionary:

mactable = {}

To add an element:

mactable[0x123] = 2

To check for dictionary membership:

if 0x123 in mactable:
    print 'element 2 in mactable'

To print a debug message in NOX:

log.debug('saw new MAC!')

To print an error message in NOX:

log.error('unexpected packet causing system meltdown!')

To print all member variables and functions of an object:

print dir(object)

To comment a line of code:

# Prepend comments with a #; no // or /**/

More Python resources:

The subsections below give details about NOX APIs that should prove useful in the exercise.

Sending OpenFlow messages with NOX

Some functions that will be useful include:

Component.send_openflow( ... ) # send a packet out a port
Component.install_datapath_flow( ... ) # push a flow to a switch

These functions, part of the core NOX API, are defined in ~/noxcore/src/nox/lib/ To save the need to look through this source code, the relevant documentation is below:

send_openflow( ... )

     def send_openflow(self, dp_id, buffer_id, packet, actions,
        Sends an openflow packet to a datapath.

        This function is a convenient wrapper for send_openflow_packet
        and send_openflow_buffer for situations where it is unknown in
        advance whether the packet to be sent is buffered.  If
        'buffer_id' is -1, it sends 'packet'; otherwise, it sends the
        buffer represented by 'buffer_id'.

        dp_id - datapath to send packet to
        buffer_id - id of buffer to send out
        packet - data to put in openflow packet
        actions - list of actions or dp port to send out of
        inport - dp port to mark as source (defaults to Controller

Here's an example use, from the starter code:

self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)

This code floods a packet cached at the switch (with the given bufid) out all ports but the input port. Replace openflow.OFPP_FLOOD with a port number to send a packet packet out a specific port, unmodified.

install_datapath_flow( .... )

    def install_datapath_flow(self, dp_id, attrs, idle_timeout, hard_timeout,
                              actions, buffer_id=None, 
                              inport=None, packet=None):
        Add a flow entry to datapath

        dp_id - datapath to add the entry to

        attrs - the flow as a dictionary (described above)

        idle_timeout - # idle seconds before flow is removed from dp

        hard_timeout - # of seconds before flow is removed from dp

        actions - a list where each entry is a two-element list representing
        an action.  Elem 0 of an action list should be an ofp_action_type
        and elem 1 should be the action argument (if needed). For
        OFPAT_OUTPUT, this should be another two-element list with max_len
        as the first elem, and port_no as the second

        buffer_id - the ID of the buffer to apply the action(s) to as well.
        Defaults to None if the actions should not be applied to a buffer

        priority - when wildcards are present, this value determines the
        order in which rules are matched in the switch (higher values
        take precedence over lower ones)

        packet - If buffer_id is None, then a data packet to which the
        actions should be applied, or None if none.

        inport - When packet is sent, the port on which packet came in as input,
        so that it can be omitted from any OFPP_FLOOD outputs.

Note that install_datapath_flow() takes in an attributes dictionary with parts of the OpenFlow match. Here's an example:

attrs = {}
attrs[core.IN_PORT] = inport
attrs[core.DL_DST] = packet.dst

install_datapath_flow also requires a list of actions. Here's another example:

actions = [[openflow.OFPAT_OUTPUT, [0, outport]]]

You will want to use exactly this action list for the tutorial. The format is a list of actions; we've defined one action, which forwards to a single port (OFPAT = OpenFlow Action Type: Output). The [0, outport] part that follows is the set of parameters for the output action type: 0 is max_len, which is only defined for packets forwarded to the controller (ignore this), while the outport param specifies the output port.

For more details on the format, see the NOX core Python API code in src/nox/

For more information about OpenFlow constants, see the main OpenFlow types/enums/structs file, openflow.h, in ~/openflow/include/openflow/openflow.h

Parsing Packets with the NOX packet libraries

The NOX packet parsing libraries are automatically called to parse a packet and make each protocol field available to Python.

The parsing libraries are in:


Each protocol has a corresponding parsing file.

For the first exercise, you'll only need to access the Ethernet source and destination fields. To extract the source of a packet, use the dot notation:


The Ethernet src and dst fields are stored as arrays, so you'll probably want to to use the mac_to_str() function or mac_to_int. I suggest mac_to_str, and it avoids the need to do any hex conversion when printing. The mac_to_str() function is already imported, and comes from packet_utils in ~noxcore/src/nox/lib/packet/

To see all members of a parsed packet object:

print dir(packet)

Here's what you'd see for an ARP packet:

 'VLAN_TYPE', '__doc__', '__init__', '__len__', '__module__', '__nonzero__',
 '__str__', 'arr', 'dst', 'err', 'find', 'hdr', 'hdr_len', 'msg', 'next', 'parse', 
 'parsed', 'payload_len', 'prev', 'set_payload', 'src', 'tostring', 'type',

Many fields are common to all Python objects and can be ignored, but this can be a quick way to avoid a trip to a function's documentation.

Testing Your Controller

To test your controller-based Ethernet switch, first verify that when all packets arrive at the controller, only broadcast packets (like ARPs) and packets with unknown destination locations (like the first packet sent for a flow) go out all non-input ports. You can do this with tcpdump running on an xterm for each host.

Once the switch no longer has hub behavior, work to push down a flow when the source and destination ports are known. You can use dpctl to verify the flow counters, and if subsequent pings complete much faster, you'll know that they're not passing through the controller. You can also verify this behavior by running iperf in Mininet and checking that no OpenFlow packet-in messages are getting sent.

Let the instructor know when your learning switch works!

Support Multiple Switches

Your controller so far has only had to support a single switch, with a single MAC table. In this section, you'll extend it to support multiple switches.

Start mininet with a different topology. In the Mininet console:

mininet> exit

Then in the SSH shell:

$ sudo mn --topo linear --switch ovsk --controller remote

Your created topology looks like this:


This will create a 2-switch topology where each switch has a single connected host.

Now, modify your switch so that it stores a MAC-to-port table for each DPID. This strategy only works on spanning tree networks, and the delay for setting up new paths between far-away hosts is proportional to the number of switches between them. Other modules with NOX, including routing, act smarter. NOX routing, for example, maintains an all-pairs shortest path data structure and will immediately push down all flow entries needed to previously-seen sources and destinations.

After the mods, to verify that your controller works, in the Mininet console, run:

mininet> pingall

Benchmark Your Controller

cbench is a program for testing OpenFlow controllers by generating packet-in events for new flows. More info is available at the oflops/cbench page.

Cbench emulates a bunch of switches which connect to a controller, send packet-in messages, and watch for flow-mods to get pushed down.

To benchmark your (flow-based) controller, first close down Mininet from the Mininet console:

mininet> exit

Kill your controller, too, with Ctrl-c, then re-start it without the verbose option - this is a performance test after all.

$ ./nox_core -i ptcp: pytutorial

Start up cbench in the previously-Mininet terminal:

$ cd ~/oflops/cbench
$ ./cbench -l5

This command runs 5 loops with 16 virtual switches, then reports the number of flow setups per second. The value shown under-reports the real number, and in effect, measures latency. Cbench by default only sends additional packet-ins when one has been received.

To run cbench in throughput mode, with many simultaneous in-flight packet-ins, run:

$ ./cbench -l5 -t

To compare with the reference controller, close down your controller with Ctrl-c, and start up the reference controller:

$ controller ptcp:

Re-run cbench:

$ ./cbench -l5 t

Is it a little faster? Straight C generally wins against interpreted Python. What about C++? To run the built-in NOX C++ switch, run:

$ ./nox_core -i ptcp: switch

Compare cbench both with and without -t; how do the numbers compare?

You can improve these numbers by expanding your controller to use multiple cores or by compiling NOX with the --ndebug option, but these are out of scope for the tutorial.

Congratulations on getting this far. You have three options:

  • run your code over real networking gear
  • add layer-3 forwarding capabilities to your switch
  • add firewall capabilities to your switch

Proceed to the section you prefer.

Control a Slice of a real Network

NOTE: This part is still in beta, so be prepared that things could break down the road...

In this exercise you'll use the code you have so far to control a slice of a real network consisting of 3 OpenFlow switches, a server and a wireless client. Your goal is to access a website and post a message. The interesting part is that your controller should allow traffic to go from client to server and vice versa. The setup includes:

  1. 3 OpenFlow-enabled LinkSys Access Points.
  2. FlowVisor ( to virtualize the network and create slices)
  3. 1 controller/team
  4. 1 Webserver
  5. 1 Wireless device/team (could be your laptop's WiFi, your iPhone, Droid etc)

Ideally, you shouldn't write any code for this experiment. You will have to form teams though. When you are ready to start, ask the instructors to put you in a team.

Here is the topology that we will use:

Virtualized layout detail.png

Setting up your Network

Here you'll work with a real network, so we won't use mininet. Go to your mininet console and type

mininet> exit

You will have to deal with two network configurations.

  1. The control network which will allow your controller to talk with the FlowVisor and OpenFlow switches (192.168.10. subnet).
  2. The actual network we want to control, i.e. your wireless client to access the Web Server (10.0.0. subnet).

Control Network Configuration

  • Ask the instructor for an ethernet cable. This will go to a standard (non-OpenFlow) switch and connects to the FlowVisor.
  • At your local machine, configure the interface where you plugged your ethernet cable with the following characteristics:
IP address : 192.168.10.X (where X = 100+TeamIndex, e.g. X=101 for Team1)
Netmask :

For Linux you'll have to do something like :

$ sudo ifconfig eth0 192.168.10.X netmask


$ sudo ifconfig en0 192.168.10.X netmask

For Windows

Go to your Control Panel->Network Settings and configure your LAN device.

Now your local machine can access FlowVisor. To verify, ping FlowVisor from a terminal on your local machine:

$ ping

But what we really need is the guest VM - where the controller is - to be able to communicate with the FlowVisor. We will use port-forwarding to do that.

First, note the IP address of your VM guest. At your VM's shell, type:

$ ifconfig eth1

Now, we need to configure port-forwarding.

Linux and Mac users

From your local machine:

$ ssh openflow@<guestIP> -L192.168.10.X:6633:<guestIP>:6633

where <guestIP> is the IP address of the eth1 interface of the VM, and X is 100 + your team number.

Windows users

To enable port forwarding on the Putty, please enter the appropriate fields during connection setup

Putty port fwding.PNG

Verify reachability

To verify that everything worked, use tcpdump at your guest VM and see whether you receive any incoming OpenFlow-related packets

$ sudo tcpdump -i lo port 6633

Note: The reason we specify the interface 'lo' not 'eth1' here is that SSH port forwarding arrives to the interface eth1 tcp port 22 and forwarded to the local interface 'lo' tcp port 6633.

Due to reconnection backoff, it might take up to one minute before you see any packets coming in. If you don't get any packets after 1 minute, ask one of the instructors for help.

Wireless Client Configuration

You will have to configure your wireless client's network interface. First login to the wireless network with SSID "OpenFlow-Tutorial". Depending on your OS use ControlPanel/ifconfig or any other similar utility :

For Linux:

$ sudo ifconfig wlan0 10.0.0.X netmask

For Mac:

$ sudo ifconfig en1 10.0.0.X netmask

For Windows, go to Control Panel->Network Settings and configure it manually.

Write down your wireless card MAC address. We'll use this shortly.

Try to ping the WebServer at Does it work? If not, why?

FlowVisor Configuration

Several teams will be using the same switches at the same time, so we have to virtualize our network and give each team a separate slice. Each controller will have a limited view of the network, as this is dictated by its slice configuration. In this exercise, each team will control all the traffic that comes from and goes to its wireless client. To do that we will need the MAC address of your team's wireless client. Hopefully you already have this from the previous step. Give this MAC address to the instructor to update your slice configuration at the FlowVisor.

Here is how a slice definition looks at the flowvisor configuration :

Name: team1
ID: 1
Host: tcp:

FlowSpace: allow: dl_src: 00:22:41:66:13:1c
FlowSpace: allow: dl_dst: 00:22:41:66:13:1c

Note that points to this slice's OF controller, 00:22:41:66:13:1c is the MAC address of the wireless client, and every packet with that ethernet_src or ethernet_dst is assigned to this controller.

For more details on FlowVisor, look at the wikipage.

Run your controller

Go to your directory and start your controller.

$ cd ~/noxcore/build/src/
$ ./nox_core -i ptcp: -v pytutorial

What do you see? Are there any switches connecting to your controller? Use your debug messages or wireshark for that.

Accessing the WebServer

By now, you should have a functional network between your client and the webserver.

Try again to ping the server:

$ ping

Does it work now? How packets travel from client to the server? Check the switch flow-tables using dpctl.

$ dpctl dump-flows tcp:192.168.10.X (X=11,12,13)

What do you see? Do you recognize all flows?

If ping works, you are ready to go to the final step. Fire your browser and go to Write and post a short message and make sure you fill your team's number.

Look what others said at

Create Router

In this exercise, you'll make a static layer-3 forwarder/switch. It's not exactly a router, because it won't decrement the IP TTL and recompute the checksum at each hop (so traceroute won't work). Actions to do TTL and checksum modification are expected in the upcoming OpenFlow version 1.1. However, it will match on masked IP prefix ranges, just like a real router.

From RFC 1812:

An IP router can be distinguished from other sorts of packet switching devices in that a router examines the IP protocol header as part of the switching process. It generally removes the Link Layer header a message was received with, modifies the IP header, and replaces the Link Layer header for retransmission.

To simplify the exercise, your "router" will be completely static. With no BGP or OSPF, you'll have no need to send or receive route table updates.

Each network node will have a configured subnet. If a packet is destined for a host within that subnet, the node acts as a switch and forwards the packet with no changes, to a known port or broadcast, just like in the previous exercise. If a packet is destined for some IP address for which the router knows the next hop, it should modify the layer-2 destination and forward the packet to the correct port.

Our hope is that this exercise will show that with an OpenFlow-enabled forwarding device, the network is effectively layerless; you can mix switch, router, and higher-layer functionality.

Please note that this is an advanced exercise, and given that most implementation details are up to you, will be harder.

Create Topology

You'll need a slightly different topology, something like this:

Router topo.png

… which will need to be described in a way that Mininet will understand.

There's an example custom topology at:

$ ~/mininet/custom/

First, copy the example to a new file:

$ cp ~/mininet/custom/

To run a custom topology, pass Mininet the custom file and pass in the custom topology:

$ sudo mn --custom --topo mytopo --mac

Then, in the Mininet console, run:

mininet> pingall

Now, modify your topology file to match the picture and verify full host connectivity with pingall in the Mininet console.

Set up hosts

First, you may need to update to the latest version of Mininet (which supports CLI scripting and the --prefixlen option, which you may find to be useful.)

$ pushd ~/mininet; git pull; popd

Next, set up IP configuration on each virtual host to force each one to send to the gateway for destination IPs that are outside of their configured subnet.

You'll need to configure each host with a subnet, IP, gateway, and netmask.

There are several ways that this can be done:

  • Unix commands via Mininet CLI

From within the Mininet CLI, you can send commands to hosts to configure them:

mininet> h2 ifconfig h2-eth0
mininet> h2 route add default gw
mininet> h2 route -n
  • Regular Unix commands via an xterm

Another way of configuring hosts is to open up an xterm

mininet> xterm h2

and then to type into that xterm window to configure the host:

# ifconfig h2-eth0
  • Running a configuration script

You can also run scripts on the hosts themselves, for example, if you have a script called config_script, you can run it on host h2 from the Mininet CLI:

mininet> h2 config_script

If you write such a script, you can either have it automatically know what to do (e.g. based on MAC address, which you can assign based on node number with --mac ) or pass in additional parameters as desired.

  • CLI scripting

To avoid repetitive CLI typing, it is possible to create a file consisting of multiple CLI commands, and then run that script in Mininet:

mininet> source my_cli_script


# mn --pre my_cli_script

A sample CLI script might look like:

py "Configuring network"
h3 ifconfig h3-eth0
h4 ifconfig h4-eth0
h5 ifconfig h5-eth0
h3 route add default gw
h4 route add default gw
h5 route add default gw
py "Current network:"

CLI scripting is designed to save typing rather than to be a full programming environment (although you can evaluate Python expressions from the CLI, as shown above using the 'py' command!) For advanced tasks, the Mininet API provides flexible access to all Mininet capabilities.

  • Mininet API

Mininet's Python API provides a much more powerful means of creating and configuring networks programatically, but is probably beyond the scope of this tutorial. Some examples of using the Mininet API may be found in mininet/examples, and they are described in mininet/examples/README.

  • Changing the node IDs in the topology

It is also possible to change the default IP addresses by changing node IDs in a topology.

The node ID in a topology is the default IP address in base 256. For example, setting node ID 258 will result in a default IP address of

The default IP prefix length may be changed with the command-line option --prefixlen. For example,

# mn --prefixlen 24

will use /24 as the default prefix length (i.e. netmask of

For the this tutorial, you may find that using CLI scripting or changing the node IDs (and setting the prefix length to 24) may be most convenient.

Once you have your new topology configured and connected to your pytutorial controller, you should be able to ping between hosts on the same subnet, but not between hosts on different subnets. Your job is to create a new (or revised) controller that installs rules to forward packets between the two subnets!


A router generally has to respond to ARP requests. You will see ethernet broadcasts which will (initially at least) be forwarded to the controller.

Your controller should probably construct ARP replies and forward them out the appropriate ports.

It may be possible to avoid dealing with ARP (at least initially) by adding static ARP entries in each host for all of the nodes on its subnet.

Static Routing

Once ARP has been handled, you will need to handle routing for the static configuration. Since we know what is connected to each port, we can match on IP address (or prefix, in the case of the remote subnet) and forward out the appropriate port.

In the case of the left switch, for example, we will want to forward packets destined for an attached host to the appropriate port, while packets destined for the remote subnet should be forwarded to the right switch.


Additionally, your controller may receive ICMP echo (ping) requests for each switch, which it should respond to.

Lastly, packets for unreachable subnets should be responded to with ICMP network unreachable messages.

Testing your router

If the router works properly:

  • attempts to send from to an unknown address range like should yield an ICMP destination unreachable message.
  • packets sent to hosts on the same subnet should be treated like before.
  • packets sent to hosts on a known address range should have their MAC dst field changed to that of the next-hop router.
  • the router should be pingable, and should generate an ICMP echo reply in response to an ICMP echo request.

The exercise is meant to give more practice with packet parsing and show how to use OpenFlow to modify packets.

Let the instructor know when you get stuck or when you complete the exercise. This one is more open, and you'll need different actions (MAC dst modify) and matching (IP dst/prefix combinations), for which NOX should help.

Create Firewall

In this exercise, you'll modify your switch to reject connection attempts to specific ports, just like a firewall.

This exercise is meant to show how OpenFlow can even do basic layer-4 tasks. Other uses could even extend into layer 7; cookie-based load balancing, for example.

Testing your Firewall

To run iperf on xterms, on the xterm for h2, start up a server:

iperf -s

Then on the xterm for h3 start up a client:

iperf -c

Your task is to prevent this from happening, and to block all flow entries with this particular port.

You can change the port used by iperf with the -p option. Both server and client will need this option specified. Again, NOX will be useful for figuring out how to specify a flow entry that matches on wildcard ports. Also note that an empty action list will drop a packet; there's no explicit drop action.

Learn More


To learn more about OpenFlow in general, consult the main OpenFlow page. There are videos, blog entries, and more. Check the wiki for link to OpenFlow-based projects and demos.

Additional Tools

Old Regression Tests

Note: you will need to install additional stuff to get the old regression tests working. See the install instructions for your platform, referenced at the top of the OpenFlow wiki

The OpenFlow reference distribution includes a set of tests to verify that an OpenFlow switch correctly sends and receives packets. In this section, you'll run through some of the "Black Box" tests, where the regression switch acts as a controller and verifies that a switch responds properly to OpenFlow messages, as well as properly forwards packets sent to the input ports of the switch. The Black Box regression tests use this layout:

Regression tests.png

First, exit from the Mininet console:

mininet> exit

To run the tests, log in as root, from the same SSH terminal:

$ sudo su

Run a script to start up virtual ethernet pairs locally.

# openflow/regress/bin/ 

Veth0 connects to veth1, for example, and anytime a packet is sent to veth0, it'll pop out veth1, and vice versa. The regression suite will allocate four veth pair halves to a software OpenFlow switch and the other four to the test suite, which sends packets and checks the contents and locations of responses.

In an SSH terminal:

# ifconfig -a

You should see 8 new virtual interfaces, veth0..veth7.

Configure Wireshark to show OpenFlow messages and TCP resets in red (which delimit individual tests). In the Wireshark filter box, enter:

of || tcp.flags.reset == 1

Start running the tests, with Wireshark running on lo (loopback interface):

# openflow/regress/bin/

You may see OpenFlow messages for each test - if not, hit Ctrl-C to stop the tests, and clean up any leftover state:

# openflow/regress/bin/

Sometimes on the first run, the tests fail; we're not sure why this is happening. Restart after tearing down and they should work.

Then, re-run the tests:

# openflow/regress/bin/

When you get bored, stop the tests and check the messages. Then clean up any state:

# openflow/regress/bin/

The regression suite is useful for verifying new switch features, as well as diagnosis divergent behavior between different switches. The suite is generally used with 4 physical ports on hardware switches. We won't do anything more with it in this tutorial, but feel free to peruse the code. See the openflow/regress/projects/black_box directory, which has a file for each test.

To teardown virtual ethernet pairs, run:

# openflow/regress/bin/ 

A replacement test suite is in the making, and is expected for mid 2010. The new suite will be based on Python and reorganized to make switch-specific tests and port configurations much easier to define and debug.

Exit back to regular username:

# exit


This tutorial was written by Brandon Heller and Yiannis Yiakoumis and beta-tested by Bob Lantz, KK Yap and Masayoshi Kobayashi.



  • How does one scroll an xterm?
    • possible answer: start it with the flag -sl 500 to store 500 lines of output

Frequently Asked Questions (FAQ)

VirtualBox-specific Instructions

VirtualBox Networking

VirtualBox requires a few extra commands to set up networking.

To allow network access in the VM, execute:

sudo dhclient eth1

which grabs an IP address. Else, you can change the default interface as shown below and execute sudo dhclient eth0.

Now we need to provide SSH access from your local machine into the VM.

OS X / Linux Users Run the VBoxManage commands below from a local terminal (not the VM window).

Windows Users If you are using Windows Vista, first close Virtual box, to ensure that config files aren't locked. Then open a command line prompt, by click on 'Start', then 'Run', then typing 'cmd' and hitting enter. In the terminal that appears, change to the VirtualBox directory:

cd "C:\Program Files\Sun\xVM VirtualBox"

All OSes: From a terminal on your local machine (NOT the VM/VirtualBox), run:

VBoxManage setextradata OpenFlowTutorial "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/HostPort" 2222
VBoxManage setextradata OpenFlowTutorial "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/GuestPort" 22
VBoxManage setextradata OpenFlowTutorial "VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/Protocol" TCP

Verify the settings:

VBoxManage getextradata OpenFlowTutorial enumerate

The three values you added above should be shown.

Save your network settings for future reboots, by powering down the VM, from the VM window:

sudo poweroff

Restart the OpenFlowTutorial VM once again, by clicking 'Start' at the top of VirtualBox. Login again as user openflow with password openflow.

Windows Users You may need to change the VM configuration. Edit /etc/network/interfaces. Check that it says:

allow hot-plug eth1
iface eth1 inet dhcp

If it says eth0, change it to eth1; note that to write the file you'll need to use sudo. If you changed the interfaces file, poweroff the machine (sudo poweroff) and then start it again.

VirtualBox SSH Connections

Mac OS X and Linux

To SSH from the local machine to the VM, on the local machine run:

ssh -Y -l openflow -p 2222 localhost

with password openflow. Test the X11 forwarding by running on the local machine:


and a new terminal window should appear. If you have succeeded, you are done with the basic setup. Close the xterm.

Windows XP

Start Xming; nothing exciting will happen but it will show an icon on the right of the toolbar.

Open a terminal: click 'Start', 'run', then enter 'cmd'.

Change to the directory where you saved putty.

cd <dir>


putty.exe -X -P 2222 -l openflow localhost

A new window will pop up; type in the password 'openflow'. Now, type:


A white terminal window should appear. If you have succeeded, you are done with the basic setup. Close the xterm.