Ryu学习总结(持续更新)
Ryu学习总结
这篇学习笔记与对Ryu控制器代码进行分析的笔记相异,在内容安排上主要根据程序架构进行模块化总结。鉴于本人是刚入门的学习者,在理论掌握上可能存在不足之处,请指导指正;如有其他问题或建议,请随时提出。
以下的内容主要来源:
- 源码
- 官方文档
- OpenFlow1.3.3 手册
处理一个事件的标准模板
首先,我们来看一个标准的控制器处理事件的模板
@set_ev_cls(ofp_event.Event, DISPATCHER(s))
def your_function(self, ev):
...
代码解释
具体来说,在OFPPacketEvent框架中,
@set_ev_cls(ofp_event.Event,_DISPATCHER(s))
这一注释的作用体现在每当有DISPATCHER(s)事件发生时会自动触发your_function处理流程。
支持单个DISPATCHER以及支持多个DISPATCHER构成的列表。
| Defination | Explanation |
|---|---|
| HANDSHAKE_DISPATCHER | 交换HELLO消息 |
| CONFIG_DISPATCHER | 等待接收SwitchFeatures消息 |
| MAIN_DISPATCHER | 正常状态 |
| DEAD_DISPATCHER | 连接断开 |
在研习了若干个Ryu程序后,深刻认识到理解这些事件是关键;并深入解析其源码和OpenFlow 1.3.3协议的相关内容,结合官方方案例题的学习过程中
ofp_event
该Python文件中的ofp_event类主要用于实现OpenFlow事件的管理逻辑,并负责处理与特定事件相关的操作流程。该类通过调用set_cls_ev方法能够对不同类型的事件进行相应的响应和处理机制。
ofp_event.EventOFPSwitchFeatures
ofp_event.EventOFPPacketIn
ofp_event.EventOFPStateChange
在源码中,对EventOFPStateChange这样进行介绍:
An event class for negotiation phase change notification.
An instance of this class is sent to observer after changing
the negotiation phase.
An instance has at least the following attributes.
========= =================================================================
Attribute Description
========= =================================================================
datapath ryu.controller.controller.Datapath instance of the switch
========= =================================================================
代码解释
可以理解为该类负责处理协商阶段中的变更通知事件,在协商更改完成后,则会向观察者发送此消息
当我们运行某个特定的命令时, 我们就可以充当一个观察者. 当接收到此类消息时, 我们可以依次进行接收和处理.
@set_ev_cls(ofp_event.EventOFPStateChange,
[MAIN_DISPATCHER, DEAD_DISPATCHER])
代码解释
详细案例见Traffic Monitor
在协商环节中, MAIN_DISPATCHER表示新交换机加入网络, 而DEAD_DISPATCHER表明已有交换机断开连接.
总结:
| 发起事件 | 处理事件 |
|---|---|
| 交换机状态变化 | EventOFPStateChange |
ofp_event.EventOFPFlowStatsReply
在源码中,对EventOFPFlowStatsReply这样介绍:
Individual flow statistics reply message
The switch responds with this message to an individual flow statistics
request.
代码解释
具体来说,该事件负责处理个体流量统计回复消息,即用于收集某一交换机上的流量信息。这些流量统计信息则包含于body(ev.msg.body)结构体中。
table_id 表ID
duration_sec 持续秒数
duration_nsec 持续纳秒数
priority 优先级
idle_timeout 空闲超时时间和硬超时时间
hard_timeout 硬截止时间
flags 标志位
cookie Cookie字段
packet_count 包计数
byte_count 字节数
match 匹配条件
instructions 指令集
使用范例:
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def flow_stats_reply_handler(self, ev):
flows = []
for stat in ev.msg.body:
flows.append('table_id=%s '
'duration_sec=%d duration_nsec=%d '
'priority=%d '
'idle_timeout=%d hard_timeout=%d flags=0x%04x '
'cookie=%d packet_count=%d byte_count=%d '
'match=%s instructions=%s' %
(stat.table_id,
stat.duration_sec, stat.duration_nsec,
stat.priority,
stat.idle_timeout, stat.hard_timeout, stat.flags,
stat.cookie, stat.packet_count, stat.byte_count,
stat.match, stat.instructions))
self.logger.debug('FlowStats: %s', flows)
代码解释
来源:源码
ryu\ofproto\ofproto_v1_3_parser.py
与前一事件的来源不同者,并非由于交换机状态的变化导致。而非交换机状态变化所引发的情况是由控制器主动发起这一事件并进行处理的行为所导致。其发起的请求为...OFPFlowStatsRequest$函数。
同样,查看源码中该函数的文档
"""
Individual flow statistics request message
The controller uses this message to query individual flow statistics.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
table_id ID of table to read
out_port Require matching entries to include this as an output
port
out_group Require matching entries to include this as an output
group
cookie Require matching entries to contain this cookie value
cookie_mask Mask used to restrict the cookie bits that must match
match Instance of ``OFPMatch``
================ ======================================================
代码解释
看见,该函数作用就是发出流量统计请求的。文档同样给出范例程序:
Example::
def send_flow_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
cookie = cookie_mask = 0
match = ofp_parser.OFPMatch(in_port=1)
req = ofp_parser.OFPFlowStatsRequest(datapath, 0,
ofp.OFPTT_ALL,
ofp.OFPP_ANY, ofp.OFPG_ANY,
cookie, cookie_mask,
match)
datapath.send_msg(req)
代码解释
查看构造函数:
def __init__(self, datapath, flags=0, table_id=ofproto.OFPTT_ALL,
out_port=ofproto.OFPP_ANY,
out_group=ofproto.OFPG_ANY,
cookie=0, cookie_mask=0, match=None, type_=None):
代码解释
在实际应用中无需特别指定时,在这里我们通常建议仅设置一个datapath参数,并让其余采用默认设置。
小结:
| 发起事件 | 处理事件 |
|---|---|
| OFPFlowStatsRequest | EventOFPFlowStatsReply |
ofp_event.EventOFPPortStatsReply
在源码中对该函数的说明如下:
"""
Port statistics reply message
The switch responds with this message to a port statistics request.
================ ======================================================
Attribute Description
================ ======================================================
body List of ``OFPPortStats`` instance
================ ======================================================
代码解释
该函数为端口统计应答消息,文档中给的范例程序如下:
Example::
@set_ev_cls(ofp_event.EventOFPPortStatsReply, MAIN_DISPATCHER)
def port_stats_reply_handler(self, ev):
ports = []
for stat in ev.msg.body:
ports.append('port_no=%d '
'rx_packets=%d tx_packets=%d '
'rx_bytes=%d tx_bytes=%d '
'rx_dropped=%d tx_dropped=%d '
'rx_errors=%d tx_errors=%d '
'rx_frame_err=%d rx_over_err=%d rx_crc_err=%d '
'collisions=%d duration_sec=%d duration_nsec=%d' %
(stat.port_no,
stat.rx_packets, stat.tx_packets,
stat.rx_bytes, stat.tx_bytes,
stat.rx_dropped, stat.tx_dropped,
stat.rx_errors, stat.tx_errors,
stat.rx_frame_err, stat.rx_over_err,
stat.rx_crc_err, stat.collisions,
stat.duration_sec, stat.duration_nsec))
self.logger.debug('PortStats: %s', ports)
代码解释
通过案例程序,我们可以看到,从该消息中,我们可以获取到:
receiver Packets, transmitter Packets, receiver Bytes, transmitter Bytes, receiver dropped, transmitter dropped, receiver errors, transmitter errors, receiver frame errors, transmitter overflows, receiver CRC errors, collisions, duration in seconds (单位:秒), duration in nanoseconds (单位:纳秒)
也即该事件亦有对应地存在一个端口统计请求事件OFPPortStatsRequest;在源码中对此函数的描述如下
"""
Port statistics request message
The controller uses this message to query information about ports
statistics.
================ ======================================================
Attribute Description
================ ======================================================
flags Zero or ``OFPMPF_REQ_MORE``
port_no Port number to read (OFPP_ANY to all ports)
================ ======================================================
代码解释
使用范例如下:
Example::
def send_port_stats_request(self, datapath):
ofp = datapath.ofproto
ofp_parser = datapath.ofproto_parser
req = ofp_parser.OFPPortStatsRequest(datapath, 0, ofp.OFPP_ANY)
datapath.send_msg(req)
代码解释
小结:
| 发起事件 | 处理事件 |
|---|---|
| OFPPortStatsRequest | EventOFPPortStatsReply |
