| 1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
|---|
| 2 | <html xmlns="http://www.w3.org/1999/xhtml"> |
|---|
| 3 | <head> |
|---|
| 4 | <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
|---|
| 5 | <meta http-equiv="Content-Style-Type" content="text/css" /> |
|---|
| 6 | <meta name="generator" content="pandoc" /> |
|---|
| 7 | <title>SDN / OpenFlow tutorial</title> |
|---|
| 8 | <style type="text/css">code{white-space: pre;}</style> |
|---|
| 9 | <link rel="stylesheet" href="./style.css" type="text/css" /> |
|---|
| 10 | </head> |
|---|
| 11 | <body> |
|---|
| 12 | <div id="header"> |
|---|
| 13 | <h1 class="title">SDN / OpenFlow tutorial</h1> |
|---|
| 14 | <h3 class="date">First SDN Application</h3> |
|---|
| 15 | </div> |
|---|
| 16 | <h1 id="introduction">Introduction</h1> |
|---|
| 17 | <p>In this lab we will connect write our first SDN application and run it on the controller.</p> |
|---|
| 18 | <h1 id="goals">Goals</h1> |
|---|
| 19 | <ul> |
|---|
| 20 | <li>Write an SDN application using the Ryu framework</li> |
|---|
| 21 | <li>Start the application on the controller.</li> |
|---|
| 22 | </ul> |
|---|
| 23 | <h1 id="notes">Notes</h1> |
|---|
| 24 | <ul> |
|---|
| 25 | <li>Commands preceded with "$" imply that you should execute the command as a general user - not as root.</li> |
|---|
| 26 | <li>Commands preceded with "#" imply that you should be working as root.</li> |
|---|
| 27 | <li>Commands with more specific command lines (e.g. "RTR-GW>" or "mysql>") imply that you are executing commands on remote equipment, or within another program.</li> |
|---|
| 28 | </ul> |
|---|
| 29 | <h1 id="installation">Installation</h1> |
|---|
| 30 | <h2 id="a-very-simple-switch.">A very simple switch.</h2> |
|---|
| 31 | <p>Open up a terminal on the controller and create the following file</p> |
|---|
| 32 | <pre><code>$ vi ~/l2.py</code></pre> |
|---|
| 33 | <p>It should contain the following</p> |
|---|
| 34 | <pre><code>from ryu.base import app_manager |
|---|
| 35 | from ryu.controller import mac_to_port |
|---|
| 36 | from ryu.controller import ofp_event |
|---|
| 37 | from ryu.controller.handler import MAIN_DISPATCHER |
|---|
| 38 | from ryu.controller.handler import set_ev_cls |
|---|
| 39 | from ryu.ofproto import ofproto_v1_3 |
|---|
| 40 | from ryu.lib.mac import haddr_to_bin |
|---|
| 41 | from ryu.lib.packet import packet |
|---|
| 42 | from ryu.lib.packet import ethernet |
|---|
| 43 | |
|---|
| 44 | class L2Switch(app_manager.RyuApp): |
|---|
| 45 | def __init__(self, *args, **kwargs): |
|---|
| 46 | super(L2Switch, self).__init__(*args, **kwargs) |
|---|
| 47 | |
|---|
| 48 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) |
|---|
| 49 | def packet_in_handler(self, ev): |
|---|
| 50 | msg = ev.msg |
|---|
| 51 | dp = msg.datapath |
|---|
| 52 | ofp = dp.ofproto |
|---|
| 53 | ofp_parser = dp.ofproto_parser |
|---|
| 54 | in_port = msg.match['in_port'] |
|---|
| 55 | |
|---|
| 56 | actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)] |
|---|
| 57 | out = ofp_parser.OFPPacketOut( |
|---|
| 58 | datapath=dp, buffer_id=msg.buffer_id, in_port=in_port, |
|---|
| 59 | actions=actions) |
|---|
| 60 | dp.send_msg(out)</code></pre> |
|---|
| 61 | <p>With one window open on your controller, and the other window on your datapath element, start this application on the controller with the following command.</p> |
|---|
| 62 | <pre><code>$ ryu-manager --verbose ~/l2.py</code></pre> |
|---|
| 63 | <p>Then run the following on the datapath element</p> |
|---|
| 64 | <pre><code># /root/bootovs-rb532.sh </code></pre> |
|---|
| 65 | <p>Once everything has started you can confirm that the datapath element has contacted the controller</p> |
|---|
| 66 | <pre><code>2014-01-28T04:56:02Z|00030|rconn|INFO|br0<->tcp:10.10.0.1:6633: connected</code></pre> |
|---|
| 67 | <p>Every time a packet arrives on either of the datapath ports the following message will be printed on the controller screen</p> |
|---|
| 68 | <pre><code>EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 69 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 70 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 71 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 72 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 73 | EVENT ofp_event->L2Switch EventOFPPacketIn</code></pre> |
|---|
| 74 | <p>You can confirm this by having someone plug a laptop into the rb532</p> |
|---|
| 75 | <h2 id="a-more-complicated-switch">A more complicated switch</h2> |
|---|
| 76 | <pre><code>git clone https://code.google.com/r/dean-nsss/ |
|---|
| 77 | |
|---|
| 78 | ryu-manager --verbose ./dean-nsss/simple_switch_13.py</code></pre> |
|---|
| 79 | <p>On the datapath element run the monitor_flows command</p> |
|---|
| 80 | <pre><code>$ ./monitor_flows.sh</code></pre> |
|---|
| 81 | <p>This should give the output similar to the following</p> |
|---|
| 82 | <pre><code>Tue Jan 28 05:01:57 UTC 2014 |
|---|
| 83 | OFPST_FLOW reply (OF1.3) (xid=0x2): |
|---|
| 84 | cookie=0x0, duration=10.535s, table=0, n_packets=27, n_bytes=4624, priority=1,in_port=1,dl_src=3c:07:54:49:ee:97 actions=goto_table:1 |
|---|
| 85 | cookie=0x0, duration=93.21s, table=1, n_packets=3, n_bytes=1026, priority=10,dl_dst=ff:ff:ff:ff:ff:ff actions=ALL |
|---|
| 86 | cookie=0x0, duration=93.21s, table=1, n_packets=0, n_bytes=0, priority=5,dl_type=0x88cc actions=drop |
|---|
| 87 | cookie=0x0, duration=93.21s, table=1, n_packets=0, n_bytes=0, priority=5,dl_type=0x05ff actions=drop |
|---|
| 88 | cookie=0x0, duration=93.21s, table=1, n_packets=15, n_bytes=3058, priority=11,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=ALL |
|---|
| 89 | cookie=0x0, duration=93.21s, table=1, n_packets=0, n_bytes=0, priority=10,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=ALL |
|---|
| 90 | cookie=0x0, duration=93.21s, table=1, n_packets=9, n_bytes=540, priority=0 actions=FLOOD,CONTROLLER:64</code></pre> |
|---|
| 91 | <p>--End</p> |
|---|
| 92 | </body> |
|---|
| 93 | </html> |
|---|