OpenFlow 1.2で遊んでみた。Play with OpenFlow 1.2

大平です。
最近何かと話題のOpenFlowについて、私もちょっと触ってみましたのでそのご報告を兼ねまして。

OpenFlowがどういうものなのか、導入前に何を考えるべきかなどは、Software Design 2012年11月号あたりをご参照ください。
本記事では、「とりあえずそのあたりはなんとなくわかった。じゃあ実際のところどういう風にコントローラを作りこんでいけばいいのか」といったところを書いてみようと思います。

OpenFlow 1.2の詳しい仕様は、OpenFlow Switch Specificationをご参照いただければと思いますが、マッチングルールの書き方が全く変わってしまったことから、OF1.0(or1.1)とはほぼ別物と思ってもらっていいように思います。
IPv6対応のこともありますので、OF1.0(or1.1)は今後忘れることにします。

ざっくりとしたOpenFlowでの制御の流れ

スイッチがどういう転送を行うか、その制御をコントローラが行うことになります。
ではまず、制御用のメッセージがスイッチとコントローラの間でどのように交換されるか見ていきましょう。

of_msg

初期情報として、スイッチにどのようなポートがあるのか、それぞれのインタフェース速度は、などの情報をスイッチから受け取ります。
また、スイッチが取り扱い方法を知らないパケットが来た時には随時、「こんなパケットが来たんだけど」という情報がスイッチから送られてきます。

コントローラで何か制御するためにはこれらのメッセージ(図中緑字)を解釈して、赤字のメッセージを出せばよいことがわかります。
初期設定では、

  • スイッチから受け取ったFeatures Replyメッセージの解釈
  • スイッチに送るFlow Modメッセージの作り込み

逐次設定では、

  • スイッチから受け取ったPacket Inメッセージの解釈
  • スイッチに送るPacket Out及びFlow Modメッセージの作り込み

を行うことになります。

いざ実践

材料

OpenFlow1.2に対応したスイッチとコントローラを用意します。今回は下記のものを使いました。
スイッチ: of12softswitch
コントローラ: Ryu

作品1 (ラーニングスイッチ)

Ryuのサンプルコードとして最初から存在するのですが、こいつはOpenFlow1.0で作られた代物なので、1.2対応に作り変えてしまいます。
また、MACアドレス情報をmatchフィールドから取得するように変更します。
なお、この際なので関数名・引数の整理なども行います。

詳細はソースコード(of12play1.py)を見ていただくとして、ざっくりと、Packet Inを受け取ったら下記の処理をする旨、packet_in_handler関数に書いています。

  1. matchフィールドをざっと見て、入力ポート(in_port)、送信元MACアドレス(dl_src)、宛先MACアドレス(dl_dst)の情報を取得する。
  2. 送信元MACアドレスと入力ポートの対応関係を控えて今後の出力ポート(out_port)決定に備える。
  3. addflow関数経由でOFPFlowMod関数を呼び出し、Flow Modメッセージをスイッチに送る。
  4. OFPPacketOut関数を呼び出し、Packet Outメッセージをスイッチに送る。

packet_in_handler関数から呼び出されるaddflow関数では、スイッチでどのようなパケットをmatch対象にすべきかをOFPMatch関数及びそれに続くmatch.set_XXX関数で設定しています。

作品2 (ミラーリングスイッチ)

最初のpacket_inが来る前に、スイッチの初期動作を定義したいということがあるかと思います。
詳細はソースコード(of12play2.py) を見ていただくとして、ざっくりと、Features Replyを受け取ったら下記の処理をする旨、switch_features_hander関数に書いています。なお、本例ではスイッチのポート#1 と#2の間でやり取りされるパケットを#3にミラーリングする、という想定です。

  1. #1からのパケットの出力先を#2と#3に設定する。#2からのパケットの出力先を#1と#3に設定する。それ以外のパケットは捨てるように設定する。
  2. addflow関数経由でOFPFlowMod関数を呼び出し、1.の指示を含めたFlow Modメッセージをスイッチに送る。

出力先ポートを複数設定したい場合の書き方がこれでお分かりかと思います。
あと、もうお気づきかと思いますが、OFPFlowMod関数のout_port引数は無視されます。

あれ?

上記2作品、IPv6なんてひとつも出てきてないやんと気づかれた方、正解です。
そのあたりは今後作り込んでいこうと思っています。
が、「どういう制御をしたいか」と「どこにどういうことを書けば実現できそうか」の両方を押さえていれば、そのあたりはさくっと出来ますよね(希望的観測
あとほんとはエラー処理とかいろいろやらないといけないことはあるのですが、それも全部「今後の課題」とさせてください。

それでは。