Skip to content
yasuhito edited this page Apr 18, 2011 · 1 revision

Hello trema!

それではさっそくチュートリアルの定番、"Hello trema!" から始めましょう! 画面に "Hello trema!" メッセージを出力する Trema アプリケーションのソースコードは次のようになります:

#include "trema.h"

int main( int argc, char *argv[] ) {
  init_trema( &argc, &argv );
  info( "Hello trema!" );
  start_trema();
  return 0;
}

このプログラムは Trema を使った最も簡単なプログラムであると同時に、すべての Trema アプリケーションに共通する最低限のテンプレートになっています。驚くべきことにたったの 8 行しかありません!

それでは、それぞれの部分について簡単に説明していきましょう。

ヘッダファイルのインクルード

まず、すべての Trema アプリケーションは、頭に次の #include 行がなくてはなりません。

#include "trema.h"

これによって、Trema アプリケーションに必要なヘッダファイルがすべて読み込まれます。

初期化

init_trema() はその名のとおり、Trema フレームワークの初期化を行います。

  init_trema( &argc, &argv );

main() の引数 argcargv へのポインタを引数として渡していることに注意してください。これは、起動時のコマンドラインオプションをパーズするためです。今回はコマンドラインオプションは使いませんが、Trema が解釈するコマンドラインオプションについては後のチュートリアルで詳しく説明します。

メッセージの出力

info() は Trema 標準のメッセージ出力関数の一つです。たとえば次のようにして使います。

  info( "Hello trema!" );

この例は引数として指定されたメッセージ "Hello trema!" を画面やログファイルに適切なフォーマットで出力します。

メッセージ出力関数は、重要度の順に次の 6 種類があります。メッセージレベルの設定やメッセージの出力先の設定については後のチュートリアルで説明します。

  • critical()
  • error()
  • warn()
  • notice()
  • info()
  • debug()

メインループ

start_trema() は Trema のメインループを開始します。

  start_trema();

Trema のプログラムは Gtk などの一般的な GUI ライブラリと同じイベントドリブンモデルになっています。つまり、このメインループの中で OpenFlow のメッセージ到着やタイマなどのイベントを待ち、イベントの到着に応じて対応するハンドラを呼び出します。

コンパイルと実行

次のコマンドでコンパイルし、実行ファイル hello_trema を生成します。

% gcc -o hello_trema hello_trema.c `./trema-config --cflags --libs`

コンパイルできたらさっそく実行してみましょう。すべての Trema アプリケーションは trema run コマンドで実行することができます。

% ./trema run hello_trema
Hello trema!  # Ctrl-c で停止

いかがでしょうか? Trema のアプリケーションはとても簡単に書けることがわかったと思います。

スイッチを接続してみる

ここまでで Trema アプリケーションのひながたができました。今度はこれを元にして、OpenFlow スイッチを実際に接続し、スイッチのユニーク ID (Datapath unique ID, datapath_id とも呼ばれる) を出力するアプリケーションを書いてみましょう。スイッチのユニーク ID がわかれば、スイッチを実際に制御できるようになります。

仮想 OpenFlow スイッチ

ちょっと待ってください。私は OpenFlow 対応スイッチを持っていませんが大丈夫でしょうか?

心配いりません。Trema の最も強力な機能の一つとして仮想ネットワーク機能があります。これは仮想スイッチや仮想ホスト同士を接続した仮想的なネットワークトポロジ上でアプリケーションを実行する機能です。これによって、プログラマは実際に OpenFlow スイッチなどのハードウェアを準備しなくとも Trema の世界だけで開発やテストを完結できます。さらにすばらしいことに、こうして作ったアプリケーションは実際のハードウェア上でもそのまま動作します! それではこの機能を使って仮想スイッチを 1 つ作ってみましょう。

仮想スイッチを定義する

仮想スイッチを起動するには、次の内容の設定ファイルを trema コマンドと同じディレクトリに trema.conf として保存します。定義した仮想スイッチは trema run 実行時に自動的に起動します。

vswitch {
  datapath_id "0xabc"
}

datapath_id は 64 ビットの任意の 16 進数を指定できます。適当な値を選んでください。

スイッチ接続イベントの捕捉

Trema は OpenFlow スイッチと接続が完了すると switch_ready イベントを発生します。そこで、スイッチが接続したことを知るにはハンドラをセットし、switch_ready イベントを捕捉すればよいことになります。このハンドラをセットするための API が set_switch_ready_handler() です。次のように init_trema()start_trema() の間で呼び出してください。

#include "trema.h"

// ハンドラの定義
static void handle_switch_ready( uint64_t datapath_id, void *user_data ) {
  info( "Hello %#llx from %s!", datapath_id, user_data );
}

int main( int argc, char *argv[] ) {
  init_trema( &argc, &argv );
  set_switch_ready_handler( handle_switch_ready, argv[ 0 ] ); // ハンドラをセット
  start_trema();
  return 0;
}

ここで set_switch_ready_handler() の第一引数 handle_switch_ready はハンドラの関数ポインタです。第二引数はハンドラへ渡す任意のユーザデータで、ここでは実行ファイル名 ("hello_trema") を渡しています。

ハンドラ handle_switch_ready の中では得られた datapath_idinfo() で表示しています。

コンパイルと実行

それではさっそくコンパイルして実行してみましょう。コンパイルと実行の手順はさきほどとまったく同じです。

% gcc -o hello_trema hello_trema.c `./trema-config --cflags --libs`

実行する前に、さきほどの設定ファイルが trema.conf として trema コマンドと同じディレクトリにあることを確認してください。

% ./trema run hello_trema
Hello 0xabc from hello_trema!  # Ctrl-c で停止

無事、仮想スイッチの datapath_id が表示されました。後のチュートリアルではこの datapath_id を使って実際にスイッチに対していろいろな操作をしてみましょう。

まとめ

このチュートリアルではすべての Trema アプリケーションのテンプレートとなる "Hello trema!" アプリケーションを書きました。また、これを改造して OpenFlow 対応スイッチの datapath_id を取得できるようにしました。学んだことは次の 6 つです。

  • trema.h#include することによって必要なヘッダファイルを読み込む
  • init_trema( &argc, &argv ) で Trema を初期化
  • info() でメッセージを出力
  • start_trema() でアプリケーションを開始
  • trema.conf 内の vswitch で仮想スイッチを定義
  • set_switch_ready_handler()switch_ready イベントに対するハンドラを定義