Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
92 views

Programming Assignment 3: Programming A Simple Controller: Instructions

In this exercise, you will learn about an open-source OpenFlow controller “POX”. You will learn how to write network applications, i.e., Hub and Layer 2 MAC Learning etc., on POX and run them on a virtual network based on Mininet.

Uploaded by

Zaskel
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
92 views

Programming Assignment 3: Programming A Simple Controller: Instructions

In this exercise, you will learn about an open-source OpenFlow controller “POX”. You will learn how to write network applications, i.e., Hub and Layer 2 MAC Learning etc., on POX and run them on a virtual network based on Mininet.

Uploaded by

Zaskel
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

Programming Assignment 3: Programming a Simple

Controller: Instructions
In this exercise, you will learn about an open-source OpenFlow controller “POX”. You will learn
how to write network applications, i.e., Hub and Layer 2 MAC Learning etc., on POX and run
them on a virtual network based on Mininet.
After the exercise, you will be asked to create and submit a network application that implements
Layer 2 Firewall that disables inbound and outbound traffic between two systems based on their
MAC address. More details on creating and submitting the code will be provided later on in the
instructions. So, make sure that you follow each step carefully.
(Note: you can skip this section and start directly with the assignment at the end, if you feel
confident and are already familiar with POX and its basic functions)

Overview
The network you'll use in this exercise includes 3 hosts and a switch with an OpenFlow
controller (POX):

Figure 1: Topology for the Network under Test


POX is a Python based SDN controller platform geared towards research and education. For
more details on POX, see About POX or POX Documentation on NOXRepo.org.
We’re not going to be using the reference controller anymore, which is the default controller that
Mininet uses during it simulation. Make sure that it’s not running in the background:
$ ps -A | grep controller
If so, you should kill it either press Ctrl-C in the window running the controller program, or from
the other SSH window:
$ sudo killall controller
You should also run sudo mn -c and restart Mininet to make sure that everything is clean and
using the faster kernel switch: From you Mininet console:
mininet> exit
$ sudo mn -c
$ sudo mn --topo single,3 --mac --switch ovsk --controller remote
The POX controller comes pre-installed with the provided VM image.
Now, run the basic hub example:
$ pox.py log.level --DEBUG forwarding.hub
This tells POX to enable verbose logging and to start the hub component.
The switches may take a little bit of time to connect. When an OpenFlow switch loses its
connection to a controller, it will generally increase the period between which it 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. Alternately, you exit Mininet to remove the switch(es), start the controller, and then
start Mininet to immediately connect.
Wait until the application indicates that the OpenFlow switch has connected. When the switch
connects, POX will print something like this:
INFO:openflow.of_01:[Con 1/1] Connected to 00-00-00-00-00-01
DEBUG:samples.of_tutorial:Controlling [Con 1/1]

Verify Hub behavior with tcpdump


Now 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 h1 h2 h3
Arrange each xterm so that they're all on the screen at once. This may require reducing the
height to fit a cramped laptop screen.
In the xterms for h2 and h3, run tcpdump, a utility to print the packets seen by a host:

# tcpdump -XX -n -i h2-eth0


and respectively:
# tcpdump -XX -n -i h3-eth0
In the xterm for h1, send a ping:
# ping -c 1 10.0.0.2
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. This is how a hub works; it sends all packets to every port
on the network.
Now, see what happens when a non-existent host doesn't reply. From h1 xterm:
# ping -c 1 10.0.0.5
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.
Now, lets look at the hub code:
from pox.core import core
import pox.openflow.libopenflow_01 as of
from pox.lib.util import dpidToStr
log = core.getLogger()
def _handle_ConnectionUp (event):
msg = of.ofp_flow_mod()
msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
event.connection.send(msg)
log.info("Hubifying %s", dpidToStr(event.dpid))
def launch ():
core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp)
log.info("Hub running.")

Table 1. Hub Controller


Useful POX API’s

 connection.send( ... ) function sends an


OpenFlow message to a switch.

When a connection to a switch starts, a ConnectionUp event is fired. The above code invokes
a _handle_ConnectionUp () function that implements the hub logic.

 ofp_action_output class

This is an action for use with ofp_packet_out and ofp_flow_mod. It specifies a switch port
that you wish to send the packet out of. It can also take various "special" port numbers. An
example of this, as shown in Table 1, would be OFPP_FLOOD which sends the packet out all
ports except the one the packet originally arrived on.
Example. Create an output action that would send packets to all ports:
out_action = of.ofp_action_output(port = of.OFPP_FLOOD)
 ofp_match class (not used in the code above but might be
useful in the assignment)

Objects of this class describe packet header fields and an input port to match on. All fields are
optional -- items that are not specified are "wildcards" and will match on anything.
Some notable fields of ofp_match objects are:

dl_src - The data link layer (MAC) source


address
 dl_dst - The data link layer (MAC) destination address
 in_port - The packet input switch port

Example. Create a match that matches packets arriving on port 3:


match = of.ofp_match()
match.in_port = 3

 ofp_packet_out OpenFlow message (not used in


the code above but might be useful in the assignment)

The ofp_packet_out message instructs a switch to send a packet. The packet might be one
constructed at the controller, or it might be one that the switch received, buffered, and forwarded
to the controller (and is now referenced by a buffer_id).
Notable fields are:

 buffer_id - The buffer_id of a buffer you


wish to send. Do not set if you are sending a
constructed packet.
 data - Raw bytes you wish the switch to
send. Do not set if you are sending a
buffered packet.
 actions - A list of actions to apply (for this
tutorial, this is just a single
ofp_action_output action).
 in_port - The port number this packet
initially arrived on if you are sending by
buffer_id, otherwise OFPP_NONE.

Example. send_packet() method:


def send_packet (self, buffer_id, raw_data, out_port, in_port):
"""
Sends a packet out of the specified switch port.
If buffer_id is a valid buffer on the switch, use that. Otherwise,
send the raw data in raw_data.
The "in_port" is the port number that packet arrived on. Use
OFPP_NONE if you're generating this packet.
"""
msg = of.ofp_packet_out()
msg.in_port = in_port
if buffer_id != -1 and buffer_id is not None:
# We got a buffer ID from the switch; use that
msg.buffer_id = buffer_id
else:
# No buffer ID from switch -- we got the raw data
if raw_data is None:
# No raw_data specified -- nothing to send!
return
msg.data = raw_data

action = of.ofp_action_output(port = out_port)


msg.actions.append(action)

# Send message to switch


self.connection.send(msg)

Table 2: Send Packet

 ofp_flow_mod OpenFlow message

This instructs a switch to install a flow table entry. Flow table entries match some fields of
incoming packets, and executes some list of actions on matching packets. The actions are the
same as for ofp_packet_out, mentioned above (and, again, for the tutorial all you need is the
simple ofp_action_output action). The match is described by an ofp_match object.
Notable fields are:

 idle_timeout - Number of idle seconds


before the flow entry is removed. Defaults to
no idle timeout.
 hard_timeout - Number of seconds before
the flow entry is removed. Defaults to no
timeout.
 actions - A list of actions to perform on
matching packets (e.g.,
ofp_action_output)
 priority - When using non-exact
(wildcarded) matches, this specifies the
priority for overlapping matches. Higher
values are higher priority. Not important for
exact or non-overlapping entries.
 buffer_id - The buffer_id of a buffer to
apply the actions to immediately. Leave
unspecified for none.
 in_port - If using a buffer_id, this is the
associated input port.
 match - An ofp_match object. By default,
this matches everything, so you should
probably set some of its fields!

Example. Create a flow_mod that sends packets from port 3 out of port 4.
fm = of.ofp_flow_mod()
fm.match.in_port = 3
fm.actions.append(of.ofp_action_output(port = 4))

Verify Switch behavior with tcpdump


This time, let’s verify that hosts can ping each other when the controller is behaving like a Layer
2 learning switch. Kill the POX controller by pressing Ctrl-C in the window running the controller
program and run the l2_learning example:
$ pox.py log.level --DEBUG forwarding.l2_learning

Like before, we'll create xterms for each host and view the traffic in each.
In the Mininet console, start up three xterms:
mininet> xterm h1 h2 h3
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 h2 and h3, run tcpdump, a utility to print the packets seen by a host:

# tcpdump -XX -n -i h2-eth0


and respectively:
# tcpdump -XX -n -i h3-eth0
In the xterm for h1, send a ping:
# ping -c 1 10.0.0.2
Here, the switch examines 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.
You can close the xterms now.
The code for l2_learning application is provided under ~/pox/pox/forwarding and is explained
with greater detail in the Module 3.3 lecture on SDN Controller.

