OpenFlow on RPi Li Lin, Regina Hain The goal of this work is to run an OpenFlow controller on a raspberry pi. To do so, we used Open vSwitch to configure the virtual switches on the pi server and Ryu to run the controller and to inject custom flows. There are three major pieces of this project: 1. Use OVS to setup a useful and interesting network 2. Run a custom script with the Ryu controller to install flows and route packets 3. Demoing the system with a streaming webcam application ==Part I: Using OVS to set up a useful and interesting network== =Topology= _______________________________________________________________________ |Pi Server | | ____________ _______________ _______________ | | | BR1 | | BR2 | | BR3 | | | | 10.10.1.1 | PP* | 10.10.2.1 | PP* | 10.10.3.1 | | | | 2|-------|2 3|-------|2 | | | |_____1______| |______1________| |______1________| | | _____|______ ______|________ ______|________ | | |eth1 | |eth2 | |eth3 | | | |10.10.1.x | |10.10.2.x | |10.10.3.x | | | |____________| |_______________| |_______________| | | | | | | | | | | | |________|_____________________|_______________________|________________| | | | _____|______ ______|________ ______|________ | Pi1 | | Pi2 | | Pi3 | | 10.10.1.2 | | 10.10.2.2 | | 10.10.3.2 | |____________| |_______________| |_______________| *: PP means patch port =Description= This setup consists of 4 pi's- one acting as a server 3 as the clients. There are 3 accompanying interfaces on the server- eth1, eth2, eth3, each their own subnet. Additionally, each is connected to a separate OVS bridge. The OVS bridges forward packets to all other bridges via patch ports. =Setup on server= To configure this network, run configure_pt1 =Setup on client= To configure the ip address of client pi's, add the following lines to /etc/dhcpcd.conf depending on its ip address and router values # In pi1 /etc/dhcpcd.conf interface eth0 static ip_address=10.10.1.2/24 static router=10.10.1.1 # In pi2 /etc/dhcpcd.conf interface eth0 static ip_address=10.10.2.2/24 static router=10.10.2.1 # In pi3 /etc/dhcpcd.conf interface eth0 static ip_address=10.10.3.2/24 static router=10.10.3.1 =Test= To test, run ping from one client Pi to another client Pi. Connectivity should be present, via the OVS bridge and patch port topology, between all three client Pi's. =Teardown= To teardown this network, run teardown_pt1 ==Part II: Using Ryu to install flows and route packets over our OVS network== =Topology= _______________________________________________________________________ |Pi Server | | ____________________________________________________________ | | | BR1 | | | | 10.10.1.10 | | | | | | | |_____1_____________________3_______________________2________| | | _____|______ ______|________ ______|________ | | |eth1 | |eth2 | |eth3 | | | |10.10.1.1 | |10.10.1.3 | |10.10.1.2 | | | |____________| |_______________| |_______________| | | | | | | | | | | | |________|_____________________|_______________________|________________| | | | _____|______ ______|________ ______|________ | Pi1 | | Pi2 | | Pi3 | | 10.10.1.4 | | 10.10.1.5 | | 10.10.1.6 | |____________| |_______________| |_______________| Note that this topology is different from that in part I. This is because having 3 bridges added too much unneeded complexity when crafting custom flows. This time we used 1 bridge to connect all three interfaces and connecting them up through separate ports. =RYU Script Description= This script creates a custom flow that matches on any packet coming in on port 1 (source 10.10.1.4) and out on port 3 (destination 10.10.1.5). It forwards that packet as usual, but also creates a duplicate packet, modifies its destination (to the address of pi3) and sends to port 2 (pi 3). The result is that pi3 gets a copy of every packet that is sent from pi1 to pi2. Note that to turn on the special flow, *insert_special_flow* must be set to True in ryu_13_custom.py To see that the custom flow is installed correctly (note that installation will occur only on the first instance of a packet with source 10.10.1.4 and destination 10.10.1.5 captured by our controller), on the server type $ sudo ovs-ofctl dump-flows br1 =Setup= To configure this network, run configure_pt2 Note that step 5, connecting the controller to the bridge, takes the ip address of the server's eth0 interface. This can change based on network and pi. To find the correct ip address to use, in a terminal type $ ifconfig -a =Run= To run the ryu controller with our custom script type: $ ryu-manager ./path/to/ryu_13_custom.py To ensure controller connectivity type: $ sudo ovs-vsctl show and you should see something like this (if connected): Bridge "br1" Controller "tcp:128.89.68.110:6633" is_connected: true =Testing= Ping test On 10.10.1.4 (pi1) type $ ping 10.10.1.5 You will see that 2 different hosts will reply to the pings- both pi2 (10.10.1.5) and pi3 (10.10.1.6). Netcat test On 10.10.1.5 (pi2) type $ nc -l 1234 On 10.10.1.6 (pi3) type $ nc -l 1234 On 10.10.1.4 (pi1) type $ echo "HELLO WORLD" | nc 10.10.1.5 1234 -u You should see that HELLO WORLD should be printed on both pi2 and pi3. This only works in udp mode (-u) and the reason is left as an exercise for the reader. =Teardown= To teardown this network, run teardown_pt2 ==Part III: Demoing via a streaming webcam application== In this demo, pi1 (10.10.1.4) will send raw video bytes captured from its webcam to pi2 (10.10.1.5) via the netcat application. Pi2 will capture the udp packets by using netcat to listen on a specified port and save the data to a pipe file. Pi2 will then run mplayer on the file to output the video to screen. Pi3 will perform the same exact functions as Pi2, and since the controller sends a duplicate copy of every udp packet to Pi3, it can receive and render the webcam video also. On Pi1: 1. Compile the C file used to read data from the webcam $ gcc capturevideo.c -o capturevideo 2. Execute and pipe the output to 10.10.1.5 via netcat $ ./capturevideo -c 1000 -o | nc 10.10.1.5 5000 *. Instructions and code taken from: https://www.raspberrypi.org/forums/viewtopic.php?t=98778&p=685576 On Pi2: 1. If not installed already, install mplayer $ sudo apt-get install mplayer 2. Create a pipe file $ mkfifo video.fifo 3. Call netcat and listen to specified port $ nc.traditional -lu -p 5000 > video.fifo 4. Use mplayer to open video $ mplayer video.fifo -demuxer rawvideo -rawvideo w=640:h=480:format=yuy2 On Pi3: 1. If not installed already, install mplayer $ sudo apt-get install mplayer 2. Create a pipe file $ mkfifo video.fifo 3. Call tcpdump to listen to specified port $ sudo tcpdump -i eth0 udp port 5000 -w video.fifo Note: Netcat will not accept packets because it requires a connection, even when solely listening for udp packets, when the datagram size is over 1500 bytes. 4. Use mplayer to open video $ mplayer video.fifo -demuxer rawvideo -rawvideo w=640:h=480:format=yuy2