pimdを使用したLinux上のPIM-SMマルチキャストルーティング:サブネットを越えてIPTVを配信する方法

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

ユニキャストが大規模環境で破綻する理由

ユニキャストを使用して数十台のワークステーションにライブ映像を配信すると、膨大な帯域幅が無駄に消費されます。例えば、120人の従業員が8 Mbpsの1080p社内ブロードキャストを同時に視聴する場合を考えてみましょう。メディアサーバーは単一のネットワークインターフェースから約1 Gbps(960 Mbps)ものトラフィックを送り出さなければなりません。その結果、スイッチのアップリンクは飽和し、レイテンシが急上昇して、たちまちフレーム落ちが発生します。

ブロードキャストでもこの問題は解決できません。ブロードキャストストームによって拠点全体が機能停止するのを防ぐため、ルーターはサブネットの境界でブロードキャストパケットを意図的に破棄するからです。

この課題を解決するのがマルチキャストです。メディアサーバーはクラスDのマルチキャストアドレス(例: 239.255.1.100)に対してストリームを1本だけ送信します。下流のスイッチやルーターは、IGMP(Internet Group Management Protocol)を介してグループメンバーシップを追跡し、アクティブな受信者が存在する物理セグメントにのみパケットを複製して転送します。

標準のLinuxカーネルはユニキャストルーティングを難なく処理しますが、専用のルーティングデーモンがなければインターフェース間でマルチキャストトラフィックを転送しません。ここで標準プロトコルとして機能するのがPIM-SM(Protocol Independent Multicast – Sparse Mode)です。PIM-SMは受信者が疎(まばら)に存在することを前提とし、ホストから配信要求があった場合にのみソースへと遡る配信ツリーを構築します。

ここでは、実績のあるPIM-SMデーモンであるpimdを使用します。元々はBSD向けに書かれたもので、現在はJoachim Nilsson氏(troglobit)によってLinux向けにメンテナンスされています。高ビットレートのMPEG-TS配信、監視カメラの映像、RTSPリレートラフィックなどを最小限のCPUオーバーヘッドで処理できます。

前提条件とカーネル設定

pimdを設定する前に、カーネルのビルドフラグを確認し、システムパラメータを調整します。

1. カーネルのマルチキャストサポート確認

稼働中のカーネルがマルチキャストルーティングのサポートを有効にしてコンパイルされていることを確認します。

grep -E "CONFIG_IP_MROUTE|CONFIG_IP_PIMSM" /boot/config-$(uname -r)

Ubuntu、Debian、AlmaLinux、Rocky Linuxでは、これらのオプションがデフォルトで有効になっています。各フラグが=yまたは=mを返すことを確認してください。

CONFIG_IP_MROUTE=y
CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V1=y
CONFIG_IP_PIMSM_V2=y

2. sysctl設定の構成

マルチキャストルーティングには、sysctlに関する2つのよくある落とし穴があります。リバースパスフィルタリング(RPF)と、mc_forwardingが読み取り専用である点です。net.ipv4.conf.all.mc_forwarding = 1を直接手動で設定しようとしないでください。カーネルは手動での書き込みを拒否し、pimdがマルチキャストルーティングソケット(MRT_INIT)を初期化する際に自動的に有効化されます。

ただし、標準のIPv4転送を有効にし、厳格なリバースパスフィルタリング(Strict RPF)を無効にする必要があります。ユニキャストルーティングテーブルに対称的なエンコーダーへの戻りルートが存在しない場合、Strict RPFによってカーネルが受信マルチキャストストリームを破棄してしまうことがよくあります。

/etc/sysctl.d/99-multicast.confを作成します。

sudo bash -c 'cat <<EOF > /etc/sysctl.d/99-multicast.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.eth1.rp_filter = 0
net.ipv4.conf.eth2.rp_filter = 0
EOF'

sudo sysctl --system

3. pimdのインストール

Debian 11/12およびUbuntu 22.04/24.04では、パッケージを直接インストールできます。

sudo apt update
sudo apt install -y pimd

RHEL系システムや最小構成の環境で最新のアップストリームリリースをソースからコンパイルする場合:

sudo apt install -y build-essential automake autoconf pkg-config
git clone https://github.com/troglobit/pimd.git
cd pimd
./autogen.sh
./configure --prefix=/usr --sysconfdir=/etc
make
sudo make install

ネットワークトポロジーと設定

今回の構成例は以下の通りです。

  • eth1 (192.168.10.1/24): 映像送信元サブネット(エンコーダーIP: 192.168.10.50)
  • eth2 (192.168.20.1/24): クライアントサブネット(受信ワークステーション: 192.168.20.0/24)
  • マルチキャストチャネル: 239.255.1.100(UDPポート 5004 でリスン)

1. /etc/pimd.confの編集

デフォルトでは、pimdはループバックや管理用ポートを含め、検出されたすべてのアクティブなインターフェース上で動作しようとします。そのため、最初にすべてのインターフェースを無効化し、ストリーミングに使用するインターフェースのみを明示的に有効化します。

