This tutorial is intended for beginners to SDN application development for the POX platform. Some Python knowledge will be useful, though it isn’t absolutely necessary.
- To get started, download and set up the SDN Hub Tutorial VM in Virtualbox or VMware Player.
- Run Mininet on a terminal window using the following command. This starts a network emulation environment to emulate 1 switch with 3 hosts. The switch tries to connect to port 6633 on localhost. Initially, there is no controller listening.
$ sudo mn --topo single,3 --mac --controller remote --switch ovsk
- Since POX does not support OpenFlow 1.3 yet, it is best to statically set the OpenFlow version of the OVS
$ sudo ovs-vsctl set bridge s1 protocols=OpenFlow10
- Next, start the POX Controller. Assuming that the main folder where POX is installed is /home/ubuntu/pox, the command below starts the controller by initiating the OpenFlow Protocol Handler and our tutorial_hub application.
$ cd /home/ubuntu/pox && ./pox.py log.level --DEBUG forwarding.tutorial_l2_hub
- The above command runs POX controller in DEBUG mode. This prints additional output of messages exchanged with the switch
POX 0.1.0 (betta) / Copyright 2011-2013 James McCauley, et al. DEBUG:core:POX 0.1.0 (betta) going up... DEBUG:core:Running on CPython (2.7.3/Sep 26 2013 16:35:25) DEBUG:core:Platform is Linux-3.5.0-30-generic-x86_64-with-Ubuntu-12.10-quantal INFO:core:POX 0.1.0 (betta) is up. DEBUG:openflow.of_01:Listening on 0.0.0.0:6633 INFO:openflow.of_01:[00-00-00-00-00-01 1] connected
- Next, check if the hosts in the mininet topology can reach each other
mininet> h1 ping h2 PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_req=1 ttl=64 time=49.1 ms 64 bytes from 10.0.0.2: icmp_req=2 ttl=64 time=46.3 ms 64 bytes from 10.0.0.2: icmp_req=3 ttl=64 time=29.1 ms 64 bytes from 10.0.0.2: icmp_req=4 ttl=64 time=42.9 ms 64 bytes from 10.0.0.2: icmp_req=5 ttl=64 time=26.2 ms
2. Understanding the code
The code for the hub application we used above is in /home/ubuntu/pox/pox/forwarding/tutorial_l2_hub.py. When the application is started, the launch() function is automatically invoked. This is the function where the application registers all event listeners, and creates objects of any application class. For instance, the tutorial_l2_hub has the following launch() function:
def launch (): def start_switch (event): L2Hub(event.connection) core.openflow.addListenerByName("ConnectionUp", start_switch)
The above function instantiates a new L2Hub object for every new switch that connects to it.
2A. Listening to events
There are two common ways for an application to register with the controller for events.
- Register callback functions for specific events thrown by either the OpenFlow handler module or specific modules like Topology Discovery
- From the launch or from the init of a class, perform core.openflow.addListenerByName(“EVENTNAME”, CALLBACK_FUNC, PRIORITY)
- Register object with the OpenFlow handler module or specific modules like Topology Discovery
- From typically the init of a class, perform addListeners(self). Once this is added, the controller will look for a function with the name _handle_EVENTNAME(self, event). This method is automatically registered as an event handler.
2B. Parsing packets
POX provides several primitives to parse well-known packets. The ethernet packet received through a packet_in event can be extracted using this command and then the match for the flow rules can be created using the from_packet function:
packet = event.parsed src_mac = packet.src dst_mac = packet.dst if packet.type == ethernet.IP_TYPE: ipv4_packet = event.parsed.find("ipv4") # Do more processing of the IPv4 packet src_ip = ipv4_packet.srcip src_ip = ipv4_packet.dstip
POX provides a simple way to construct the match headers from an incoming packet:
match = of.ofp_match.from_packet(packet)
2C. Sending messages to switch
Sending packet_out, flow_mod and other OpenFlow messages to program the switch is simple with POX. The steps are to construct the appropriate message object and populate it with the decision fields and the send to the switch using the connection object self.connection.send(). Here is an example from the hub implementation:
msg = of.ofp_packet_out() # Create packet out message msg.buffer_id = event.ofp.buffer_id # Use the incoming packet as the data for the packet out msg.in_port = packet_in.in_port # Set the in_port so that the switch knows msg.match = of.ofp_match.from_packet(packet) # Add an action to send to the specified port action = of.ofp_action_output(port = of.OFPP_FLOOD) msg.actions.append(action) # Send message to switch self.connection.send(msg)
2D. Managing multiple applications
POX supports spawning multiple applications simultaneously. The call back functions for the events received by the controller are processed in the priority specified in the addListenerByName()
3. More Theory
|Events generated from messages from switch||Packets parsed by pox/lib|
arp, dhcp, dns
Also see `grep class pox/pox/openflow/libopenflow_01.py` for a list of messages that the application can send to the switch.
4. More Example applications
- L2 MAC Learning Switch: Convert pox/pox/misc/of_tutorial.py to L2 switch using the hints provided
- Stateless load-balancer: pox/pox/forwarding/tutorial_stateless_lb.py implements a load-balancer where incoming HTTP requests are sent, on a round-robin basis, to a list of servers. In the code, we statically set the IP addresses of the servers. When traffic arrives for the virtual IP of the load-balancer, it selects the server in a round-robin basis and sends request to a different server after doing IP header rewriting in both directions. The mininet setup for this example is available here.