Linux BridgeでIGMPスヌーピングを設定:仮想スイッチにおけるマルチキャストフラッディングを抑制する

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

課題:マルチキャストが無制御なブロードキャストへと化すとき

前四半期のオフピークバックアップウィンドウ中、監視システムが予期せぬアラートを発報しました。Postgresのリードレプリカをホストしていた3台のKVMゲストで、p99レイテンシが4msから280ms以上へと突如急上昇し、同時に定常的な4%のパケットロスが発生したのです。ゲスト側のメトリクスを調査したところ、データベースクエリとは何の関係もないトラフィックを、これらのVMが毎秒約65,000パケットも処理し続けていたことが判明しました。

トラフィックを追跡すると、同じホストブリッジ(br0)を共有していたIPTVのテスト配信ストリームと3ノードのCorosyncクラスタに行き着きました。デフォルト状態の標準的なLinuxソフトウェアブリッジは、マルチキャストフレームに対してダムハブのように振る舞います。標準状態ではLayer 3の認識機能を持たないため、特に設定を行わない限り、カーネルは受信したマルチキャストトラフィックを未知のLayer 2フレームとして扱い、アクティブなすべてのブリッジポートへ無差別にフラッディング(転送)してしまいます。

仮想化された本番環境において、この挙動は直ちに以下のような深刻な問題を引き起こします。

  • CPUリソースの枯渇:無関係なフレームを検査・破棄するためだけに、各仮想NIC(vnet* / tap)がゲストカーネル内でソフトウェア割り込みを大量に発生させます。
  • 帯域幅の圧迫:400 Mbpsのカメラ映像配信や高頻度なストレージのハートビートといった高スループットなストリームが、ホストで共有している10GbEや25GbEのアップリンク帯域を食いつぶします。
  • セキュリティリスク:同一のLayer 2セグメント上に存在する、信頼されていないマルチテナントVMへ機密性の高いマルチキャストペイロードが漏洩します。

基本概念:IGMPスヌーピングがブリッジを制御する仕組み

トラフィックを転送する前に、ブリッジは「誰が実際にそのデータを要求したのか」を把握する必要があります。

IGMPスヌーピングとは何か?

ホストはIGMP(Internet Group Management Protocol)を使用し、受信を希望するマルチキャストグループを上流のルーターに通知します。IGMPスヌーピングは、そのインテリジェンスをLayer 2に持ち込む仕組みです。ブリッジはポートを通過するこれらの制御メッセージを受動的に監視(スヌープ)します。

スヌーピングを有効にすると、Linuxカーネルはマルチキャスト転送データベース(MDB)を構築します。VM-Aがグループ239.1.1.1に対するIGMP Joinを発行すると、カーネルはVM-Aのtapインターフェース(例:vnet1)とそのマルチキャストIPを紐付けます。データパケットが239.1.1.1宛てに送られてくると、ブリッジはそれをvnet1のみに転送します。受信を希望していないVMにはフレームが1つも届きません。

IGMPクエリア(Querier)の極めて重要な役割

スヌーピングが正常に機能し続けるには、定期的なステータス確認が欠かせません。ホストは初回こそIGMP Joinで受信の意思を伝えますが、その後は定期的に送信される「IGMP General Query」パケットから問い合わせを受けない限り、メンバーシップの更新(応答)を行いません。エンタープライズのデータセンターでは専用のコアスイッチやマルチキャストルーターがこれらのQueryパケットを生成しますが、分離された仮想化ホスト上には上流クエリアが存在しないケースが多々あります。

継続的なQueryがないと、ブリッジMDB内のグループメンバーシップはタイムアウト(通常は260秒後)してしまいます。期限切れになると、ブリッジは再びフラッディングモードへと逆戻りします。幸いなことに、Linuxカーネルにはブリッジ内部で直接有効化できる内蔵IGMPクエリアが備わっています。

実践演習:ステップ・バイ・ステップでのブリッジ設定

標準的なiproute2およびbridgeユーティリティを使用して、IGMPスヌーピングの確認、設定、検証を行う手順を解説します。

1. 現在のブリッジ状態を確認する

まず、対象となるブリッジデバイス(ここではbr0を使用)を確認します。

# ブリッジの詳細な属性を表示
ip -d link show br0

出力結果からmcast_snoopingおよびmcast_querierのフラグを探します。sysfsツリーを直接確認することも可能です。

cat /sys/class/net/br0/bridge/multicast_snooping
cat /sys/class/net/br0/bridge/multicast_querier

値が0なら無効、1なら有効を意味します。

2. ブリッジでIGMPスヌーピングを有効化する

ipコマンドを使用してスヌーピングを有効にします。

sudo ip link set dev br0 type bridge mcast_snooping 1

