Ryu 学习总结
之前一直在用 ovs-vsctl 工具控制 Open vSwitch,决定使用专门的控制器,趁机学习下openflow协议细节,辗转了POX,Floodlight,OpenDaylight等多个控制器之后,发现还是喜欢Python语言的控制器ryu。
ryu是日本NTT公司推出的SDN控制器框架,它基于Python开发,模块清晰,可扩展性好,逐步取代了早期的NOX,支持OpenFlow 1.0到1.5版本,也支持Netconf,OF-CONIFG等其他南向协议,提供了丰富的组件,便于开发者构建SDN应用。
我的新书《LangChain编程从入门到实践》 已经开售!推荐正在学习AI应用开发的朋友购买阅读!
ryu 代码结构
ryu/app
基于ryu控制器开发的app,内含ryu的图形界面、北向防火墙、北向QoS、简易L2交换机、L3路由器等。ryu/base
内含app_manager.py脚本,其作用是RYU应用的管理中心,用于加载ryu应用程序,接受从APP发送过来的信息,同时也完成消息的路由。定义了两大基类:RyuApp和AppManager。RyuApp定义了App的基本属性,AppManager则定义了用于管理多个App的方法和属性。ryu/controller
该文件夹中含有许多关键的ryu源码文件,controller.py
文件中含有两个十分重要的类:OpenFlowController 定义了构建一个控制器的基本方法和属性,DataPath 是用于描述OpenFlow控制器和交换机是如何连接的类: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
70class OpenFlowController(object):
def __init__(self):
super(OpenFlowController, self).__init__()
if not CONF.ofp_tcp_listen_port and not CONF.ofp_ssl_listen_port:
self.ofp_tcp_listen_port = ofproto_common.OFP_TCP_PORT
self.ofp_ssl_listen_port = ofproto_common.OFP_SSL_PORT
# For the backward compatibility, we spawn a server loop
# listening on the old OpenFlow listen port 6633.
hub.spawn(self.server_loop,
ofproto_common.OFP_TCP_PORT_OLD,
ofproto_common.OFP_SSL_PORT_OLD)
else:
self.ofp_tcp_listen_port = CONF.ofp_tcp_listen_port
self.ofp_ssl_listen_port = CONF.ofp_ssl_listen_port
# Example:
# self._clients = {
# ('127.0.0.1', 6653): <instance of StreamClient>,
# }
self._clients = {}
...
class Datapath(ofproto_protocol.ProtocolDesc):
"""
A class to describe an OpenFlow switch connected to this controller.
An instance has the following attributes.
.. tabularcolumns:: |l|L|
# entry point
==================================== ======================================
Attribute Description
==================================== ======================================
id 64-bit OpenFlow Datapath ID.
Only available for
ryu.controller.handler.MAIN_DISPATCHER
phase.
ofproto A module which exports OpenFlow
definitions, mainly constants appeared
in the specification, for the
negotiated OpenFlow version. For
example, ryu.ofproto.ofproto_v1_0 for
OpenFlow 1.0.
ofproto_parser A module which exports OpenFlow wire
message encoder and decoder for the
negotiated OpenFlow version.
For example,
ryu.ofproto.ofproto_v1_0_parser
for OpenFlow 1.0.
ofproto_parser.OFPxxxx(datapath,...) A callable to prepare an OpenFlow
message for the given switch. It can
be sent with Datapath.send_msg later.
xxxx is a name of the message. For
example OFPFlowMod for flow-mod
message. Arguemnts depend on the
message.
set_xid(self, msg) Generate an OpenFlow XID and put it
in msg.xid.
send_msg(self, msg) Queue an OpenFlow message to send to
the corresponding switch. If msg.xid
is None, set_xid is automatically
called on the message before queueing.
send_packet_out deprecated
send_flow_mod deprecated
send_flow_del deprecated
send_delete_all_flows deprecated
send_barrier Queue an OpenFlow barrier message to
send to the switch.
send_nxt_set_flow_format deprecated
is_reserved_port deprecated
==================================== ======================================
"""
...ryu/cmd
定义了ryu的命令系统。ryu/contrib
社区贡献者的代码。ryu/lib
该目录下定义了一些数据报的格式和数据结构,及诸多网络协议。ryu/ofproto
该目录下的文件分为两类,一类定义协议的数据结构,另外一类用于协议报文解析。ryu/services
完成了bgp、vrrp协议及ovsdb的实现。ryu/tests
用于测试。ryu/topology
定义了自定义拓扑文件中需要的一些模块和方法,其中的switches.py
(关键文件),完成了对一整套交换机处理流程的定义。
L2Switch example(来自官网)
1 | from ryu.base import app_manager |
分析具体的数据操作:
- ev.msg:每一个事件类ev中都有msg成员,用于携带触发事件的数据包。
- msg.datapath:已经格式化的msg其实就是一个packet_in报文,msg.datapath直接可以获得packet_in报文的datapath结构。datapath用于描述一个交换网桥,也是和控制器通信的实体单元。datapath.send_msg()函数用于发送数据到指定datapath,通过datapath.id可获得dpid数据。
- datapath.ofproto对象是一个OpenFlow协议数据结构的对象,成员包含OpenFlow协议的数据结构,如动作类型OFPP_FLOOD。
- datapath.ofp_parser则是一个按照OpenFlow解析的数据结构。
- actions是一个列表,用于存放action list,可在其中添加动作。
- 通过ofp_parser类,可以构造构造packet_out数据结构,括弧中填写对应字段的赋值即可。
- 如果datapath.send_msg()函数发送的是一个OpenFlow的数据结构,RYU将把这个数据发送到对应的datapath。
一个标准的控制器处理事件的模板,@set_ev_cls(ofp_event.Event, DISPATCHER(s))
装饰器的含义就是,当接收到DISPATCHER(s)情况的Event事件进行handler_function处理,其中handler_function是自定义的函数处理过程,命名可以任意指定;ofp_event.Event是由ofp_event.py提供的一系列事件。
1 | @set_ev_cls(ofp_event.Event, DISPATCHER(s)) |
DISPATCHER(s)可以为单独一个,也可以为由多个DISPATCHER组成的列表,DISPATCHER描述的情况包括:
Defination | Explanation |
---|---|
HANDSHAKE_DISPATCHER | 交换HELLO消息 |
CONFIG_DISPATCHER | 等待接收SwitchFeatures消息 |
MAIN_DISPATCHER | 正常状态 |
DEAD_DISPATCHER | 连接断开 |
ofp_event
ofp_event类位于ryu/controller/ofp_event.py
,主要定义了OpenFlow中的各种事件,配合set_cls_ev可以对指定事件进行处理,接下来,在分析学习官方案例的同时,也会整合Ryu源码与OpenFlow1.3.3协议的内容,对这些事件进行深入的理解与分析。
EventOFPMsgBase
事件类描述了从交换机接收OpenFlow消息的过程,按照约定,它们被命名为ryu.controller.ofp_event.EventOFPxxxx,其中xxxx是相应的OpenFlow消息的名称。例如,EventOFPPacketIn用于packet-in message,Ryu的OpenFlow控制器部分自动解码从交换机接收到的OpenFlow消息,并将这些事件发送(ryu.controller.handler.set_ev_cls)到Ryu应用程序,EventOFPMsgBase事件类是所有EventOFPxxxx的基类。
1 | class EventOFPMsgBase(event.EventBase): |
EventOFPStateChange
发起事件 | 处理事件 |
---|---|
交换机状态变化 | EventOFPStateChange |
1 | class EventOFPStateChange(event.EventBase): |
该class是处理协商阶段变更通知的事件,在协商更改后发生此消息给观察者,当我们使用以下的命令,我们就成为了观察者,发生此类消息时,便可以进行接收和处理。
1 |
|
在协商阶段,MAIN_DISPATCHER意味着有新的交换机接入,DEAD_DISPATCHER意味着有交换机脱离连接。
EventOFPPortStateChange
发起事件 | 处理事件 |
---|---|
OFPPortStatsRequest | EventOFPPortStateChange |
1 | class EventOFPPortStateChange(event.EventBase): |
参考链接
Welcome to RYU the Network Operating System(NOS)
RYU入门教程(李呈大神)
Ryu 学习总结