Linux上のOpen vSwitchでGENEVEトンネリングを設定する:次世代オーバーレイネットワークの構築

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

現実世界の課題:最新オーバーレイにおけるパケットテレメトリとメタデータのボトルネック

ベアメタルノード間で隔離されたマルチテナントネットワークを運用する際、通常は標準的なカプセル化から始まります。かつて4つのサーバーラックにまたがる120台のベアメタルハイパーバイザーを展開した際、私たちのチームはデフォルトのオーバーレイとして標準的なVXLANを採用していました。動的なセキュリティサービス挿入、ステートフルパケットフィルタリング、そしてエンドツーエンドのトレーシングを導入するまでは、すべてが順調に稼働していました。しかし、導入した途端に深刻な運用上の問題に直面したのです。

VXLANは、24ビットの仮想ネットワーク識別子(VNI)を含む8バイトのヘッダーに依存しています。これは1600万以上のテナントセグメントをサポートできる一方で、実行時の運用コンテキストを格納するスペースは一切用意されていません。

私たちのミドルボックスは、テナントのセキュリティタグ、インプレスポート識別子、分散ファイアウォールの状態、レイテンシマーカーといったインラインメタデータを必要としていました。VXLANヘッダーは可変長フィールドを運ぶことができないため、エッジノードは中継ホスト間で帯域外(アウトオブバンド)通信を行って状態テーブルを同期する必要がありました。クラスタが200ノードに達した時点で、キープアライブと状態同期によってホストCPUの15%が消費され、VMのライブマイグレーション中に20ミリ秒のp99レイテンシスパイクが発生し、断続的なフローのパケットドロップが引き起こされました。

根本原因の分析:なぜVXLANとNVGREでは不十分なのか

根本的なボトルネックは、初期のカプセル化フォーマットにおける構造的な硬直性にあります。IETFがVXLAN(RFC 7348)およびNVGRE(RFC 7637)を策定した際、その目標はシンプルでした。レイヤー3の境界を越えて従来の4,094というVLANの上限を打ち破ることです。どちらのプロトコルも、最新のソフトウェア定義ネットワーク(SDN)コントロールプレーン向けの動的な状態情報を運ぶようには設計されていませんでした。

固定長ヘッダーの制約

両プロトコルとも柔軟性に欠けるヘッダーレイアウトを採用しています。24ビットのセグメント識別子を確保した後、残りのビットは厳格に割り当てられているか、ゼロクリアされています。SDNコントローラーが64ビットのマイクロセグメンテーションセキュリティトークン、フロートラッキングID、インバンドネットワークテレメトリ(INT)カウンターなどを埋め込もうとしても、標準のフレームには収めることができません。

コントロールプレーンとデータプレーンの非同期化

Open Virtual Network(OVN)などの最新のSDNコントローラーは、データプレーンのパケットをインテリジェントなキャリアとして扱います。固定長ヘッダーによるカプセル化では、送信元ノードはパケットを回線に送出する前に、ローカルパイプラインのすべてのメタデータを削ぎ落とさなければなりません。その後、宛先のハイパーバイザーはそのコンテキストを一から再構築する必要があります。この重複した計算はホップごとにCPUサイクルを浪費し、フロールックアップテーブルを肥大化させ、インラインパケットステアリングを妨げます。

ソリューションの比較:VXLAN vs. GRE vs. GENEVE

この制約を解決するには、LinuxネットワークスタックおよびOpen vSwitch(OVS)でサポートされているオーバーレイプロトコルを比較検討する必要があります。

  • VXLAN(UDPポート 4789):汎用のTop-of-RackスイッチからSmartNICに至るまで、広範なハードウェアサポートを誇ります。信頼性の高いLayer 2-over-UDP転送を提供しますが、8バイトの固定ヘッダーのためカスタムメタデータを格納できません。
  • GRE(IPプロトコル 47):オプションのキーフラグを提供しますが、UDPラッパーなしで直接IP上で動作します。UDP送信元ポートのエントロピーがないため、リーフ・スパイン型のネットワークスイッチにおいて等コストマルチパス(ECMP)リンク全体にトラフィックを均等に分散することができません。
  • GENEVE(RFC 8926、UDPポート 6081):UDPによるECMPロードバランシングの強みと、拡張可能なType-Length-Value(TLV)オプションヘッダーを兼ね備えています。SDNコントローラーは、セキュリティグループ識別子、インプレスポートマップ、テレメトリマークなどの任意の実行時データを、標準フレームに違反することなく最大252バイトまでトンネルヘッダーに直接追加できます。

これらの理由から、OVN、VMware NSX、そしてCiliumなどのエンタープライズ向けKubernetes CNIといった最新プラットフォームでは、GENEVEがデフォルトのオーバーレイプロトコルとして採用されています。

実践演習:Open vSwitchを使用したポイントツーポイントGENEVEトンネルの構築

Linux上でOpen vSwitchを使用してGENEVEをセットアップすることで、最新のコンテナやVMプラットフォームとシームレスに連携する、将来性がありメタデータに対応したオーバーレイを構築できます。ここでは、標準的なレイヤー3アンダーレイを経由して2台のLinuxノードを接続する実践的なデプロイ手順を解説します。

シナリオのトポロジー

  • ホスト1のアンダーレイIP: 192.168.10.11
  • ホスト2のアンダーレイIP: 192.168.10.12
  • オーバーレイサブネット: 10.10.100.0/24
  • オーバーレイポート: UDP 6081(標準GENEVE)

