« 2012年12月 | トップページ | 2013年2月 »

2013年1月

2013年1月29日 (火)

【TremaでOpenFlowプログラミング】リピーターハブを5行で作る

OpenFlow フレームワーク Trema についてくるサンプルにすでにリピーターハブがあるし、ネットを検索すると実装例が見つかります。しかし、どうもそれらは冗長[※1]な気がして、短く簡潔に実装してみたくなりました。

以前、OpenWRT with OpenFlow 1.0 にてコマンドを実行してフローを追加しましたが、今回はそれの Trema 版です。以前と同様に、OpenFlow スイッチが FLOOD をサポートしていることを前提にしています。

■コード

class MultiRepeaterHub < Controller
  def switch_ready( datapath_id )
    send_flow_mod_add( datapath_id, :actions => SendOutPort.new( OFPP_FLOOD ) )
  end
end

たった5行です。それでも、複数台の OpenFlow スイッチにも対応しています。

■仮想ネットワークでテスト

構成は2台のホストを2つの OpenFlow スイッチでつないだ構成でテストします。

  host1(192.168.0.1)  --- sw1 --- sw2 --- host2(192.168.0.2)

仮想ネットワークの定義:

vswitch( "sw1" ) {
  datapath_id "0x1"
}
vswitch( "sw2" ) {
  datapath_id "0x2"
}
vhost( "host1" ) {
  ip "192.168.0.1"
}
vhost( "host2" ) {
  ip "192.168.0.2"
}

link "sw1", "host1"
link "sw1", "sw2"
link "sw2", "host2"

テスト結果:

今回は、テストする前に、こちらの記事に該当するので回避策を実施しておきました。

$ trema dump_flow sw1      --- (1)
NXST_FLOW reply (xid=0x4):
 cookie=0x1, duration=12.715s, table=0, n_packets=0, n_bytes=0, priority=65535 actions=FLOOD
$ trema dump_flow sw2      --- (2)
NXST_FLOW reply (xid=0x4):
 cookie=0x1, duration=15.822s, table=0, n_packets=0, n_bytes=0, priority=65535 actions=FLOOD
$ trema show_stats host2   --- (3)
Sent packets:

Received packets:

$ trema send_packets --source host1 --dest host2  --- (4)
$ trema show_stats host2   --- (5)
Sent packets:

Received packets:
ip_dst,tp_dst,ip_src,tp_src,n_pkts,n_octets
192.168.0.2,1,192.168.0.1,1,1,50

(1)(2) OpenFlow スイッチ sw1, sw2 にフローエントリが登録されていることを確認。

(3) パケットを飛ばす前はまだ host2 の統計情報は空であることを確認。

(4) host1 から host2 へパケットを送付。

(5) host2 の統計情報において、 192.168.0.1(host1)から送られたパケットを受信したことを確認。


※1

  Trema(0.3.3) 付属のサンプルやネットで見つかるリピーターハブの実装は、なぜか packet_in を受けてからフローを追加しています。しかし、リピーターの役割を考えれば不要な処理です。任意のパケットを FLOOD の対象にして良いのですから、packet_in を待つ必要がありません。

Lubuntu 12.10 で Trema の仮想ネットワーク機能を使うときはネットワークマネージャーを止めましょう

OpenFlowフレームワーク Trema で仮想ネットワーク機能を使ってテストしていると、まだ全く通信をしていないのに trema dump_flow の出力結果ではどんどんと通信パケットが増えているという謎の現象が発生しました。

■発生OS:

   Lubuntu 12.10 Desktop (i386)

  Ubuntu 12.10 Desktop でも同じではないかと思います。

   また、Lubuntu 12.04 Desktop では起きていないので 12.10 からの現象のようです。

■現象:

  通信をさせていないのに、フローエントリに一致して処理したパケット数 n_packets およびバイト数 n_bytes のところがどんどん増えていきます。

$ trema dump_flow sw1
NXST_FLOW reply (xid=0x4):
 cookie=0x1, duration=41.285s, table=0, n_packets=55, n_bytes=11670, priority=65535 actions=FLOOD
$ trema dump_flow sw1
NXST_FLOW reply (xid=0x4):
 cookie=0x1, duration=42.994s, table=0, n_packets=58, n_bytes=11928, priority=65535 actions=FLOOD
