世の中のOpenFlowコントローラの動向から透けて見えるもの?(Nicira Networks編)

エンジニア、みんな大好きな、PublickeyにOpenFlow界の注目かつ謎の企業Nicira Networksのインタビュー記事が出たことを記念して!?OpenFlow界の動向など書いてみる。

インタビュー:ネットワーク仮想化で注目される米ベンチャーNicira Networksが実現しようとしていること - Publickey

今回、Publickeyにインタビュー記事が出たNicira Networks。言わずとしれた、OpenFlowの申し子というべき企業。Nick McKeown研究室出身のMartin CasadoをCTOに据え、一番有名と思われるOpenFlowコントローラであるNOXを開発してきた企業だ。

私が見るに、OpenFlow界というか、ネットワーク仮想化の業界においてトップランナーだと思われるのだが、いかんせんPublickeyの記事にもあるようにステルスモードなので、外からは全く何をしているのかよく分からない。一方で、NTTと共同で遠隔ライブマイグレーション実験などを行ったり、東京エレクトロン日本での販売代理店契約を結んだりしている。

アメリカでどの位商品を販売しているのかという情報がうかがい知れないのだが、日本で販売活動をしているというのが、意外というか、日本を市場として重視していそうな気配である。

その、Niciraの商品はNicira Network Virtualization Platformというらしいのだが、これまた製品として販売しているわりには正体が分からない。

NOXの開発がGitのログを見る限りここ最近(2011年3月くらいから)全く活発ではない、また、CTOのMartin Casadoを含めたNiciraの面々が著者のOnix: A Distributed Control Platform for Large-scale Production Networksを2010年のOSDIに発表していることを考えると、上記のNicira Network Virtualization PlatformはNOXをベースではなく、Onixベースの商品と考えられる。

Onixは、マルチコントローラに対応したOpenFlowコントローラの実装である。OpenFlowのコンセプトで重要なのは、Logically centralizedなネットワーク制御だと私は思っているので、そのコンセプトを具現化した現時点で明らかになっている唯一の実装といって良い。論文の詳細はそのうちブログで紹介したいと思うが、Onixの核をなす思想は、ネットワークの状態というのはグラフ構造で表現できるというものだ。論文の中では、NIB (Network Information Base)と読んでいる。スイッチ間のトポロジだけでなく、スイッチとポートの関係などネットワーク全体の情報は、ノードとエッジ、それらに付けられた属性からなるグラフ構造そのものだというのが彼らの主張である。また、アプリケーションによって求められる一貫性のレベルやレスポンスが異なるので、Onixでは、SQLが使えるトランザクションをサポートしたデータベースと、DynamoライクなKey-Value Storeを用意しているということだ。

Niciraの求人を見ると、Senior Software Engineer - Distributed Systems, Apache Zookeeper, Cassandraとか出ているのを見るとやっぱりOnixベースの商品を開発しているんだという考えをサポートするものだ。余談ではあるが、ちょっと前には、Suppor Engineer - Tokyoなるポジションも出ていた(もう無くなっている)

Niciraは、Open vSwitchには、OpenFlowプロトコルにNXMというNiciraのベンダー拡張機能を実装しており、そのメッセージはOpenFlow標準のメッセージより遙かに大量にあったり、OpenStackにも相当コミットしていると聞く。CTOのMartin Casadoは自身のブログでSoftware Defined NetworkのコントローラのAPIの標準化には否定的な考えをしてしているが、これは、自社の製品への自信から来るものなのかもしれない(もちろん、自社へのメリットを得るためのポジショントークの面もあると思う)

LinkedInに登録されている従業員数だけでも70人なので、従業員100人規模くらいであろう。来年2月には、ステルスモードから脱却するということで、それは怖くもあり楽しみでもある。

第2回クラウドネットワーク研究会で発表しました

通常、こういう勉強会では単なる聴講者の立場なんですが、細々とOpenFlowコントローラを作っているという話をしたというのをきっかけにして、@ibuchoさんの好意で第2回クラウドネットワーク研究会で発表する機会を頂けました。

参加者の人がまとめたブログがあまり見つけられなかったので、自分で作ったTogetterを張っておきます。Ustream録画もあるようなので、大体話は追えるような気がします。ツイート量が多くて追うのも大変かもしれませんが。
第2回クラウドネットワーク研究会 - Togetter

  • NTTデータの樋口さんからは、OpenFlowのオーバービューとマルチベンダ相互接続実験の話
  • 私からは、世の中にOpenFlowコントローラはどんなものがあるのかと、実際にOpenFlowコントローラを作るにはどうすればいいのかという話
  • あくしゅの山崎さんからは、Wakame-vdcでのOpenFlowのユースケースの紹介
  • NECの高宮さんからはOpenFlowフレームワークのTremaの設計思想とその紹介

