Skip to content

OpenFlow 1.3 Tutorial

ederlf edited this page Dec 13, 2012 · 18 revisions

Welcome to the OpenFlow-1.3 Tutorial!

This tutorial is inspired by the [OpenFlow 1.0 Tutorial] (http://www.openflow.org/wk/index.php/OpenFlow_Tutorial) and is a basic guide to start a practical experience with the OpenFlow 1.3 version.

At the end you should be able to:

  • Install and view flows with dpctl utility.
  • Dissect OpenFlow messages with Wireshark.
  • Create basic NOX applications.

Pre-Requisites

In order to be able to go through this tutorial you will need the following development tools for OpenFlow.

Setup

In this part we show how to do a fast setup. For more details please check their documentation.

OpenFlow 1.3 Software switch

Install Netbee dependencies

$ sudo apt-get install libpcap-dev libxerces-c2-dev libpcre3-dev flex bison libboost-all-dev

Pre-Building

Download the source code on http://www.nbee.org/download/nbeesrc-12-11-12.php
$ cd nbeesrc/src  
$ cmake .
$ make
$ cd ..
$ sudo cp bin/libn*.so /usr/local/lib
$ sudo ldconfig
$ sudo cp -R include/* /usr/include

Build

$ ./boot.sh
$ ./configure
$ make
$ sudo make install
NOX

Install all NOX dependencies

Build

$./boot.sh
$ mkdir build
$ cd build
$ ../configure
$ make
OpenFlow dissector for Wireshark

Install Wireshark

$ sudo apt-get install wireshark-dev

Install scons

$ sudo apt-get install scons

Set the Wireshark include directory $ export WIRESHARK=/usr/include/wireshark

Building

$ cd src
$ scons install
Mininet

Download and Install

cd  $HOME/
git clone git://github.com/mininet/mininet
mininet/util/install.sh -n

Important: If you do not downloaded the pre-configured Virtual Machine, some changes are needed to run the software switch with mininet.

To make it work you have make changes to the file node.py, where the commands to start the switches are called

vim mininet/node.py

Change the following piece of code

self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
        ' punix:/tmp/' + self.name + mac_str + ' --no-slicing ' +
        ' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' )
self.cmd( 'ofprotocol unix:/tmp/' + self.name +
        ' tcp:%s:%d' % ( controller.IP(), controller.port ) +
        ' --fail=closed ' + self.opts +
        ' 1> ' + ofplog + ' 2>' + ofplog + ' &' )

Change the code to

self.cmd( 'ofdatapath -i ' + ','.join( intfs ) +
        ' punix:/var/run/' + self.name + '.sock --no-slicing '
        +' 1> ' + ofdlog + ' 2> ' + ofdlog + ' &' ) 
self.cmd( 'ofprotocol unix:/var/run/' + self.name +
        '.sock tcp:%s:%d' % ( controller.IP(), controller.port )+
        ' 1> ' + ofplog + ' 2>' + ofplog + ' &' )

Install the modified mininet

sudo make install .

Starting the topology

Let's start a simple topology on mininet.

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

The command above will create a topology with a single switch connecting two hosts.

Using dpctl

Dpctl is a good utility to change and show the network state in a fast manner, avoiding changes to your controller when you want only punctual actions.
Let's see some examples and how to make the hosts of the topology created in the last step ping each other.

Examples

Show all flows present in table 0.

$ sudo dpctl  unix:/var/run/s1.sock stats-flow table=0

Install a flow in the table 0, to match an IPv6 src address and output to port 2.

$ sudo dpctl  unix:/var/run/s1.sock flow-mod table=0,cmd=add eth_type=0x86dd,ipv6_src=2001:0db8:85a3:0042:0000:8a2e:0370:7334 apply:output=2

Install a flow in the table 0, with default parameters, matching on in_port and eth_type and a set_field action to rewrite the ip src.

$ sudo dpctl  unix:/var/run/s1.sock flow-mod table=0,cmd=add in_port=1,eth_type=0x800 apply:set_field=ipv4_src=192.168.0.1

Create a group.

$ sudo dpctl  unix:/var/run/s1.sock group-mod cmd=add,group=1,type=all

Install flow with an action to send to the group created.

$ sudo dpctl unix:/var/run/s1.sock flow-mod table=0,cmd=add eth_type=0x800,eth_src=00:01:02:03:04:05 apply:group=1

Create a meter with a 10MB rate limiting

$ sudo dpctl unix:/var/run/s1.sock meter-mod cmd=add,flags=1,meter=1 drop:rate=10000

Create a flow that points to a meter instruction $ sudo dpctl unix:/var/run/s1.sock flow-mod table=0,cmd=add in_port=1 meter:1 apply:output=2

Ping between the topology hosts

Just add two rules to direct the traffic from the port 1 to port 2 and from port 2 to port 1.

$ sudo dpctl  unix:/var/run/s1.sock flow-mod table=0,cmd=add in_port=1 apply:output=2
$ sudo dpctl  unix:/var/run/s1.sock flow-mod table=0,cmd=add in_port=2 apply:output=1

Now try to execute ping the between the hosts on mininet.

h2 ping h3
h3 ping h2

Dissecting OpenFlow messages

Start Wireshark

$ sudo wireshark &

To filter OpenFlow 1.3 messages type in the filter box near the top

of13.<field to filter>

For example, to filter messages by the header present in all OpenFlow messages

of13.ofp_header

Filter flow_mod messages

of13.ofp_flow_mod 

Creating a basic NOX application

Now it's time to learn about the modifications on the NOX C++ API needed to reflect OpenFlow 1.3 changes, showing the essential code that an application expects to run. For a more detailed description of NOX, as we will focus on the API changes, please look at NOX Classic Wiki.

Typical application body

Every application developed in NOX should have a class which will have the name of your app. That class will be where OpenFlow message handlers should be implemented plus a configure and an install methods. The configure method is useful to pass config arguments to the application, while the install method is used to register the message handlers.

class MyApp
: public Component{
public:
MyApp(const Context* c,
const json_object*) 
: Component(c) { }

void configure(const Configuration*);
 
void install();

/*some message handler*/
Disposition handle(const Event&);
};