Assignment
Background
A Firewall is a network security system that is used to control the flow of ingress and egress
traffic usually between a more secure local-area network (LAN) and a less secure wide-area
network (WAN). The system analyses data packets for parameters like L2/L3 headers (i.e.,
MAC and IP address) or performs deep packet inspection (DPI) for higher layer parameters (like
application type and services etc) to filter network traffic. A firewall acts as a barricade between
a trusted, secure internal network and another network (e.g. the Internet) which is supposed to
be not very secure or trusted.
In this assignment, your task is to implement a layer 2 firewall that runs alongside the MAC
learning module on the POX OpenFlow controller. The firewall application is provided with a list
of MAC address pairs i.e., access control list (ACLs). When a connection establishes between
the controller and the switch, the application installs flow rule entries in the OpenFlow table to
disable all communication between each MAC pair.
Network Topology
Your firewall should be agnostic of the underlying topology. It should take MAC pair list as input
and install it on the switches in the network. To make things simple, we will implement a less
intelligent approach and will install rules on all the switches in the network.
Handling Conflicts
POX allows running multiple applications concurrently i.e., MAC learning can be done in
conjunction with firewall, but it doesn’t automatically handles rule conflicts. You have to make
sure, yourself, that conflicting rules are not being installed by the two applications e.g., both
applications trying to install a rule with same src/dst MAC at the same priority level but with
different actions. The most simplistic way to avoid this contention is to assign priority level to
each application.
Understanding the Code
To start this exercise, download Programming-Assignment3.zip. It consists of three files:
 firewall.py: a sekleton class which you will
update with the logic for installing firewall rules.
 firewall-policies.csv: a list of MAC pairs
(i.e., policies) read as input by the firewall
application.
 submit.py: used to submit your code and output
to the course servers for grading.

You don’t have to do any modifications in firewall-policies.csv and submit.py.


The firewall.py is populated with a skeleton code. It consists of a firewall class that has
a _handle_ConnectionUp function. It also has a global variable, policyFile, that holds the
path of the firewall-policies.csv file. Whenever a connection is established between the
POX controller and the OpenFlow switch the _handle_ConnectionUp functions gets
executed.
Your task is to read the policy file and update the _handle_ConnectionUp function. The
function should install rules in the OpenFlow switch that drop packets whenever a matching
src/dst MAC address (for any of the listed MAC pairs) enters the switch. (Note: make sure that
you handle the conflicts carefully. Follow the technique described in the section above)
Testing your Code
Once you have your code, copy the firewall.py in the ~/pox/pox/misc directory on your
VM. Also in the same directory create the following file:
$ cd ~/pox/pox/misc
$ touch firewall-policies.csv
and copy the following lines in it:
id,mac_0,mac_1
1,00:00:00:00:00:01,00:00:00:00:00:02
This will cause the firewall application to install a flow rule entry to disable all communication
between host (h1) and host (h2).
Run POX controller:
$ cd ~
$ pox.py forwarding.l2_learning misc.firewall &
This will run the controller with both MAC learning and firewall application.
Now run mininet:
$ sudo mn --topo single,3 --controller remote --mac
In mininet try to ping host (h2) from host (h1):
mininet> h1 ping -c 1 h2
What do you see? If everything has be done and setup correctly then host (h1) should not be
able to ping host (h2).
Now try pinging host (h3) from host (h1):
mininet> h1 ping -c 1 h3
What do you see? Host (h1) is able to ping host (h3) as there is no flow rule entry installed in
the network to disable the communication between them.

Submitting your Code


This time copy the firewall.py and the provided firewall-policy.csv in the
~/pox/pox/misc directory on your VM.
Also copy the submit.py script in the HOME (~/) directory.
To submit your code, run the submit.py script:
$ sudo python submit.py
Your mininet VM should have internet access by default, but still verify that it has internet
connectivity (i.e., eth0 set up as NAT). Otherwise submit.py will not be able to post your code
and output to our course servers.
The submission script will ask for your login and password. This password is not the general
account password, but an assignment-specific password that is uniquely generated for each
student. You can get this from the assignments listing page.
Once finished, it will prompt the results on the terminal (either passed or failed).
Note, if during the execution submit.py script crashes for some reason or you terminate it
using CTRL+C, make sure to clean mininet environment using:
$ sudo mn -c
Also, if it still complains about the controller running. Execute the following command to kill it:
$ sudo fuser -k 6633/tcp

* Part of these instructions are adapted from mininet.org and noxrepo.org.

You might also like