日本語 man コマンド類 (ja-man-1.1j_5) と日本語 man ドキュメント (ja-man-doc-5.4 (5.4-RELEASE 用) など) をインストールすると、以下のような man コマンド閲覧、キーワード検索が コンソールからできるようになります。
4.11-RELEASE-K, 5.4-RELEASE-K, 5.5-RELEASE-K, 6.0-RELEASE-K から 6.4-RELEASE-K, 7.0-RELEASE-K から 7.4-RELEASE-K, 8.0-RELEASE-K から 8.4-RELEASE-K, 9.0-RELEASE-K から 9.3-RELEASE-K, 10.0-RELEASE-K から 10.3-RELEASE-K, 11.0-RELEASE-K から 11.4-RELEASE-K, 12.0-RELEASE-K, 12.1-RELEASE-K は、 プライベート版 (小金丸が編集してまとめたもの) ですが、 より多くの翻訳したファイルが含まれています。 (5.4-RELEASE-K から 6.4-RELEASE-K, 7.0-RELEASE-K から 7.4-RELEASE-K, 8.0-RELEASE-K から 8.4-RELEASE-K, 9.0-RELEASE-K から 9.3-RELEASE-K, 10.0-RELEASE-K から 10.3-RELEASE-K, 11.0-RELEASE-K から 11.4-RELEASE-K, 12.0-RELEASE-K から 12.3-RELEASE-K, 13.0-RELEASE-K から 13.2-RELEASE-K は、全翻訳済み)
13.3-STABLE-K, 15.0-CURRENT-K は現在、作成中で日々更新されています。
Table of Contents
MULTICAST(4) FreeBSD カーネルインタフェースマニュアル MULTICAST(4) 名称 multicast -- マルチキャスト経路制御 書式 options MROUTING #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip_mroute.h> #include <netinet6/ip6_mroute.h> int getsockopt(int s, IPPROTO_IP, MRT_INIT, void *optval, socklen_t *optlen); int setsockopt(int s, IPPROTO_IP, MRT_INIT, const void *optval, socklen_t optlen); int getsockopt(int s, IPPROTO_IPV6, MRT6_INIT, void *optval, socklen_t *optlen); int setsockopt(int s, IPPROTO_IPV6, MRT6_INIT, const void *optval, socklen_t optlen); 解説 マルチキャスト経路制御は、マルチポイントネットワークでデータパケットを効 率的に一連のマルチキャストリスナに伝播するために使用されます。ユニキャス トがすべてのリスナにデータを複製するために使用されるなら、いくつかのネッ トワークリンクは、同じデータパケットの複数のコピーを伝達するかもしれませ ん。マルチキャスト経路制御で、オーバヘッドは、ネットワークリンク単位で (多くても) 1 つのコピーまで下げられます。 すべてのマルチキャスト可能なルータは、一般的なマルチキャスト経路制御プロ トコルを実行しなければなりません。Protocol Independent Multicast - スパー ス (まばらな) モード (PIM-SM)、または、Protocol Independent Multicast - デンス (濃い) モード (PIM-DM) のいずれかは、現在、インターネットコミュニ ティで一般的に、受け入れられたプロトコルであるので、これらを使用すること を勧めます。歴史セクションで、以前のマルチキャスト経路制御プロトコルにつ いて議論しています。 マルチキャスト経路制御を始めるためには、ユーザは、カーネル (カーネル設定 オプションについては、書式を参照) でマルチキャスト転送を有効にしなければ ならなくて、マルチキャスト経路制御可能なユーザレベルプロセスを実行しなけ ればなりません。開発者の観点から、プログラミングガイドセクションで説明さ れたプログラミングガイドは、カーネルにおけるマルチキャスト転送を制御する ために使用されるでしょう。 プログラミングガイド このセクションは、基本的なマルチキャスト経路制御 API に関する情報を提供し ます。いわゆる ``高度なマルチキャスト API'' は、高度なマルチキャスト API プログラミングガイドデクションで説明されます。 最初に、マルチキャスト経路制御ソケットがオープンされなければなりません。 そのソケットは、カーネルでマルチキャスト転送を制御するために使用されるで しょう。以下でのほとんどの操作がある種の特権 (すなわち、root の特権) を必 要とすることに注意してください: /* IPv4 */ int mrouter_s4; mrouter_s4 = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); int mrouter_s6; mrouter_s6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); IGMP か MLD マルチキャストグループメンバシップメッセージの送信か受信にお いて、IGMP か ICMPv6 ソケット (それぞれ IPv4 と IPv6 の場合) をルータが オープンする必要があるなら、同様に mrouter_s4 か mrouter_s6 ソケットは、 それぞれ IGMP か MLD メッセージの送信か受信に使用されるべきであることに注 意してください。BSD 派生カーネルの場合には、IGMP か MLD メッセージのため だけに別々のソケットをオープンできるかもしれません。しかしながら、ある他 のカーネル (例えば、Linux) は、マルチキャスト経路制御ソケットが IGMP か MLD メッセージの送受信を使用しなければならないことを必要とします。した がって、移植性の理由で、マルチキャスト経路制御ソケットは、同様に IGMP と MLD メッセージのために再利用すべきです。 マルチキャスト経路制御ソケットがオープンされた後に、それは、カーネルでマ ルチキャスト転送を有効にするか無効にするために使用することができます: /* IPv4 */ int v = 1; /* 1 は、有効, または 0 は、無効 */ setsockopt(mrouter_s4, IPPROTO_IP, MRT_INIT, (void *)&v, sizeof(v)); /* IPv6 */ int v = 1; /* 1 は、有効, または 0 は、無効 */ setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_INIT, (void *)&v, sizeof(v)); ... /* 必要なら, すべての ICMPv6 メッセージをフィルタする */ struct icmp6_filter filter; ICMP6_FILTER_SETBLOCKALL(&filter); setsockopt(mrouter_s6, IPPROTO_ICMPV6, ICMP6_FILTER, (void *)&filter, sizeof(filter)); マルチキャスト転送が有効にされた後に、マルチキャスト経路制御ソケットは、 PIM-SM か PIM-DM が実行されているなら、カーネルで PIM 処理を有効にするた めに使用することができます (pim(4) 参照)。 マルチキャスト転送に使用される、それぞれのネットワークインタフェース (例 えば、物理または仮想トンネル) については、対応するマルチキャストインタ フェースがカーネルに追加されなければなりません: /* IPv4 */ struct vifctl vc; memset(&vc, 0, sizeof(vc)); /* すべての vifctl フィールドを適切に割り当てます */ vc.vifc_vifi = vif_index; vc.vifc_flags = vif_flags; vc.vifc_threshold = min_ttl_threshold; vc.vifc_rate_limit = 0; memcpy(&vc.vifc_lcl_addr, &vif_local_address, sizeof(vc.vifc_lcl_addr)); setsockopt(mrouter_s4, IPPROTO_IP, MRT_ADD_VIF, (void *)&vc, sizeof(vc)); vif_index は、vif 単位でユニークでなければなりません。vif_flags は、 <netinet/ip_mroute.h> で定義されるように VIFF_* フラグを含んでいます。 VIFF_TUNNEL フラグは、もはや FreeBSD でサポートされません。トンネル上でマ ルチキャストデータグラムを転送したいユーザは、gif(4) または gre(4) トンネ ルを設定して、物理インタフェースとして、それを使用することを考慮すべきで す。 min_ttl_threshold は、マルチキャストデータパケットがその vif で転送される ためになければならない最小の TTL (有効期間) を含んでいます。通常、それ は、1 の値となります。 max_rate_limit 引数は、もはや FreeBSD でサポートされず、0 に設定されるべ きです。マルチキャストデータグラムをレート制限したいユーザは、dummynet(4) または altq(4) の使用を考慮すべきです。 vif_local_address は、対応するローカルインタフェースのローカル IP アドレ スを含んでいます。vif_remote_address は、DVMRP マルチキャストトンネルの場 合にリモート IP アドレスを含んでいます。 /* IPv6 */ struct mif6ctl mc; memset(&mc, 0, sizeof(mc)); /* すべての mif6ctl フィールドを適切に割り当てます */ mc.mif6c_mifi = mif_index; mc.mif6c_flags = mif_flags; mc.mif6c_pifi = pif_index; setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_ADD_MIF, (void *)&mc, sizeof(mc)); mif_index は、vif 単位でユニークでなければなりません。mif_flags は、 <netinet6/ip6_mroute.h> で定義されるように MIFF_* を含んでいます。 pif_index は、対応するローカルインタフェースの物理的なインタフェースイン デックスです。 マルチキャストインタフェースは、次によって削除されます: /* IPv4 */ vifi_t vifi = vif_index; setsockopt(mrouter_s4, IPPROTO_IP, MRT_DEL_VIF, (void *)&vifi, sizeof(vifi)); /* IPv6 */ mifi_t mifi = mif_index; setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_DEL_MIF, (void *)&mifi, sizeof(mifi)); マルチキャスト転送が有効にされて、マルチキャスト仮想インタフェースが追加 された後に、カーネルは、以前に MRT_INIT または MRT6_INIT でオープンされて いるマルチキャスト経路制御ソケット上で upcall メッセージ (このテキストの 後ろでまたの名は、シグナルです) を配信できます。IPv4 upcall は、フィール ド im_mbz を 0 に設定した struct igmpmsg ヘッダ (<netinet/ip_mroute.h> 参 照) があります。このヘッダは、プロトコルフィールド ip_p を 0 に設定した struct ip 構造体が後に続くことに注意してください。IPv6 upcall は、フィー ルド im6_mbz を 0 に設定した struct mrt6msg ヘッダ (<netinet6/ip6_mroute.h> 参照) があります。このヘッダは、次のヘッダフィー ルド ip6_nxt を 0 に設定した struct ip6_hdr 構造体が後に続くことに注意し てください。 upcall ヘッダは、それぞれ IPv4 と IPv6 のための upcall のタイプ IGMPMSG_* と MRT6MSG_* でフィールド im_msgtype と im6_msgtype を含んでいます。 upcall ヘッダフィールドの残りの値と upcall メッセージの本体は、特定の upcall タイプに依存します。 upcall メッセージタイプが IGMPMSG_NOCACHE または MRT6MSG_NOCACHE であるな ら、これは、マルチキャストパケットがマルチキャストルータに到達したことを 示しますが、ルータには、そのパケットのための転送状態がありません。通常、 upcall は、適切な Multicast Forwarding Cache (MFC) エントリをカーネルにイ ンストールするためにマルチキャストのユーザレベルのプロセスのためのシグナ ルとなります。 MFC エントリは、次によって追加されます: /* IPv4 */ struct mfcctl mc; memset(&mc, 0, sizeof(mc)); memcpy(&mc.mfcc_origin, &source_addr, sizeof(mc.mfcc_origin)); memcpy(&mc.mfcc_mcastgrp, &group_addr, sizeof(mc.mfcc_mcastgrp)); mc.mfcc_parent = iif_index; for (i = 0; i < maxvifs; i++) mc.mfcc_ttls[i] = oifs_ttl[i]; setsockopt(mrouter_s4, IPPROTO_IP, MRT_ADD_MFC, (void *)&mc, sizeof(mc)); /* IPv6 */ struct mf6cctl mc; memset(&mc, 0, sizeof(mc)); memcpy(&mc.mf6cc_origin, &source_addr, sizeof(mc.mf6cc_origin)); memcpy(&mc.mf6cc_mcastgrp, &group_addr, sizeof(mf6cc_mcastgrp)); mc.mf6cc_parent = iif_index; for (i = 0; i < maxvifs; i++) if (oifs_ttl[i] > 0) IF_SET(i, &mc.mf6cc_ifset); setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_ADD_MFC, (void *)&mc, sizeof(mc)); source_addr と group_addr は、(upcall メッセージで設定されるような) マル チキャストパケットのソースとグループアドレスです。iif_index は、この特定 のソースとグループアドレスのためのマルチキャストパケットが受信されるべき であるマルチキャストインタフェースの仮想インタフェースインデックスです。 oifs_ttl[] 配列は、マルチキャストパケットが発信インタフェースで転送される ために持つべきである最小の TTL (インタフェース毎の) を含んでいます。TTL 値が 0 であるなら、対応するインタフェースは、発信インタフェースのセットに 含まれていません。IPv6 だけの場合に発信インタフェースのセットが指定できる ことに注意してください。 MFC エントリは、次によって削除されます: /* IPv4 */ struct mfcctl mc; memset(&mc, 0, sizeof(mc)); memcpy(&mc.mfcc_origin, &source_addr, sizeof(mc.mfcc_origin)); memcpy(&mc.mfcc_mcastgrp, &group_addr, sizeof(mc.mfcc_mcastgrp)); setsockopt(mrouter_s4, IPPROTO_IP, MRT_DEL_MFC, (void *)&mc, sizeof(mc)); /* IPv6 */ struct mf6cctl mc; memset(&mc, 0, sizeof(mc)); memcpy(&mc.mf6cc_origin, &source_addr, sizeof(mc.mf6cc_origin)); memcpy(&mc.mf6cc_mcastgrp, &group_addr, sizeof(mf6cc_mcastgrp)); setsockopt(mrouter_s6, IPPROTO_IPV6, MRT6_DEL_MFC, (void *)&mc, sizeof(mc)); 次の方法は、カーネルにインストールされた MFC エントリ毎に様々な統計値 (例 えば、ソースとグループアドレス毎の転送パケットの数) を得るために使用でき ます: /* IPv4 */ struct sioc_sg_req sgreq; memset(&sgreq, 0, sizeof(sgreq)); memcpy(&sgreq.src, &source_addr, sizeof(sgreq.src)); memcpy(&sgreq.grp, &group_addr, sizeof(sgreq.grp)); ioctl(mrouter_s4, SIOCGETSGCNT, &sgreq); /* IPv6 */ struct sioc_sg_req6 sgreq; memset(&sgreq, 0, sizeof(sgreq)); memcpy(&sgreq.src, &source_addr, sizeof(sgreq.src)); memcpy(&sgreq.grp, &group_addr, sizeof(sgreq.grp)); ioctl(mrouter_s6, SIOCGETSGCNT_IN6, &sgreq); 次の方法は、カーネルでマルチキャスト仮想インタフェース毎の様々な統計値 (例えば、インタフェース毎の転送パケットの数) を得るために使用できます: /* IPv4 */ struct sioc_vif_req vreq; memset(&vreq, 0, sizeof(vreq)); vreq.vifi = vif_index; ioctl(mrouter_s4, SIOCGETVIFCNT, &vreq); /* IPv6 */ struct sioc_mif_req6 mreq; memset(&mreq, 0, sizeof(mreq)); mreq.mifi = vif_index; ioctl(mrouter_s6, SIOCGETMIFCNT_IN6, &mreq); 高度なマルチキャスト API プログラミングガイド カーネルに新しい機能を追加したいと思うなら、後方互換性 (バイナリと API) を保つのが難しくなって、同時にユーザレベルプロセスに (カーネルがそれらを サポートするなら) 新しい機能を利用することを許容します。 私たちが後方互換性を保つことができるようするメカニズムの 1 つは、ユーザレ ベルプロセスとカーネルの間の一種のネゴシエーション (交渉) です: 1. ユーザレベルプロセスは、カーネルで使用したい新しい機能 (と対応する API) のセットを有効にしようとします。 2. カーネルは、それについて知っている機能の (サブ) セットを返して、進ん で有効にします。 3. ユーザレベルプロセスは、カーネルが同意した機能のセットだけを使用しま す。 後方互換性をサポートするために、ユーザレベルプロセスが少しも新しい機能を 要求しないなら、カーネルは、基本的なマルチキャスト API (プログラミングガ イドセクションを参照) をデフォルトとします現在は、高度なマルチキャスト API は、IPv4 のためだけに存在します。将来は、同様に IPv6 サポートがあるで しょう。 下記は、拡張可能な API ソリューション (解決法) の概要です。すべての新しい オプションと構造体は、ほかに規定されたものがある場合を除き <netinet/ip_mroute.h> と <netinet6/ip6_mroute.h> で定義されることに注意し てください。 ユーザレベルプロセスは、カーネルとの API 機能ネゴシエーション (交渉) を実 行するために、新しい getsockopt()/setsockopt() オプションを使用します。こ のネゴシエーション (交渉) は、マルチキャスト経路制御ソケットがオープンさ れた直後に実行しなければなりません。要求/許容の機能のセット (集合) は、 ビットセットとして保存されます (現在、uint32_t で、すなわち、最大 32 の新 しい機能です)。新しい getsockopt()/setsockopt() オプションは、 MRT_API_SUPPORT と MRT_API_CONFIG です。例えば: uint32_t v; getsockopt(sock, IPPROTO_IP, MRT_API_SUPPORT, (void *)&v, sizeof(v)); これは、v にカーネル API サポートで前もって定義されたビットを設定します。 uint32_t 中の 8 つの最下位ビットは、他の新しい機能について 24 個のフラグ を残す struct mfcctl (これらのフラグについては、下記参照) の新しい定義の 一部として mfcc_flags で使用することができる、可能性がある 8 つのフラグ MRT_MFC_FLAGS_* と同様です。getsockopt(MRT_API_SUPPORT) によって返された 値は、読み込み専用です。言い換えれば、setsockopt(MRT_API_SUPPORT) 失敗す るでしょう。 API を変更して、カーネルに何らかの特有の機能を設定するためには: uint32_t v = MRT_MFC_FLAGS_DISABLE_WRONGVIF; if (setsockopt(sock, IPPROTO_IP, MRT_API_CONFIG, (void *)&v, sizeof(v)) != 0) { return (ERROR); } if (v & MRT_MFC_FLAGS_DISABLE_WRONGVIF) return (OK); /* 成功 */ else return (ERROR); 言い換えれば、setsockopt(MRT_API_CONFIG) が呼び出されるとき、それへの引数 は、API とカーネルで有効にされる機能の要求されるセットを指定します。v の リターン値は、カーネルで有効にされた機能の実際の (サブ) セットです。有効 にされた機能の同じセットを後で取得ためには: getsockopt(sock, IPPROTO_IP, MRT_API_CONFIG, (void *)&v, sizeof(v)); 有効にされた機能のセットは、グローバルです。言い換えれば、 setsockopt(MRT_API_CONFIG) は、setsockopt(MRT_INIT) の直後に呼び出される べきです。 現在は、新しい機能の次のセットは、次のように定義されます: #define MRT_MFC_FLAGS_DISABLE_WRONGVIF (1 << 0) /* WRONGVIF シグナルを 無効にする */ #define MRT_MFC_FLAGS_BORDER_VIF (1 << 1) /* ボーダ vif */ #define MRT_MFC_RP (1 << 8) /* RP アドレスを有効にする */ #define MRT_MFC_BW_UPCALL (1 << 9) /* bw upcall を有効にする */ 高度なマルチキャスト API は、旧来の struct mfcctl2 の代わりに新たに定義さ れた struct mfcctl を使用します。オリジナルの struct mfcctl は、そのまま に保持されます。新しい struct mfcctl2 は、以下の通りです: /* * MRT_ADD_MFC と MRT_DEL_MFC のための新しい引数の構造体は、 * 古い struct mfcctl をオーバレイして拡張しています。 */ struct mfcctl2 { /* the mfcctl fields */ struct in_addr mfcc_origin; /* マルチキャストの ip 始点 */ struct in_addr mfcc_mcastgrp; /* マルチキャストグループ関連*/ vifi_t mfcc_parent; /* 着信 vif */ u_char mfcc_ttls[MAXVIFS];/* vif の転送 ttl */ /* extension fields */ uint8_t mfcc_flags[MAXVIFS];/* MRT_MFC_FLAGS_* フラグ */ struct in_addr mfcc_rp; /* RP アドレス */ }; 新しいフィールドは、mfcc_flags[MAXVIFS] と mfcc_rp です。互換性の理由のた めにそれらが終わりに追加されることに注意してください。 mfcc_flags[MAXVIFS] フィールドは、(S,G) エントリ単位でインタフェース毎の 様々なフラグを設定するために使用されます。現在、定義されたフラグは、次の 通りです: #define MRT_MFC_FLAGS_DISABLE_WRONGVIF (1 << 0) /* WRONGVIF シグナルを 無効にする */ #define MRT_MFC_FLAGS_BORDER_VIF (1 << 1) /* ボーダ vif */ MRT_MFC_FLAGS_DISABLE_WRONGVIF フラグは、マルチキャストデータパケットが間 違ったインタフェースで到着するなら、(S,G) 精度で IGMPMSG_WRONGVIF カーネ ルシグナルを明らかに無効にするために使用されます。通常、このシグナルは、 PIM-SM マルチキャスト経路制御の場合に最短パスのスイッチを完了するか、また は PIM アサートメッセージをトリガするために使用されます。しかしながら、発 信インタフェースセットでなくて、着信インタフェースになると期待していない インタフェースに配信するべきではありません。したがって、 MRT_MFC_FLAGS_DISABLE_WRONGVIF フラグがインタフェースのいくつかに設定され るなら、データパケットは、MFC エントリが WRONGVIF シグナルをトリガしない インタフェースで到着します。そのフラグが設定されないなら、シグナルは、ト リガされます (デフォルト動作)。 MRT_MFC_FLAGS_BORDER_VIF フラグは、PIM レジスタメッセージの境界ビットが設 定されるべきであるかどうか (レジスタカプセル化がカーネルの中で実行される ときの場合に) 指定するために使用されます。それが特別な PIM レジスタカーネ ル仮想インタフェースに設定されるなら (pim(4) 参照)、RP に送られたレジスタ メッセージ中の境界ビットが設定されます。 残っている 6 ビットは、将来の使用のために予約されています。 mfcc_rp フィールドは、カーネルレベル PIM レジスタカプセル化を実行したいと 思うなら、マルチキャストグループ G に (PIM-SM マルチキャスト経路制御の場 合に) RP アドレスを指定するためにに使用されます。mfcc_rp フィールドは、 MRT_MFC_RP 高度な API フラグ/ケーパビリティが setsockopt(MRT_API_CONFIG) によってうまく設定された場合にだけ、使用されます。 MRT_MFC_RP フラグが setsockopt(MRT_API_CONFIG) によってうまく設定されたな ら、カーネルは、ユーザレベルカプセル化のためにマルチキャストデータパケッ トをユーザレベル (IGMPMSG_WHOLEPKT upcall の中の) に送る代わりに PIM レジ スタカプセル化自体を実行するのを試みます。RP アドレスは、新しい struct mfcctl2 内の mfcc_rp フィールドから取られるでしょう。しかしながら、 MRT_MFC_RP フラグがうまく設定されたとしても、mfcc_rp フィールドが INADDR_ANY に設定されたなら、カーネルは、まだマルチキャストデータパケット と共に IGMPMSG_WHOLEPKT upcall をユーザレベルプロセスに配信します。 さらに、マルチキャストデータパケットが PIM レジスタカプセル化の後で単一の IP パケットの中で適合することができないくらい大きいなら (例えば、約 65500 バイトのサイズがあったなら)、データパケットは、断片化され、それぞれの断片 は、別々にカプセル化されます。通常、カプセル化を実行するのと同じホストか ら局所的に送出された場合にだけ、マルチキャストデータパケットが大きい場合 があることに注意してください。そうでなければ、例えばイーサネット上のマル チキャストデータパケットの送信は、もっと小さな部分に断片化したでしょう。 通常、マルチキャスト経路制御のユーザレベルプロセスは、何らかのデータフ ローについて転送帯域幅を知る必要があるでしょう。例えば、マルチキャスト経 路制御プロセスがタイムアウトアイドル MFC エントリを必要とするかもしれませ ん、または例えば、帯域幅レートがスレッシュホールドを超えているなら、PIM SM の場合に (S,G) 最短パススイッチを開始することができます。 データフローの帯域幅を測定する独創的な解決策は、ユーザレベルプロセスが定 期的に (S,G) あたりの転送パケット/バイトの数に関してカーネルに問い合わせ ることでした、そして、そしてそれらの数に基づいて、ソース (始点) がアイド ルであるかどうか、またはソースの通信帯域幅がスレッシュホールドを超えてい るかどうかを評価するでしょう。その解決策は、決してスケーラブル (測定可能) ではありません、したがって、帯域幅モニタリングのための新しいメカニズムが 必要です。 次は、帯域幅のモニタリングのメカニズムの説明です。 • データフローの帯域幅がいくつかの前もって定義されたフィルタを満足させ るなら、カーネルは、マルチキャスト経路制御ソケット上の upcall をその フィルタをインストールしたマルチキャスト経路制御プロセスに配信しま す。 • 帯域幅 upcall フィルタは、(S,G) 単位でインストールされます。(S,G) ご とに 1 つ以上のフィルタがあり得ます。 • すべての可能な比較操作 (すなわち、< <= == != > >= ) をサポートする代 わりに、カーネルレベルの実装をより簡単にして、実質的にそれらの 2 だけ を必要とするので、<= と >= 操作だけサポートがあります。さらに、不足 している操作は、それらの <= と >= フィルタの二次ユーザレベルフィルタ リングによってシミュレートすることができます。例えば、!= をシミュレー トするために、フィルタ ``bw <= 0xffffffff'' をインストールする必要が あり、そして、upcall が受け付けられた後に ``measured_bw != expected_bw'' であるかどうかチェックする必要があります。 • 帯域幅 upcall メカニズムは、MRT_MFC_BW_UPCALL フラグのために setsockopt(MRT_API_CONFIG) によって有効にされます。 • 帯域幅 upcall フィルタは、それぞれ新しい setsockopt(MRT_ADD_BW_UPCALL) と setsockopt(MRT_DEL_BW_UPCALL) (もち ろん、適切な struct bw_upcall 引数で) によって追加されるか/削除されま す。 アプリケーション観点から、開発者は、次のことについて知る必要があります: /* * 測定される帯域幅がスレッシュホールドを越えているかまたは下回るなら、 * upcall をインストールするか、または配信するるための構造体。 * * ユーザプログラム (例えば、デーモン) は、いくつかのデータフローに * よって使用される帯域幅がいつ、スレッシュホールドが越えているか * または下回るかを知る必要があるかもしれません。このインタフェースは、 * ユーザランドが (バイト単位、およびパケット単位で) スレッシュホールド * と測定される間隔を指定できるようにします。フローは、同じ発信元 (始点) * と宛先 (終点) IP アドレスがあるすべてのパケットです。 * 現在のところ、コードは、マルチキャストの宛先 (終点) に使用される * だけですが、ユニキャストの使用を防ぐものはありません。 * * 測定される間隔は、いくらかの Tmin (現在 3 秒) より短いはずがありません。 * スレッシュホールドは、per_interval のパケット単位およびバイト単位で * 設定されます。 * * 測定は、次の通り動作します: * * >= 測定値のために: * 最初のパケットは、測定される間隔の始まりを示します。間隔の間、私たちは、 * パケットとバイトを数えます、そして、スレッシュホールドが渡されたとき、 * 私たちは、upcall を配信し、終わります。間隔の終わりの後の最初のパケット * は、カウントをリセットして、測定を再開します。 * * <= 測定値のために: * 私たちは、間隔の終わりで発火するようにタイマを始動し、それぞれの着信 * パケットに関して、パケットとバイトを数えます。タイマが発火するとき、 * 私たちは、スレッシュホールドと値を比べて、下回っているなら upcall * をスケジュールし、(タイマを再スケジュールしカウンタを 0 にして) * 測定を再開します。 */ struct bw_data { struct timeval b_time; uint64_t b_packets; uint64_t b_bytes; }; struct bw_upcall { struct in_addr bu_src; /* ソース (始点) アドレス */ struct in_addr bu_dst; /* 宛先 (終点) アドレス */ uint32_t bu_flags; /* その他のフラグ (下記参照) */ #define BW_UPCALL_UNIT_PACKETS (1 << 0) /* (パケット単位の) スレッシュホールド */ #define BW_UPCALL_UNIT_BYTES (1 << 1) /* (バイト単位の) スレッシュホールド */ #define BW_UPCALL_GEQ (1 << 2) /* bw >= スレッシュホールド なら, upcall */ #define BW_UPCALL_LEQ (1 << 3) /* bw <= スレッシュホールド なら, upcall */ #define BW_UPCALL_DELETE_ALL (1 << 4) /* s,d のための upcall をすてべ削除 */ struct bw_data bu_threshold; /* bw スレッシュホールド */ struct bw_data bu_measured; /* 測定される bw */ }; /* 一緒に配送する upcall の最大数 */ #define BW_UPCALLS_MAX 128 /* 帯域幅測定のための最小スレッシュホールド時間の間隔 */ #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC 3 #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC 0 bw_upcall 構造体は、setsockopt(MRT_ADD_BW_UPCALL) と setsockopt(MRT_DEL_BW_UPCALL) への引数として使用されます。各 setsockopt(MRT_ADD_BW_UPCALL) は、bw_upcall 引数で送信元 (始点) と宛先 (終点) アドレスのためにカーネルにフィルタをインストールし、そして、その フィルタは、次の疑似アルゴリズムに従って upcall をトリガします: if (bw_upcall_oper IS ">=") { if (((bw_upcall_unit & PACKETS == PACKETS) && (measured_packets >= threshold_packets)) || ((bw_upcall_unit & BYTES == BYTES) && (measured_bytes >= threshold_bytes))) SEND_UPCALL("measured bandwidth is >= threshold"); } if (bw_upcall_oper IS "<=" && measured_interval >= threshold_interval) { if (((bw_upcall_unit & PACKETS == PACKETS) && (measured_packets <= threshold_packets)) || ((bw_upcall_unit & BYTES == BYTES) && (measured_bytes <= threshold_bytes))) SEND_UPCALL("measured bandwidth is <= threshold"); } 同じ bw_upcall では、BYTE と PACKET の両方でユニットを指定することができ ます。しかしながら、GEQ と LEQ フラグは、互いに排他的です。 基本的に、upcall は、測定される帯域幅が (指定された測定間隔中に) スレッ シュホールド帯域幅より >= か <= なら、配信されます。実際的な理由で、測定 する間隔の最も小さい値は、3 秒です。より小さい値が許可されるなら、帯域幅 見積りがそれほど正確でないし、潜在的に生成された upcall の大変高い頻度 は、あまりに多くのオーバヘッドを持ち込むかもしれません。>= 操作のために、 答えは、threshold_interval の終わりまでに知っているかもしれません、した がって、upcall は、より早く配信されるかもしれません。しかしながら、<= 操 作のために、スレッシュホールドの間隔が答えを知るための期限が切れるまで、 私たちは、待たなければなりません。 使用例: struct bw_upcall bw_upcall; /* すべての bw_upcall フィールドを適切に割り当てます */ memset(&bw_upcall, 0, sizeof(bw_upcall)); memcpy(&bw_upcall.bu_src, &source, sizeof(bw_upcall.bu_src)); memcpy(&bw_upcall.bu_dst, &group, sizeof(bw_upcall.bu_dst)); bw_upcall.bu_threshold.b_data = threshold_interval; bw_upcall.bu_threshold.b_packets = threshold_packets; bw_upcall.bu_threshold.b_bytes = threshold_bytes; if (is_threshold_in_packets) bw_upcall.bu_flags |= BW_UPCALL_UNIT_PACKETS; if (is_threshold_in_bytes) bw_upcall.bu_flags |= BW_UPCALL_UNIT_BYTES; do { if (is_geq_upcall) { bw_upcall.bu_flags |= BW_UPCALL_GEQ; break; } if (is_leq_upcall) { bw_upcall.bu_flags |= BW_UPCALL_LEQ; break; } return (ERROR); } while (0); setsockopt(mrouter_s4, IPPROTO_IP, MRT_ADD_BW_UPCALL, (void *)&bw_upcall, sizeof(bw_upcall)); 単一のフィルタを削除するために、MRT_DEL_BW_UPCALL を使用し、bw_upcall の フィールドは、MRT_ADD_BW_UPCALL が呼び出された時と全く同じに設定しなけれ ばなりません。 与えられた (S,G) のためのすべての帯域幅を削除するために、struct bw_upcall 中の bu_src と bu_dst フィールドのみを設定する必要があり、つぎにフィール ド bw_upcall.bu_flags 内の BW_UPCALL_DELETE_ALL フラグだけを設定します。 帯域幅 upcall は、新しい upcall メッセージでそれらを集めることによって受 け付けます: #define IGMPMSG_BW_UPCALL 4 /* BW モニタリング upcall */ このメッセージは、struct bw_upcall (BW_UPCALLS_MAX = 128 までの) 要素の配 列です。128 保留中 (pending) の upcall があるとき、または前の upcall 以来 1 秒の期限が切れているとき (どれが最初になっても)、upcall は、配信されま す。struct upcall 要素では、bu_measured フィールドは、特定の測定値を示す ために書き込まれます。しかしながら、特定の間隔が測定される方法のために、 ユーザは、bu_measured.b_time がどのように使用されているか注意するべきで す。例えば、フィルタが upcall をトリガするためにインストールされ、パケッ トの数が >= 1 であるなら、bu_measured は、>= フィルタのための測定される 間隔が転送されたパケットによって ``時間を計る'' ので、最初のものの後の upcall で 0 の値であるかもしれません。したがって、転送されたデータの帯域 幅の正確な値を測定するのにこの upcall メカニズムを使用するべきではありま せん。正確な帯域幅を測定するために、ユーザは、ioctl(SIOCGETSGCNT) メカニ ズム (プログラミングガイドセクションを参照) で転送されたパケット統計値を 得る必要があるでしょう。 フィルタのための upcall は、特定のフィルタが削除されるまで、配信されます が、bu_threshold.b_time 毎に一度より頻繁ではないことに注意してください。 例えば、フィルタがシグナルを配信するために指定され、bw >= 1 パケットであ るなら、最初のパケットは、シグナルのトリガとなりますが、次の upcall は、 前の upcall の後に bu_threshold.b_time より早くトリガされません。 関連項目 getsockopt(2), recvfrom(2), recvmsg(2), setsockopt(2), socket(2), sourcefilter(3), altq(4), dummynet(4), gif(4), gre(4), icmp6(4), igmp(4), inet(4), inet6(4), intro(4), ip(4), ip6(4), mld(4), pim(4) 歴史 Distance Vector Multicast Routing Protocol (DVMRP) は、最初に開発されたマ ルチキャスト経路制御プロトコルでした。その後に、Multicast Extensions to OSPF (MOSPF) のような他のプロトコルと Core Based Trees (CBT) が同様に開発 されました。現在、自律システム境界のルータは、Border Gateway Protocol (BGP) を通してピア (相手側) とマルチキャスト経路を交換できます。他の多く の経路制御プロトコルは、PIM-SM と PIM-DM で使用するためにマルチキャスト経 路を再配信することができます。 作者 元のマルチキャストコードは、David Waitzman (BBN Labs) によって書かれ、後 で次の個人によって修正されました: Steve Deering (Stanford), Mark J. Steiglitz (Stanford), Van Jacobson (LBL), Ajit Thyagarajan (PARC), Bill Fenner (PARC)。IPv6 マルチキャストサポートは、KAME プロジェクト (http://www.kame.net) によって実装され、IPv4 マルチキャストコードに基づい ています。高度なマルチキャスト API とマルチキャスト帯域幅モニタリングは、 Chris Brown (NextHop) と共同して Pavlin Radoslavov (ICSI) によって実装さ れました。 このマニュアルページは、Pavlin Radoslavov (ICSI) によって書かれました。 FreeBSD 12.2 May 27, 2009 FreeBSD 12.2