summaryrefslogtreecommitdiffhomepage
path: root/doc/source/writing_ryu_app.rst
blob: 7f15ed9a95bc27bda9d53863ac9604f2b31dca3e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
*********************
The First Application
*********************

Whetting Your Appetite
======================

If you want to manage network gear (switches, routers, etc) your
own way, you just need to write your own Ryu application. Your application
tells Ryu how you want to manage the gear. Then Ryu configures the
gear by using OpenFlow protocol, etc.

Writing Ryu applications is easy. They're just Python scripts.


Start Writing
=============

Here we show a Ryu application that makes an OpenFlow switch work as a dumb
layer 2 switch.

Open a text editor and create a new file with the following content:

.. code-block:: python
   
   from ryu.base import app_manager
   
   class L2Switch(app_manager.RyuApp):
       def __init__(self, *args, **kwargs):
           super(L2Switch, self).__init__(*args, **kwargs)

Ryu applications are just Python scripts so you can save the file with
any name, any extension, and any place you want. Let's name the file
'l2.py' in your home directory.

This application does nothing useful yet, however it's a complete Ryu
application. In fact, you can run this Ryu application::
   
   % ryu-manager ~/l2.py
   loading app /Users/fujita/l2.py
   instantiating app /Users/fujita/l2.py


All you have to do is define a new subclass of RyuApp to run
your Python script as a Ryu application.

Next let's add some functionality that sends a received packet to all
the ports.

.. code-block:: python
   
   from ryu.base import app_manager
   from ryu.controller import ofp_event
   from ryu.controller.handler import MAIN_DISPATCHER
   from ryu.controller.handler import set_ev_cls
   from ryu.ofproto import ofproto_v1_0
   
   class L2Switch(app_manager.RyuApp):
       OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION]

       def __init__(self, *args, **kwargs):
           super(L2Switch, self).__init__(*args, **kwargs)
   
       @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
       def packet_in_handler(self, ev):
           msg = ev.msg
           dp = msg.datapath
           ofp = dp.ofproto
           ofp_parser = dp.ofproto_parser
   
           actions = [ofp_parser.OFPActionOutput(ofp.OFPP_FLOOD)]
           out = ofp_parser.OFPPacketOut(
               datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port,
               actions=actions)
           dp.send_msg(out)


A new method 'packet_in_handler' is added to the L2Switch class. This is
called when Ryu receives an OpenFlow packet_in message. The trick is the
'set_ev_cls' decorator. This decorator tells Ryu when the decorated
function should be called.

The first argument of the decorator indicates which type of event this
function should be called for. As you might expect, every time Ryu gets a
packet_in message, this function is called.

The second argument indicates the state of the switch. You probably
want to ignore packet_in messages before the negotiation between Ryu
and the switch is finished. Using 'MAIN_DISPATCHER' as the second
argument means this function is called only after the negotiation
completes.

Next let's look at the first half of the 'packet_in_handler' function.

* ev.msg is an object that represents a packet_in data structure.

* msg.dp is an object that represents a datapath (switch).

* dp.ofproto and dp.ofproto_parser are objects that represent the
  OpenFlow protocol that Ryu and the switch negotiated.

Ready for the second half.

* OFPActionOutput class is used with a packet_out message to specify a
  switch port that you want to send the packet out of. This
  application uses the OFPP_FLOOD flag to indicate that the packet should
  be sent out on all ports.

* OFPPacketOut class is used to build a packet_out message.

* If you call Datapath class's send_msg method with a OpenFlow message
  class object, Ryu builds and sends the on-wire data format to the switch.


There, you finished implementing your first Ryu application. You are ready to
run a Ryu application that does something useful.


Is a dumb L2 switch is too dumb? You want to implement a learning L2
switch? Move to `the next step
<https://github.com/osrg/ryu/blob/master/ryu/app/simple_switch.py>`_. You
can learn from the existing Ryu applications at `ryu/app
<https://github.com/osrg/ryu/blob/master/ryu/app/>`_ directory and
`integrated tests
<https://github.com/osrg/ryu/blob/master/ryu/tests/integrated/>`_
directory.