Wakame-vdcでのOpenFlowの使い方は、全然気がつかなかったけど、言われてみれば確かにその通りと思うような内容だったし、Tremaの設計思想はとてもユーザーフレンドリーで使いやすさを重視とということでとてもためになったし、刺激的な勉強会でした。

Ustreamの録画をおそるおそる見たりしての自分の発表についての反省は、

  • 母に指摘されたが、語尾がもごもごしている
  • 「えーとっ」とか「まー」とか、無駄な埋め草が多い。言葉が出てこないなら、一呼吸置いた方が聞いている人も聞きやすいだろう
  • 話すスピードが早いので、聞いている人に考える間を与えずにすっ飛ばしている印象を与えている可能性が高い

などと、反省すべきところがたくさんで、自分の発表の録画を見返すものは見ていて精神的につらいものです(笑)スライド作るの精一杯で、練習できなかったことに全て起因しているので反省しまくりです。練習不足とか、スティーブから怒りの鉄拳が飛んできそうです(笑)

零細!?OpenFlowコントローラ開発者としては、Tremaの話を聞いて、ユーザーに楽をさせるために、開発者が頑張らないといけないのだということを強く感じました。開発者が楽をするために、ユーザーが面倒なことをすることを強制するソフトの作りにしてはダメで、ユーザーのことを思って面倒くさいこと、単調作業だけどやらなくてはいけないことを開発者が引き受けないといけないのだと。このように感じたことを生かして、使いやすいOpenFlowコントローラ目指して時間が最近取れていませんが細々開発して参ります。

まずは、使ってもらえる気になるドキュメントが必要だなと・・・・ APIは試行錯誤なので、しばらくは安定しない予感。。。

懇親会の時に、話しかけてもらいやすくなるってのと、なんだかTwitterのフォローが増えるってのが、発表した目に見える影響って感じでしょうか。

ソースコードがカオスという話もありますが、Open vSwitchの知識が不足していると感じるので、自分にブーストをかけるためにもOpen vSwitch勉強会&ソースコードリーディングでも行えたらなと思ったりしています。勉強会するまでもなく、実際に使っているという話が多そうな気もしていますが。

Python Developers Festa 2010.10で発表してきました

Python Developers Festa 2010.10に行ってきた。LTを申し込んでみたのだが枠一杯ということで単なる1聴講者のつもりで参加する気でいたら、AWSの発表者が仕事が忙しく発表できなくなってしまったらしく水曜日だか木曜日に@Voluntasさんから発表しないかとのお誘いがきて、せっかくの機会なので引き受けることにして急遽発表者としての参加に。機会をくれた@Voluntasさんに感謝します。

会場はオラクル青山センター。何度か行ったことはあるが、毎回、本当にいい環境だなと思う。100人以上の人がWiFi使っても急激に遅くなったりするようなこともないし、本当にファシリティーがすばらしい。会場提供のオラクルさんにも感謝しなくてはいけないなと。ねー、自分の会社でも、こういった勉強会を開けたらいいんだろうけどぱっと見は難しそう。勉強会クラスタにあまり多くない気がする私の会社。でも、オラクルだって最初の1回を行うのにはいろいろの人の努力があって筋道が出来て、既成事実化して今があるのかとか考えたりした。先駆者の皆様、本当にありがとうございます。

こういう勉強会って、「俺、オープンソースのXXXっていうプロジェクトのコミッターやってるけど」とか、「未踏ソフトのスーパークリエイターでした」とか、そういう感じにプレゼンスの高いスーパーハッカーの集まりのイメージがあったけど、会場に入ってみると女性も結構いるし、年齢層も思いの外幅広い印象。午前中のハンズオンは、Python初心者向けのが一番人が集まっていたし、印象と実際はかなり違うのもであると感じた。Pythonって勉強しようと思わないとやることのないマニアック言語だと思っていたんだけど、かなり浸透しているのだろうか?

ハンズオン

午前中のハンズオンは、@Voluntas講師によるgit-flowのレクチャーに参加したが、この時点で午後の発表資料は完成していないという状態。GitもMercurialも使い方は大体分かるのだが、ソフトウェア開発を生業にしているわけでもないので、一人で使うことはあってもチームでの開発をするってことは無い環境にいる私はこういうVCSの運用ルールの定石とかよく分かっていない。そういうこともあって、git-flowのブランチ戦略の話は凄いためになった。

Gitはハイスキルなメンバーからなる少人数での開発に適しているという話を聞いて、Gitを使って開発をしようとしている自分としては一抹の不安を覚えてしまった。git-flowを導入しようかな・・・・

git-flowのインストールをMacportsでやるために実行したら、依存関係のある大量のソフトのコンパイルが始まってしまい、あげく依存関係解消後に行われるgit-flowのインストールはGitのポートが開いていないため失敗。周りの人の進み具合からも完全に取り残された感じになったので、午後の発表資料の内職に入るなど講師の方に失礼なことをしてしまったことを考えると、最初から素直にモクモクゾーンで作業をした方が良かったのかもしれない。

