-
Notifications
You must be signed in to change notification settings - Fork 192
OpenFlow 1.3 Tutorial
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.
In order to be able to go through this tutorial you will need the following development tools for OpenFlow.
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.
In this part we show how to setup the tools required for this tutorial. For more details please check their documentation.
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
Install all NOX dependencies
Build
$./boot.sh
$ mkdir build
$ cd build
$ ../configure
$ make
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
Download and Install
cd $HOME/
git clone git://github.com/mininet/mininet
mininet/util/install.sh -n
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.
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:
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
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
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
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.
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.
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;
}
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.
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*/);
For examples of NOX applications using our modified API, please take a look on the Hub and Switch in the nox13oflib repository.
You can find more information about Dpctl and NOX usage on the following pages: