Ryu 應用程式開發介面(API)

Ryu 應用程式開發模型

執行緒(Threads)、事件、事件隊列(Queues)

在Ryu 中,Ryu 應用程式是一個實作網路功能的單執行緒(single-threaded)應用 程式。事件與訊息會在不同的應用程式之間傳遞。

Ryu 應用程式會透過非同步的方式將事件傳送至其他應用程式中。 事件傳送與接收的執行緒不一定是一支 Ryu 應用程式,他有可能會是其他非 Ryu 應用程式產生的執行緒,舉例來說,OpenFlow Controller 就是一個 會產生並傳送 Ryu 事件的一支非 Ryu 的應用程式。 一個事件可以夾帶許多已經封裝好的 Python 物件,在這邊我們並不鼓勵將過於複雜 (例如:未封裝的資料)的物件封裝在事件當中並傳送。

每一個不同的 Ryu 應用程式都會包含一個專門用來接收事件的隊列。 隊列提供了先進先出(FIFO)的規則,讓每一個事件都會依序的被執行。 而每一個 Ryu 應用程式都會有一個負責處理事件的執行緒,這一個執行緒會持續的 將事件隊列中的事件取出並且將事件傳送給對應的方法。 每一個事件都會在同一個執行緒中處理,因此在設計事件處理的方法時必須要非常小心 避免一個處理方法將事件執行緒停住(Blocking),若一個事件執行緒被其中一個處理事件的 方法給停止,則該 Ryu 應用程式將不會再接收(處理)任何的事件。

有部分的事件是以同步(synchronous)的方式處理,他可以讓不同的 Ryu 應用程式 相互呼叫。 當一個事件以同步的方式呼叫,則它們的回應(reply)會被放置在隊列中以避免死結(deadlock) 問題。

在 Ryu 中所使用的執行緒以及隊列是使用 eventlet/greenlet 這一套函式庫所實作,這邊 並不鼓勵直接在 Ryu 應用程式中直接使用它們。

Contexts

Contexts 是一個共享於不同 Ryu 應用程式之間的 Python 物件。使用共享的物件 可以避免一個功能或是物件重複被創造。

建立一個 Ryu 應用程式

Ryu 應用程式是一個繼承自 ryu.base.app_manager.RyuApp 的類別。 如果在一個 Python 模組(module)中定義了兩個以上的 Ryu 應用程式類別, 則 app_manager 會以名稱作為排序,並且取用第一個應用程式作為這一個模組中 的 Ryu 應用程式執行。

Ryu 應用程式為一個獨立執行個體(singleton):每一個 Ryu 應用程式僅會有一個 實體(instance)。

事件接收

Ryu 應用程式會事先透過 ryu.controller.handler.set_ev_cls 去註冊需要接收的事件。

產生事件

Ryu 應用程式在產生出事件物件之後,可以透過 send_event 傳送事件至特定的 Ryu 應用程式, 或是透過 send_event_to_observers 傳送到有註冊該事件的應用程式。

事件類別

事件類別表示了在 Ryu 中所產生(發生)的事件。 一般而言,所有事件的類別都會在名稱前方加上「Event」用以區別。 一個事件可以被 Ryu 的核心程式或是一般 Ryu 應用程式產生。 Ryu 應用程式可以事先註冊他所想要接收的 Event 類別,只需在處理該事件的方法前 加上 ryu.controller.handler.set_ev_cls 修飾詞(decorator)即可。

OpenFlow 事件類別

當連上的交換器傳送 OpenFlow 訊息時,ryu.controller.ofp_event 模組能夠將該訊息 轉換成事件類別。

原則上,每一個事件類別都會以 EventOFP 作為開頭,舉例來說 EventOFPPacketIn 就是 packet-in 訊息所產生的事件類別。

Ryu 架構下的 Controller 會自動將接收到的 OpenFlow 訊息解碼,並將事件物件傳送到 使用 ryu.controller.handler.set_ev_cls 去註冊該事件的 Ryu 應用程式。

OpenFlow 事件包含了下列兩項屬性:

Attribute Description
msg OpenFlow 訊息內容,依據接收到的訊息會有所不同。
msg.datapath 接收到該訊息的 ryu.controller.controller.Datapath 實體

