LoginSignup
3
3

More than 5 years have passed since last update.

Ryu tutorial 補遺

Last updated at Posted at 2017-01-26

ryu python openflow library で、Tutorial に載っていそうで見つけられずに苦労したことのメモ。

まずはじめに ryu では、「イベント駆動」アプリケーションとして書きます。イベントはryu.event.EventBase の派生クラスです。

openflow アプリケーションを書くときに「最初に~する」というのはよくあります。ryu で、この時に使うべきイベントに迷うのですが、こうするのが良さそうです。

app.py
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import set_ev_cls, MAIN_DISPATCHER

class App1(app_manager.RyuApp):
    @set_ev_cls(ofp_event.EventOFPStateChange, MAIN_DISPATCHER)
    def on_switch_ready(self, ev):
        assert isinstance(ev, ofp_event.EventOFPStateChange)
        print("switch ready")

実行例。例えば Ubuntu で ryu-bin パッケージを入れると実行できるようになります。

ryu-manager --config-file=/dev/null app.py

Event

ryu はイベント駆動なので、イベントを知らないことには話が始まりません。標準的に使われる ryu.controller 配下には、次のようなイベントがあります。まずはざっと列挙します。後に解説を書きます。

from は Event の publisher 側、to は subscriber 側を表現しています。

ryu.controller.ofp_event

比較的 openflow プロトコルのメッセージに 1:1 対応したイベントが扱われている。

datapath state 通知系

  • EventOFPStateChange
    • from: ryu.controller.controller.Datapath [HANDSHAKE_DISPATCHER]
    • from: ryu.controller.ofp_handler.OFPHandler.hello_handler [CONFIG_DISPATCHER]
    • from(<1.3): ryu.controller.ofp_handler.OFPHandler.switch_features_handler [MAIN_DISPATCHER]
    • from(>=1.3): ryu.controller.ofp_handler.OFPHandler.multipart_reply_handler [MAIN_DISPATCHER]
    • from: ryu.controller.controller.Datapath.close [DEAD_DISPATCHER]
    • to: ryu.controller.dpset.DPSet.dispatcher_change [MAIN_DISPATCHER, DEAD_DISPATCHER]

以下は EventOFPMsgBase のサブクラスとして動的に生成されている。全て recv loop からイベントが生成される。

  • EventOFPHello
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.hello_handler [HANDSHAKE_DISPATCHER]
  • EventOFPSwitchFeatures
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.switch_features_handler [CONFIG_DISPATCHER]
    • to: ryu.controller.dpset.DPSet.switch_features_handler [CONFIG_DISPATCHER]
  • EventOFPPortDescStatsReply
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.multipart_reply_handler [CONFIG_DISPATCHER]
  • EventOFPEchoRequest
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.echo_request_handler [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER]
  • EventOFPEchoReply
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.echo_reply_handler [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER]
  • EventOFPPortStatus
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.port_status_handler [MAIN_DISPATCHER]
    • to: ryu.controller.dpset.DPSet.port_status_handler [MAIN_DISPATCHER]
  • EventOFPErrorMsg
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.error_msg_handler [HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER]

port state 通知系。EventOFPPortStatus の後に発行される。

  • EventOFPPortStateChange
    • from: ryu.controller.ofp_handler.OFPHandler.port_status_handler

ryu.controller.dpset

openflow プロトコル直接というよりは、もう一段上の層で datapath の有効無効やポートの状態をハンドルできるイベント。DPSet Service として使えるようになっている。

  • EventDP
    • from: ryu.controller.dpset.DPSet._register
    • from: ryu.controller.dpset.DPSet._unregister
  • EventDPReconnected
    • from: ryu.controller.dpset.DPSet._register
  • EventPortAdd
    • from: ryu.controller.dpset.DPSet.port_status_handler
  • EventPortDelete
    • from: ryu.controller.dpset.DPSet.port_status_handler
  • EventPortModify
    • from: ryu.controller.dpset.DPSet.port_status_handler

