◆ 単純なブリッジの実装【OpenFlow1.0をTremaの土管として使う】
[2013/10/25 追記。テスト結果を加執しました]
前回の記事の方針をもとにして、2ポートのブリッジを作成しました。今回は何も機能がなくて、MAC の学習機能もフィルタリング機能もなく、リピーターと変わりません。
■Tremaのコード
class SimpleBridge < Controller def start @port_list = [ 1, 2 ] # all port numbers end def switch_ready( datapath_id ) info "Switch[0x%016x] is up." % datapath_id send_flow_mod_add( datapath_id, :priority => 100 ) @port_list.each do | port | send_flow_mod_add( datapath_id, :match => Match.new( :in_port => port ), :actions => SendOutPort.new( OFPP_CONTROLLER ) ) end end def switch_disconnected( datapath_id ) info "Switch[0x%016x] is disconnected." % datapath_id end def packet_in( datapath_id, message ) return unless message.reason == Trema::PacketIn::OFPR_ACTION if ( message.in_port == @port_list[0] ) target_port = @port_list[1] else target_port = @port_list[0] end send_packet_out( datapath_id, :packet_in => message, :actions => SendOutPort.new( target_port ) ) end end
■解説
実現しているのは以下の機能:
(1) 1番ポートから入って来たパケットを2番ポートへ送る。
(2) 2番ポートから入って来たパケットを1番ポートへ送る。
それだけです。
start
対象とする2つの OpenFlow ポートの番号をインスタンス変数の配列 @port_listに格納しています。
ここを書き換えれば 1, 2 番以外のポートを対象にすることができます。
switch_ready
OpenFlowスイッチが接続してきたらフローエントリを登録します。
登録しているエントリは3つです。
・フローエントリ1
パケットを捨てる。
優先度(priority)を 100 と低くしています。これにより、次に示すフローエントリ2,3に合致しないパケットに対して適用されるフローエントリにしています。
つまり、対象とする2つの OpenFlow ポート以外のパケットは捨てるという動作を OpenFlow スイッチにさせています。
・フローエントリ2、および 3
対象とする2つの OpenFlow ポートに入ってきたパケットを OpenFlow コントローラに送る。
Trema のデフォルトでは優先度は 65535 でフローエントリを登録するので 100 より優先されます。
参照:http://rubydoc.info/github/trema/trema/master/Trema/Controller:send_flow_mod_add
:priority (Number) ? default: 0xffff - The priority level of the flow entry.
packet_in
1行目は、パケットが入ってきた理由が OFPR_ACTION (アクションにより届いたパケット)かどうかを判定しています。
フローエントリ2、3以外の理由でパケットが入ってきた場合は return で抜けて何もしない(=パケットを捨てる)ようしています。
これにより、フローエントリの登録が完了する前にOpenFlowスイッチが受信したパケットが要因で packet_in が呼ばれた場合でも何もしないようにしています。
前回の記事で考察したように、パケットのデータに欠けがないパケットのみを処理対象にするためにアクションにより届いたパケットのみを扱うようにしています。
2行目からは、入って来たポート番号を確認し、もう一方のポートにパケットを送りだしています。
では、実行してみます。
■実行環境
・OS: Lubuntu 13.04 Desktop (i386)
・Trema: 0.4.3
・Ruby: 1.9.3p194
■Trema の仮想ネットワークによる実行
(1) 仮想ネットワーク定義
vswitch("ofs1") {
datapath_id "0x1"
}
netns("host1") {
ip "192.168.0.1"
netmask "255.255.255.0"
}
netns("host2") {
ip "192.168.0.2"
netmask "255.255.255.0"
}
link "host1", "ofs1"
link "host2", "ofs1"
(2) 実行前の下準備
Trema の仮想ネットワークに勝手にパケット流して邪魔するのでテストの間はネットワークマネージャを一時停止しておきます。
$ sudo service network-manager stop
network-manager stop/waiting
(3) Trema の起動
ここでは、Trema のコードのファイル名を SimpleBridge.rb とし、仮想ネットワーク定義のファイル名を vnet-2netns.conf としています。
$ trema run SimpleBridge.rb -c vnet-2netns.conf
Switch[0x0000000000000001] is up.
(4) ping の実行
別の端末を用意して、host1 から host2(192.168.0.2) へ ping をパケットサイズ1000で実行します。
$ sudo ip netns exec host1 ping -c3 -s1000 192.168.0.2
PING 192.168.0.2 (192.168.0.2) 1000(1028) bytes of data.
1008 bytes from 192.168.0.2: icmp_req=1 ttl=64 time=81.8 ms
1008 bytes from 192.168.0.2: icmp_req=2 ttl=64 time=29.5 ms
1008 bytes from 192.168.0.2: icmp_req=3 ttl=64 time=28.7 ms
--- 192.168.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2001ms
rtt min/avg/max/mdev = 28.799/46.737/81.846/24.828 ms
128バイトを超えるパケットもきちんと応答が返りました。テスト成功です。
(5) Trema の終了
以下のコマンドでTremaを終了させます:
$ trema killall
すると、trema run を実行していた端末では以下が出力されて trema が終了しています。
Switch[0x0000000000000001] is disconnected.
(6) 必要なら...ネットワークマネージャの再起動
以下のようにして再起動します:
$ sudo service network-manager start
network-manager start/running, process 313
上記の313の箇所はプロセスIDなので実行ごとに異なる値です。
最近のコメント