Ryu學習總結
該篇學習筆記,與其他分析Ryu控制器代碼的筆記不同,主要按照程序的構成來進行分塊總結,由於本人為新手入門,不能保證沒有錯誤,如果發現錯誤,歡迎指教。
以下的內容主要來源:
- 源碼
- 官方文檔
- OpenFlow1.3.3 手冊
處理一個事件的標准模板
首先,我們來看一個標准的控制器處理事件的模板
@set_ev_cls(ofp_event.Event, DISPATCHER(s))
def your_function(self, ev):
...
簡單說,@set_ev_cls(ofp_event.Event, DISPATCHER(s))
的含義就是,當接收到DISPATCHER(s)情況的Event
事件進行your_function處理。
DISPATCHER(s)可以為單獨一個,也可以為由多個DISPATCHER組成的列表,DISPATCHER描述的情況包括:
Defination | Explanation |
---|---|
HANDSHAKE_DISPATCHER | 交換HELLO消息 |
CONFIG_DISPATCHER | 等待接收SwitchFeatures消息 |
MAIN_DISPATCHER | 正常狀態 |
DEAD_DISPATCHER | 連接斷開 |
其中your_function
是由你自己定義的函數處理過程,命名可以任意指定;ofp_event.Event
是由ofp_event.py提供的一系列事件,在學習了幾個Ryu的程序之后,深感,其核心就在於對這些事件的理解。所以,接下來,在分析學習官方案例的同時,也會整合Ryu源碼與OpenFlow1.3.3協議的內容,對這些事件進行深入的理解與分析。
ofp_event
ofp_event類位於ryu/controller/ofp_event.py
,主要定義了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
========= =================================================================
意思說,該class是處理協商階段變更通知的事件,在協商更改后發生此消息給觀察者。
當我們使用一下的命令,我們就成為了觀察者,發生此類消息時,便可以進行接收和處理
@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
- duration_sec
- duration_nsec
- priority
- idle_timeout
- hard_timeout
- flags
- 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)
通過案例程序,我們可以看到,從該消息中,我們可以獲取到:
- rx_packets
- tx_packets
- rx_bytes
- tx_bytes
- rx_dropped
- tx_dropped
- rx_errors
- tx_errors
- rx_frame_err
- tx_overerr
- rx_crc_err
- collisions
- duration_sec
- duration_nsec
同樣該事件同樣對應存在一個端口統計請求事件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 |