''' [wiki:GENIExperimenter/Tutorials/OpenFlowOVS Intro to OpenFlow Tutorial (OVS)] ''' {{{ #!html
Image Map
}}} [[PageOutline]] == Step 4. Execute Experiment == Now that the switch is up and running we are ready to start working on the controller. For this tutorial we are going to use the [https://floodlight.atlassian.net/wiki/spaces/floodlightcontroller Floodlight Controller]. === 4a. Login to your hosts === To start our experiment we need to ssh into all of our hosts. Depending on which tool and OS you are using there is a slightly different process for logging in. If you don't know how to SSH to your reserved hosts learn [wiki:HowTo/LoginToNodes how to login.] Once you have logged in follow the rest of the instructions. === 4b. Use a Learning Switch Controller === In this example we are going to run a very simple learning switch controller to forward traffic between `host1` and `host2`. [[BR]] 1. First start a ping from `host1` to `host2` , which should timeout, since there is no controller running. {{{ ping 10.0.0.2 -c 10 }}} 2. Start the Floodlight Controller by running the following commands: {{{ cd /local/floodlight java -jar target/floodlight.jar }}} The output should look like this: [[Image(GENIExperimenter/Tutorials/OpenFlowOVS-Floodlight/Execute:Open vSwitch.png, 50%)]] 3. In the terminal window of `host1`, ping `host2` i.e. 10.0.0.2: {{{ [pjayant@host1:~$ ping 10.0.0.2 PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data. 64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=327 ms 64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=23.2 ms 64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=2.08 ms 64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=1.71 ms 64 bytes from 10.0.0.2: icmp_seq=5 ttl=64 time=1.77 ms 64 bytes from 10.0.0.2: icmp_seq=6 ttl=64 time=1.74 ms 64 bytes from 10.0.0.2: icmp_seq=7 ttl=64 time=1.69 ms 64 bytes from 10.0.0.2: icmp_seq=8 ttl=64 time=1.55 ms 64 bytes from 10.0.0.2: icmp_seq=9 ttl=64 time=1.60 ms 64 bytes from 10.0.0.2: icmp_seq=10 ttl=64 time=1.67 ms 64 bytes from 10.0.0.2: icmp_seq=11 ttl=64 time=1.73 ms 64 bytes from 10.0.0.2: icmp_seq=12 ttl=64 time=1.50 ms 64 bytes from 10.0.0.2: icmp_seq=13 ttl=64 time=1.82 ms 64 bytes from 10.0.0.2: icmp_seq=14 ttl=64 time=1.69 ms ^C --- 10.0.0.2 ping statistics --- 14 packets transmitted, 14 received, 0% packet loss, time 13019ms rtt min/avg/max/mdev = 1.501/26.489/327.007/83.532 ms }}} Now the ping should work. You can see that the time for the first ICMP packet is longer than the rest of the ICMP packets. This is because the Open vSwitch consults the controller the first time a packet-in event occurs. The controller then inserts the flow in the Open vSwitch and the switch consults this flow for further packet-in events. Similarly, ping `host3` i.e. 10.0.0.3 from `host1`. 4. Go to your Open vSwitch host and take a look at the flows. You should see that your controller installed flows based on the mac addresses of your packets. Enter the following command: {{{ pjayant@switch:~$ sudo ovs-ofctl dump-flows br0 NXST_FLOW reply (xid=0x4): cookie=0x20000005000000, duration=4.782s, table=0, n_packets=4, n_bytes=392, idle_timeout=5, idle_age=0, priority=1,ip,in_port=2,dl_src=02:55:0d:1e:32:8d,dl_dst=02:bd:52:92:0e:86,nw_src=10.0.0.2,nw_dst=10.0.0.1 actions=output:1 cookie=0x20000004000000, duration=4.790s, table=0, n_packets=4, n_bytes=392, idle_timeout=5, idle_age=0, priority=1,ip,in_port=1,dl_src=02:bd:52:92:0e:86,dl_dst=02:55:0d:1e:32:8d,nw_src=10.0.0.1,nw_dst=10.0.0.2 actions=output:2 cookie=0x0, duration=1275.644s, table=0, n_packets=6, n_bytes=512, idle_age=4, priority=0 actions=CONTROLLER:65535 }}} === 4c. Look around your OVS switch === 1. To see messages go between your switch and your controller, open a new ssh window to your controller node and run tcpdump on the `eth1` interface and on the tcp port that your controller is listening on usually 6653. (You can also run `tcpdump` on the `OVS` control interface if you desire.) {{{ sudo tcpdump -i eth0 tcp port 6653 }}} You will see (1) periodic keepalive messages being exchanged by the switch and the controller, (2) messages from the switch to the controller (e.g. when there is a table miss) and an ICMP Echo message in, and (3) messages from the controller to the switch (e.g. to install new flow entries). 3. Kill your Floodlight controller by pressing `Ctrl-C`: {{{ 2016-10-30 21:00:47.333 INFO [n.f.l.i.LinkDiscoveryManager] Sending LLDP packets out of all the enabled ports 2016-10-30 21:01:02.339 INFO [n.f.l.i.LinkDiscoveryManager] Sending LLDP packets out of all the enabled ports 2016-10-30 21:01:17.344 INFO [n.f.l.i.LinkDiscoveryManager] Sending LLDP packets out of all the enabled ports ^C pjayant@controller:~/floodlight$ }}} 4. Notice what happens to your ping on host1. 5. If you are using OVS, check the flow table entries on your switch: {{{ sudo ovs-ofctl dump-flows br0 }}} Since you set your switch to "secure" mode, i.e. don't forward packets if the controller fails, you will not see flow table entries. If you see flow table entries, try again after 10 seconds to give the entries time to expire. ==== Soft vs Hard Timeouts ==== All rules on the switch have two different timeouts: * '''Soft Timeout''': This determines for how long the flow will remain in the forwarding table of the switch if there are no packets received that match the specific flow. As long as packets from that flow are received the flow remains on the flow table. * '''Hard Timeout''': This determines the total time that a flow will remain at the forwarding table, independent of whether packets that match the flow are received; i.e. the flow will be removed after the hard timeout expires. Can you tell now why there were packets flowing even after you killed your controller? === 4d. Debugging your Controller === While you are developing your controller, some useful debugging tools are: ==== i. Print messages ==== Run your controller in verbose mode (add --verbose) and add print messages at various places to see what your controller is seeing. ==== ii. Check the status in the switch ==== If you are using an OVS switch, you can dump information from your switch. For example, to dump the flows: {{{ sudo ovs-ofctl dump-flows br0 }}} Two other useful commands show you the status of your switch: {{{ sudo ovs-vsctl show sudo ovs-ofctl show br0 }}} ==== iii. Use Wireshark to see the OpenFlow messages ==== Many times it is useful to see the OpenFlow messages being exchanged between your controller and the switch. This will tell you whether the messages that are created by your controller are correct and will allow you to see the details of any errors you might be seeing from the switch. You can use Wireshark on both ends of the connection; in hardware switches you have to rely only on the controller view. The controller host and OVS has the Wireshark application already installed, including the openflow dissector. For more information on Wireshark you can take a look at the [http://wiki.wireshark.org/ Wireshark wiki]. [[Image(GENIExperimenter/Tutorials/Graphics:4NotesIcon_512x512.png, 5%, nolink)]] To display the Wireshark window on your local host you must ''' ''setup X11 forwarding'' ''', many sites are available that explain how this is done. This is [http://www.seas.upenn.edu/cets/answers/x11-forwarding.html an example] that provides instructions for Windows, Linux and MAC operating systems. Here is how to use the OpenFlow dissector for Wireshark on the reserved controller host. If you are on a Linux friendly machine (this includes MACs) open a terminal and ssh to your controller machine using the -Y command line argument, i.e. {{{ ssh -Y @ }}} Assuming that the public IP address on the controller is on eth0, run Wireshark by typing: {{{ sudo wireshark -i eth0& }}} When the Wireshark window pops up, you might still have to choose eth0 for a live capture. And you will want to use a filter to cut down on the chatter in the Wireshark window. One such filter might be to see what shows up on port 6653. To do that type ''' ''tcp.port eq 6653'' ''' in the filter window, assuming that 6653 is the port that the controller is listening on. Once messages are captured, you can choose one, right click to "Decode as ...." and then choose ''OFP protocol'' to see its content. === 4e. Web GUI === The Floodlight Controller comes equipped with a [https://floodlight.atlassian.net/wiki/display/floodlightcontroller/Web+GUI web-based GUI]. The GUI can be accessed by pointing your favorite browser to the following URL: {{{ http://:8080/ui/pages/index.html }}} is the IP address of the control interface of the Controller node(eth0). === 4f. Topology Details === Before we insert flows into the Open vSwitch, we are going to need all the details regarding the topology such as the DPID of the Open vSwitch, MAC addresses of the hosts, the port numbers on which the Hosts are connected to the Open vSwitch etc. These details can be found out by issuing the following command in a new Controller terminal: {{{ curl http://localhost:8080/wm/device/ | python -m json.tool }}} In the output, we obtain a list of the OpenFlow device (i.e OVS) that Floodlight Controller has learned about. Next, ''ping'' Host2 & Host3 from Host1 and then re-run the command. Note that you output details will differ. [[Image(GENIExperimenter/Tutorials/OpenFlowOVS-Floodlight/Execute:Topology_Details.png, 50%)]] [[Image(GENIExperimenter/Tutorials/Graphics:4NotesIcon_512x512.png, 5%, nolink)]] Highlighted are all the important details you need to note down before you start manipulating flows. Note down all the highlighted details for each '''Host'''. The Host IP's will be of the form 10.0.0.* for Host *. === 4f. Run a traffic duplication controller === In the above example we ran a very simple learning switch controller. [[BR]] [[Image(GENIExperimenter/Tutorials/Graphics:4NotesIcon_512x512.png, 5%, nolink)]] The power of !OpenFlow comes from the fact that you can decide to forward the packet any way you want based on the supported !OpenFlow actions. A very simple but powerful modification you can do, is to duplicate all the traffic of the switch out a specific port. This is very useful for application and network analysis. You can imagine that at the port where you duplicate traffic you connect a device that does analysis. For this tutorial we are going to verify the duplication by doing `tcpdump` on two ports on the OVS switch. 1. ''' Insert the flow to Duplicate Traffic ''' We are going to duplicate IPv4 traffic from Host1 destined to Host2 on Host3. Open a new ''Controller'' terminal and type the following flow: {{{ #!div style="background: #ffd; border: 3px ridge; width: 800px;" {{{ #!sh curl -X POST -d '{"switch":"","name":"flow-1","priority":"32768","in_port":"","active":"true", "eth_type":"0x0800", "eth_src":"", "eth_dst":"", "ipv4_src":"10.0.0.1", "ipv4_dst":"10.0.0.2", "actions":"set_field=eth_dst->,set_field=ipv4_dst->10.0.0.2,output=,set_field=eth_dst->,output="}' http://localhost:8080/wm/staticflowpusher/json }}} }}} [[BR]] [[Image(GENIExperimenter/Tutorials/Graphics:4NotesIcon_512x512.png, 5%, nolink)]] Scroll all the way to the right to view the complete flow and get rid of the <> brackets when inserting the flow. To see that duplication is happening, on Host2 and Host3 , run: {{{ sudo tcpdump -i eth1 }}} You should see traffic from host1 to host2 showing up in the tcpdump window for host3 as shown below: {{{ pjayant@host3:~$ sudo tcpdump -i eth1 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes 02:48:38.270572 IP Host1-link-1 > Host2-link-2: ICMP echo request, id 8877, seq 1, length 64 02:48:38.270639 IP Host3-link-3 > Host1-link-1: ICMP redirect Host2-link-2 to host Host2-link-2, length 92 02:48:38.270654 IP Host1-link-1 > Host2-link-2: ICMP echo request, id 8877, seq 1, length 64 02:48:39.271350 IP Host1-link-1 > Host2-link-2: ICMP echo request, id 8877, seq 2, length 64 02:48:39.271390 IP Host3-link-3 > Host1-link-1: ICMP redirect Host2-link-2 to host Host2-link-2, length 92 02:48:39.271403 IP Host1-link-1 > Host2-link-2: ICMP echo request, id 8877, seq 2, length 64 02:48:40.272525 IP Host1-link-1 > Host2-link-2: ICMP echo request, id 8877, seq 3, length 64 02:48:40.272570 IP Host3-link-3 > Host1-link-1: ICMP redirect Host2-link-2 to host Host2-link-2, length 92 02:48:40.272582 IP Host1-link-1 > Host2-link-2: ICMP echo request, id 8877, seq 3, length 64 }}} === 4g. Run a Port Forwarding Controller === Now let's do a slightly more complicated controller. OpenFlow gives you the power to overwrite fields of your packets at the switch, for example the TCP source or destination port and do port forwarding. You can have clients trying to contact a server at port 5000, and the OpenFlow switch can redirect your traffic to a service listening on port 6000. 1. To test your controller we are going to use netcat. Open two terminals window on host2. In one terminal run: {{{ nc -l 5000 }}} and in the other terminal run {{{ nc -l 6000 }}} 2. We will check the normal functionality before the flow for a Port Forwarding Controller is inserted. Go to the terminal of host1 and connect to host2 at port 5000: {{{ nc 10.0.0.2 5000 }}} 3. Type something and you should see it in the terminal on host2 at port 5000. 4. Now, we insert the flow for a Port Forwarding Controller: {{{ #!div style="background: #ffd; border: 3px ridge; width: 800px;" {{{ #!sh curl -X POST -d '{"switch":"","name":"flow-2","priority":"32768","in_port":"","active":"true", "eth_type":"0x0800", "ip_proto":"0x06", "eth_src":"", "eth_dst":"", "tcp_dst":"5000", "ipv4_src":"10.0.0.1", "ipv4_dst":"10.0.0.2", "actions":"set_field=tcp_dst->6000,output="}' http://localhost:8080/wm/staticflowpusher/json }}} }}} 5. In the previous step, we inserted a flow to forward TCP traffic from Host1 destined to Host2 at port 5000 to port 6000. But Host1 still thinks it is speaking to Host2 at port 5000. So we need to insert a flow to handle traffic from Host2 Port 6000 for a seamless transition. {{{ #!div style="background: #ffd; border: 3px ridge; width: 800px;" {{{ #!sh curl -X POST -d '{"switch":"","name":"flow-3","priority":"32768","in_port":"","active":"true", "eth_type":"0x0800", "ip_proto":"0x06", "eth_src":"", "eth_dst":"", "tcp_src":"6000", "ipv4_src":"10.0.0.2", "ipv4_dst":"10.0.0.1", "actions":"set_field=tcp_src->5000,output="}' http://localhost:8080/wm/staticflowpusher/json }}} }}} 6. Repeat the netcat scenario described above in step 1 and 2. Now, your text should appear in the other terminal window on host2 that is listening to port 6000. === 4h. Run a Server Proxy Controller === As our last exercise, instead of diverting the traffic to a different server running on the same host, we will divert the traffic to a server running on a different host and on a different port. 1. On the terminal window of `host3` run a netcat server: {{{ nc -l 6000 }}} 2. On the controller host, we will insert a flow to implement a controller that will divert traffic destined for `host2` to `host3`. Before you start implementing think about what are the side effects of diverting traffic to a different host. * Is it enough to just change the IP address? * Is it enough to just modify the TCP packets? 3. Insert the following flow in the Controller terminal to implement a Server Proxy Controller: {{{ #!div style="background: #ffd; border: 3px ridge; width: 800px;" {{{ #!sh curl -X POST -d '{"switch":"","name":"flow-4","priority":"32768","in_port":"","active":"true", "eth_type":"0x0800", "ip_proto":"0x06", "eth_src":"", "eth_dst":"", "tcp_dst":"5000", "ipv4_src":"10.0.0.1", "ipv4_dst":"10.0.0.2", "actions":"set_field=eth_dst->,set_field=tcp_dst->6000,set_field=ipv4_dst->10.0.0.3,output="}' http://localhost:8080/wm/staticflowpusher/json }}} }}} 4. In the previous step, we inserted a flow to forward TCP traffic from Host1 destined to Host2 at port 5000 to Host 3 at port 6000. But Host1 still thinks it is speaking to Host2 at port 5000. So we need to insert a flow to handle traffic from Host3 Port 6000 for a seamless transition. {{{ #!div style="background: #ffd; border: 3px ridge; width: 800px;" {{{ #!sh curl -X POST -d '{"switch":"","name":"flow-5","priority":"32768","in_port":"","active":"true", "eth_type":"0x0800", "ip_proto":"0x06", "eth_src":"", "eth_dst":"", "tcp_src":"6000", "ipv4_src":"10.0.0.3", "ipv4_dst":"10.0.0.1", "actions":"set_field=eth_src->,set_field=ipv4_src->10.0.0.2,set_field=tcp_src->5000,output="}' http://localhost:8080/wm/staticflowpusher/json }}} }}} 5. Go back to the terminal of `host1` and try to connect netcat to `host2` port 5000 {{{ nc 10.0.0..2 5000 }}} 6. If your controller works correctly, you should see your text appearing on the terminal window of `host3`. === 4i. Delete your bridge === Before moving to the next step make sure you delete the bridge you have created, especially if you are using the same reservation for a different exercise: {{{ sudo ovs-vsctl del-br br0 }}} {{{ #!comment == 4. Moving to a Hardware Switch == To try your controller with a GENI Hardware !OpenFlow switch: * Delete the sliver with your experiment topology. '''Do not''' delete your controller. * Follow the instructions at [wiki:GENIExperimenter/Tutorials/OpenFlowOVS/HW/DesignSetup OpenFlow Design and Setup for Hardware Switch] If you do not want to do the Hardware !OpenFlow portion of the tutorial, proceed to [wiki:GENIExperimenter/Tutorials/OpenFlowOVS/Finish Finish] }}} ---- ''' [wiki:GENIExperimenter/Tutorials/OpenFlowOVS-Floodlight/DesignSetup Prev: Design and Setup for OVS] ''' {{{ #!comment ''' [wiki:GENIExperimenter/Tutorials/OpenFlowOVS/NATExecute Next: Make your switch to act as a NAT server] ''' ''' [wiki:GENIExperimenter/Tutorials/OpenFlowOVS/FirewallExecute Next: Make your switch to act as a Firewall] ''' }}} ''' [wiki:GENIExperimenter/Tutorials/OpenFlowOVS-Floodlight/Finish Next: Finish] '''