昼食

とんかつメンバーに混ざるも、お目当てのとんかつやはセレブな奥様方の鍋会?に占拠されており、インドカレーにリダイレクト。ナンのおかわりをしたのはやり過ぎたかもしれない。午後ずっとお腹に感じる存在感がはんぱなかった。カレー自体はおいしく、ぼっちめしも回避できたので良かった。

LT@午後

@Voluntasさんから開催案内に載せているLTの発表順序はフェイクというかその発表順序とは関係なく、適当に呼び出しますとアナウンスされて、「聞いてないよー」という気分に。そういうこともあって、自分の発表の前の発表は心を落ち着けて聞けなかった。ザ・小心者。Koshinukeは是非とも欲しいです。社内からGitHubやBitbucketを使うのはいろいろ難しそうだし、そういうルールが時代に追いついていない感じで正面突破もいばらの道そうだし。

で、自分の発表。一言で感想を言うと、聞く側への配慮が足りない発表であったと凄まじく反省。結果として、全力で会場を置いてきぼりにしたような雰囲気になってしまった。一人で暴走している雰囲気は自分で感じ取ったんですがどうすることも出来ず。バックグラウンドがいろいろな人が混じったところでの発表の難しさを再認識。一応、自分では配慮したつもりではあったけど、それは配慮すらなっていなかったという話。この辺、研究会とか同じ背景知識を共有しているコミュニティでの発表が多い弊害だなと思った。ルータとか分かるだろって思っていたのが間違いの始まりだった。結局、OpenFlowを知っている人には知っている話しか提供できず、OpenFlowを全然知らない人には全くついて行けない発表になってしまった。。。。

そんな中でも、話に興味を持ってくれたり、新しい知識として刺激を受けた人がいたとすれば幸いです。

HadoopやAsakusaの発表で、Hadoopのことを知っている人の多さには驚いた。もう、普通の技術になってきているってことなのか?だとすると、もうHadoopのシステムくめますとか、プログラミングできますとかでは差別化要素にならないっていう状態になってきているのだなと思うと、技術の流れの速さは凄まじいなと。

最後のLTは、ウェブ魚拓の社長による東日本大震災被災の体験記。非常に中身の詰まった重い話だった。とても考えさせられた。

次回

会場で次回の開催日程が決まった。今のところ何もなければ参加予定。すでに、194/145ってすごくないか!?
http://www.zusaar.com/event/158001

ITpro EXPOでNTTデータのOpenFlowデモを見てきた

NTTデータが先日発表したOpenFlowのマルチベンダ相互接続の展示をITpro EXPOしているというのを本日の朝にしったので急遽出張。OpenFlowのコントローラを作っているという話なのでそのあたりを詳しく聞くのが目的

展示内容

NTTデータの開発したOpenFlowコントローラと複数のベンダーが開発したOpenFlowスイッチの相互接続をするというデモ

ネットワークの構成要素は以下の通り

  • OpenFlowコントローラ
    • NTTデータフルスクラッチで開発した
    • Hinemosに追加するオプションとして開発
    • 来年4月に発売することを目指して開発している。Hinemosの追加オプションとして提供予定
    • 発売当初には、NOXなどで提供されているデベロッパ向けのAPIは提供せず、ありものを使う形の予定
  • OpenFlowスイッチ
    • ハードウェア実装: Brocade, Arista, Extreme, NEC, Pronto
    • ソフトウェア実装: Open vSwitch
    • NEC, Prontoのスイッチは商用製品を購入。Brocade, Arista, Extremeは開発中のプロトタイプを借りている
  • ロードバランサ
    • NetScaler
  • ファイアーウォール
  • Vyatta
  • 仮想化環境
    • Citrix XenServer

Hinemosで仮想ネットワークを図を書くように定義するとそれに合わせて設定してくれるらしい。物理ネットワーク画面上に設定されているフローの経路が表示され、一つのスイッチを無効化してそのスイッチを通らないような設定にすると、それを避けるように経路が再計算されて、新しい経路がスイッチに設定されるというデモだった。エンドホスト間でpingを送信し続けていて、経路切り替え時にはRTTが増加。