sudo nano /etc/pimd.conf

ファイルに以下の設定を記述します。

# /etc/pimd.conf

# 明示的に宣言されていない限りインターフェースを無視
default-phyint-status disable

# IPTVエンコーダーからの入力(Ingress)インターフェース
phyint eth1 enable

# クライアントワークステーションへの出力(Egress)インターフェース
phyint eth2 enable

# このホストをランデブーポイント(RP)として構成
# 管理用スコープマルチキャスト範囲 239.0.0.0/8 を処理
rp-candidate eth1 priority 20 time 30
group-prefix 239.0.0.0 masklen 8

# このホストをブートストラップルーター(BSR)候補として構成
bsr-candidate eth1 priority 5

2. Netfilter / iptablesルールの設定

Linuxのファイアウォールは、デフォルトで未要求のマルチキャストパケットや制御シグナリングを破棄します。そのため、IGMP(プロトコル2)、PIM制御メッセージ(プロトコル103)、およびルーティング対象のUDPマルチキャストパケットを許可する必要があります。

# ローカルのIGMPおよびPIM制御トラフィックを許可
sudo iptables -A INPUT -p igmp -j ACCEPT
sudo iptables -A INPUT -p 103 -j ACCEPT

# ルーティングピア間のPIM転送を許可
sudo iptables -A FORWARD -p 103 -j ACCEPT

# 送信元サブネットからクライアントサブネットへのUDPマルチキャストパケット転送を許可
sudo iptables -A FORWARD -i eth1 -o eth2 -d 239.0.0.0/8 -p udp --dport 5004 -j ACCEPT

3. デーモンの起動と自動起動の有効化

pimdを起動し、systemdのステータスを確認してデーモンがインターフェースに正しくバインドされているか確認します。

sudo systemctl restart pimd
sudo systemctl enable pimd
sudo systemctl status pimd

動作確認とトラブルシューティング

以下のチェックを実行し、マルチキャストパケットがパケットロスなくサブネット間を通過していることを確認します。

1. マルチキャスト仮想インターフェース(VIF)の確認

カーネルの仮想マルチキャストインターフェーステーブルを確認します。

cat /proc/net/ip_mr_vif

eth1がVIF 0に、eth2がVIF 1に割り当てられていることが確認できます。ストリーミングが開始されると、eth1のPktsIn列とeth2のPktsOut列の数値が増加していきます。

2. カーネルマルチキャスト転送キャッシュの確認

iproute2を使用して現在のマルチキャストルートを確認します。

ip mroute show

クライアントがグループに参加し、送信元がアクティブになると、カーネルはインストールされた(S,G)ルートを表示します。

(192.168.10.50, 239.255.1.100)  Iif: eth1  Oifs: eth2

出力にOifs: unresolvedと表示される場合やeth2がリストされない場合は、クライアントがIGMPレポートを送信していないか、ファイアウォールによってブロックされている可能性があります。

3. pimdの内部状態の確認

USR1シグナルを送信して、pimdにルーティングテーブル、グループタイマー、ネイバーリストをダンプさせます。

sudo killall -USR1 pimd
cat /var/run/pimd/pimd.dump 2>/dev/null || cat /var/tmp/pimd.dump

(*,G)および(S,G)のセクションを確認します。ルーター自身がRPとして選出され、アップストリームのエンコーダーを登録しているかどうかが確認できます。

4. エンドツーエンドのテスト実行

この構成をテストするために高価なハードウェアエンコーダーを用意する必要はありません。2つのテストコマンドでルーターが正常に機能しているか検証できます。

ステップ1: クライアント側(192.168.20.50)でグループに参加

# socatを使用してグループ参加を要求し、UDP 5004でリスン
socat - UDP4-RECV:5004,ip-add-membership=239.255.1.100:192.168.20.50

または、クライアントマシンでVLCを開き、メディア > ネットワークストリームを開くからURL udp://@239.255.1.100:5004 を指定します。

ステップ2: 送信元マシン(192.168.10.50)からテスト用のカラーバーをストリーミング配信

重要なポイント: マルチキャストのTTLを1より大きく設定してください。多くのツールではマルチキャストTTLのデフォルトが1になっているため、最初のルーターでパケットが即座に破棄されてしまいます。

ffmpeg -re -f lavfi -i testsrc=size=1280x720:rate=30 \
  -vcodec libx264 -preset ultrafast -b:v 2500k -f mpegts \
  "udp://239.255.1.100:5004?pkt_size=1316&ttl=16"

tcpdumpを使用して、ルーターの出力(Egress)インターフェースでパケットの到達を確認します。

sudo tcpdump -n -i eth2 host 239.255.1.100 and udp port 5004

eth2上にパケットが表示されれば、Linuxホストが不要なサブネットフラッディングを起こすことなく、低遅延でサブネット境界を越えてマルチキャスト映像を正常にルーティングできています。

Share: