Skip to content

スイッチの情報を調べる

yasuhito edited this page Apr 18, 2011 · 1 revision

スイッチの情報を調べる

このチュートリアルではスイッチの詳しい情報を調べる Trema アプリケーションを書きます。スイッチから取得できる情報は次のとおりで、OpenFlow のスペックで詳しく定義されています。

  • datapath ID
  • バッファリングしておけるパケットの数
  • フローテーブルの数
  • ケイパビリティ
  • サポートしているオープンフローのアクション
  • 物理ポートの一覧

スイッチの情報を取得する

スイッチの情報を取るためには、スイッチに features request というメッセージを投げます。

// features request メッセージを作る
buffer *message = create_features_request( get_transaction_id() );
// 作ったメッセージを送る
send_openflow_message( datapath_id, message );
// メモリの開放
free_buffer( message );

このメッセージはいつスイッチに送ればいいのでしょうか? 答えはスイッチが準備 OK になったときです。前回のチュートリアルで作った switch_ready ハンドラの中で呼べばよいですね。

static void
handle_switch_ready( uint64_t datapath_id, void *user_data ) {
  // features request メッセージを作る
  buffer *message = create_features_request( get_transaction_id() );
  // 作ったメッセージを送る
  send_openflow_message( datapath_id, message );
  // メモリの開放
  free_buffer( message );
}

features request の返事を受けとるには、features_reply ハンドラを書きます。たとえば各種情報を表示するハンドラは info() 関数を使って次のように書けます。

static void
handle_features_reply (
  uint64_t datapath_id,
  uint32_t transaction_id,
  uint32_t n_buffers,
  uint8_t n_tables,
  uint32_t capabilities,
  uint32_t actions,
  const list_element *phy_ports,
  void *user_data
) {
  info( "datapath_id: %#llx", datapath_id );
  info( "transaction_id: %#lx", transaction_id );
  info( "n_buffers: %lu", n_buffers );
  info( "n_tables: %u", n_tables );
  info( "capabilities: %lu", capabilities );
  info( "actions: %lu", actions );
  info( "#ports: %d", list_length_of( phy_ports ) );
}

物理ポートの数を表示する部分で使っている list_length_of は Trema 標準関数で、物理ポート一覧 (phy_ports) の要素数を返します。

最終的なコードはこうなります。

#include "trema.h"


static void
handle_switch_ready( uint64_t datapath_id, void *user_data ) {
  buffer *message = create_features_request( get_transaction_id() );
  send_openflow_message( datapath_id, message );
  free_buffer( message );
}


static void
handle_features_reply (
  uint64_t datapath_id,
  uint32_t transaction_id,
  uint32_t n_buffers,
  uint8_t n_tables,
  uint32_t capabilities,
  uint32_t actions,
  const list_element *phy_ports,
  void *user_data
) {
  info( "datapath_id: %#llx", datapath_id );
  info( "transaction_id: %#lx", transaction_id );
  info( "n_buffers: %lu", n_buffers );
  info( "n_tables: %u", n_tables );
  info( "capabilities: %lu", capabilities );
  info( "actions: %lu", actions );
  info( "#ports: %d", list_length_of( phy_ports ) );
}


int
main( int argc, char *argv[] ) {
  init_trema( &argc, &argv );

  set_switch_ready_handler( handle_switch_ready, NULL );
  set_features_reply_handler( handle_features_reply, NULL );

  start_trema();

  return 0;
}

コンパイルと実行

さっそくコンパイルして実行してみましょう。

% gcc -o features_request features_request.c `./trema-config --cflags --libs`
% ./trema
trema> vswitch { datapath_id "0xabc" }
trema> app { path "./features_request" }
trema> run
datapath_id: 0xabc
transaction_id: 0x27aa0001
n_buffers: 256
n_tables: 2
capabilities: 135
actions: 2047
#ports: 1

うまく仮想スイッチの情報を表示できました。ここでは、datapath_id0xabc になっていることと、ポートの数はスイッチのコントロールポート 1 つだけであることに注目してください。

ポートの数を増やす

もうちょっと遊んでみましょう。スイッチのポートを増やし、表示されるスイッチ情報に反映されることを確認します。スイッチにポートを増やすには、次のようにあたらしくスイッチ 0xdef を追加し、スイッチ間にリンクを張ります。リンクを張るには、次の link ディレクティブを使います。

trema> link スイッチ名1, スイッチ名2

さきほどのセッションに続けて、次のように入力します。

trema> vswitch { datapath_id "0xdef" }
trema> link "0xabc", "0xdef"  # スイッチ 0xabc と 0xdef にポートがひとつ追加される

実行すると、スイッチが 2 つになりポートの数もそれぞれ 2 つずつ (コントロールポート + スイッチ間接続のポート) になります。

trema> run
datapath_id: 0xdef
transaction_id: 0x7200002
n_buffers: 256
n_tables: 2
capabilities: 135
actions: 2047
#ports: 2  # ポートが 2 つになった
datapath_id: 0xabc
transaction_id: 0x7200001
n_buffers: 256
n_tables: 2
capabilities: 135
actions: 2047
#ports: 2  # ポートが 2 つになった

まとめ

このチュートリアルではスイッチの情報を取得する Trema アプリケーションを書きました。学んだことは次の 5 つです。

  • スイッチに features request メッセージを送るとスイッチの情報を取得できる
  • create_features_request() で features reqeust メッセージを作る
  • send_openflow_message() で作ったメッセージを送る
  • set_features_reply_handler() で features reply メッセージのハンドラを登録
  • link でスイッチ間にリンクを作ることができる