Event 解説

総合すると、openflow 1.3 なスイッチとの接続では、次のようにイベントが自動的に流れます。

  • TCP 接続確立
  • EventOFPStateChange
    • from: ryu.controller.controller.Datapath [HANDSHAKE_DISPATCHER]
  • 対向が接続確立後に OFPT_HELLO を送ってくる
  • EventOFPHello
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.hello_handler [HANDSHAKE_DISPATCHER]
  • EventOFPStateChange
    • from: ryu.controller.ofp_handler.OFPHandler.hello_handler [CONFIG_DISPATCHER]
  • ryu.controller.ofp_handler.OFPHandler.hello_handler が OFPFeaturesRequest を送る
  • 対向が OFPT_FEATURES を送ってくる
  • EventOFPSwitchFeatures
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.switch_features_handler [CONFIG_DISPATCHER]
    • to: ryu.controller.dpset.DPSet.switch_features_handler [CONFIG_DISPATCHER]
  • ryu.controller.ofp_handler.OFPHandler.switch_features_handler が OFPPortDescStatsRequest を送る
  • 対向が OFPT_MULTIPART_REPLY/OFPMP_PORT_DESC を送ってくる
  • EventOFPPortDescStatsReply
    • from: ryu.controller.controller.Datapath._recv_loop
    • to: ryu.controller.ofp_handler.OFPHandler.multipart_reply_handler [CONFIG_DISPATCHER]
  • EventOFPStateChange
    • from(>=1.3): ryu.controller.ofp_handler.OFPHandler.multipart_reply_handler [MAIN_DISPATCHER]
    • to: ryu.controller.dpset.DPSet.dispatcher_change [MAIN_DISPATCHER]
  • EventDP
    • from: ryu.controller.dpset.DPSet._register

なので、いわゆる on switch ready みたいなポイントは、EventOFPStateChange, MAIN_DISPATCHER あるいは、EventDP となります。

Service

上記の DPSet のように、イベント発信元はサービスとして追加できるようになっています。サービスは ryu の内部では文字列で識別されています。ryu の中には次のようなサービスが存在します。これらは通常は event handler を登録して使い始める(set_ev_cls)と、自動的に有効化されるようになっています。

  • ryu.controller.dpset
  • ryu.controller.ofp_handler
  • ryu.services.protocols.ovsdb.manager
  • ryu.services.protocols.vrrp.manager
  • ryu.topology.switches

例えば ryu.controller.dpset を使う場合は次のようにします。

app2.py
from ryu.base import app_manager
from ryu.controller import dpset, ofp_event
from ryu.controller.handler import set_ev_cls

class App2(app_manager.RyuApp):
    @set_ev_cls(dpset.EventDP)
    def on_dp_change(self, ev):
        print("datapath event", ev.enter)

Service を使った on switch ready なポイントとして、次のような例もアリです。

app3.py
import ryu.topology.event
from ryu.base import app_manager
from ryu.controller.handler import set_ev_cls

class App3(app_manager.RyuApp):
    @set_ev_cls(ryu.topology.event.EventSwitchEnter)
    def on_enter(self, ev):
        print("switch ready")

Dependent singleton

サービス化されていない形のものとして、RyuApp._CONTEXTS に明示的に依存するクラスを登録して使う方法もあります。起動時に singleton として生成され、RyuApp.__init__ の kwargs 経由で渡されます。

app4.py
from ryu.base import app_manager

class A(object):
   def __init__(self):
       print("init A")

class App4(app_manager.RyuApp):
    _CONTEXTS = dict(a=A)
    def __init__(self, *args, **kwargs):
        super(App4, self).__init__(*args, **kwargs)
        print(kwargs)

この例は openflow メッセージに対するハンドラを設定していないので、初期化完了後に exit します。ryu 自体は event hub であり、openflow プロトコルは ofp_event カテゴリのイベントで駆動されるアプリケーションの一つ、という発想で作られているようです。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3