Cookie 記入拡張

Cookie の値を自分で設定する


フローテーブルの中の 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 を起動する。

Cookie の操作(C++)

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
といった値になる。

Python での Cookie

C++ のコードでは普通に cookie の記入ができた。 それだけなら簡単で良かったが Python API にはそれがない。

NOX の Python API を改造して Cookie を直接扱えるようにする

Python ライブラリが Cookie 対応していない

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 に入っていない?よく調べてないない。。)
C++にはあるが Python wrapper にはない
先の記事でのパッチには以下のような記述がある。
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 から容易にできるようになった。



Yutaka Yasuda (yasuda [ at ] ylb.jp)