ステップ1:両方のホストにOpen vSwitchをインストール

UbuntuまたはDebianノードで以下のコマンドを実行し、Open vSwitchをインストールして起動します。

sudo apt-get update
sudo apt-get install -y openvswitch-switch
sudo systemctl enable --now openvswitch-switch

カーネルモジュールが正常にロードされたことを確認します。

lsmod | grep openvswitch

ステップ2:ファイアウォールでGENEVEトラフィックを許可

GENEVEは内部フレームを宛先ポート6081のUDPデータグラム内にカプセル化します。物理インターフェースでこのトラフィックを許可してください。

# ホスト1およびホスト2で実行
sudo ufw allow 6081/udp comment "GENEVEオーバーレイを許可"

ステップ3:ホスト1でブリッジとトンネルを設定

ホスト1で統合ブリッジbr-overlayを作成し、内部管理ポートをプロビジョニングしてオーバーレイIPアドレスを割り当て、ホスト2をターゲットとするGENEVEトンネルを接続します。

# 1. OVS統合ブリッジを作成
sudo ovs-vsctl add-br br-overlay

# 2. ローカルオーバーレイエンドポイント用の内部ポートを追加
sudo ovs-vsctl add-port br-overlay vport1 -- set Interface vport1 type=internal

# 3. 仮想インターフェースにオーバーレイIPを割り当て
sudo ip addr add 10.10.100.11/24 dev vport1
sudo ip link set vport1 up

# 4. ホスト2に向けたGENEVEトンネルを接続
sudo ovs-vsctl add-port br-overlay geneve-to-host2 \
    -- set Interface geneve-to-host2 type=geneve \
    options:remote_ip=192.168.10.12 \
    options:key=1000

key=1000パラメータは仮想ネットワーク識別子(VNI)として機能し、このインターフェースをオーバーレイセグメント1000に固定します。

ステップ4:ホスト2でブリッジとトンネルを設定

ホスト2でも同様の設定を行い、トンネルのエンドポイントをホスト1に向けます。

# 1. OVS統合ブリッジを作成
sudo ovs-vsctl add-br br-overlay

# 2. ローカルオーバーレイエンドポイント用の内部ポートを追加
sudo ovs-vsctl add-port br-overlay vport2 -- set Interface vport2 type=internal

# 3. 仮想インターフェースにオーバーレイIPを割り当て
sudo ip addr add 10.10.100.12/24 dev vport2
sudo ip link set vport2 up

# 4. ホスト1に向けた対向GENEVEトンネルを接続
sudo ovs-vsctl add-port br-overlay geneve-to-host1 \
    -- set Interface geneve-to-host1 type=geneve \
    options:remote_ip=192.168.10.11 \
    options:key=1000

ステップ5:OVS設定の確認

ホスト1でブリッジのステータスを確認し、両方のインターフェースが正しくバインドされていることを確認します。

sudo ovs-vsctl show

ターミナルに以下のような構造の出力が表示されます。

    Bridge br-overlay
        Port geneve-to-host2
            Interface geneve-to-host2
                type: geneve
                options: {key="1000", remote_ip="192.168.10.12"}
        Port br-overlay
            Interface br-overlay
                type: internal
        Port vport1
            Interface vport1
                type: internal

ステップ6:オーバーレイの疎通確認とフレームのキャプチャ

ホスト1からホスト2へ、仮想リンク経由で4回のICMPエコー要求(ping)を送信します。

ping -c 4 10.10.100.12

アンダーレイ上に平文フレームが漏れることなく、パケットが実際にカプセル化されていることを確認します。ホスト2で物理インターフェースeth0に対してパケットキャプチャを実行します。

sudo tcpdump -i eth0 -nn -v "udp port 6081"

内部のICMPエコーペイロードがGeneve, VNI 1000ヘッダーによってラップされていることを示す出力が確認できます。

ステップ7:本番環境における設計・運用の指針

  • MTUの設計とフラグメンテーション:GENEVEの基本的なカプセル化オーバーヘッドは50バイト(外部IPv4 20バイト + UDP 8バイト + 基本GENEVE 8バイト + 内部Ethernet 14バイト)であり、TLVオプションが付加されるとさらに増加します。標準的な物理ネットワークでは1500バイトを超えるフレームは破棄されます。物理スイッチでMTU 9000(または少なくとも1600バイト)のジャンボフレームを設定してください。物理アンダーレイが1500バイトに固定されている場合は、オーバーヘッドの大きいIPフラグメンテーションを回避するため、すべての仮想インターフェースおよびゲストワークロードのMTUを1450に制限(クランプ)します。
  • 動的フローベーストンネル:本番のSDN環境では、ホストごとに静的なポイントツーポイントトンネルをプロビジョニングすることは避けます。代わりに、options:key=flowおよびoptions:remote_ip=flowを使用して単一のワイルドカードポートを設定します。これにより、OVS OpenFlowパイプラインテーブルがパケットごとに宛先IPとトンネルメタデータを動的に設定できるようになります。
  • ハードウェアオフロードの確認:NVIDIA Mellanox ConnectX-5/6やIntel E810などのエンタープライズNICは、GENEVEの内部チェックサム検証およびセグメンテーション(TSO/LRO)をオフロードします。ethtool -k eth0 | grep tx-udp_tnl-segmentationを使用してオフロードの状態を確認してください。これにより、カプセル化処理でホストのCPUコアを浪費することなく、ワイヤーレートに近いスループットを確保できます。
Share: