Skip to content

OpenFlow 1.3 Tutorial

Eder Leão Fernandes edited this page Jan 7, 2019 · 18 revisions

Welcome to the OpenFlow-1.3 Tutorial!

This tutorial is inspired by the old OpenFlow 1.0 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.

The shortest path...

Mininet now has options to install the OpenFlow 1.3 software switch and NOX.

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

The commands above will install Mininet,the software switch, NOX and Wireshark in only one shot! You still need to install the OpenFlow 1.3 plugin for wireshark.

$ sudo apt-get install scons
$ git clone https://github.com/CPqD/ofdissector    
$ cd src
$ export WIRESHARK=/usr/include/wireshark
$ scons install

And that's it! But, if you prefer to install all of them separately, follow the steps below.

The (not so) long road

In this part we show how to setup the tools required for this tutorial. 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

Clone and install Netbee.

$ git clone https://github.com/netgroup-polito/netbee.git
$ 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

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.

Further documentation and use cases are available in the links below:

Examples

Show all flows present in table 0.

$ sudo dpctl  unix:/tmp/s1 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:/tmp/s1 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:/tmp/s1 flow-mod table=0,cmd=add in_port=1,eth_type=0x800 apply:set_field=ip_src:192.168.0.1

Create a group.

$ sudo dpctl  unix:/tmp/s1 group-mod cmd=add,group=1,type=all

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

$ sudo dpctl unix:/tmp/s1 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:/tmp/s1 meter-mod cmd=add,flags=1,meter=1 drop:rate=10000

Create a flow that points to a meter instruction

$ sudo dpctl unix:/tmp/s1 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:/tmp/s1 flow-mod table=0,cmd=add in_port=1 apply:output=2
$ sudo dpctl  unix:/tmp/s1 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

It is strongly recommended to use a controller under constant development, such as Ryu or ONOS. I will keep this section just for past reference

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.

Useful pages

You can find more information about Dpctl and NOX usage on the following pages: