【実務・中級編】 仮想スイッチ(Open vSwitch: OVS)のOpenFlowプロトコルによるフローテーブル制御とパケットフォワード – クラウドインフラと仮想化ネットワーク実践ガイド

SDNの心臓部を覗く:Open vSwitchとOpenFlowが奏でる「パケットの旅」の正体

クラウドインフラを設計していると、どうしても抽象化されたクラウドベンダーのネットワーク機能に頼りがちになります。しかし、その裏側で何が起きているのかを知っているかどうかで、トラブルシューティングの「勘」は劇的に変わります。

今日は、現代の仮想ネットワークの黒幕とも言える Open vSwitch (OVS) と、その指揮者である OpenFlow プロトコルについて、現場の視点から深掘りしていきましょう。教科書的な概念解説はそこそこに、パケットがどう判定され、どこへ向かうのか。その泥臭い仕組みを紐解きます。

—

1. OVSにおける「フローテーブル」という名の裁き

OVSを単なる仮想L2スイッチだと思っているなら、それは大きな誤解です。OVSは、いわば「パケットが到着するたびにルールブックをめくる、非常に仕事熱心な検問官」です。

パケットがOVSに入力されると、まず「フローテーブル」と呼ばれる照合表が参照されます。ここには、以下の要素からなる「マッチング条件」が書かれています。

  • in_port: どのインターフェースから来たか
  • dl_src / dl_dst: 送信元/宛先MACアドレス
  • nw_src / nw_dst: 送信元/宛先IPアドレス
  • tp_src / tp_dst: 送信元/宛先ポート番号

この条件に合致(マッチ)した際、OpenFlowコントローラが指示した「アクション」が実行されます。アクションは output:1(ポート1へ転送)のような単純なものから、set_field:192.168.1.10->ip_dst(宛先IPの書き換え、いわゆるNAT)といった高度なものまで多岐にわたります。

—

2. パケット転送のシーケンス:脳と手足の関係

OpenFlow環境では、OVS(手足)とOpenFlowコントローラ(脳)が分離されています。通信のライフサイクルは以下のようなシーケンスで動きます。

1. Packet-In: OVSに知らないパケット(マッチするフローがない)が届く。OVSはパケットのヘッダー情報をコントローラに「これどうすればいい?」と問い合わせる(Packet-In メッセージ)。
2. Flow-Mod: コントローラが判断を下す。この通信を今後どう扱うかのルールをOVSに書き込む(Flow-Mod メッセージ)。
3. Packet-Out: 待機させていたパケットを、コントローラの指示通りに転送する(Packet-Out メッセージ)。

この一連のやり取りを TCP 通信(デフォルトは 6633 や 6653 ポート)で行うため、コントローラがダウンするとネットワーク全体が「思考停止」に陥るリスクがある。これがSDN運用の最大の注意点です。

—

3. 実践:フローテーブルを操作する

現場で最もよく使うのが ovs-ofctl コマンドです。まずは現在のフローテーブルを確認してみましょう。

# 現在のフローテーブルを表示。優先度(priority)とマッチ条件、アクションが確認できる
sudo ovs-ofctl dump-flows br-int

フローの追加例

特定のIPからの通信を別のポートへ飛ばすような、制御ルールを追加してみます。

# 優先度100で、宛先IPが10.0.0.5のパケットをポート2に転送するルール
sudo ovs-ofctl add-flow br-int \
  "table=0, priority=100, ip, nw_dst=10.0.0.5, actions=output:2"

—

4. API経由で制御する:コントローラの自作という選択肢

クラウドネイティブな環境では、CLIを叩くのではなく、REST APIを介してネットワークを動的に再構成したい場面があります。Pythonの ryu フレームワークなどを使えば、独自のSDNコントローラを構築可能です。

以下は、curl で直接コントローラのREST APIを叩くイメージ(架空のコントローラAPI)です。

# Pythonのrequestsライブラリでやるならこんな感じ
import requests

# コントローラのAPIエンドポイント
url = "http://sdn-controller:8080/stats/flowentry/add"

# フローの定義
flow_rule = {
    "dpid": 1,
    "priority": 10,
    "match": {"nw_dst": "192.168.1.10", "dl_type": 0x0800},
    "actions": [{"type": "OUTPUT", "port": 3}]
}

# 実行
response = requests.post(url, json=flow_rule)
print(f"Status Code: {response.status_code}")

—

5. 現場のSREが教えるデバッグTips

ネットワークのトラブルで最も多いのは「ルールはあるのに転送されない」ケースです。そんな時は、迷わずパケットをキャプチャしましょう。tcpdump を使うのが手っ取り早いですが、OVS内の特定のポートで何が起きているかを見るなら、ovs-appctl が強力です。

# OVS内部のパケットの動きをトレースする(非常に強力)
sudo ovs-appctl ofproto/trace br-int in_port=1,dl_src=00:11:22:33:44:55,dl_dst=aa:bb:cc:dd:ee:ff

このコマンドは、実際にパケットを流さなくても「もしこのパケットが来たら、どのフローテーブルにマッチして、どのポートから出るか」をシミュレーションしてくれます。本番環境で障害が起きたとき、切り分けの初動として必ず行うべき作業です。

最後に

OVSとOpenFlowは、魔法のように見えて、実は非常に論理的なパケットの「仕分け作業」です。もし皆さんが担当する環境でネットワークが遅延したり、特定の通信だけが通らないという事象に遭遇したら、まずは ovs-ofctl dump-flows で、誰がそのパケットを「ドロップ(破棄)」しているのか、あるいは「本来意図しないアクション」を指示しているのかを探ってみてください。

ネットワークが見えるようになると、インフラエンジニアとしての視界は格段に広がります。頑張ってください。

コメント

タイトルとURLをコピーしました