ブースの担当者の方との会話から

  • コントローラがデベロッパーに見せるAPIをどのように設計するかというのは難しい問題で、協力しているNECさんも同じ事を言っている。APIがプリミティブだと作り込みが大変だし,抽象化したAPIだとかゆいところに手が届かないってことがあり得る
  • HinemosはJavaベースで開発されているため,恐らくコントローラもJavaで開発しているだろう(実際に開発を担当した人が不在であったため詳細不明)
  • SIerの立場から,お客様への対応を見越して,ノウハウの蓄積という意味でマルチベンダ間の相互接続検証を進めている
  • 今回の発表やデモに名前が出せなかったベンダーもあり、そのスイッチについての検証を進めている
  • コントローラがターゲットとするOpenFlowのバージョンは1.0.Ver. 1.1対応の実装ってのは現時点ではないはず
  • OpenFlowスイッチの実装としては,Open vSwitchが標準的な実装だという考えでいる
  • OpenFlowの仕様書の記述は甘いところが多いという印象がある
  • 物理トポロジのディスカバリーはLLDPでやっている。この辺は、NECの実装も同じではないか。
  • マルチベンダの相互接続時によくある,各社の実装の違いによる差の吸収がやはり大変だった
  • フローテーブルの書き込みに対して各スイッチの反応時間がばらつきが原因でうまく動かなかったりした
  • OpenFlowスイッチとしてしか動作しないスイッチと,単なるL2スイッチやルータとしても動くしOpenFlowスイッチとしても動くというような動作の違いがベンダーによってあった。
  • プロトタイプのスイッチが実際に届いたのは2ヶ月前
  • サーバー,VMの管理からネットワークの管理までを統合的に行えるところはアメリカにはほとんど無いらしい
  • ブロケードはOpenFlowコントローラは作らないと宣言しているし,サーバからネットワークまでの統合ソリューションを持っているのはミドクラぐらいではないのか
  • (今回展示したスイッチは商品化前提のプロトタイプなのか?という質問に対して)BrocadeとExtremeは確か製品として販売予定であるというような発表をもうしているはずで来年ぐらいには出てくるのではないか,Aristaはそのような発表をしてはいないのでどうなるのかよく分からないという回答
  • 今は業界を盛り上げるのが大切.競合より協業.
  • OpenFlowコントローラはまだ決定的なものがないので,今からでもメインプレーヤになれる可能性がある可能性があるのではないか

感想

やはり、プロトタイプのスイッチを入手して一緒になってInteropをやれるのは大企業だからこそと感じた。個人の場合は、まず、Open vSwitchくらいしか入手できないし。

Open vSwitchがOpenFlowスイッチの標準的な実装であるとか、Ver. 1.1準拠の実装がないとか、OpenFlowの仕様書の書き方が甘いとかというのは私の認識と同じだった。

Galibierの実装頑張らないといけないなぁ

第1回GraphDB勉強会に参加してきた

10/7にフューチャーアーキテクトさんで開催された、第1回GraphDB勉強会に参加してきた。

この手の勉強会には、今のところ完全に聞く側だけの参加で何のコントリビューションも出来ていないので、運営側の人には感謝しっぱなし。ありがとうございます。

資料とTogetterは@bibrostさんがまとめてくれている模様。
http://graphdb.jp/2011/10/51/

それにしても、@doryokujinさんは3セッション=3時間の話のネタを用意して実際に発表するのだから凄いなと。それでいて、私よりも何歳も若いと来ているのだから、自分のコンピテンシーについて考えさせられてしまう。

The Definition of GraphDB (@doryokujin)

グラフって何かという話。棒グラフとかのグラフではなく、グラフ理論のグラフ。頂点とそれらを結ぶ辺から構成される。

グラフの種類
  • 有向グラフとか無向グラフがあるけれども、無向辺は2つの有向辺に変換可能なので全部有向グラフとして扱う
  • Single-Relational Graph
    • 全部の頂点と辺のタイプが単一のグラフ
  • Multi-Relational Graph
    • 辺のタイプが単一ではない
    • 頂点のタイプも単一ではない

いろいろなGraphDBで共通のグラフモデルとして扱われているのはProperty Graphと呼ばれる種類のグラフ。Multi-Relational Graphの頂点や辺にKey-Valueで表現されるプロパティを持つグラフをProperty Graphと呼ぶらしい。

Hyper Graphというグラフの種類を採用したGraphDBもあるらしい。

グラフの探索
  • GraphDBにおけるクエリ=グラフの探索
  • ある頂点を起点として、その近傍を調べていく
    • RDBではある条件を満たす集合を調べるのに対して、GraphDBでは一つのノードに注目してその周囲を調べる
    • RDBのクエリはGlobalな検索、GraphDBのクエリはLocalな検索
  • 幅優先探索深さ優先探索がある
  • Stepと呼ばれる最小単位でグラフ探索の移動を表現する
  • GraphDBを使うためにはどのようなクエリを実行したいかが念頭にないと難しい
    • 特定のノードに着目した検索はGraphDBは得意
    • 条件を満たすノード全てを取得するような検索はGraphDBは得意ではない。こういうのはRDBの方が良い。
GraphDBと呼ばれる条件

RDBでも当然グラフ構造を格納することは出来る。では、GraphDBと呼ばれるためには何が必要か?-->Index-Free Adjacency

  • Index-Free Adjacency
    • Adjacencyの発音が難しいw
    • 全てのエレメントが自分の隣接のエレメントの情報を持っているという性質
    • DB的に言うとダイレクトポインタを全てのエレメントが持っている (Mini-Index)
    • 大規模グラフにおいて、インデックスツリーを参照するコストがバカにならないので、それを抑えられる。
    • GraphDBでは、Globalな検索はしないので
    • 辺やノードに与えられたプロパティについてはインデックスツリーを持っているが、ノードや辺の関係性を表現するためにはインデックスツリーを持っていない

