Skip to content
cdburkard edited this page May 30, 2014 · 8 revisions

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.

Table of Contents

Create Topology

You'll need a slightly different topology, something like this: Note: For Mininet 2.0, the hosts have been renumbered h1-h3 and 10.1-10.3.

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

There's an example custom topology at:

 ~/mininet/custom/topo-2sw-2host.py

First, copy the example to a new file:

 $ cp ~/mininet/custom/topo-2sw-2host.py mytopo.py

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

 $ sudo mn --custom mytopo.py --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

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.

It may seem obvious, but we will warn you anyway: do not attempt to assign IP addresses to the interfaces belonging to switches s1 and s2. If you need to handle traffic "to" or "from" a switch, do so using OpenFlow.

We can do this directly from the custom topology that you created with mininet. Edit your "mytopo.py" to include the information above.

Helpful Code:

host1 = self.addHost( 'h1', ip="10.0.1.100/24", defaultRoute = "via 10.0.1.1" )

ARP

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 construct ARP replies and forward them out the appropriate ports.

Structures you will need:

     * arp cache
     * routing table (create a structure with all of the information statically assigned)
     * ip to port dictionary
     * message queue (while the router waits for an ARP reply)

Sample Routing Table:

(ip with network prefix, ip of host, interface name, interface address, switch port)

  ['10.0.1.100/24', '10.0.1.100', 's1-eth1', '10.0.1.1', 1],
  ['10.0.2.100/24', '10.0.2.100', 's1-eth2', '10.0.2.1', 3],
  ['10.0.3.100/24', '10.0.3.100', 's1-eth3', '10.0.3.1', 2]

NOTE: the port number does not correspond to the switch name. This is not a typo but a known mininet bug.

You will need to send a MAC address back to the host that is arping for you. It does not matter what this address is, so feel free to make up your own!

Helpful information about packet structure: NOTE: The following information is specific to the POX Controller

packet = event.parsed packet contains the ethernet packet

protocol = packet.payload strips the ethernet header and contains the ipv4 or arp packet

packet.payload.payload strips the protocol header and contains the underlying packet(ICMP?)

packet.payload.payload.payload strips the ICMP header and contains the echo or unreach packet, assuming this is an ICMP packet

...etc

ARP structure contains:

     - hwdst (hardware address of destination - what we are asking for)
     - hwsrc (hardware address of source)
     - protodst (IP address of destination)
     - protosrc (IP address of source)
     - opcode (type of arp package[REQUEST, REPLY, REV_REQUEST, REV_REPLY])

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.

We need to handle all ipv4 traffic that comes through the router by forwarding it to the correct subnet. The only change in the packet should be the source and destination MAC addresses.

If the router does not know the MAC address of the destination, it will have to arp for that host.

ICMP

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

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

NOTE: the controller only accepts 128 byte packet_ins by default. If your messages are getting truncated, this could be why. As a workaround, add another component at the end of your call too the controller. it should look like this:

$ ./pox.py log.level --DEBUG (your controller) misc.full_payload

Testing your router

If the router works properly:

  • attempts to send from 10.0.1.2 to an unknown address range like 10.99.0.1 should yield an ICMP destination unreachable message.
  • 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.
Now run iperf to test tcp and udp traffic. In mininet, open up xterm in host 1 and host 3 with

mininet>xterm h1 h3

host 3 will be the iperf server, so in it's own terminal run the command

$ iperf -s

host 1 will be the client, so in it's own terminal run the command

$ iperf -c (ip address of iperf server)

you may also test udp traffic by adding a -u option to the end of both commands

Note the results for this test. In your code's current state, the router sends all of the traffic to the controller via packet_ins, which makes a routing decision and sends a packet_out to the router. The next step is to install flow mods, which should yield better performance with iperf.

Flow Mods

Flow mods should be relatively easy to install. There are a few important structures to consider when creating the flow mod:

  • of.ofp_flow_mod() ==> the packet that will eventually be sent to the router to add a flow entry
  • of.ofp_match() ==> the structure containing the criteria for a packet to be matched on
  • of.ofp_action_output(port = [port]) ==> action to be performed on matching packets. This action specifies a port to output the packet to
  • of.ofp_action_dl_addr.set_src([hwsrc]) ==> action to change the ethernet packet's hardware source address
There are many other actions that may be performed on matching packets. See the open flow spec 1.0 for more information

Steps to install flow mod:
1) Create a match for the type of packet coming insteps
2) Create an ofp_flow_mod structure, and set the match attribute to your match
3) Specify the actions to be taken when receiving this type of packet
4) Append each action to the flow mod structure
5) Send the flow mod back to the router

Now that you have flow mods installed, run the iperf tests again and notice the performance difference

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

Next Step

Congratulations! By now you understand the basics of openflow, and probably have many ideas of things to implement in your own controller. The following exercises are just examples of further projects, but the possibilities are limitless. If you wish to continue with this tutorial, below are a few more exercises you may complete: