Contenu connexe Similaire à Rubyで創るOpenFlowネットワーク - LLまつり (20) Rubyで創るOpenFlowネットワーク - LLまつり2. 2
おしながき
1. イントロ(2分)
2. SDNとOpenFlowのはなし(10分)
3. Tremaのはなし(8分)
※簡単のためバージョン間の差異異などに触れないので、この資料料をreferenceにしないでください
3. 3
川上
雄也 (@yuyarin)
2008年年4⽉月
株式会社ドワンゴ 研究開発本部
ニコニコ動画のバックエンドシステムの開発
2011年年4⽉月 NTTコミュニケーションズ
2011年年8⽉月
インターネットマルチフィード
技術部
JPNAPのネットワークエンジニア
10/100GbE(広帯域L2網)、DWDM、BGP、鯖・ツール類等
コミュニティ活動
JANOG30&31、InteropTokyo2012&2013 スタッフ
wakamonog, ハチロク世代
代表幹事
7. 7
これまでのネットワーク
それぞれのネットワーク機器(ルータやスイッチ)が⾃自律律協調して動作
個々の機器に対してログインして操作(CLI)、個々の機器から情報収集(NMS)
Control Plane
Data Plane
App/Service
Control Plane
Data Plane
App/Service
Control Plane
Data Plane
App/Service
CLI/NMS/Tool
Router/Switch
Router/Switch
Router/Switch
13. 13
開流
`
L2
マッチに使える条件の例例
⼊入⼒力力ポート番号
送信元MACアドレス
宛先MACアドレス
Ethernet Type
VLAN ID
VLAN Priority
送信元IPアドレス
宛先IPアドレス
IP Protocol
送信元ポート番号
宛先ポート番号
L3
L4
15. 15
⽤用語の説明
フロー
MACアドレスやVLAN ID、IPアドレスやポート番号などのフィールド
の組み合わせで識識別される⼀一連のパケットの流流れ
フローテーブル
マッチングルール(ヘッダフィールド)、アクション、統計情報の要
素からなるフローエントリを登録するテーブル
Packet-In
フローテーブルのエントリにマッチしなかった場合やコントローラで
の処理理が必要な時に、スイッチからパケットをコントローラに送ること
Packet-Out
コントローラからスイッチにパケットを送らせると
22. 22
OpenFlowの規格とフレームワーク
Ver.
Framework
1.0
NOX(C++), POX(Python),
Trema(C, Ruby), Floodlight(Java)
1.1
1.2
POX1.2(Python)
1.3
Trema-edge(C, Ruby),
Floodlight(Java)
26. 26
取間
Tremaのいいところ
イベントドリブンで書ける
ネットワークエミュレータがついてる
他のフレームワークより少ない⾏行行数で同じ機能を書ける
サンプルコードが豊富
開発者が⽇日本⼈人で⽇日本語の記事が多い
⽇日本語の本がある
しかも⾃自前でTeXをコンパイルしたらタダ
Rubyだ
28. 28
取間
Trema-edgeのインストール
1. Ubuntu 12.04 (64-bit) を⽤用意する
2. RVMをインストールする
curl -L https://get.rvm.io | bash -s stable
3. 必要なパッケージをインストールする
sudo apt-get install gcc make libsqlite3-dev libpcap-dev libssl-dev git
4. trema-edgeをcloneする
git clone https://github.com/trema/trema-edge.git
cd trema-edge
5. Ruby 2.0.0-p0をインストールする
rvm install ruby-2.0.0-p0
rvm use 2.0.0-p0 -default
6. trema-edgeをビルドする
bundle install
rake
./trema --version
29. 29
取間
Tremaの使い⽅方
コントローラをデーモンとして起動
コントローラをネットワークエミュレータと起動
ネットワークエミュレータを操作する
trema run -d mycontroller.rb
trema run mycontroller.rb -c mynetwork.conf
trema send_packets -source host1 -dest host2
trema show_stats host1 -r
31. 31
イベントハンドラの例例
handler
発⽣生条件
start
コントローラ起動時
switch_ready
OFスイッチが起動した
switch_disconnected
OFスイッチが切切断された
packet_in
Packet-Inが発⽣生した
flow_removed
フローエントリが時効で削除された
port_status
ポートの状態が変わった
32. 32
スイッチの操作の例例
handler
発⽣生条件
send_flow_mod_add
フローエントリを追加する
send_flow_mod_delete フローエントリを削除する
send_flow_mod_modify
フローエントリを修正する
send_packet_out
Packet-Outを発⽣生させる
33. 33
コントローラの書き⽅方の例例
class MyController < Controller
def switch_ready datapath_id
action = SendOutPort.new( port_number: OFPP_CONTROLLER, max_len: OFPCML_NO_BUFFER )
apply_ins = ApplyAction.new( actions: [ action ] )
send_flow_mod_add( datapath_id, priority: OFP_LOW_PRIORITY,
buffer_id: OFP_NO_BUFFER,
instructions: [ apply_ins ] )
end
def packet_in datapath_id, message
# ...
send_flow_mod_add(
datapath_id,
:match => Match.new( :in_port => message.in_port, ...),
:actions => [ StripVlanHeader.new, SendOutPort.new(port_no) ] )
send_packet_out(
datapath_id,
:packet_in => message )
end
# ...
end
※内容に意味はありません
Packet-Inを起こすアクション
マッチするエントリがない場合は
Packet-Inを起こすように設定
マッチングルールとアクションの対を
作成してフローテーブルに登録
Packet-Inしたパケットを送り返す
34. 34
MAC学習L2スイッチ (1/2)
class LearningSwitch < Controller
def start
@fdb = FDB.new
end
def switch_ready datapath_id
action = SendOutPort.new( port_number: OFPP_CONTROLLER, max_len: OFPCML_NO_BUFFER )
ins = ApplyAction.new( actions: [ action ] )
send_flow_mod_add( datapath_id, priority: OFP_LOW_PRIORITY,
buffer_id: OFP_NO_BUFFER,
flags: OFPFF_SEND_FLOW_REM,
instructions: [ ins ] )
end
def packet_in datapath_id, message
@fdb.learn message.eth_src, message.in_port
port_no = @fdb.port_no_of( message.eth_dst )
if port_no
flow_mod datapath_id, message, port_no
packet_out datapath_id, message, port_no
else
flood datapath_id, message
end
end
⼊入⼒力力ポートでMACを学習
出⼒力力ポートが決まったらフローを
登録してPacket-Out
出⼒力力ポートが未学習だったら
フラッディングする
デフォルトPacket-In
35. 35
MAC学習L2スイッチ (2/2)
private
def flow_mod datapath_id, message, port_no
action = SendOutPort.new( port_number: port_no )
ins = Instructions::ApplyAction.new( actions: [ action ] )
send_flow_mod_add( datapath_id, match: ExactMatch.from( message ),
instructions: [ ins ])
end
def packet_out datapath_id, message, port_no
action = Actions::SendOutPort.new( port_number: port_no )
send_packet_out( datapath_id, packet_in: message,
actions: [ action ] )
end
def flood datapath_id, message
packet_out datapath_id, message, OFPP_ALL
end
end
36. 36
ネットワークエミュレータの設定
trema_switch( "lsw" ) {
datapath_id "0xabc"
}
vhost ("host1") {
ip "192.168.0.1"
netmask "255.255.0.0"
mac "00:00:00:01:00:01"
}
vhost ("host2") {
ip "192.168.0.2"
netmask "255.255.0.0"
mac "00:00:00:01:00:02"
}
link "host1", "lsw:1"
link "host2", "lsw:2"
Open vSwitch
lsw
Trema
Controller
phost
host1
phost
host2
1
2
37. 37
テスト駆動開発ができる!
describe RepeaterHub do
it "は、⼊入ってきたパケットを他のすべてのポートに転送する" do
network {
vswitch( "switch" ) { dpid "0xabc" }
vhost( "host1" ) { promisc "on" }
vhost( "host2" ) { promisc "on" }
vhost( "host3" ) { promisc "on" }
link "switch", "host1"
link "switch", "host2"
link "switch", "host3"
}.run( RepeaterHub ) {
send_packets "host1", "host2"
# host2 と
host3 がひとつずつパケットを受け取る
vhost( "host2" ).stats( :rx ).should have( 1 ).packets
vhost( "host3" ).stats( :rx ).should have( 1 ).packets
}
end
end