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 から容易にできるようになった。