$ trema dump_flow sw1
NXST_FLOW reply (xid=0x4):
 cookie=0x1, duration=44.851s, table=0, n_packets=64, n_bytes=12432, priority=65535 actions=FLOOD

  今回は、どんな内容のパケットにもマッチするフローエントリだったので変なパケットが飛んでくると皆引っかかってしまいます。

どうも、Lubuntu 12.10 ではネットワークマネージャーが余計なことに Trema が追加したネットワークインタフェースを検出して悪さしているようです。

画面右下のネットワークマネージャところをクリックしてみると、"Trema" と名前がついたインタフェースが検出されてしまっています。

Networkservice


■回避策:

   Trema の仮想ネットワークを使っている時はネットワークマネージャーを一時的に停止します。

$ sudo service network-manager stop

再開するには、以下のコマンドを実行します:

$ sudo service nework-manager start

2013年1月27日 (日)

書籍『OpenFlow ネットワーク入門』は、Trema の解説書だった

『OpenFlow実践入門』を見ながら OpenFlow コントローラのフレームワークである Trema で動くコードを書き始めたみた。が、どうにも理解が進まなくて困ってしまった。

この本はサンプルコードを解説する形で説明していて、それはそれで面白いけど、Trema 自体の体系的な説明がされていない。また、説明されている機能はごく一部でしかない。

