Cookie の値を自分で設定する
OpenFlow のフローテーブルの出力に Cookie なるものがある。64bit 。 これをとりあえず NOX のコントローラプログラムの中で記入することが出来ないか。
クッキーは ovs-ofctl の dump-flows で確認することが出来る。 # ovs-ofctl dump-flows br0 NXST_FLOW reply (xid=0x4): cookie=0x0, duration=5.382s, table_id=0, n_packets=1, n_bytes=238, idle_timeout=5,udp,in_port=1,vlan_tci=0x0000,dl_src=00:16:01:71:79:ea,dl_dst=00:03:47:89:8f:e5,nw_src=192.168.12.1,nw_dst=192.168.12.47,tp_src=53,tp_dst=42413 actions=output:2 cookie=0x0, duration=5.427s, table_id=0, n_packets=1, n_bytes=86, idle_timeout=5,udp,in_port=2,vlan_tci=0x0000,dl_src=00:03:47:89:8f:e5,dl_dst=00:16:01:71:79:ea,nw_src=192.168.12.47,nw_dst=192.168.12.1,tp_src=42413,tp_dst=53 actions=output:1 # 値は全部 0 だが、ovs-ofctl の add-flows のオプションとして cookie の登録機能がある。 $ man ovs-ofctl で、 The add-flow, add-flows, and mod-flows commands support an additional optional field: cookie=value A cookie is an opaque identifier that can be associated with the flow. value can be any 64-bit number and need not be unique among flows. とある。適当に調べると 1.0 から 64bit の cookie が追加された模様。
このゼロ(0x0)の部分に何か値を入れるようなコントローラを作成してそれを使って NOX を起動する。
C++ のコードには確かに Cookie 対応処理が入っている。
例えば C++ 版 pyswitch とも言うべき単純 MAC learning switch である
/home/hoge/nox/src/nox/coreapps/switch/switch.cc
にも Cookie を操作する処理がある。
Switch::handle(const Event& e) 関数の /* Set up a flow if the output port is known. */ の部分に、 ofm = (ofp_flow_mod*) raw_of.get(); して作った ofm に対して、 ofm->match.in_port = htons(flow.in_port); とかしたり、 ofm->cookie = htonl(0); などとしている。(これだ!)その後、 ofm->command = htons(OFPFC_ADD); して、 send_openflow_command(pi.datapath_id, &ofm->header, true); をやっている。
上記の ofm->cookie = を例えば htonl(100) などと修正して make し直してやれば、実際にフローテーブルの中の Cookie が 100 になっていることが確認できる。
ただし ovs-ofctl の dump-flow は hexadecimal でホストバイトオーダーのまま出すので、 # ovs-ofctl dump-flows br0 NXST_FLOW reply (xid=0x4): cookie=0x6400000000000000, duration=2.327s, table_id=0, n_packets=1, n_bytes=98, idle_timeout=51,icmp,in_port=3,vlan_tci=0x0000,dl_src=00:16:01:71:79:ea,dl_dst=00:03:47:b7:22:46,nw_src=211.9.56.37,nw_dst=192.168.12.36,icmp_type=0,icmp_code=0 actions=output:1 といった値になる。
C++ のコードでは普通に cookie の記入ができた。 それだけなら簡単で良かったが Python API にはそれがない。
http://permalink.gmane.org/gmane.network.nox.devel/2065
[PATCH] support passing the 64-bit cookie in send_flow_command from Python code
という記事がある。これ、2010 Dec の記事。
ざっと読むと、
「C++ 実装は全てのコマンドで Cookie を渡せるけど Python wrapper にはそれがない」<<< おいおいおいおい!
ので、そのためのパッチ、ということらしい。
core.py の diff として、以下のように install_datapath_flow( ) 関数など主要なものが含まれている。
def install_datapath_flow(self, dp_id, attrs, idle_timeout, hard_timeout, <<< 実際上 install_datapath_flow で Cookie をセットするのが最適なのでこれは良い actions, buffer_id=None, priority=openflow.OFP_DEFAULT_PRIORITY, - inport=None, packet=None): + inport=None, packet=None, cookie=0): <<< 引数を増やしている で、残念ながらインストールした NOX のソースコードを見たが、それには反映されていない。 (ひょっとしてまだ全く git に入っていない?よく調べてないない。。)
先の記事でのパッチには以下のような記述がある。 diff --git a/src/nox/coreapps/pyrt/context.i b/src/nox/coreapps/pyrt/context.i index 803513d..560c84e 100644 --- a/src/nox/coreapps/pyrt/context.i +++ b/src/nox/coreapps/pyrt/context.i @@ -96,7 +96,8 @@ public: void send_flow_command(uint64_t datapath_id, ofp_flow_mod_command, const ofp_match&, uint16_t idle_timeout, uint16_t hard_timeout, const Nonowning_buffer& actions, - uint32_t buffer_id, uint16_t priority); + uint32_t buffer_id, uint16_t priority, + uint64_t cookie=0); 実際に手元にインストールした NOX のコードを見ると、 coreapps/pyrt/context.i は void send_flow_command(uint64_t datapath_id, ofp_flow_mod_command, const ofp_match&, uint16_t idle_timeout, uint16_t hard_timeout, const Nonowning_buffer& actions, uint32_t buffer_id, uint16_t priority); となっており、パッチ前の状態。 が、coreapps/pyrt/pycontetxt.hh (C++ のヘッダ) void send_flow_command(uint64_t datapath_id, ofp_flow_mod_command command, const ofp_match& match, uint16_t idle_timeout, uint16_t hard_timeout, const Nonowning_buffer&, uint32_t buffer_id, uint16_t priority=OFP_DEFAULT_PRIORITY, uint64_t cookie); となっており、あるぢゃん! coreapps/pyrt/pycontetxt.cc でも void PyContext::send_flow_command(uint64_t datapath_id, ofp_flow_mod_command command, const ofp_match& match, uint16_t idle_timeout, uint16_t hard_timeout, const Nonowning_buffer& actions, uint32_t buffer_id, uint16_t priority , uint64_t cookie) { .... ofm->cookie = cookie; となっている。これが C++ インタフェイスでは追加されたが Python にはない、という話の実体か。
(send_flow_command 関数は send_openflow_command 関数の wrapper になっており、
send_flow_command 関数を cookie 引数つきで呼び出すと、内部で ofc->cookie に代入して、
send_openflow_command 関数を呼び出すようになっている。see; pycontext.cc )
というわけで、このパッチを当ててみるか?
先のパッチを実際に適用する。対象ファイルは ./nox/coreapps/pyrt/context.i と ./nox/lib/core.py の二つ。成功したら、以下のようにして再ビルド。 # cd /home/hoge/nox/build # make -j 5 正しく pyrt だけ rebuild されたことを確認した。
この状態で NOX を pyswitch で再起動して正常動作を確認する。(この時点では Cookie はゼロ) 次に pyswitch.py を修正して、inst.install_datapath_flow() 呼び出しの最終引数に Cookie 値として100を追加。 /home/hoge/nox/build/src/nox/coreapps/examples/ylbswitch.py inst.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, openflow.OFP_FLOW_PERMANENT, actions, bufid, openflow.OFP_DEFAULT_PRIORITY, inport, buf, 100) << これが Cookie この状態で NOX を pyswitch で再起動し、トラフィックを流して ovs-ofctl dump-flows br0 でクッキー値を確認。 # ovs-ofctl dump-flows br0 NXST_FLOW reply (xid=0x4): cookie=0x6400000000000000, duration=2.327s, table_id=0, n_packets=1, n_bytes=98, idle_timeout=51,icmp,in_port=3,vlan_tci=0x0000,dl_src=00:16:01:71:79:ea,dl_dst=00:03:47:b7:22:46,nw_src=211.9.56.37,nw_dst=192.168.12.36,icmp_type=0,icmp_code=0 actions=output:1 と、正しく Cookie 値が 100 (バイトオーダーの関係で 0x6400... )であることが確認できた。
以上で Cookie の記入が Python から容易にできるようになった。