REGISTER_COMPONENT(container::Simple_component_factory<MyApp>, MyApp);

Also, every class must inherit from Component and include the macro REGISTER_COMPONENT.

Registering for OpenFlow messages

The method install, as said, is used to install OpenFlow message handlers and it's slightly different from the NOX Classic. The example below illustrates how to register for a Packet_in event, which will be raised for every packet that goes to controller.

void install()
{
register_handler(Ofp_msg_event::get_name(OFPT_PACKET_IN), boost::bind(&MyApp::handler, this, _1));
}

The message handler should be implemented on the class and always return a Disposition, which can be CONTINUE, to proceed the event to the next listener, or STOP, ending the event processing.

Disposition handler(const Event& e)
{
return CONTINUE;
} 
Creating and sending a Flow message

The NOX API relies on the oflib, used to convert messages between an OpenFlow format, which is how the message bytes will travel over the network and a Host format, to ease message manipulation. While it's possible to directly use the oflib structs to create and send messages, the TLV based match approach of OpenFlow 1.3 makes the creation of messages including these fields a bit more trickier. So To ease the creation of messages including match fields we provide an extension to the NOX API.
Let's see it by an example.

Flow  f;
uint32_t in_port = 2;
uint32_t out_port = 1;
f.Add_Field("in_port", in_port);
Actions *acts = new Actions();
acts->CreateOutput(out_port);
Instruction *inst =  new Instruction();
inst->CreateApply(acts);
FlowMod *mod = new FlowMod(0x00ULL,0x00ULL, 0,OFPFC_ADD, 1, OFP_FLOW_PERMANENT, OFP_DEFAULT_PRIORITY,in->buffer_id, OFPP_ANY, OFPG_ANY, ofd_flow_mod_flags());
mod->AddMatch(&f.match);
mod->AddInstructions(inst); 

In the example above a flow_mod message is created with an in_port field to match every packet that comes by the port 2 and an action to send all matched packets to port 1.

Sending OpenFlow messages with NOX

To send the flow_mod message created above you should use the method send_openflow_msg. Any other OpenFlow message should be send using that.

send_openflow_msg(pi.dpid, (struct ofl_msg_header *)&mod->fm_msg, 0/*xid*/, true/*block*/);
App examples

For examples of NOX applications using our modified API, please take a look on the Hub and Switch in the nox13oflib repository.