Skip to content

Latest commit

 

History

History
622 lines (434 loc) · 38.5 KB

hello_trema.adoc

File metadata and controls

622 lines (434 loc) · 38.5 KB

Hello, Trema!

Trema(トレマ)を使うと楽しくSDNの世界が味わえます。これでいよいよあなたもOpenFlowプログラマの仲間入りです!

izakaya

作ってわかるOpenFlow

いよいよOpenFlowを使ってネットワークを実際にプログラムしていきます。職場や自宅のような小規模ネットワークでもすぐに試せるコードを通じ、OpenFlowの世界を体験しましょう。実際に手を動かし実行してみれば「OpenFlowってどんな場面で使えるの?」というよくある疑問も徐々に氷解していくでしょう。

実装はステップバイステップで進みます。最初はOpenFlowやプログラミングの基礎から始めます。そしてパッチパネルやイーサネットスイッチ、ファイアウォール、ルータの実装など徐々に複雑な機能へとステップアップしていきます。そして最終的には、データセンターでも動く本格的なネットワーク仮想化の実装を目標とします。

Hello Trema (本章)

OpenFlow 版 Hello World

スイッチ監視ツール (4章)

スイッチの死活監視ツール

Cbenchベンチマーク (5章)

OpenFlow のマイクロベンチマークツール

パッチパネル (6章)

ソフトウェアとして実装したインテリジェント・パッチパネル

ラーニングスイッチ (7章)

イーサネットスイッチをエミュレートするコントローラ

ラーニングスイッチ OpenFlow1.3 (8章)

ラーニングスイッチの OpenFlow1.3 による実装

テスト駆動開発 (9章)

コントローラのテスト駆動開発

ブリッジ (10章)

レガシーなネットワークとOpenFlowネットワークのブリッジ

ファイアウォール (11章)

透過型ファイアウォール

ルータ (12章,13章,14章)

基本的なレイヤ3スイッチ (ルータ)

トポロジ (15章)

中規模〜大規模ネットワークのトポロジ検知

ルーティングスイッチ (16章)

中規模〜大規模ネットワーク用の仮想レイヤ2スイッチ

ネットワークスライス (17章)

ルーティングスイッチに仮想ネットワーク機能を追加

OpenVNet (18章)

Tremaベースの商用SDN

まずは、OpenFlowプログラミングのためのフレームワーク、Tremaを改めて紹介します。

Tremaとは

TremaはOpenFlowコントローラを開発するためのフリーソフトウェアです。GitHub上でオープンに開発を進める、GPL2ライセンスのフリーソフトウェアです。その強力な機能や使いやすさから、国内外の企業・大学・研究機関などの幅広い組織が採用しています。

Tremaの情報はおもに次のURLから入手できます。

Tremaホームページ

https://trema.github.com/trema/

GitHubのプロジェクトページ

https://github.com/trema/

メーリングリスト

http://groups.google.com/group/trema-dev/

Twitterアカウント

https://twitter.com/trema_news

Tremaの特徴はRuby on Rails[1]と同じく「プログラミングフレームワーク」を謳っていることです。でも、プログラミングフレームワークとはいったい何でしょうか。

Webサービスの世界では、90年代半ばには原始的なプログラミングが開発の主流でした。HTTPプロトコルを意識した低レベルなCGIをCやPerlで書かねばならず、ごく単純な掲示板サービスを作るのにも大量のコーディングが伴いました。

しかし2000年代に入り状況は一変します。より生産性の高い開発手法の登場 — プログラミングフレームワークによるアジャイル開発 — によって一気にWebサービスは「カンブリア爆発」を迎えました。Railsを代表とするWebプログラミングフレームワークは、HTTPプロトコルの詳細を抽象化した高レベルなAPIを提供します。また、RubyやPythonをはじめとするスクリプティング言語の採用や、開発全体をラップトップPC1台で完結できる数々の開発支援ツールの提供によって、生産性を劇的に向上します。

この流れをOpenFlow界にも吹き込んだのがTremaです。Tremaは「OpenFlow版Rails」を合言葉として、2011年に初のOpenFlowプログラミングフレームワークとして登場しました。開発言語にはRailsと同じくRubyを採用し、また高レベルなOpenFlow APIを提供することで、プログラマはごく短いコードでOpenFlowコントローラを実装できます。また強力なOpenFlow開発ツール群を提供することで、ソフトウェアテストを中心とした反復的で段階的なアジャイル開発を可能にします。