每一個訊息物件中都會包含許多而外的資訊,這些資訊都是從原始的訊息所解碼出來的。 詳細可以參考 OpenFlow 協定 API 章節。

ryu.base.app_manager.RyuApp

請參閱 Ryu API 參考說明 章節。

ryu.controller.handler.set_ev_cls(ev_cls, dispatchers=None)

set_ev_cls 是一個用於將方法註冊成 Ryu 事件處理器的一個修飾器,被修飾的 方法將會成為一個事件處理器。

ev_cls 表示了一個想要被該 Ryu 應用程式接收的事件類別。

dispatchers 則表示了該事件處理器將會在哪些談判階段(negotiation phases) 去接收此一類型的事件,舉例來說,HANDSHAKE_DISPATCHER 表示了在交換器與 控制器連線(交握)階段所產生的事件。

談判階段(Negotiation phase) 說明
ryu.controller.handler.HANDSHAKE_DISPATCHER 送出以及等待 hello 訊息
ryu.controller.handler.CONFIG_DISPATCHER 版本協議以及送出 feature-request 訊息
ryu.controller.handler.MAIN_DISPATCHER 接收 Switch-features 訊息以及 傳送 set-config 訊息
ryu.controller.handler.DEAD_DISPATCHER 連線被其中一方中斷,或是未知錯誤導致 雙方連線中斷。

ryu.controller.controller.Datapath

一個包含了連上控制器交換器資訊的物件,任何程式要傳送訊息(OpenFlow Message)給控制 器均需透過本物件來傳送。

Datapath 類別中包含了以下屬性:

屬性 說明
id 64-bit OpenFlow Datapath ID。 這一個屬性只有在 ryu.controller.handler.MAIN_DISPATCHER 階段有效。
ofproto 一個能夠表示該控制器所使用的 OpenFlow 版本以及該版本訊息之定義,詳細的定義 可以參考 OpenFlow 協定 API 章節, 此屬性會以 ryu.ofproto.ofproto_vxxx 為主 ,舉例來說 ofproto_v1_0 表示了該交換器使用 OpenFlow 1.0 協定。
ofproto_parser 此屬性是一個以該交換器協定所實作的編碼及 解碼器,這一個物件是依據上一個屬性所定義的 舉例來說,若他是 ryu.ofproto.ofproto_v1_0_parser 則他就會透過 OpenFlow 1.0 協定去編碼及 解碼訊息。
ofproto_parser.OFPxxxx(datapath, ....) 透過呼叫 OFPxxxx 來產生出訊息,這一個訊息 可以透過 send_msg 這一個方法去傳送給實體 的交換器。xxxx 表示了訊息名稱,舉例來說 OFPFlowMod 表示了一個 flow-mod 的訊息 每一個訊息的參數都是基於原始訊息去定義的。
set_xid(self, msg) 產生一個 OpenFlow 的 XID 然後將這一個 XID 放置到 msg.xid 中。
send_msg(self, msg) 將訊息放置到一個傳送專用的隊列(queue) 中,隨後將會被一個專門傳送訊息的執行緒給 傳送。如果msg.xid 為 None,則會自動先 呼叫 set_xid 方法,在放入隊列中。
send_packet_out 將被棄用。
send_flow_mod 將被棄用。
send_flow_del 將被棄用。
send_delete_all_flows 將被棄用。
send_barrier 將 barrier 訊息放置傳送用的隊列中。
send_nxt_set_flow_format 將被棄用。
is_reserved_port 將被棄用。

ryu.controller.event.EventBase

所有的事件類別都會繼承自 EventBase。 若需自行設計事件類別,只需要建立一個繼承自它的類別即可。

ryu.controller.event.EventRequestBase

若需透過 RyuApp.send_request 傳送同步(synchronous)的事件,則 需要讓事件類別繼承自 EventRequestBase。

ryu.controller.event.EventReplyBase

若需要透過 RyuApp.send_reply 來回覆同步請求事件,則該事件需要 繼承 EventReplyBase。

ryu.controller.ofp_event.EventOFPStateChange