ノードは内向きの辺、外向きの辺両方について情報を持っているので、自分に向かう辺も簡単に得られるらしい。

An Introduction to Neo4j (@doryokujin)

  • グラフ探索
    • 引数たくさんのメソッド呼び出し
    • メソッドチェーン
    • NeoなのでMatrixの人物相関図がグラフの例として使われることが多いw
  • Cypher
    • SQLライクな?グラフ探索用のDSL
    • 個人的には読みやすいとは思えなかった
    • 出てからまだ数ヶ月しか経っていない
  • その他機能
    • High Availability
    • Online backup
      • こちらも有償版のみ
    • Java Firstで開発されているが、ErlangPython, Ruby, Scalaなどから使うことが出来る。JVM言語はサポートされている感じ

An Introduction to Tinkerpop (@doryokujin)

各GraphDB固有のAPIに依存せずに統一的なGraphの操作を行うためのライブラリがTinkerPop

  • Blueprints
    • Graph DBに対する共通のAPIを提供している
    • ベンダーロックインを避けるのを目標として開発されている
    • RDBでのJDBCに相当するもの
    • TinkerGraphというLightweightなim-memoryのGraphDBがあり、ちょいと使うには便利
  • Pipes
    • フローを記述できる?よく分からなかった。。。
  • Gremlin
    • グラフ操作に特化したグラフ特化言語
    • GremlinはTinkerPopの真骨頂
    • 直感的な言語で対話的な操作が可能
  • reXster
    • REST APIを提供
    • InputはURI, OutputはJSON
    • The Dog Houseというウェブコンソールが提供されている

から構成される。

Enjoy Graph DB! (@bibrost)

この辺で追いつくのに力尽き。。。

次回

ミクシィさんで開催

OpenFlowのベンチマークプログラムをJavaで書く

昨日に引き続き、OpenFlowネタ。昨日のエントリの最後の方で、OpenFlowコントローラのベンチマークの話に少しだけ触れた。OpenFlowコントローラを作っている過程でOpenFlowコントローラ用のベンチマークプログラムを自作したのもあり、OpenFlowのベンチマークについて書く。

OpenFlowスイッチやコントローラのベンチマークプログラムで一番に思い浮かぶのは、OpenFlowの総本山スタンフォード大学のProf. Nick McKeownのグループが開発しているoflopsである。というか、oflops以外に少なくとも私は聞いたことがない。

oflopsはgitレポジトリから

# git clone git://gitosis.stanford.edu/oflops.git

で、入手可能。正しく説明すると、oflopsはOpenFlowスイッチ用のベンチマークで、同じパッケージに含まれているcbenchがOpenFlowコントローラ用のベンチマークになる。そのため、コントローラのベンチマークが目的な今回はcbenchに限った話である。私はOpenFlowスイッチを作っているわけではないので、oflopsをどのように使うのか調べたことがないのでよく分からないが、恐らくOpen vSwitchのOpenFlow対応部分を作っている人などは使っているのだろうと思われる。

私の不勉強のせいなのか、そもそもLinuxに依存しているのか、はたまた依存ライブラリを入れていないだけなのかよく分からないが、私が使っているMac OS X Snow Leopardではoflopsパッケージ全体のmakeに失敗して、それを解決するのもMacPortsやら何やらが絡むと面倒そうだったので、思い切って自作してみることにした。コントローラと同じ様にJavaで作る。Javaで作れば、ポータビリティが高くなるし、Netty使えばとりあえずパフォーマンスは問題無さそうな気がしたので。

OpenFlowコントローラのベンチマークって?

OpenFlowコントローラのベンチマークって一体何をして負荷をかけるのか?という疑問がまず起きる。素直にcbenchを参考にさせて頂くという方針をとった。cbenchのREADMEによると、

cbench is a benchmarking tool for controllers

Algorithm:
    pretend to be n switches (n=16 is default)
    create n openflow sessions to the controller
    if latency mode (default):
        for each session:
            1) send up a packet in
            2) wait for a matching flow mod to come back
            3) repeat
            4) count how many times #1-3 happen per sec
    else in throughtput mode (i.e., with '-t'):
        for each session:
            while buffer not full:
                queue packet_in's
                count flow_mod's as they come back


NOTE: packet_in messages are the only (?) switch-solicited openflow
packet that should get a response from a controller.  Would be
nice to evaluate more, but this is at least something.

とある。つまり、n個(デフォルトではn=16)のスイッチのふりをして、コントローラに接続する。レイテンシモードでは、各セッション毎に

  1. PACKET_INをコントローラに送り、
  2. コントローラからFLOW_MODが返ってくるのを待ち、
  3. それを繰り返す。

スループットモードでは、各セッション毎に、

  1. バッファがフルになるまでPACKET_INをキューイングし、
  2. FLOW_MODの返信と関係なくPACKET_INを送信し続け
  3. FLOW_MODが返信されたら、カウントする。

という動作をしているとのこと。

さらに、ソースコードの内容の中身を見てみて、動作の詳細を確認。fakeswitch.cの中のvoid fakeswitch_handle_read(struct fakeswitch *fs)を理解すればほぼ内容がつかめる。その動作をおおざっぱに要約すると、

  • セッション確立時にはHELLOを送る
  • FEATURES_REQUESTを受信したら、FEATURES_REPLYを返信
  • ECHO_REQUESTを受信したら、ECHO_REPLYを返信
  • VENDORを受信したら、VENDORを返信
  • GET_CONFIG_REQUESTを受信したら、GET_CONFIG_REPLYを返信
  • PACKET_OUTもしくはFLOW_MODを受信したら、カウンタをカウントアップして、PACKET_INをスイッチに送信

という感じの動作をしている。

Javaでのベンチマークプログラム

Nettyを使って、昨日のコントローラの用にChannelPipelineでframer, decoder, encoder, handlerを構成し、handlerにベンチマーク用の動作を記述すれば良いことになる。framer, decoder, encoderは使い回せる。

massageReceivedの中身は以下の通り。

素直に、必要な動作を記述している。このとき、返信するのに必要なデータの作成と受信したメッセージのカウントはfakeSwitchに委譲している。cbenchでは、FEATURES_REPLY, PACKET_INはwiresharkからキャプチャしたバイト配列がソースコードに直接記述されており、そのデータを送信するようになっているが、自作のベンチマークではFEATURES_REPLYのデータはcbenchのものを拝借したが、PACKET_INのデータは0で埋めたバイト列を送信するように手抜きしている。そのため、コントローラによってはPACKET_INに含まれるデータが有効なパケットデータと見なされずにうまく動作しない可能性もある。ただし、今のところリピータハブやL2スイッチ程度のアプリケーションを動かしたコントローラの動作しか試していないので、その範囲ではこのデータでも問題がなかった。

また、今回は、cbenchでいうレイテンシモードだけを実装になっている。というのは、スループットモードでは、送信バッファ一杯になるまでPACKET_INをキューイングしなければいけないのだが、Nettyを使ってそれをどうやって実現するか分からなかったためである。その実現方法を教えて頂ける方がいらしたら幸いである。

ソースコード

https://github.com/oshothebig/galibier
ソースコードを公開している。作り途中のOpenFlowコントローラの一部として今回のベンチマークプログラムが含まれている形を取っている(org.galibier.benchmarkパッケージがベンチマーク関係)前回同様、openflowjが別途必要である。

Mavenをいまいちちゃんと理解していないので、実行方法があまり美しくないが、以下のコマンドで、ビルドとlocalhostの6633番ポートで待ち受けるコントローラに対してベンチマークが実行が出来る。Mavenのセオリーを勉強しないといけないのだけれども、全容が把握できていないのと、ユースケースとそれを解決するセオリー的なやり方が分かっていない・・・

# git clone git://github.com/oshothebig/galibier.git
# cd galibier
# mvn package
# java -cp target/galibier-controller-0.1.0-devel-jar-with-dependencies.jar org.galibier.benchmark.Main localhost

設定可能なオプションは以下の通り。

 -d (--duration) N : Duration of a loop in milli sec
 -h (--help)       : Print this help
 -l (--loops) N    : Number of loops
 -m (--message) N  : Bytes of the payload of a packet in
 -p (--port) N     : Port number of the controller
 -s (--switch) N   : Number of switches

動作の不具合やソースのおかしな場所を見つけた場合には、ご連絡頂けると幸いです。

300行足らずで書けるJavaによるOpenFlowコントローラ

276行(ライセンス宣言を除いた222行)という数値にはインパクトがないような気もするが、OpenFlowコントローラをJavaで書いたみたので、その事をネタに久しぶりにブログを更新してみようかと。

いくつかのコントローラの実装を見たところ、エラー処理、例外処理とかを除けば基本的な部分を作成するのは自分でも出来る気がしたので、OpenFlowに興味もあるし、勉強がてら単純なOpenFlowコントローラを実装してみた。OpenFlowは今のところver. 1.1まで仕様が公開されているが、実装としてはver. 1.0までしか公開されていないようなので、ver. 1.0ベースでの実装ということにした。

言語の選択

個人的には、最近、Pythonをよく使っている(NetworkXが便利というのがその理由だが)のもあって、Pythonが一番慣れているのだが、動的型付け言語なので型チェックがないとか補完がないのが不便に思うことがあって、静的型付け言語から選ぶことにした。

