2013年10月22日火曜日

Tremaを試す ~traffic monitor その1~

こんにちは。鯵王です。

前回のlearning_switchはわかったでしょうか?
learning_switchがわかっていれば、今回のtraffic_monitorもわかると思います。

ではさっそくtraffic_monitorのソースを見て行きましょう。

(traffic-monitor.rb)
 1  require "counter"
 2  require "fdb"
 3  
 4  class TrafficMonitor < Controller
 5    periodic_timer_event :show_counter, 10
 6  
 7    def start
 8      @counter = Counter.new
 9      @fdb = FDB.new
10    end
11  
12    def packet_in datapath_id, message
13      macsa = message.macsa
14      macda = message.macda
15  
16      @fdb.learn macsa, message.in_port
17      @counter.add macsa, 1, message.total_len
18      out_port = @fdb.lookup( macda )
19      if out_port
20        packet_out datapath_id, message, out_port
21        flow_mod datapath_id, macsa, macda, out_port
22      else
23        flood datapath_id, message
24      end
25    end
26  
27    def flow_removed datapath_id, message
28      @counter.add message.match.dl_src, message.packet_count, message.byte_count
29    end
30  
31    private
32  
33    def show_counter
34      puts Time.now
35      @counter.each_pair do | mac, counter |
36        puts "#{ mac } #{ counter[ :packet_count ] } packets (#{ counter[ :byte_count ] } bytes)"
37      end
38    end
39  
40    def flow_mod datapath_id, macsa, macda, out_port
41      send_flow_mod_add(
42        datapath_id,
43        :hard_timeout => 10,
44        :match => Match.new( :dl_src => macsa, :dl_dst => macda ),
45        :actions => ActionOutput.new( out_port )
46      )
47    end
48  
49    def packet_out datapath_id, message, out_port
50      send_packet_out(
51        datapath_id,
52        :packet_in => message,
53        :actions => ActionOutput.new( out_port )
54      )
55    end
56  
57    def flood datapath_id, message
58      packet_out datapath_id, message, OFPP_FLOOD
59    end


このプログラムではlearning switchをベースに以下のような変更をしています。
・パケットの送信回数、送信バイト数を集計し、定期的に画面に表示します
・フローエントリの有効期限を10秒に設定し、フローエントリを削除します
・フローエントリが削除されるタイミングでスイッチから送信回数と送信バイト数を取得します

1~2行目
requireではCounterクラスとFDBクラスを読み込んでいます。
FDBクラスは前回のlearning_switchに出てきたものよりもだいぶシンプルな内容になっています。
Counterクラスはパケットの送信回数と送信バイト数を管理するクラスです。
これらのクラスの説明は後ほど行います。

4行目
TrafficMonitorクラスを定義しています。

5行目
periodic_timer_eventはタイマーでメソッドを実行します。
「show_counter」メソッドを10秒おきに実行します。

6~10行目
startメソッドでCounterクラスのオブジェクトとFDBクラスのオブジェクトを作成しています。
@counterと@fdbはTrafficMonitorクラスの内で参照できます。

12~14行目
packet_inイベントハンドラです。
スイッチのフローテーブルにマッチしないパケットを受け取った時に実行されます。
引数のmessageから送信元のmacアドレスと送信先のmacアドレスを取得し、変数にセットしています。

16行目
@fdb.learnはFDBクラスのメソッドです。
このメソッドはmessageオブジェクトから取得した送信元macアドレスをハッシュキーにして物理ポート番号を@fdbオブジェクトに追加します。
learnメソッドについては後ほど見ます。

17行目
@counter.addはCounterクラスのメソッドです。
このメソッドはmessageオブジェクトから取得した送信元のmacアドレスをハッシュキーにして、パケットの送信回数と送信バイト数を@counterオブジェクトに追加します。
addメソッドについては後ほど見ます。

18行目
@fdb.lookupはFDBクラスのメソッドで、送信先のmacアドレスに対応した物理ポート番号を@fdbオブジェクトから取得するメソッドです。
lookupメソッドについては後ほど見ます。

19~24行目
lookupメソッドで物理ポート番号が取得できた場合は以下の処理を行います。
@fdbオブジェクトから物理ポート番号が取得できた場合、以下の処理を行います。
 49行目にあるpacket_outメソッドを実行し、送信先の物理ポート宛てにパケットを送ります。
 40行目にあるflow_modメソッドを実行し、フローテーブルにフローエントリを追加します。

lookupメソッドで物理ポート番号が取得できなかった場合、以下の処理を行います。
 57行目にあるfloodメソッドを実行し、送信元の物理ポート以外の全てのポートにパケットを流します。

27~29行目
flow_removedイベントハンドラです。フローテーブルからフローエントリが削除される時に実行されます。
messageはFlowRemovedクラスのオブジェクトで、ここから削除するフローエントリの情報が取得できます。
@counter.addメソッドでフローテーブルに保持されてていた統計情報を@counterオブジェクトに加算します。

31行目
priveateからは下に書かれたメソッドは外部から参照することはできません

33~38行目
5行目に記述のあったタイマーで実行されるメソッドです
まず、現在時刻を画面に出力します。
35行目から37行目はCounterクラスのeach_pairメソッドを実行しています。
ここではブロック引数という書き方をしていて、doからendまでの処理を@counterクラスのeach_pairメソッドに渡して実行します。
each_pairの処理については後ほど見ます。

40~47行目
flow_modメソッドでは、send_flow_mod_addというフローエントリの追加・変更をするメソッドを実行します。
:hard_timeoutはフローエントリの有効期限を定義しています。ここでは10をセットしているので10秒間フローテーブルに保持されます。
「条件」にあたる「:match」にはMatchオブジェクトを作成して、送信元と送信元のmacアドレスを条件に指定しています。
「処理」にあたる「:actions」には、指定した物理ポート番号に対しパケットを送るようにします。

49~55行目
packet_outメソッドではsend_packet_outメソッドを実行してパケットを送ります。
「:pacekt_in」で送るパケットやパケットの送信元物理ポート等をセットしています。
「:actions」では指定した物理ポート番号にパケットを送るようにします。

floodメソッドは49行目にかかれたpacket_outメソッドを実行し、送信元以外の全ての物理ポートにパケットを送ります。

今回はここまで。
次回につづく。。。

0 件のコメント:

コメントを投稿