用於傳送談判階段(negotiation phase)在替換時所產生的事件,當一個 階段轉換完成時,此事件會被傳送。 這一個類別包含了以下屬性。

屬性 說明
datapath ryu.controller.controller.Datapath 的實體

ryu.controller.dpset.EventDP

當一個實體交換器連上或是斷線的時候會產生此事件。 對於 OpenFlow 交換器,這一個事件原則上跟 ryu.controller.ofp_event.EventOFPStateChange 是一樣的。EventDP 包含了以下屬性。

屬性 說明
dp ryu.controller.controller.Datapath 的實體,用於表示交換器。
enter 若表示一個交換器連上,則為 True,若斷線則為 False。

ryu.controller.dpset.EventPortAdd

當一個新的埠口連接到一台交換器上面,則此事件會被觸發。 對於 OpenFlow 交換器,這一個事件等同於 ryu.controller.ofp_event.EventOFPPortStatus 這一個事件至少包含了以下屬性:

Attribute Description
dp ryu.controller.controller.Datapath 的實體,用於表示交換器。
port 該埠口的埠口編號

ryu.controller.dpset.EventPortDelete

當一個埠口從交換器上面移除,則此事件會被觸發。 對於 OpenFlow 交換器,這一個事件等同於 ryu.controller.ofp_event.EventOFPPortStatus 這一個事件至少包含了以下屬性:

Attribute Description
dp ryu.controller.controller.Datapath 的實體,用於表示交換器。
port 該埠口的埠口編號

ryu.controller.dpset.EventPortModify

當一個埠口的屬性被更改(例如將埠口設定成OFPPC_NO_STP),則此事件會被觸發。 對於 OpenFlow 交換器,這一個事件等同於 ryu.controller.ofp_event.EventOFPPortStatus 這一個事件至少包含了以下屬性:

Attribute Description
dp ryu.controller.controller.Datapath 的實體,用於表示交換器。
port 該埠口的埠口編號

ryu.controller.network.EventNetworkPort

當一個埠口透過 REST API 在一個網路中加入或是移除,則此事件會被觸發。 這一個事件至少包含了以下屬性:

屬性 說明
network_id 網路編號(Network ID)
dpid 該埠口所存在交換器之 OpenFlow Datapath ID。
port_no 該埠口的 OpenFlow 埠口編號。
add_del 新增時為 True,刪除時則是 False。

ryu.controller.network.EventNetworkDel

當透過 REST API 刪除一個網路資料時便會觸發。 這一個事件至少包含了以下屬性:

屬性 說明
network_id 網路編號(Network ID)

ryu.controller.network.EventMacAddress

當一個終端設備(特定埠口下)的 Mac 位址透過 REST API 更新時,則會觸發此事件。 這一個事件至少包含了以下屬性:

屬性 說明
network_id 網路編號(Network ID)
dpid 該埠口所存在交換器之 OpenFlow Datapath ID。
port_no 該埠口的 OpenFlow 埠口編號。
mac_address 若 add_del 為 False,則此一屬性為舊的 MAC 位址,否則就會是新的 MAC 位址。
add_del 若要移除該終端設備,則此屬性為 False,否則為 True。

ryu.controller.tunnels.EventTunnelKeyAdd

當透過 RESP API 註冊(新增)或是更新一個 Tunnel Key 時,則會觸發此一事件。 這一個事件至少包含了以下屬性:

屬性 說明
network_id 網路編號(Network ID)
tunnel_key Tunnel Key

ryu.controller.tunnels.EventTunnelKeyDel

當透過 RESP API 刪除一個 Tunnel Key 時,則會觸發此一事件。 這一個事件至少包含了以下屬性:

屬性 說明
network_id 網路編號(Network ID)
tunnel_key Tunnel Key

ryu.controller.tunnels.EventTunnelPort

當一個 tunnel 埠口透過 REST API 新增或是刪除時,則會觸發此一事件。 這一個事件至少包含了以下屬性:

屬性 說明
dpid OpenFlow Datapath ID
port_no OpenFlow 埠口編號。
remote_dpid tunnel 另一端的埠口編號。
add_del 新增為 True,刪除為 False。