こうした強力なツールの一つがTremaの仮想ネットワーク機能です。OpenFlowスイッチを持っていない開発者でも、Tremaを使えばラップトップPC1台の中に仮想的なOpenFlowネットワークを作り、そこで自分の開発したコントローラを実行できます。この「作ったものをすぐに実行できる」という利点は、生産性の向上だけでなくSDNやOpenFlowのような新しい技術の習得にもつながります。正しい理解のためには概念の理解に加えて実践、つまり実際に手を動かすことが欠かせないからです。

ここからは実際にTremaを使ってOpenFlowコントローラを作り、そして動かしていきます。まずはTremaの実行環境をセットアップしましょう。

Note
Tremaの由来は?

Tremaの名前は、著者の一人がファンである「とれまレコード」(http://www.fumiyatanaka.com/toremarecords/) という大阪の小さなレコードレーベルの名前から来ています。とれまレコードの楽曲は国内だけでなく海外でも人気があり、海外のクラブチャートにもよくランクインします。

この「とれまレコード」の名前には面白い由来があります。日本がバブルの頃、道路上の「とまれ」という標示がよく「とれま」と間違えて描かれており、これに目をつけたレーベルオーナーが「とれまレコード」と名付けたのだそうです。

このありえないミスの原因は、バブル景気時代にまでさかのぼります。当時の景気に乗って急増した外国人労働者達は、日本語もままならないまま工事現場で働いていました。そのおかげで道路に「とれま」と描いてしまう珍事が発生したのだそうです。

この逸話にのっとって、Tremaの公式ロゴも図 3-Aのとおり道路標識の写真になっています。……ちなみに、こんな道路標識は日本中どこを探してもありません! 本書の編集者が画像編集ソフトで試しに作ってみたところ評判が良かったので、そのまま公式ロゴになりました。

Trema実行環境のセットアップ

TremaはLinux用のソフトウェアです。次のLinuxディストリビューションでの動作を確認しています。

  • Ubuntu Linux

  • Debian GNU/Linux

  • CentOS 6 系, 7 系

Tremaに必要なソフトウェアは次の4つです。

sudo

Trema が root 権限でコマンドを実行するのに使います。あらかじめ、sudo コマンドを使って root 権限でコマンドを実行できるかどうか、sudo の設定ファイルを確認しておいてください。

Ruby

Trema の実行には Ruby のバージョン 2.0 以降が必要です。Trema を使ったコントローラの開発にも Ruby を使います。

Bundler [2]

Ruby ライブラリのインストーラです。Trema 本体と実行に必要なライブラリ一式を自動的にインストールするのに使います。

Open vSwitch [3]

OpenFlow に対応したソフトウェアスイッチの一種です。Trema の仮想ネットワーク機能で使用します。

Rubyのインストール

Rubyのインストール方法は、Linuxディストリビューションごとに異なります。

Ubuntu/Debianにインストールする場合

標準のパッケージマネージャ apt で以下のようにRuby関連パッケージをインストールします。

$ sudo apt-get update
$ sudo apt-get install ruby2.0 ruby2.0-dev build-essential

なお build-essential パッケージは Trema が依存する外部ライブラリのインストールに必要な gcc コンパイラなどを含んでいます。

CentOS にインストールする場合

標準のパッケージマネージャ yum で以下のようにRuby関連パッケージをインストールします。

$ sudo yum update
$ sudo yum install ruby ruby-devel gcc gcc-c++

なお gcc と gcc-c++ パッケージは Trema が依存する外部ライブラリのインストールに必要です。

Bundler のインストール

Bundler は次のコマンドでインストールできます。

$ gem install bundler

なお gem は Ruby の標準ライブラリ形式 .gem をインストールするコマンドです。ここでは最新版の Bundler の .gem を自動的にダウンロードしてインストールしています。

Open vSwitchのインストール

Open vSwitchのインストール方法も、Linuxディストリビューションごとに異なります。

Ubuntu/Debian にインストールする場合

Open vSwitchも apt-get コマンドで簡単にインストールできます。

$ sudo apt-get install openvswitch-switch

CentOS にインストールする場合

yum コマンドでOpen vSwitchをインストールします。RDO(RPM Distribution of OpenStack)[4]というRedHat系Linux用のOpenStackパッケージリポジトリを使うと、簡単にインストールできます。

$ sudo yum update
$ sudo yum install https://rdoproject.org/repos/rdo-release.rpm
$ sudo yum install openvswitch
$ sudo systemctl start openvswitch.service

以上でTremaを使うための準備が整いました。それでは早速、入門の定番Hello, Worldを書いて実行してみましょう。

Hello, Trema!

Hello Trema!はもっとも簡単なOpenFlowコントローラです。その唯一の機能は、スイッチと接続して Hello, 0xabc! (0xabc はスイッチのユニーク ID) と表示するだけです。このように機能は単純ですが、そのソースコードはTremaでコントローラを作るのに必要な基本知識をすべて含んでいます。

Hello Tremaを書く

コントローラの実装はプロジェクト用ディレクトリを作ることから始めます。まずは次のように、Hello Trema!用の空のディレクトリ hello_trema/ と、ソースコード用ディレクトリ hello_trema/lib/mkdir -p コマンドで新たに作ってください。

$ mkdir -p hello_trema/lib
$ cd hello_trema

プロジェクトディレクトリの中身

プロジェクトディレクトリには、コントローラに関連するすべてのファイルを置きます。コントローラのソースコードをはじめ、README.mdやLICENSEといったドキュメント類、コントローラの動作をテストするためのテストファイル、そして各種設定ファイルがここに入ります。

プロジェクトディレクトリのお手本として、GitHub の trema/hello_trema リポジトリ (https://github.com/trema/hello_trema) を見てみましょう。このリポジトリは、標準的な Ruby プロジェクトのファイル構成に従っています。次に主要なファイルを挙げます。

README.md

メインのドキュメント

LICENSE

配布ライセンスの指定

CHANGELOG.md

開発履歴

Gemfile

実行に必要なgemパッケージの定義

Rakefile

開発用タスク

lib/

コントローラの実装

features/

受け入れテスト

spec/

ユニットテスト

tasks/

開発用タスク定義

Note

このうち受け入れテスト関連の features/ ディレクトリについては、9 章「Trema でテスト駆動開発」で詳しく説明します。

コントローラ本体の実装

エディタで hello_trema ディレクトリ内の lib/hello_trema.rb を開き、次の Ruby コードを入力してください。.rb は Ruby プログラムの標準的な拡張子です。Ruby の文法は必要に応じておいおい説明しますので、もしわからなくても気にせずそのまま入力してください。

lib/hello_trema.rb
link:vendor/hello_trema/lib/hello_trema.rb[role=include]

スイッチの定義

Hello Trema! の実行には OpenFlow スイッチが 1 台必要です。さきほどインストールした Open vSwitch を Hello Trema コントローラに接続することにしましょう。次の設定ファイル trema.conf をエディタで hello_trema/ ディレクトリ直下に作成してください。

trema.conf
vswitch { datapath_id 0xabc }

コントローラを実行する際にこの設定ファイルを指定することで、Open vSwitch を起動しコントローラに接続できます。

この設定ファイルでは1台のソフトウェアスイッチを定義しています。vswitch で始まる行が1台の仮想スイッチに対応します。続く波括弧({ })内で指定している datapath_id (0xabc) は、仮想スイッチを識別するための16進数の値です。

この Daptapath ID とはちょうどMACアドレスのような存在で、スイッチを一意に特定するIDとして使います。OpenFlowの仕様では、この値には64ビットの一意な整数値を割り振ることになっています。仮想スイッチでは好きな値を設定できるので、もし複数台の仮想スイッチを作る場合にはお互いがぶつからないように注意してください。

Note
Datapath ってどういう意味?

実用的には「Datapath = OpenFlowスイッチ」と考えて問題ありません。”データパス”で検索すると、「CPUは演算処理を行うデータパスと、指示を出すコントローラから構成されます」というハードウェア教科書の記述が見つかります。つまり、ハードウェアの世界では一般に

  • 筋肉にあたる部分 = データパス

  • 脳にあたる部分 = コントローラ

という分類をするようです。

OpenFlowの世界でも同じ用法を踏襲しています。OpenFlowのデータパスはパケット処理を行うスイッチを示し、その制御を行うソフトウェア部分をコントローラと呼びます。

Trema のインストール

Hello Trema の実行にはもちろん Trema が必要です。実行に必要な Ruby のアプリケーションやライブラリの gem を hello_trema/ ディレクトリ直下の Gemfile というファイルに次のように書くことで、Hello Trema の実行環境として Trema を使うということを指定します。

Gemfile
source 'https://rubygems.org/' # (1)

gem ‘trema’# (2)
  1. gem の取得元として標準的な https://rubygems.org を指定する

  2. 実行環境に Trema を追加する

Gemfile に記述した実行環境のセットアップには Bundler を使います。hello_trema ディレクトリ直下で次の bundle install --binstubs コマンドを実行すると、Gemfile に記述した Trema と Trema が依存する .gem ファイル一式を自動的にインストールし、Trema の実行コマンド tremabin/ ディレクトリに生成します。

$ bundle install --binstubs
$ ./bin/trema --version
trema version 0.9.0

実行に最低限必要なコードはこれだけです。それでは細かい部分は後で説明するとして「習うより慣れろ」でさっそく実行してみましょう。

実行してみよう(trema run)

作成したコントローラは trema run コマンドですぐに実行できます。Rubyはインタプリタ言語なので、コンパイルの必要はありません。ターミナルで次のように入力し、コントローラを起動してみてください。

$ ./bin/trema run ./lib/hello_trema.rb -c trema.conf
Trema started.
Hello, 0xabc! # (1)
$
  1. kbd:[Ctrl+c] でコントローラを終了

このように Trema started. Hello, 0xabc! と出力できたら成功です。

ここまで見てきたように、trema コマンドを使うと、とても簡単にコントローラを実行できます。trema コマンドには他にもいくつかの機能がありますので、ここで簡単に紹介しておきましょう。

trema コマンド

trema コマンドは Trema 唯一のコマンドラインツールであり、コントローラの起動やテストなどさまざまな用途に使います。

たとえばHello, Trema!で見たように、trema run はコントローラの起動コマンドです。起動したコントローラは OpenFlow スイッチと接続しメッセージをやりとりします。また、trema run コマンドに -c (--conf) オプションを指定することで、コントローラを仮想ネットワークのスイッチとも接続できます (図 3-1)。

trema overview
図 3-1: trema runコマンドの実行イメージ

trema コマンドは gitsvn コマンドと似たコマンド体系を持っています。trema に続けて run などのサブコマンドを指定することで、さまざまな機能を呼び出します。こうしたコマンド体系を一般に「コマンドスイート」と呼びます。

一般的なコマンドスイートと同じく、サブコマンドの一覧は trema help で表示できます。また、サブコマンド自体のヘルプは trema help サブコマンド名 で表示できます。以下に、trema help で表示されるサブコマンド一覧をざっと紹介しておきます。それぞれの使い方は続く章で説明していきますので、今は目を通すだけでかまいません。

trema run

コントローラをフォアグラウンドまたはバックグラウンド (デーモンモード) で実行する

trema killall

バックグラウンドで起動している Trema プロセス全体を停止する

trema stop

指定した仮想ホストまたは仮想スイッチを停止する

trema start

指定した仮想ホストまたは仮想スイッチを再び有効にする

trema send_packets

仮想ネットワーク内でテストパケットを送信する

trema show_stats

仮想ホストで送受信したパケットの統計情報を表示する

trema reset_stats

仮想ホストで送受信したパケットの統計情報をリセットする

trema port_down

仮想スイッチのポートを落とす

trema port_up

仮想スイッチのポートを上げる

trema delete_link

仮想ネットワーク内の仮想リンクを切る

trema netns

仮想ホストのネットワークネームスペースでコマンドを実行する

trema dump_flows

仮想スイッチのフローテーブルを表示する

では、気になっていた Ruby の文法にそろそろ進みましょう。今後はたくさん Ruby を使いますが、その都度必要な文法を説明しますので心配はいりません。しっかりついてきてください。

即席Ruby入門

Rubyを習得する一番の近道は、コードを構成する各要素の種類(品詞)を押さえることです。これは、外国語を習得するコツに近いものがあります。ただし外国語と違い、Rubyの構成要素にはその品詞を見分けるための視覚的なヒントがかならずあります。このためRubyのコードはずいぶんと読みやすくなっています。

品詞 視覚的ヒント

定数

HelloTrema, Trema::Controller

大文字で始まる

インスタンス変数

@switches, @name

@ で始まる

シンボル

:match, :actions

: で始まる

Note

インスタンス変数とシンボルについては4 章「スイッチ監視ツール」で詳しく説明します。

このように最初の文字を見れば、それがどんな品詞かすぐにわかります。たとえば、大文字で始まる名前はかならず定数です。品詞がわかれば、そのRubyコードがどんな構造かも見えてきます。これからそれぞれの品詞について順に説明していきますが、最初からすべてが理解できなくとも構いません。しばらくすればRubyコードのあらゆる部分が識別できるようになっているはずです。

定数

HelloTremaTrema::Controller など、大文字で始まる名前が定数です。Rubyの定数は英語や日本語といった自然言語における固有名詞にあたります。

lib/hello_world.rb
# Hello World!
class HelloTrema < Trema::Controller # (1)
  def start(_args)
    logger.info 'Trema started.'
  end

  def switch_ready(datapath_id)
    logger.info "Hello #{datapath_id.to_hex}!"
  end
end
  1. HelloTremaTrema::Controller が定数

英語でも固有名詞は大文字で始めることになっています。たとえば英語のTokyo Tower(東京タワー)がそうです。東京タワーは動かすことができませんし、何か別なものに勝手に変えることもできません。このように、固有名詞は時間とともに変化しないものを指します。そして固有名詞と同様、Rubyの定数は一度セットすると変更できません。もし変更しようとすると、次のように警告が出ます。

$ irb
> TokyoTower = "東京都港区芝公園4丁目2-8"
> TokyoTower = "増上寺の近く"
(irb):2: warning: already initialized constant TokyoTower
(irb):1: warning: previous definition of TokyoTower was here
=> "東京都港区芝公園4丁目2-8"
Note

ここで使っている irb (Interactive Ruby) は Ruby のインタラクティブな実行ツールです。ちょっとしたサンプルコードを試したり、Rubyの挙動を調べるのに便利です。

class に続く定数はクラス定義です。Hello, Trema!の例では HelloTrema がクラス名です。「class +クラス名」から始まるクラス定義は、同じ字下げレベルの end までの範囲です。

lib/hello_trema.rb
class HelloTrema < Trema::Controller # (1)
  def start(_args)
    logger.info "Trema started."
  end

  def switch_ready(datapath_id)
    logger.info "Hello #{datapath_id.to_hex}!"
  end
end # (2)
  1. HelloTremaクラス定義の始まり

  2. クラス定義の終わり

コントローラクラスの継承

Tremaではすべてのコントローラはクラスとして定義し、Tremaの提供する Trema::Controller クラスをかならず継承します。クラスを継承するには、class クラス名 < 親クラス名 と書きます.

lib/hello_trema.rb
class HelloTrema < Trema::Controller # (1)
  ...
end
  1. Trema::Controller クラスを継承した HelloTrema クラスを定義

Trema::Controller クラスを継承することで、コントローラに必要な基本機能が HelloTrema クラスに追加されます。たとえば次に説明するハンドラもその基本機能の一つです。

ハンドラの定義

さて、こうして定義した HelloTrema クラスはどこから実行が始まるのでしょうか。C言語で言う main() 関数に当たるものがどこにも見あたりません。

その答はTremaの動作モデルであるイベントドリブンモデルにあります。Tremaのコントローラは、さまざまなイベントに反応するイベントハンドラ (以下、ハンドラと呼びます) をいくつも持ちます。コントローラが動作するのは、さまざまなイベントに対してハンドラが反応したときです。

ハンドラの定義は def に続く名前から end までの部分で、実際にはメソッド定義です。たとえば HelloTrema の例では start ハンドラと switch_ready ハンドラを定義しています。ハンドラ名の後のカッコで囲まれた部分 (_argsdatapath_id) はそれぞれのメソッドに渡される引数です。

lib/hello_trema.rb
class HelloTrema < Trema::Controller
  def start(_args) # (1)
    logger.info "Trema started."
  end

  def switch_ready(datapath_id) # (2)
    logger.info "Hello #{datapath_id.to_hex}!"
  end
end
  1. start ハンドラの定義

  2. switch_ready ハンドラの定義

start ハンドラ

コントローラの起動イベント発生時、つまり trema run でコントローラを起動したときに自動で呼び出します。

switch_ready ハンドラ

スイッチがコントローラに接続し、初期化が完了したときに自動で呼び出します。

Note
Rubyのイディオム: アンダーバー (_) で始まる引数名

メソッドの中で使わない引数は、_args のようにアンダーバーで始めます。これによって、この引数はメソッドの中で使われていないことが一目でわかります。

# メソッド内で _args は使っていない
def start(_args)
  logger.info "Trema started."
end
# メソッド内で args を使っている
def start(args)
  logger.info "Arguments = #{args.join ', '}"
end

このほかにTremaでよく使うハンドラをリストアップしておきます。

switch_disconnected ハンドラ

スイッチがコントローラから切断したときに呼び出します。

packet_in ハンドラ

Packet In メッセージ (5 章「マイクロベンチマークCbench」で紹介) がコントローラへ到着したときに呼び出します。

flow_removed ハンドラ

フローが消えたときのFlow Removedメッセージ到着時に呼び出します。

Note
ハンドラの自動呼び出し

「ハンドラを定義しただけで、なぜ自動的に呼び出せるんだろう?」と不思議に思う人もいるでしょう。コード中にどんなメソッドがあるか、というコンパイル時情報をプログラム自身が実行時に知るためには、言語処理系の助けが必要です。

Rubyではオブジェクトが自らの持つメソッドを実行時に調べられます。これをイントロスペクション(リフレクションや自己反映計算などとも言う)と呼びます。たとえばPacket Inメッセージが到着したとき、コントローラはイントロスペクションして自分が packet_in メソッドを持っているかどうかを実行時に調べます。そしてもし見つかればそのメソッドを呼ぶというわけです。

この仕組みは Trema::Controller クラスを継承したとき、自動的にコントローラへ導入されます。

キーワード

Rubyにはたくさんの組込みの語 (キーワード) があり、それぞれに意味があります。これらのキーワードを変数として使ったり、自分の目的に合わせて意味を変えたりはできません。

alias and BEGIN begin break case class def defined do else elsif END
end ensure false for if in module next nil not or redo rescue retry
return self super then true undef unless until when while yield

このうち、Hello, Trema!では classdefend の 3 つのキーワードを使いました。先ほど説明したように、class キーワードは続く名前のクラスを定義します。そして def キーワードは続く名前のメソッドを定義します。

この defclass で始まって end で終わる領域のことをブロックと呼びます。すべてのRubyプログラムはこのブロックがいくつか組み合わさったものです。

さて、ここまででHello Trema!に必要なRubyの文法は学びました。再びHello Trema!のソースコードに戻りましょう。

スイッチの起動を捕捉する

新しくスイッチが起動すると switch_ready ハンドラが起動します。switch_ready ハンドラは、接続したスイッチのDatapath IDを16進形式(0xで始まる文字列)でログに出力します。

HelloTrema#switch_ready (lib/hello_trema.rb)
def switch_ready(dpid)
  logger.info "Hello #{dpid.to_hex}!"
end
Note
switch_readyの中身

実は OpenFlow の仕様には switch_ready というメッセージは定義されていません。実は、これは Trema が独自に定義するイベントなのです。switch_ready の裏では図 3-Bに示す一連の複雑な処理が行われていて、Trema がこの詳細をうまくカーペットの裏に隠してくれているというわけです。

switch ready
図 3-B: switch_ready イベントが起こるまで

最初に、スイッチとコントローラがしゃべる OpenFlow プロトコルが合っているか確認します。OpenFlow の Hello メッセージを使ってお互いにプロトコルのバージョンを知らせ、うまく会話できそうか判断します。

次は、スイッチを識別するための Datapath ID の取得です。Datapath IDのようなスイッチ固有の情報は、スイッチに対して OpenFlow の Features Request メッセージを送ることで取得できます。成功した場合、Datapath IDや最大テーブル数などの情報が Features Reply メッセージに乗ってやってきます。

最後にスイッチを初期化します。スイッチに以前の状態が残っているとコントローラが管理する情報と競合が起こるので、スイッチを初期化することでこれを避けます。

これら一連の処理が終わると、ようやく switch_ready がコントローラに通知されるというわけです。

Datapath IDを16進形式にする

to_hex は整数を16進形式の文字列に変換するメソッドです。switch_ready ハンドラの引数 dpid の値は64ビットの正の整数で、OpenFlowでは慣習的に 0xfffb などと16進で表します。この慣習に従って、ターミナルやログに出力する場合には to_hex で16進形式に変換しておいたほうがよいでしょう。

ログメッセージを出力する

ログメッセージを出力するには、logger を使います。

HelloTrema#start (lib/hello_trema.rb)
def start(_args)
  logger.info 'Trema started.'
end

logger はTrema標準のロガーで、ログメッセージの出力はこれを通じて行います。ログメッセージの重要度に応じて、unknown (重要度 最高) から debug (重要度 最低) までの次の6種類のメソッドを選べます。

unknown

不明なエラー。重要度にかかわらず常にロギングする

fatal

回復不能なエラー

error

エラー

warn

警告

info

通常レベルの情報

debug

デバッグ出力

trema run のオプションでロギングレベルを指定できます。たとえば次のコードを実行するとしましょう。

ロギングレベルの確認用コード (try_logging.rb)
class TryLogging < Trema::Controller
  def start(_args)
    logger.unknown 'UNKNOWN'
    logger.fatal 'FATAL'
    logger.error 'ERROR'
    logger.warn 'WARN'
    logger.info 'INFO'
    logger.debug 'DEBUG'
  end
end

このコードをたとえば次のようにロギングレベル warn で実行すると、infodebug メッセージは出力されません。

$ ./bin/trema run try_logging.rb --logging_level warn
UNKNOWN
FATAL
ERROR
WARN

ログメッセージはログファイルにも記録されます。ログファイルのデフォルトパスは /tmp/[コントローラのクラス名].log です。たとえばHelloTremaの場合には /tmp/HelloTrema.log になります。ログファイルの出力先ディレクトリを変更するには、trema run--log_dir または -L オプションを指定します。たとえば次のようにすると、/var/log/HelloTrema.log が作られます。

$ ./bin/trema run try_logging.rb --log_dir /var/log/

文字列に式を組込む

logger.info に渡している文字列中の #{} は、文字列内にRubyの式を組込みます。

logger.info "Hello #{dpid.to_hex}!"
#=> Hello 0xabc!

これは次のコードと同じです。

logger.info 'Hello ' + dpid.to_hex + '!'
#=> Hello 0xabc!

どちらを使っても構いませんが、文字列を + でつなげすぎると最終的な出力がコードからはわかりにくくなることがあります。その場合、このように #{} で組み込んだほうがよいでしょう。

これでHello, Trema!の説明はおしまいです。Tremaで作るコントローラは基本的にこのHello, Trema!と同じ構成をしています。これをベースにいくつか必要なハンドラメソッドを追加していけば、より複雑で実践的なコントローラも作れます。

まとめ

この章ではTremaの開発環境をセットアップし、すべてのコントローラのテンプレートとなるHello, Trema!コントローラを書きました。この章で学んだことを簡単にまとめてから、より実用的なコントローラの開発に入っていくことにしましょう。

  • コントローラはクラスとして定義し、Trema::Controller クラスを継承することでコントローラの基本機能を取り込む

  • コントローラに機能を追加するには、各種イベントに対応するハンドラをコントローラクラスに定義する

  • コントローラは trema run コマンドでコンパイルなしにすぐ実行できる

  • 仮想ネットワーク機能を使うと、OpenFlowスイッチを持っていなくてもコントローラを実行できる

これでTremaの基礎知識は充分に身に付きました。次の章では、OpenFlowコントローラのためのマイクロベンチマークツール、Cbenchを計測するためのコントローラを書きます。

参考文献

Rubyプログラミングが初めてという人達のために、この章では入門に役立つサイトや本をいくつか紹介します。

『Ruby 2.2.0 リファレンスマニュアル』(http://docs.ruby-lang.org/ja/2.2.0/doc/)

Ruby の完全なリファレンスです。Ruby でプログラミングする際は参照しましょう。

『メタプログラミングRuby 第2版』(Paolo Perrotta 著/角 征典 訳/オライリージャパン)

Ruby プログラムを短く簡潔に書くためのテクニックをたくさん紹介しています。「プロっぽい」 Ruby コードを書きたい人は必読です。

『Why’s (Poignant) Guide to Ruby』(http://mislav.uniqpath.com/poignant-guide/) [5]

Ruby界の伝説的ハッカー_why氏による風変わりで楽しいRuby入門です。この章のRubyの品詞の説明は、このドキュメントを参考にしました。