| 1 | % SDN / OpenFlow tutorial |
|---|
| 2 | % |
|---|
| 3 | % First SDN Application |
|---|
| 4 | |
|---|
| 5 | # Introduction |
|---|
| 6 | |
|---|
| 7 | In this lab we will connect write our first SDN application and run it on the controller. |
|---|
| 8 | |
|---|
| 9 | # Goals |
|---|
| 10 | |
|---|
| 11 | * Write an SDN application using the Ryu framework |
|---|
| 12 | * Start the application on the controller. |
|---|
| 13 | |
|---|
| 14 | # Notes |
|---|
| 15 | |
|---|
| 16 | * Commands preceded with "$" imply that you should execute the command as |
|---|
| 17 | a general user - not as root. |
|---|
| 18 | * Commands preceded with "#" imply that you should be working as root. |
|---|
| 19 | * Commands with more specific command lines (e.g. "RTR-GW>" or "mysql>") |
|---|
| 20 | imply that you are executing commands on remote equipment, or within |
|---|
| 21 | another program. |
|---|
| 22 | |
|---|
| 23 | # Installation |
|---|
| 24 | |
|---|
| 25 | ## A very simple switch. |
|---|
| 26 | |
|---|
| 27 | Open up a terminal on the controller and create the following file |
|---|
| 28 | |
|---|
| 29 | $ vi ~/l2.py |
|---|
| 30 | |
|---|
| 31 | It should contain the following |
|---|
| 32 | |
|---|
| 33 | from ryu.base import app_manager |
|---|
| 34 | from ryu.controller import mac_to_port |
|---|
| 35 | from ryu.controller import ofp_event |
|---|
| 36 | from ryu.controller.handler import MAIN_DISPATCHER |
|---|
| 37 | from ryu.controller.handler import set_ev_cls |
|---|
| 38 | from ryu.ofproto import ofproto_v1_3 |
|---|
| 39 | from ryu.lib.mac import haddr_to_bin |
|---|
| 40 | from ryu.lib.packet import packet |
|---|
| 41 | from ryu.lib.packet import ethernet |
|---|
| 42 | |
|---|
| 43 | class L2Switch(app_manager.RyuApp): |
|---|
| 44 | def __init__(self, *args, **kwargs): |
|---|
| 45 | super(L2Switch, self).__init__(*args, **kwargs) |
|---|
| 46 | |
|---|
| 47 | @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER) |
|---|
| 48 | def packet_in_handler(self, ev): |
|---|
| 49 | msg = ev.msg |
|---|
| 50 | dp = msg.datapath |
|---|
| 51 | ofp = dp.ofproto |
|---|
| 52 | ofp_parser = dp.ofproto_parser |
|---|
| 53 | in_port = msg.match['in_port'] |
|---|
| 54 | |
|---|
| 55 | actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)] |
|---|
| 56 | out = ofp_parser.OFPPacketOut( |
|---|
| 57 | datapath=dp, buffer_id=msg.buffer_id, in_port=in_port, |
|---|
| 58 | actions=actions) |
|---|
| 59 | dp.send_msg(out) |
|---|
| 60 | |
|---|
| 61 | |
|---|
| 62 | 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. |
|---|
| 63 | |
|---|
| 64 | $ ryu-manager --verbose ~/l2.py |
|---|
| 65 | |
|---|
| 66 | Then run the following on the datapath element |
|---|
| 67 | |
|---|
| 68 | # /root/bootovs-rb532.sh |
|---|
| 69 | |
|---|
| 70 | |
|---|
| 71 | Once everything has started you can confirm that the datapath element has contacted the controller |
|---|
| 72 | |
|---|
| 73 | 2014-01-28T04:56:02Z|00030|rconn|INFO|br0<->tcp:10.10.0.1:6633: connected |
|---|
| 74 | |
|---|
| 75 | Every time a packet arrives on either of the datapath ports the following message will be printed on the controller screen |
|---|
| 76 | |
|---|
| 77 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 78 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 79 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 80 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 81 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 82 | EVENT ofp_event->L2Switch EventOFPPacketIn |
|---|
| 83 | |
|---|
| 84 | You can confirm this by having someone plug a laptop into the rb532 |
|---|
| 85 | |
|---|
| 86 | |
|---|
| 87 | ## A more complicated switch |
|---|
| 88 | |
|---|
| 89 | git clone https://code.google.com/r/dean-nsss/ |
|---|
| 90 | |
|---|
| 91 | ryu-manager --verbose ./dean-nsss/simple_switch_13.py |
|---|
| 92 | |
|---|
| 93 | |
|---|
| 94 | On the datapath element run the monitor_flows command |
|---|
| 95 | |
|---|
| 96 | $ ./monitor_flows.sh |
|---|
| 97 | |
|---|
| 98 | This should give the output similar to the following |
|---|
| 99 | |
|---|
| 100 | Tue Jan 28 05:01:57 UTC 2014 |
|---|
| 101 | OFPST_FLOW reply (OF1.3) (xid=0x2): |
|---|
| 102 | 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 |
|---|
| 103 | 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 |
|---|
| 104 | cookie=0x0, duration=93.21s, table=1, n_packets=0, n_bytes=0, priority=5,dl_type=0x88cc actions=drop |
|---|
| 105 | cookie=0x0, duration=93.21s, table=1, n_packets=0, n_bytes=0, priority=5,dl_type=0x05ff actions=drop |
|---|
| 106 | 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 |
|---|
| 107 | 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 |
|---|
| 108 | cookie=0x0, duration=93.21s, table=1, n_packets=9, n_bytes=540, priority=0 actions=FLOOD,CONTROLLER:64 |
|---|
| 109 | |
|---|
| 110 | --End |
|---|