自分の使える言語を考えると、候補としては、C, C++, Java, Scalaから選ぶことになり、無難に(?)Javaを選択。Javaを選択した一番の理由は、OpenFlowプロトコルのメッセージのJavaのライブラリが存在しているからというもの。意外に、ここら辺を一から実装するのは面倒なので、そこは車輪の再発明を避けて、他の人の成果に乗っかろうという方針。

本当は、Scalaの勉強ついでにScalaでやるという選択肢もあったのだろうけど、NIO周りも勉強しなくてはいけないので、両方一緒に勉強するのは結局先に進まなそうだなと思ってScalaは選択せず。Scala版は次回のお楽しみということで(笑)

方針

作成するに当たっての方針は以下の通り。

  • OpenFlow ver. 1.0ベース
  • NIOを使う
  • なるべくシンプルに
  • 外部ライブラリを使えるところは使う

OpenFlow ver. 1.0ベースにした理由は前述の通り。

次にNIOを使うのはOpenFlowコントローラはサーバプログラムだし、それなりにパフォーマンスに気をつけたいという気分から来ているだけで、特に深い意味は無いし、パフォーマンスの目標値もない。あと、ソースを見たらいくつかのプログラムがNIOというか非同期IOを使っていたので、一度使ってみたいという気分になったというだけの理由。

なるべくシンプルにということで、エラー処理・例外処理とかははしょり気味。また、スイッチがコントローラに接続/切断されたときにイベントが発生する実装は行わず、単純にコントローラにメッセージが届いたときにイベントが発生するような仕組みだけを実装。

シンプルにということとも関係する部分だが、OpenFlowコントローラを実装するに当たっての本質的な処理に集中したいので、面倒な部分で外部ライブラリを使うことで楽できる部分があるなら積極的に使う方針でやる。この方針に従って、OpenFlowプロトコル周りはopenflowjを面倒そうなNIO周りの処理はNettyを使うことにした。

コントローラ上で動くアプリケーションは、とりあえずリピータハブ(通称、バカハブ)を実装する。

コード解説

コードは、githubにアップしています。全てを1ファイル上にまとめてしまったのはJava的ではないのだがお許しを。

公開先:http://github.com/oshothebig/simple-controller コードとしては、SimpleController.javaだけ。

これを試すには、openflowjが必要ですが、(ちゃんとは探していませんが)Mavenのレポジトリはないようなので別途ダウンロードする必要があります。

# git clone git://openflow.org/openflowj.git
# cd openflowj
# mvn install

ChannelPipelineの構成

OpenFlowプロトコルのメッセージはTCPコネクションを通じてやり取りされるため、受信したストリームをメッセージ単位に切り出さなければならない。また、送信時にはメッセージオブジェクトをOpenFlowプロトコルに従ってシリアライズする必要がある。NettyではChannelPipelineという仕組みを使って、受信したストリームを切り出してPOJOに変換したり、POJOシリアライズしたり、プロトコルビジネスロジックを実装したり出来る。

今回は、framer, decoder, encoder, handlerでChannelPipelineを構成する。受信時には、framer, decoder, handlerの順でパイプラインの処理が行われ、送信時にはencoderだけで処理される(上記スニペットの5〜11行目)

メッセージの切り出し(Framer)

まずは、受信したストリームをOpenFlowプロトコルのヘッダに記述されたlengthフィールドの値に従って、メッセージ単位に切り出す必要がある。OpenFlowプロトコルのヘッダ情報は、スペックによると

であり、3バイト目4バイト目の計16ビットのフィールド値がメッセージの長さになるということと、バイナリ型のプロトコル用にNettyに用意されているメッセージ切り出しのためのクラスであるLengthFieldBasedFrameDecoderを用いると簡単にメッセージ単位の切り出しを行える。

LengthFieldBasedFrameDecoderのコンストラクタの各フィールドの値の意味は、APIドキュメントに詳細な例とともに載っているのでそちらを参考にして欲しい。

メッセージのパース(Decode)

メッセージ単位で切り出されたChannelBufferを受けて、OpenFlowプロトコルのメッセージを表現するOFMessageオブジェクトに変換する。

openflowjのOFMessageFactory#parseMessage()を使うことでByteBufferからOFMessageのリストに変換できるのでそれを利用する。ただし、OFMessageFactory#parseMessage()はByteBufferを引数として受け取るので、ChannelBufferと同じ内容のByteBufferを作成して渡すところがポイント(上記スニペットの9行目)

Framerによってdecodeメソッドに渡されるmsgはメッセージ単位に切り出せたChannelBufferであるので、リストの最初の要素だけをパイプラインのさらに上位に渡すようにする(上記スニペットの10行目)

メッセージのシリアライズ(Encode)

メッセージの送信時には、OFMessageオブジェクトからOpenFlowプロトコルの仕様に従ってシリアライズする(NettyでいうとChannelBufferに変換する)必要があるが、OFMessage#writeTo()を使うことで簡単に実現可能。

メッセージの長さだけのByteBufferを割り当て(上記スニペットの7行目)、割り当てたByteBuffer(response)を引数にしてOFMessage#writeTo()を呼び出すことで、responseにシリアライズされた内容が格納される。

9行目はハマリポイント。ここで、しばしハマった。ByteBuffer#flip()を呼ばないと、これ以上読み込めないと判断されてChannelに書き込まれないので注意。

ByteBufferの割り当て、つまり、ByteBuffer#allocate()を送信時に毎回行うのはパフォーマンス上の悪影響がありそうなのだが、割り当てを一度だけ行って使い回すとスレッドセーフじゃない気がするので、今回はあえてByteBufferを毎回割り当てている。

OpenFlowプロトコルの動作

OpenFlow ver. 1.0の仕様によると、コントローラとスイッチ間のコネクションが確立した時のハンドシェイク動作は以下の通り。

  1. コネクションが確立したら、コントローラ、スイッチともに対向側にHELLOメッセージを送信する
  2. スイッチが送信したHELLOメッセージをコントローラが受信したら、コントローラはスイッチに対してFEATURES_REQUESTメッセージを送信する
  3. FEATURES_REQUESTメッセージを受信したスイッチは、コントローラに対してFEATURES_REPLYを返信する
  4. スイッチからのFEATURES_REPLYメッセージの受信をもって、ハンドシェイクが完了

ということで、まず、コネクション確立時にHELLOメッセージの送信。これは、以下の記述でOK。

それ以降の動作は、OpenFlowSimpleControllerHandler#messageReceived()に記述している。


  • HELLOメッセージを受信したら、FEATURES_REPLYメッセージを送信(上記スニペットの7行目)
  • ECHO_REQUESTメッセージを受信したら、ECHO_REPLYメッセージを返信(上記スニペットの9行目〜13行目)
  • FEATURES_REPLYメッセージを受信したら、ハンドシェイクの完了をログに出力(上記スニペットの16行目)
  • HELLO, FEATURE_REPLY, ECHO_REQUEST, ERROR以外のメッセージを受信したらリスナーを呼び出し(上記スニペットの23行目)

ECHO_REQUESTメッセージに返信を行わないと、相手側から死んでいると見なされて切断されるので9〜13行目は追加で必要となる。本来なら、ECHO_REQUESTをコントローラ側から定期的にスイッチに対して送信してLivenessのチェックをする必要があるのだが、無くてもOpen vSwitch相手の場合は問題ないので今回は入れていない。

リピータハブとしての動作

MessageListenerを実装した無名クラスを作成して、SimpleController#addMessageListener()に渡している。

スイッチに到着したパケットが、スイッチに設定されているフローテーブルの条件にどれも一致しない場合にPACKET_INメッセージがコントローラに送られてくるのだが、今回はリピータハブの実装なので、送られてきたPACKET_INメッセージの内容に従って、元のパケットの内容のままでフラッディングでの送信を実行するPACKET_OUTメッセージをスイッチに対して発行すればよい。

上記スニペットの12〜15行目でフラッディングでの動作を指定し、18〜25行目で元のパケットの内容を指定する。PACKET_INメッセージのbuffer_idが0xffffffffの時は、バッファリングされていないことを示し、その時は、PACKET_OUTメッセージのデータ領域にPACKET_INメッセージに書かれている内容を設定する。buffer_idに有効な値が設定されている場合には、PACKET_OUTメッセージのデータ領域にデータが設定されていなくても、スイッチ内でbuffer_idを元に解決される(みたい)

動作

手元の環境では、Open vSwitchをVMware上に入れて試すことぐらいしか出来ないため、ちゃんと動作確認を行えているわけではないのだが、少なくともOpen vSwitchからコントローラに接続でき、切断されないことは確認した。

以下のコマンドで、リピータハブとして動作するアプリケーションが今回作成したOpenFlowコントローラ上で実行できる。

# mvn exec:java

cbenchという、OpenFlowコントローラの性能のベンチマークプログラムを接続して、今回作成したコントローラのベンチマークも行うことが出来る。cbench(というか、cbenchを含んだプログラムであるoflops)はgitで以下のコマンドで入手できる。

# git clone git://gitosis.stanford.edu/oflops.git

手元でVMwareでcbenchを動かしてみたところ、20,000 req/secぐらいの性能だった。自作のベンチマークツールでVMwareを使わずにローカルでベンチマーク、コントローラ両方とも動かした時には、33,000 req/sec程度だった。公開されている、コントローラのベンチマークと比較すると大分スループットが小さいが、比較環境も違うしなんともいえないが。Nettyを使っているだけあって、ベンチマークで負荷をかけたときにはコアを使い切っているみたいだし、恐らくそんなにパフォーマンスは悪くない気がする。

というわけで、ざっと作ってみたものなので、アラもあると思います。ここがおかしいとか、こうした方がいいとか気がついた人はコメント頂けると幸いです。