足りないところは、Trema API (http://rubydoc.info/github/trema/trema/master/frames/index) のページで補おうとしてみたけど、このページは Trema のクラスやメソッドのリファレンスでしかないのでやっぱり全体像が見えてこない。(さらにやっかいなことに、この API のページは英語で書いてある)

ネットで検索しても断片的な解説しか見つからない。

...困ってしまった。

と、そんな時、状況を一変させてくれる本に出会った。『OpenFlowネットワーク入門』(コロナ社)だ。

この本、第5章以降はすべて Trema の解説となっていて Trema API の形で OpenFlow 1.0 の解説をしてくれています。要は、OpenFlow 1.0 の規格を Trema とともに勉強できる。

OpenFlow 1.0 の勉強と Trema の勉強が両方できて一粒で二度おいしい。

この本のおかげで、困った状況が解消されてかなり理解が進みました。

OpenFlow 1.0 の完全解説書ではないので説明が足りないところはあるが、 OpenFlow 1.0 の規格書を直接に参照して補えば良い(http://www.openflow.org/documents/openflow-spec-v1.0.0.pdf)。

■書籍『OpenFlowネットワーク入門』の残念な点

(1) 「第2章 OpenFlow ネットワークの構造と動作」の解説が OpenFlow 1.0 より後のバージョンの OpenFlow を扱っている点(たぶん、OpenFlow 1.1 か 1.2 あたり)。 一方、Trema は OpenFlow 1.0 にしか対応していない(現時点では)。 OpenFlow 1.0 とは異なる動作を説明してしまっていて、読者を混乱させてしまう。

(2) 扱っているTrema のバージョンが少し古い。「5.1 Trema」(P.85) にて「本書では trema のバージョン 0.2.5 を用いたコントローラの開発について述べる」と書いてあり、現時点の 0.3.3 より古い。説明されていない Trema の新機能があるかもしれない。

2013年1月26日 (土)

Tremaコントローラが勝手に終了してしまう現象の回避方法

書籍『OpenFlow実践入門』(初版)の P.292 には、実機の OpenFlow スイッチをラーニングスイッチとして動かしてフローエントリを表示するという手順が書いてあります。
ところが困ったことに、フローエントリを表示するコマンドを実行するとデーモンとして起動しておいたコントローラのプロセスが必ず終了してしまう現象が発生します。
使用している Trema のバージョンは現時点での最新である trema 0.3.3 です。
正しい方法なのか分からないですが回避策を見つけたので書いておきます。

回避策:
  空のファイルを作成し、コントローラ起動時に -c オプションで指定する。
 (つまり、中身のない仮想ネットワークの定義を指定します。)

空のファイルを ~/emtpy.conf に作るとすると、p.292 の1行目に記載のコントローラの起動を以下のようにすれば良いわけです(あくまでいち例です。他のやり方でも構いません)。

$ cp /dev/null ~/empty.conf
$ trema run ./learning-switch.rb -d -c ~/empty.conf

ちなみに、デーモンで起動したコントローラを停止する方法ですが「5.5 trema コマンド」の P.73 に書いてあるとおり、以下を実行します。

$ trema killall

p.s
  OpenWRT with OpenFlow 1.0 を入れたMZK-W300NH2 で試していて、コントローラと切断してしまう現象がやたらおきるのでしばらく悩んでしまいましたが上記の現象でした...。

2013年1月19日 (土)

書籍『OpenFlow実践入門』でTremaをインストール

[ 2013年10月5日 追記。Tremaのバージョンが 0.3.x から 0.4.x に上がって色々と変わってきています。最新の情報は、https://github.com/trema/trema を確認ください。また、0.4.3 のインストール記事「◆ OpenFlowフレームワーク Trema 0.4 のインストール」を書きました。]

[ 2012年2月1日 追記。 本記事に、書籍著者かつTrema開発者様よりコメントいただきました。多謝です。  --version が正しく動かない件は Trema 側で修正いただいたとのこと。

ソースからコンパイルし、正しく動くことを確認しました。確認時の バージョンは 0.3.5 です。

また、rvm を使う場合には gem install trema の実行に sudo が必要とはいえないとのことで rvm を使うケースだと別のインストール手順が必要そうです。]


『OpenFlow実践入門』が技術評論社から出版されていたのでさっそく購入してみました。

本の解説を元に OpenFlow コントローラである Trema のインストールをしようとしたら色々とつまづいたのでここに書き残しておきます。

今回使ったインストール環境:
  Lubuntu 12.10 desktop (i386)
  (2013年1月18日にソフトウェアアップデート済)

  クリーンインストール状態から実施しました。

ここで記載している節、ページは『OpenFlow実践入門』初版第1刷のものです。

Trema のインストールについては「5.3 Trema のセットアップ」(P.68) から記載されています。
パッケージを使う方法と、ソースからビルドする方法がありますがまずはパッケージを使う方法からやってみました。

■手順1: 前提パッケージの導入
  P.69 下の注1にあるように Ubuntu 12.10 以降は Ruby1.9 がデフォルトになっているので読み替えが必要。
  なので、Lubuntu 12.10 でも同じように読み替えます。
  P.69 注1の記載に誤記が1つあります:「ruby-dev1.8」→「ruby1.8-dev」

$ sudo apt-get install gcc make ruby1.8 rubygems1.8 ruby1.8-dev irb libpcap-dev libsqlite3-dev

P.68 に、Trema は 1.8.7 が必要だと書いてあるので ruby1.8 のバージョン確認をしてみます:

$ dpkg -l ruby1.8

要望=(U)不明/(I)インストール/(R)削除/(P)完全削除/(H)維持
| 状態=(N)無/(I)インストール済/(C)設定/(U)展開/(F)設定失敗/(H)半インストール/(W)トリガ待ち/(T)トリガ保留
|/ エラー?=(空欄)無/(R)要再インストール (状態,エラーの大文字=異常)
||/ 名前         バージョ アーキテ 説明
+++-==============-============-============-=================================
ii  ruby1.8        1.8.7.358-4u i386         Interpreter of object-oriented sc

1.8.7 と出ているので Trema の前提を満たしています。

■手順2:  Ruby1.8 への切替
  本には記載がない手順です。
  Trema は Ruby1.8 で動かす必要があるのですが、Lubuntu 12.10 ではデフォルトが Ruby1.8 ではなく Ruby1.9 なので 1.8 を使うように切り替えておきます。
  この切替をしていないと、trema のインストールでエラーになりました。

$ sudo update-alternatives --config ruby

alternative ruby (/usr/bin/ruby を提供) には 2 個の選択肢があります。

  選択肢    パス              優先度  状態
------------------------------------------------------------
* 0            /usr/bin/ruby1.9.1   51        自動モード
  1            /usr/bin/ruby1.8     50        手動モード
  2            /usr/bin/ruby1.9.1   51        手動モード

現在の選択 [*] を保持するには Enter、さもなければ選択肢の番号のキーを押してください: 

ここで 1 を選んで /usr/bin/ruby で /usr/bin/ruby1.8 が動くようにします。

同様に gem も切り替えておきます。

$ sudo update-alternatives --config gem

alternative gem (/usr/bin/gem を提供) には 2 個の選択肢があります。

  選択肢    パス             優先度  状態
------------------------------------------------------------
* 0            /usr/bin/gem1.9.1   181       自動モード
  1            /usr/bin/gem1.8     180       手動モード
  2            /usr/bin/gem1.9.1   181       手動モード

現在の選択 [*] を保持するには Enter、さもなければ選択肢の番号のキーを押してください: 

ここで 1 を選び /usr/bin/gem1.8 が動くようにします。

■手順3: Trema パッケージをインストール

  本の記載には sudo が抜けています。

$ sudo gem install trema

手順2を抜かしてしまうとここで以下のエラーが出てしまいます:

ERROR:  Error installing trema:
	ERROR: Failed to build gem native extension.

        "/usr/bin/ruby1.9.1" -rubygems /var/lib/gems/1.9.1/gems/rake-10.0.3/bin/rake RUBYARCHDIR=/var/lib/gems/1.9.1/gems/trema-0.3.3/ruby RUBYLIBDIR=/var/lib/gems/1.9.1/gems/trema-0.3.3/ruby
cannot load such file -- bundler/gem_tasks
cannot load such file -- rspec/core
cannot load such file -- cucumber/rake/task
cannot load such file -- reek/rake/task
cannot load such file -- roodi
cannot load such file -- flog
cannot load such file -- flay
cannot load such file -- yard
./build.rb
.mono.rant:419: syntax error, unexpected ':', expecting keyword_then or ',' or ';' or '\n'
	    when String: obj
	                ^
.mono.rant:427: warning: else without rescue is useless
.mono.rant:462: syntax error, unexpected keyword_end, expecting $end
end # module Rant
   ^
./build.rb aborted!
rake aborted!
Command failed with status (1): [./build.rb...]
/var/lib/gems/1.9.1/gems/trema-0.3.3/Rakefile:24:in `block in 

' Tasks: TOP => default (See full trace by running task with --trace) Gem files will remain installed in /var/lib/gems/1.9.1/gems/trema-0.3.3 for inspection. Results logged to /var/lib/gems/1.9.1/gems/trema-0.3.3/./gem_make.out

■手順4: バージョン確認
  本には「--version」とありますが、実行結果からするとハイフンなしの「version」

$ trema version
trema version 0.3.3

本では 0.3.0 ですが、すでに 0.3.3 になっていました。

これでインストールは完了です。

 (なぜか --version だと、--help と同じ結果がでます。
手元で確認できる古いバージョン Trema 0.2.5 では --version で version と
同じ結果が出力されるのでどこかでバグを作りこんだのでしょうか...)

■動作確認 "Hello, Trema!"
 「5.4 Hello, Trema」(p.71) のコードには脱落が1箇所あります。
  これについては、すでに正誤表が公開されていて記載がありました:
    http://gihyo.jp/book/2013/978-4-7741-5465-7/support

  誤: class HelloTrema Controller
  正: class HelloTrema < Controller

■Trema ファイルはどこ?
  パッケージで Trema をインストールした場合だと、「5.7 Trema のファイル構成」(P.79) で説明されているファイル群はどこにあるのでしょう?
 探ってみると、以下にありました:
   /var/lib/gems/1.8/gems/trema-0.3.3

 本で説明されているコードは、このディレクトリの下の src/examples というディレクトリにあります。

■ソースコードからインストールする場合
  「ソースコードから最新版をインストールする場合」(p.70)に記載されている方法でソースでも導入してみました。注意点だけ書いておきます。
本には記載がないですが、git を使うので当然事前に git をインストールしておく必要があります。

$ sudo apt-get install git

また、バージョン確認では、先に書いたのと同じ注意点があります。
本には「--version」とありますが、実行結果からするとハイフンなしの「version」

$ ./trema version
trema version 0.3.3

本では trema version 0.3.0 ですが、現時点では 0.3.3 になります。

ちなみに、手順2を抜かすと ./build.rb を実行するところで手順3に書いたエラーがでると思います
(エラーメッセージの内容からの推定で、未確認ですが)。

« 2012年12月 | トップページ | 2013年2月 »

最近のトラックバック

無料ブログはココログ