スヌーピングが有効であっても、古いカーネルでは未登録のマルチキャストグループ(アクティブな受信者が存在しないアドレス)を全ポートへフラッディングしてしまうことがあります。マルチキャストを使用しないワークロードが割り当てられたポートでは、マルチキャストフラッディングをオフにしてこれを遮断できます。

# 特定のVM tapポートで未登録マルチキャストのフラッディングを防止
sudo bridge link set dev vnet0 mcast_flood off

3. 内蔵IGMPクエリアを有効化する

ハイパーバイザーが独立したVLAN上で動作しており、定期的なIGMP Queryを送信する上流ルーターがない場合は、ブリッジの内蔵クエリアを有効化します。

sudo ip link set dev br0 type bridge mcast_querier 1

あわせてIGMPバージョンも確認しておきましょう。近年のLinuxカーネルはデフォルトでIGMPv3を使用しますが、アプリケーション層の要件に合わせて明示的に指定することもできます。

# 明示的にIGMPv3を強制
sudo ip link set dev br0 type bridge mcast_igmp_version 3

UbuntuとRHELのゲストが混在する環境のKVMホストにおいて、クエリアを有効化したところ、アイドル状態だったtapインターフェースのパケットレートが65,000 ppsからバックグラウンドの基準値(10 pps未満)へと即座に低下しました。

4. マルチキャスト転送データベース(MDB)の確認

受信側アプリケーションが起動したら、ブリッジのMDBテーブルを確認します。

sudo bridge mdb show

次のような出力が表示されます。

dev br0 port vnet1 grp 239.255.255.250 temp
dev br0 port vnet3 grp 224.0.0.251 temp

この構成例では、vnet1がSSDP検出(239.255.255.250)を受信し、vnet3がmDNS(224.0.0.251)を受信しています。br0上の他の仮想ポートには、これらのトラフィックは一切送信されません。

5. tcpdumpによるトラフィック分離のテスト

負荷をかけた状態で修正結果を検証するため、ハイパーバイザー上で2つのシェルセッションを同時に起動します。

# ターミナル1:非受信インターフェースを監視
sudo tcpdump -nn -i vnet0 ip multicast

# ターミナル2:受信インターフェースを監視
sudo tcpdump -nn -i vnet1 ip multicast

socatを使用して、任意のマルチキャストグループへテストペイロードを送信します。

# 239.1.1.1:5000へテスト用UDPペイロードを送信
socat - UDP-DATAGRAM:239.1.1.1:5000,ip-multicast-ttl=2 <<< "Multicast Ping"

ポートマッピングが正しく機能していれば、ターミナル2にのみパケットが記録され、ターミナル1側にはパケットが流れてきません。

6. 設定を永続化する

ipやbridgeコマンドで行ったランタイム変更は、システムの再起動後に失われます。必ず利用しているディストリビューションのネットワーク管理スタックを通じてブリッジパラメータを永続化してください。

systemd-networkdを使用しているシステムでは、ブリッジの.netdevファイル(例:/etc/systemd/network/10-br0.netdev)でこれらの属性を定義します。

[NetDev]
Name=br0
Kind=bridge

[Bridge]
IGMPSnooping=true
IGMPQuerier=true
IGMPVersion=3

再起動せずにネットワーク設定を再読み込みします。

sudo systemctl restart systemd-networkd

Netplan(Ubuntu)で設定されたシステムでは、/etc/netplan/01-netcfg.yamlを編集します。

network:
  version: 2
  bridges:
    br0:
      interfaces: [eth0]
      parameters:
        stp: false
        forward-delay: 0

旧バージョンのNetplanにはmcast_querier用のネイティブパラメータが存在しません。この制約は、exec-upスクリプトまたは軽量なsystemdワンショットユニットを作成することで解消できます。

# /etc/systemd/system/bridge-querier.service
[Unit]
Description=ブリッジのIGMPクエリアを設定
After=network.target

[Service]
Type=oneshot
ExecStart=/sbin/ip link set dev br0 type bridge mcast_querier 1

[Install]
WantedBy=multi-user.target

まとめ

マルチキャストは1対多の効率的な配信を実現しますが、管理されていないLinux Bridgeではあっという間に破壊的なブロードキャストフラッディングを引き起こします。IGMPスヌーピングと内蔵クエリアを有効にすることで、追加のソフトウェアライセンス費用を一切かけることなく、エンタープライズ向けハードウェアスイッチと同等のきめ細かなトラフィック分離が手に入ります。

ip -d link showとbridge mdb showを使って、数分でブリッジの状態を確認してみてください。マルチキャストパケットの転送先を指定のスイッチポートのみに限定することで、ゲストVMのCPU負荷を解放し、レプリケーションレイテンシを安定させ、ハイパーバイザー内でのテナント間パケット漏洩を防止できます。

Share: