ここまでOpenFlowのプロトコルや動作モデル、そしてTremaを使ったOpenFlowプログラミングを学んできました。一人前のOpenFlowエンジニアとしてやっていくために必要な基礎知識はすでにひととおり身についたと言えます。
あとはひたすら実践するだけです。今まで手に入れた知識を実際に道具として使い、いま生活しているネットワーク上でOpenFlowを実際に動かしてみるのが一番です。まずは自宅のネットワークをOpenFlowで置き換えましょう。これがうまくいき物足りなくなったら、こんどは職場で小規模にOpenFlowネットワークを作りましょう。このように徐々に規模を広げて行くのです。
実際にその環境で暮らしてみて、はじめて見えてくるニーズやアイデア、改善案があります。初めて自転車に乗ったときのことを思い出してください。補助輪をはずしただけで最初は派手に転びますが、多少はケガをしつつもあきらめずに練習を繰り返しているうち誰でも乗りこなせるようになります。自転車に乗れれば、隣りの街やそのまた隣りと行動範囲は一気に広がります。しかし補助輪をはずさずにただ考えているだけではどこにも行けません。
「でも、いきなりOpenFlowに移行してもし大失敗したら……」。そう考えるのが人情です。家のネットワークはともかく、もし職場のネットワークを止めて同僚に迷惑をかけてしまったらどうしよう……。管理者や上司に注意されたらどうしよう……。
本章ではそうした大失敗を防ぐためのヘルメットを紹介します。筆者らは、OpenFlowが登場したころから職場のネットワークで実験を始め、それこそ数え切れないほどの失敗を繰り返してきました。とにかく何度も怒られましたが、その経験からうまくやる方法をアドバイスできます。私たちは既存のネットワークを穏便にOpenFlowに移行するテクニックを持っています。ちょっとしたOpenFlowコントローラを書くだけで、移行の際に起こりがちなネットワーク障害を簡単に防げるのです。
まずは、私たちの失敗談を振り返らせてください。
OpenFlowが登場したばかりのころ、私たちはさっそくスイッチングハブ相当のOpenFlowコントローラを書いて小さなOpenFlowネットワークを職場に構築してみました。「おお、ちゃんと動くじゃん!」気を良くした私たちは、こともあろうにこのOpenFlowネットワークと職場ネットワークとをいきなりつないでしまいました。まあ大丈夫だろうと楽観的に考えていたのです。
しかしすぐにネットワーク障害が起こり、異常に気づいたネットワーク管理者からお叱りのメールを受け取ることになりました。障害時のセットアップを単純化すると図10-1のようになります。
職場ネットワーク(レガシーネットワークとします)のスイッチにはホストを2台つないでおり、スイッチのポート3番をOpenFlowスイッチのポート1番と接続しました。このOpenFlowスイッチは、私たちが書いたスイッチングハブ相当のOpenFlowコントローラ(仮にBuggyControllerとします)で制御していました。
ネットワーク管理者から届いた障害報告メールには次のようにありました「レガシーネットワークのホストどうしが通信できなくなった。スイッチはHost Flapping警告を出している」
Host Flappingとは、1つのホストがいくつかのポートの間で高速で移動しているように見えるという障害です。「なんでそんなことが起こるんだろう?」われわれはすぐにOpenFlowネットワークを切断し、そしてもちろんネットワーク管理者にはごめんなさいメールを出してから、原因の分析にとりかかりました。
分析の結果、図10-2のようなシナリオが起こっているという結論に至りました。
-
host1がhost2へパケットを送信する
-
BuggyControllerはOpenFlowスイッチポート1番からのPacket Inを受け取り、OpenFlowスイッチのスイッチポート1番にhost1がつながっていると学習する
-
レガシーネットワークスイッチが覚えている host1 の情報がエージアウトし消える [1]
-
host2がhost1へパケットを送信する
-
BuggyControllerはスイッチポート1番から宛先=host1のPacket Inを受け取る。ここで、host1はOpenFlowスイッチのスイッチポート1番にあると学習しているので、スイッチポート1番にPacket Outする
-
結果的に、host1はポート2と3の両方から同じパケットを受け取る。レガシーネットワークのスイッチから見ると、host2がスイッチポート2番と3番を高速に移動しているように見える
つまり、BuggyControllerがレガシーネットワークにパケットを逆流させたおかげでネットワークが大混乱し、通信できない状況が起きたのです。
振り返ると、失敗した原因は2つありました。
1つは、OpenFlowネットワークをいきなりレガシーネットワークとつないでしまったことです。OpenFlowネットワーク単体では動いていたのに、というのは言い訳にはなりません。若気の至りや経験不足から来る青いミスです。もう1つは、BuggyControllerがPacket Inと同じポートにPacket Outするという通常あり得ない動作をしていたことです。要所要所で assert
を入れるといった防御的プログラミングや、ソフトウェアテスト(9章「Trema でテスト駆動開発」を参照)を徹底していれば防げるバグでしたが、当時の私たちは動かすことに精いっぱいでそこまで気が回りませんでした。
というわけで、大障害を起こして始めて気付くという最悪のパターンになってしまったわけです。
大失敗をやらかしてしまった筆者たちは、OpenFlow移行のための作戦を練りなおさざるを得なくなりました。いろいろな方向から考えなおしたところ、OpenFlowへの移行方法には次の3つのパターンがあることがわかりました。もちろん、それぞれでメリット/デメリットや危険度が異なります。
最初のパターンは、既存のレガシーネットワークにまったく手を加えずに、それとは独立したもう1つのOpenFlowネットワークを構築する方法です(図10-3)。それぞれのネットワーク間でパケットの行き来はなく、お互いに完全に独立しています。
この状態から、レガシーネットワーク内のサーバや端末を徐々にOpenFlowネットワークに移動することで移行していきます。
それぞれのネットワーク間ではパケットが行き来できないので、OpenFlowネットワークがレガシーネットワークに悪影響を及ぼす可能性はまずありません。ただし、OpenFlowネットワークに移行する際には関連する機器同士(ファイルサーバとクライアント群など)を一度に移行する必要があります。これはトラブルを起こす可能性が高いため、レガシーネットワークの規模が大きい場合には移行が難しいという問題があります。
次のパターンは、私たちがやったようにレガシーネットワークとOpenFlowネットワークをいきなりつなげてしまう方法です(図10-4)。
この方法だと、相互に通信できるのでネットワーク間でのサーバや端末の移動は自由にできます。このため、独立ネットワークパターンに比べて移行の手間はずっと小さいと言えます。
ただしこの方法は、私たちが失敗したようにとてもリスクの高い方法です。OpenFlowネットワークのコントローラが完璧に作られていれば、このようにいきなりつなげても問題はありませんが、完璧を期するのはなかなかむずかしいものです。というのも、実際のトラフィックをコントローラに流し込んでみて初めて見つかるバグもあるからです。よって、この方法は自宅ネットワークなど他人に迷惑のかからないネットワーク以外では推奨できません。
最後のパターンは、今までに挙げてきた2つのパターンのいいとこどりです。2つのネットワークを接続するのですが、そのときに逆流防止フィルタとなるOpenFlowスイッチを間にはさむことでパケットの逆流が起きないようにします(図10-5)。
この逆流防止フィルタはたとえば、レガシーネットワーク→OpenFlow ネットワークのような一方向のパケットは通しますが、同じパケットがレガシー側に戻ることを防ぎます。逆方向も同様です。
この方法の利点は、逆流を防ぐだけで今回のケースも含めたかなりの障害を未然に防げることです。また、使い勝手はいきなり接続した場合と同じなのでOpenFlowへの移行も楽です。ただし、2つのネットワーク間にもう1つフィルタ用のOpenFlowスイッチをはさまなければならないという手間はかかります。
検討の結果、逆流防止フィルタを使ったパターンが一番良さそうでした。フィルタを動かすためのサーバもちょうど余っていましたし、何よりコントローラとして簡単に実装できそうだったからです。前置きが長くなりましたが、さっそくTremaで実装してみましょう。
逆流防止フィルタは1つのPacket Inに対して2つのフローエントリを設定します。1つは順方向のフローエントリで、入ってきたパケットをもう1つのスイッチポートに転送します。もう1つは逆方向のフローエントリで、同じパケットが逆方向に流れてきたときにこのパケットを落とします。
逆流防止フィルタ(OneWayBridge コントローラ)のソースコードは GitHub の trema/one_way_bridge リポジトリ (https://github.com/trema/one_way_bridge) からダウンロードできます。
$ git clone https://github.com/trema/one_way_bridge.git
ダウンロードしたソースツリー上で bundle install --binstubs
を実行すると、Tremaなどの実行環境一式を自動的にインストールできます。
$ cd one_way_bridge $ bundle install --binstubs
このコントローラは、Packet In と Flow Removed のハンドラだけを定義したとてもシンプルなものです。
link:vendor/one_way_bridge/lib/one_way_bridge.rb[role=include]
packet_in
ハンドラでは、Packet Inしたスイッチポートとは別のポートへパケットを転送するフローエントリを設定し(add_flow
メソッド)、Packet Inを起こしたパケットを転送します(send_packet
メソッド)。また、同じパケットが逆向きに流れないようにするフローエントリを設定することで逆流を防ぎます(add_drop_flow
メソッド)。同じパケットかどうかは送信元のMACアドレスが同じかどうかで判断します。
flow_removed
ハンドラは、順方向または逆方向のフローエントリが消えたときに呼ばれます。これらのフローエントリはどちらも :source_mac_address
に同じMACアドレスを指定しているので、delete_flow
メソッドでもう片方の対になるフローエントリを消します。
逆流防止フィルタを実行するには、レガシーネットワークとOpenFlowネットワークの間にOpenFlowスイッチをはさみ、これをOneWayBridgeコントローラで制御します。でも実機のOpenFlowスイッチを準備するのは大変なので、Tremaの仮想ネットワーク機能でやってしまいましょう。NICが2枚挿さったサーバを用意し、仮想ネットワーク内で起動した仮想スイッチ(vswitch)の各ポートとそれぞれのNICを接続します(図10-6)。
この物理構成をTrema設定ファイルにしたものが以下です。仮想リンク(link
で始まる行)の端点にインタフェース名eth0、eth1を指定していることに注目してください。
vswitch ('bridge') {
datapath_id 0xabc
}
link 'bridge', 'eth0'
link 'bridge', 'eth1'
実行するには、この設定ファイルを trema run
の -c
オプションに渡します。
$ ./bin/trema run ./lib/one-way-bridge.rb -c ./trema.conf
職場のネットワークを安全にOpenFlowに移行するためのTipsを学びました。
-
レガシーネットワークをOpenFlowに移行するいくつかのパターンを考察。自宅など自由にできるネットワークではいきなり接続パターンで十分だが、職場ネットワークでは逆流防止パターンが最適
-
逆流防止フィルタを実現するOpenFlowコントローラを実装。2つのフローエントリを設定するだけで、簡単に逆流を防止できる