まえがき
最近、Wi-Fi経由でマルチキャストIPTVを見ると、トラフィックの一部が失われることに気付きました。 問題の詳細な調査の後、この動作はマルチキャストトラフィックの性質、つまりパケット受信者のMACアドレスによって説明されることがわかりました。 受信者に依存せず、マルチキャストグループのアドレスから形成されます。 したがって、ワイヤレスアクセスポイントに接続されているすべてのクライアントがそのようなパケットに適用されます。 この結果、パッケージの一部のみが取得され、急な画像が表示されます。
通常の方法では、クライアント用に別のアクセスポイントを作成するか、特定のマルチキャストグループ用の静的ルートを作成するか、クライアントを別のVLANに配置することで問題を解決できます。 ネットワーク上に同じチャンネルを視聴したいIPTVセットトップボックスが複数ある場合、そのような決定のすべての「力」が発揮されます。さらに、インターネット上でそれらを必要とするため、ルーターの構成が複雑になります。 この問題に対する独自の解決策を以下に示します。
udpxyなどのプログラムは、パッケージの完全な構造を変更するため、ここでは適していません。 そして、クライアントソフトウェアが変更に気付かないように、ネットワークとトランスポート部分を維持しながら、必要なMACアドレスを設定するだけです。
このソリューションは、 MUT ( M ulticast to U nicast T ranslation)と呼び、次のとおりです。
- グループに接続したいクライアントのIPアドレスを見つける
- これをOSカーネルに報告してください
- クライアントMACアドレスのIPアドレスを取得する
- パッケージのコピーを作成して適切なインターフェイスに送信します
ステップ1と2の実装は、マルチキャストルーティングプログラム3と4-コアにあります。 どちらも作業に小さな変更が必要です。 すべての作業はGNU / Linux OS上で行われます。
理論のビット
Linux IP IP 4ルーティングは、次の構造に基づいています。
- sk_buffは最も一般的に使用される構造であり、ネットワークパケット全体です。 コンテンツを変更する方法に沿って、関数から関数に渡されます。
- rtable + dst_entry-ルーティングテーブルから取得したルートキャッシュ結果を格納する2つの構造。 受信者のアドレス、送信元アドレス、およびパケットのTOSフィールドに応じて、それに関して追加のポリシーが定義されます。 これらの2つの構造には、重要な情報が格納されます。送信するインターフェイス、およびゲートウェイフィールドは、L3ヘッダーを変更せずにパケットを送信できる将来のL2ネイバーです。 各フレームのキャッシュ検索は2回実行されます。入力で1回(着信トラフィック)、出力で2回(送信)です。 第二に興味があります。
- 近隣 -この構造の各インスタンスは、特定の受信者IPアドレスのL2近隣を表します。 ARP応答の後に受信した宛先MACアドレスが含まれています。 MACアドレスを決定した後に送信する必要があるsk_buffからのキュー。 タイマーなど。 マルチキャストグループの場合、ネイバーも作成され、MACアドレスのみが関数によって生成されます。 これを避けるべきです。
Linuxでは、マルチキャストトラフィックのルーティングはユーザーの領域、つまりルータープログラムから完全に制御されます。 マルチキャストルーティングの重要な要素はmfc_cache構造です。 これは、各ルートに関するすべての情報(ストリームソースのアドレス、統計、その他のルートなど)を格納するリンクリストです。 mfc_cache構造の追加と削除は、ユーザープログラムによって行われます。
mfc_cacheリストの概略図:

本「Linux Networking Architecture」からの画像
開発
カーネルはLinux 3.18カーネルになりました。 各マルチキャストグループのクライアントIPアドレスを保存するには、リンクリストを使用してmfc_cacheを展開します。
struct mut_dst { struct list_head list; __be32 ip; struct rcu_head rcu; };
新しいipmr_unicast_xmit関数の紹介。 ユニキャストrtableが生成されますが、同時にマルチキャストsk_buffを送信します。 したがって、将来の送信に必要なインターフェイスを選択します。
これで、将来、マルチキャストグループではなく、受信者に対してネイバーが作成されるように、 rtableでゲートウェイを指定します。 rt_gatewayフィールドがこれを担当します。
struct rtable *rt; rt = ip_route_output_ports(net, &fl4, NULL, m_dst->ip, 0, 0, 0, IPPROTO_IPIP, RT_TOS(iph->tos), 0); if (IS_ERR(rt)) goto out_free; rt->rt_gateway = m_dst->ip; dev = rt->dst.dev;
sysctl変数/ proc / sys / net / ipv4 / mutを導入します。 カーネルの動作モードをオンザフライで変更することが可能になります。
助けて
sysctl net.ipv4.mut = 1-新しいモードを有効にします
sysctl net.ipv4.mut = 0-標準ルーティングモードを返します
sysctl net.ipv4.mut = 0-標準ルーティングモードを返します
前と同じように、ルートのリストを見ることができます。現在はユニキャストでもあります:
root@multicast:~# cat /proc/net/ip_mr_cache
Group Origin Iif Pkts Bytes Wrong Dsts
0520C3EF 2 18842 25323648 0 01000A0A
すべての変更に関する詳細は、リポジトリにあります。 記事の最後にリンクします。
作業の視覚的表現(MACアドレスの列の変更):
ルーター
プログラムIGMPProxyに基づきます。 同じmroutedを使用できます 。 すべてのIGMPメッセージが要求インターフェイスのIPアドレスから送信されることは非常に重要であり、使用を妨げるものは何もありません。 変更の詳細を説明する意味はありません;それらは対応するリポジトリにもあります。 主なことは、カーネル管理に、プログラムがサポートする必要がある2つの新しいコマンドがあることです。
- MRT_MUT_ADD_DST(212)-受信者を追加
- MRT_MUT_DEL_DST(213)-受信者を削除
それらとともに、フォームの構造が送信されます。
struct <name> { struct in_addr group; // struct in_addr origin; // struct in_addr destination; // }
警告
IGMPプロトコルに基づいて、同じグループの別のクライアントからそのようなリクエストを受信するクライアントは、同様のリクエストを送信しないため、このアプローチでは、Membership Reportリクエストがないためにクライアントをグループから切断することはできません。 したがって、切断は、明示的なLeave Groupパッケージを受け取った後にのみ可能です。
使用する
新しい機能を有効にするには、オプションCONFIG_IP_MUT = yを使用してカーネルをコンパイルする必要があります
IGMPProxyが正しく機能するには、CONFIG_SYSCTL_SYSCALL = yを有効にする必要もあります。
参照資料
変更されたカーネル
変更されたIGMPProxy
中古文学
Rami Rosen「Linuxカーネルネットワーキング。 実装と理論»
Christian Benvenuti「Understanding Linux Network Internals」
Klaus WehrleとFrank Pahlke「Linuxネットワークアーキテクチャ」
誰かが問題を解決する別の方法をお持ちの場合は、コメントで共有してください。