こんな夜中にOpenFlowでネットワークをプログラミング!

第12回 【Trema編】動画放送局をIPマルチキャストで作ってみよう!

この記事を読むのに必要な時間:およそ 2 分

実装

では,さっそくTremaで実装してみましょう。このためのコントローラは,グループを管理するクラス(MFCクラス)とコントローラ本体であるSimpleMulticastクラスから構成されます。

MFCクラス

MFC(Multicast Forwarding Cache)クラスは,グループの一覧と,グループごとにどのホストが接続しているか(ホストが接続しているポート番号で識別します)を管理しますリスト1⁠。

リスト1 MFCクラス(mfc.rb)

require "set"

class MFC
  def initialize
    @db = Hash.new do | hash, key | ← グループの一覧を初期化
      hash[ key ] = Set.new
    end
  end

  def learn group, port ← グループに受信者接続ポートを登録
    members( group ).add( port )
  end

  def remove group, port ← グループからポートを削除
    members( group ).delete( port )
  end

  def members group ← グループの受信ホストが接続するすべてのポートを検索
    @db[ group.to_i ]
  end
en

SimpleMulticastクラス

SimpleMulticastクラスは,コントローラの本体ですリスト2⁠。

リスト2 SimpleMulticastクラス(simple-multicast.rb)

require "mfc"

class SimpleMulticast < Controller
  def start
    @mfc = MFC.new ← MFCオブジェクトを用意
  end

  def packet_in datapath_id, message
    if message.igmp? ← (1)packet_inしたパケットがIGMPか?
      handle_igmp message
    else
      members = @mfc.members( message.ipv4_daddr ) ← グループのメンバー一覧
      flow_mod datapath_id, members, message
      packet_out datapath_id, members, message
    end
  end

  private ← 以下プライベートメソッド

  def handle_igmp message ← (2)IGMPパケット受信時の処理
    group = message.igmp_group ← IGMPパケット中のグループアドレスの値
    port = message.in_port

    if message.igmp_v2_membership_report?
      @mfc.learn group, port ← グループへ参加
    elsif message.igmp_v2_leave_group?
      @mfc.remove group, port ← グループを脱退
    end
  end

  def flow_mod datapath_id, members, message ← (3)フローを設定
    send_flow_mod_add(
      datapath_id,
      :match => ExactMatch.from( message ),
      :actions => output_actions( members ), ← 視聴者のポートだけに出力
      :hard_timeout => 5 ← flow_modの有効期限は5秒
    )
  end

  def packet_out datapath_id, members, message ← packet_inパケットの転送
    send_packet_out(
      datapath_id,
      :packet_in => message,
      :actions => output_actions( members ) ← 視聴者のいるすべてのポートに出力
    )
  end

  def output_actions members ← 視聴者のいるポートだけに出力するアクション
    members.collect do | each |
      ActionOutput.new( :port => each )
    end
  end
end

packet_in ハンドラ(リスト2(1⁠⁠)ではigmp?メソッドを使い,パケットがIGMPであるかを判定しています。IGMPであった場合,handle_igmpメソッド(リスト2(2⁠⁠)で中身を見て,グループの参加/脱退を行います。このように,Trema::PacketInクラスはパケットの種別や各フィールドを参照するための便利なメソッドをたくさん持っており注2⁠,パケットの詳細を知らなくても簡単に各レイヤの情報を取り出すことができます。

flow_modメソッド(リスト2(3⁠⁠)では,視聴者だけにパケットを転送するためのフローを設定します。output_actionsメソッドを使って,視聴者の接続するポートに出力するためのアクションの配列を作り,send_flow_mod_addの:actionに指定します。

グループの情報は刻々と変化しますので,フローの有効期限は5秒としています。フローが消えると再びマルチキャストパケットがpacket_inでコントローラまで上がってきますので,その時点でのグループ情報を使って新しくフローを張りなおします。

注2)
どのようなメソッドが用意されているかは,Trema RubyAPIドキュメント中のTrema::PacketInクラスの項を参照してください。このドキュメントは,⁠trema ruby」コマンドを実行することでも表示できます。

著者プロフィール

高宮安仁(たかみややすひと)

Trema開発チーム自称リーダー。東京の大学で計算科学を学び,並列プログラミング用ライブラリや,大規模クラスタ管理ツールの開発,とくに東工大のスパコンTSUBAME,分散クラスタInTriggerの管理基盤などなど主に分散・大規模システムのミドルウェア開発者・研究者として活動。現在は企業の研究者として,OpenFlow用プログラミングフレームワークTremaのメイン開発者。モットーは何がなんでも定時に帰ること。コンピューターはもちろん映画や音楽も好きで,スクラッチDJとしても活動しています。DJの仕事ください。


鈴木一哉(すずきかずや)

Trema開発チームのメンバー。Ascend,古河電工,ヤマハ等のネットワーク機器を扱うエンジニアを経て,現在は経路制御の研究に従事。ホエールズ時代からのベイスターズファンで,98年の優勝時にはもちろん横浜スタジアムへ駆けつけました。野球のない時期には,もっぱらSFを読んでいます。会社ではランニングサークルに入っており,先日も多摩川の駅伝に参加しましたが,練習不足で全然走れませんでした。ちゃんと練習して,来年こそはしっかり走るぞ!