struct - みる会図書館


検索対象: UNIX MAGAZINE 2004年9月号
15件見つかりました。

1. UNIX MAGAZINE 2004年9月号

連載 / v6 の実装ー 0 図 3 mip6-dhaad-rep 構〕当本 (icmp6. h) mip6—dhrep—hdr ・ icmp6— mip6—dhrep—hdr ・ icmp6— 430 431 432 433 434 435 436 437 438 439 struct mip6—dhaad—rep { / * could be followed by struct icmp6—hdr #define mip6—dhrep—reserved #define mip6—dhrep—id #define mip6_dhrep—cksum #define mip6_dhrep—code #define mip6-dhrep-type / * HA Address Discovery Rep1y * / mip6—dhrep— mip6—dhrep— agent mip6—dhrep—hdr ; home addresses mip6—dhrep—hdr ・ icmp6—type hdr hdr . icmp6-data16 [ 1 ] . icmp6-data16 [ 0 ] cksum code 図 4 ポインタの言と格納可能なアドレスの個数の計算 970 971 972 937 938 939 940 941 942 943 hagent—addr = (struct in6—addr * ) (hap + 1 ) ; count = (IPV6_MMTU ー sizeof (struct ip6_hdr) sizeof (struct mip6—dhaad—rep) ) / sizeof (struct in6_addr) ; haad—reply—output (msgid, coaddr , reqaddr , haif , type , ifga—index) u—int16—t msgid; struct sockaddr_in6 *coaddr ; struct in6—addr *reqaddr ; struct hagent—ifinfo *haif ; int type , ifga—index; haad-reply-output ( ) は 6 つの引数をもちます。 msg- id は動的ホームエージェント探索要求メッセージに指定さ れていた識別子、 coaddr は要求メッセージを送信してき た移動ノードの気付アドレス、 reqaddr は要求メッセー ジの終点アドレスとして指定されていたホームエージェン トのェニーキャスト・アドレスです。 haif は reqaddr で 指定されたェニーキャスト・アドレスが割り当てられてい るインターフェイス情報 (hagent-ifinfo 構造体 ) へのポ インタです。 type は ICMPv6 メッセージのタイプ番号、 ifga-index は haif で指定されたインターフェイス情報に 含まれる、グローバル・ユニキャスト・アドレスを保持す る配列へのインデックスです。 963 964 965 966 967 968 969 hap = (struct mip6—dhaad—rep *)buf ; bzero(hap, sizeof (struct mip6-dhaad-rep) ) ; hap->mip6-dhrep—type MIP6_HA-DISCOVERY_REPLY ; hap->mip6-dhrep—code hap->mip6-dhrep—cksum = 0 ; hap->mip6-dhrep—id = msgid; len = sizeof (struct mip6—dhaad—rep) ; ージェント探索応答の場合、 145 と 0 が設定されます。 mip6-dhrep-cksum は ICMPv6 のチェックサム値です。 mip6-dhrep-id には、動的ホームエージェント探索要求 メッセージで指定された識別子のコピーが格納されます。 ホームエージェントのアドレスリストは、メッセージへッ ダの後ろに続きます。 図 4 の 970 行目で、 hagent-addr ポインタを、ホーム 工ージェント・リストを格納するメモリ領域の先頭アドレ スに合わせます。 971 ~ 972 行目で計算される count は 応答メッセージに含めることができるアドレスの最大個数 を示します。通常、応答メッセージには現在為効なすべて のホームエージェントのアドレスを含めなければなりませ ん。しかし、 1 つのホーム・ネットワークで多くのホーム 工ージェントが稼動している場合、リストが巨大になる可 能性があります。仕様では、応答メッセージが分割されな い範囲で、可能なかぎり多くのアドレスを返送しなければ ならない、と規定されています。 IPv6 の最小 MTU か ら、 IPv6 ヘッダ (sizeof(struct ip6-hdr) ) と動的ホーム 工ージェント探索 ) 芯答メッセージのヘッダ (sizeof(struct mip6-dhaad-rep) ) を引いた値を、 IPv6 アドレスの大き さ (sizeof(struct in6-addr) ) で割ることで、格納でき るアドレスの個数が分かります。ネットワークによっては MTU が最小 MTU よりも大きいこともあるため、もっと 多くのアドレスを各内できるかもしれませんが、処理の手 間を考慮して最小 MTU の場合の個数に制限しています。 963 ~ 969 行目で動的ホームエージェント探索応答メ ッセージを作成します。メッセージ形式は mip6-dhaad- rep 構造体で定義されます。この構造体の定義を図 3 に示 します。 mip6-dhrep-type と mip6-dhrep-code はそれぞれ、 ICMPv6 のタイプ番号とコード番号です。動的ホームエ UNIX MAGAZ 工 NE 2004.9 974 976 977 if ( (nhaa = hal—pick(reqaddr, hagent-addr, &src , haif , count)) く 0 ) { goto err; 95

2. UNIX MAGAZINE 2004年9月号

連載 / 旧 v6 の実装ー 0 図 8 並べ替えのための一日齡或の作成 760 #define DEFAULT_TABLE_SIZE 10 761 762 763 765 766 767 tablep = (struct hagent—entry (*)malloc (sizeof (struct hagent_entry * ) * DEFAULT_TABLE_SIZE) ; if (tablep = NULL) { return 0 ; table_size = DEFAULT_TABLE_SIZE; 図 9 並べ替えのための一日齡或の拡張 if (index > = table—size) { 776 778 779 780 782 783 784 785 786 787 788 789 } tableptmp = (struct hagent—entry **)malloc(sizeof (struct hagent—entry * ) * table—size * 2 ) ; if (tableptmp = = NULL) { free(tablep) ; return 0 ; bcopy(tablep, tableptmp, free(tablep) ; tablep = tableptmp; table_size * = 2 ; sizeof (struct hagent—entry * ) * table—size) ; hal-shuffle() はインターフェイス情報 (hagent-ifinfo 構造体 ) を引数にとり、あるインターフェイス情報に保持 されているホームエージェントのなかで、優先度が同じ工 ントリの川印をランダムに並べなおします。 760 ~ 767 行目 ( 図 8 ) で、ホームエージェント情報の並 べ替えのための一時領域を作成します。この時点では、同 じ優先度をもつホームエージェントの数が最大 10 個 (DE- FAULT-TABLE-SIZE) と仮定して領域を確保します。 この領域は、あとに続く for ループのなかで必要に応じて 拡張されます。 769 for (hap = haif-> 770 771 772 773 774 halist—pref . hagent-next-pref ; hap ; hap = haptmp) { for (haptmp = hap , index = 0 ; haptmp ; haptmp = haptmp-> hagent—next—pref) { 769 ~ 774 行目で 2 重の for ループを作ります。外側 のループはホームエージェント情報全体を処理し、内側の ループは同じ優先度をもつホームエージェントのグループ を処理します。 if (hap->hagent-pref ! = haptmp¯> 775 hagent-pref ) break ; 775 行目は内側のループの終了条件の確認です。内側の ルーフ。処理中に、優先度の異なるホームエージェントがみ つかったら外側のループに戻ります。 UN 工 X MAGAZINE 2004.9 776 ~ 789 行目 ( 図 9 ) は並べ替えのための一時領域の 拡張処理です。 index は同じ優先度をもつホームエージェ ント情報の個数を示します。一時領域に十内できるホーム 工ージェント情報の数は table-size に記億されており、初 期値は 10 (DEFAULT-TABLE-SIZE) です。もし、同 じ優先度をもつホームエージェント情報の数が table-size の値より大きければ ( 776 行目 ) 、 778 行目で一時領域を 2 倍に拡張します。新たに確保した一時領域に過去の情報 をコピーし ( 785 行目 ) 、旧い一時領域を 786 行目で解放 します。 787 ~ 788 行目で一時領域を示すポインタを更新 し、一時領域のサイズを示す table-size も 2 倍にしてお きます。 tablep [index + + ] = haptmp ; 790 791 } 790 行目で、一時領域にホームエージェント情報へのポ インタを十常内します。 内側のループを抜けると、一時領域には同じ優先度をも つホームエージェント情報へのポインタが配列として内 された状態になります。 図 10 に一時領域とホームエージェント情報の関係を例 示します。 図 11 の hal-swap-preference-order() は、引数として 渡された 2 つのホームエージェント情報を入れ替えます。 794 行目では、入れ替えるホームエージェント情報の片方 99

3. UNIX MAGAZINE 2004年9月号

連載 / 旧 v6 の実装ー 0 図 5 hagent-ifinfo 構造体の検索 909 910 911 913 914 915 916 917 918 919 920 921 922 for (i 0 ; i く ifnum; + + i ) { 0 ; j く haifinfo-tab[i] . gavec-used; + + j ) { f0 て (j ifap = haifinfo-tab [i] . haif-gavec Cj] . anycast ; if (ifap ! = NULL & & IN6_ARE_ADDR—EQUAL()( (struct sockaddr—in6 * ) (ifap—>ifa—addr) )—>sin6—addr, ha— addr ) ) return NULL ; return &haifinfo—tab [i] ; *index = j ; 923 } ーキャスト・アドレスと、そのェニーキャスト・アドレ スと同じプレフィックスをもつグローバル・ユニキャスト・ アドレスの組をイ尉寺しています。 index には、第 1 引数で 指定されたェニーキャスト・アドレスをもつ haif-gavec 配 列へのインデックスが十内されます。 図 5 の 909 ~ 922 行目で、 ha-addr をェニーキャスト・ アドレスとしてもつ hagent-ifinfo 構造体を検索します。 hagent-ifinfo 構造体は、ホームエージェントがもつネット ワーク・インターフェイスの数だけ存在します。 haifinfo- tab は hagent-ifinfo 構造体の配列で、 had プログラムの 起動時に初期化されています。 ェニーキャスト・アドレスは hagent-ifinfo 構造体の haif-gavec 配列に保持されているので、 910 行目のルー プで、 haif-gavec 配列に内されているェニーキャスト・ アドレスと第 1 引数で渡された ha-addr を比較します。 なお、 gavec-used メンバー変数は haif-gavec 配列の大き さです。 引数で渡されたアドレスと同じェニーキャスト・アドレ スをもつ hagent-ifinfo 構造体があれば、 917 行目でその ときの haif-gavec 配列のインデックスを index にコピー し、 hagent-ifinfo 構造体へのポインタを呼出し側の関数 に返します。 同じェニーキャスト・アドレスをもつインターフェイス がなければ、 922 行目で NULL を返します。 ホームエージェント・リストの構築 ホームエージェントは、ホーム・ネットワーク上で稼動し ているホームエージェントのリストを保持しています。前 回解説したとおり、各ホームエージェントは、ホームエー UNIX MAGAZINE 2004.9 ジェントが定期的に送信するルータ通知を受信し、プレフ イックス情報の一部として通知されてくるホームエージェ ントのアドレス、および MobileIPv6 で新たに定義された ホームエージェント情報オプションを処理することで、最 新のリストを維持しています。 動的ホームエージェント探索要求メッセージを受信した ホームエージェントは、構築したリストの情報をもとに 現在有効なホームエージェントのリストを動的ホームエー ジェント探索応答メッセージに含めて返送します。このと き、以下の規則に従ってリストされるホームエージェント の順番を決定します。 優先度の高いホームエージェントをリストの前方に配置 する 同じ優先度のホームエージェントは返信のたびにランダ ムな国にする hal-pick() 関数は、動的ホームエージェント探索応答メ ッセージのホームエージェント・リスト部分を、上記の条 件に従って構築します。 803 int 804 hal—pick (req—addr , hagent—addrs , src—addr , 805 806 807 808 809 haif , count) struct in6-addr *req-addr ; struct in6—addr *hagent—addrs ; struct in6_addr *src_addr; struct hagent—ifinfo *haif ; int count ; 810 { hal-pick() は 5 つの引数をもちます。 req-addr は動的 ホームエージェント探索要求メッセージを受信したェニ キャスト・アドレスへのポインタです。 hagent-addrs は 動的ホームエージェント探索応答メッセージの内部を指す 97

4. UNIX MAGAZINE 2004年9月号

連載 / 旧 v6 の実装ー 0 974 ~ 977 行目の haLpick() 関数でホームエージェン トのアドレスリストを作成します。リストは第 2 引数の hagent-addr で指定されたメモリ領域に格納され、格納 したアドレスの個数が返り値として戻ります。また、第 3 引数で渡した src には、 hal-pick() の処理の過程で決定さ れた始点アドレスが十内されます。これは応答メッセージ の始点アドレスとして使用します。 hal-pick() については あとで解説します。 978 if (IN6—IS_ADDR_UNSPECIFIED(&src) ) goto err ; 979 980 Ien + = nhaa * sizeof (struct in6—addr) ; 始点アドレスが決定できない場合には処理を中断します ( 978 行目 ) 。 nhaa は hal-pick() の返り値で、応答メッ セージにオ内されたホームエージェント・アドレスの個数 を表します。ホームエージェント・アドレスのリストを追 加したため、バケット全体の長さカ涎びています。 nhaa の 個数から拡張された長さを言 1 彜し、バケット長を示す変数 len に加えます ( 980 行目 ) 。 982 sndmhdr. msg—name = (caddr—t) coaddr ; 983 sndmhdr. msg—namelen = coaddr—>sin6—Ien; 984 sndmhdr. msg—iov [ 0 ] . iov—base (caddr—t)buf ; 985 sndmhdr. msg—iov[O] . iov—len = len; sndmhdr は msghdr 構造体の大域変数です。 msghdr 構造体は sendmsg() や recvmsg() でデータを送受信す るときに利用されます。 msg-name にはバケットの終点 アドレスへのポインタ、 msg-namelen には msg-name で指定したアドレスが格納された構造体の長さを指定しま す。動的ホームエージェント探索応答メッセージは、移動 ノードの気付アドレスに返送されます。 haad-reply-out- put() の第 2 引数で移動ノードの気付アドレス (coaddr) が指定されているので、 msg-name にはその値を定しま す。 msg-iov 配列は送信するデータを内したバッフアへ のポインタです。今回の場合、 haad-reply_output() で 作成した動的ホームエージェント探索応答メッセージを送 信する必要があるため、そのデータが十内された buf ポイ ンタと、その長さを指定します。 992 993 994 (struct in6—pktinf0 * ) CMSG—DATA (cm) ; PI pi->ipi6-addr = src; pi¯>ipi6—ifindex = 0 ; / * determined with routing table * / 987 ~ 994 行目は始点アドレスの指定です。仕様では、 始点アドレスは動的ホームエージェント探索要求を受信し たインターフェイスに割り当てられているグローバル・ユ ニキャスト・アドレスであれば、どれでもかまいません。た だ、旧い仕様では始点アドレスがホームエージェント・リ ストの一部として利用されていたことがあったため、明示 的に始点アドレスを指定するコードカっています。 996 998 999 if ((len = sendmsg(sock, &sndmhdr, の ) くの { goto err ; 1000 err: 1001 } 応答メッセージカイ乍成できたら、 sendmsg() を使ってパ ケットを送信します。 インターフェイス情報の検索 動的ホームエージェント探索要求は、ホームエージェン トのェニーキャスト・アドレスに向けて送信されます。ホ ームエージェントはその応答として、要求メッセージを受 信したネットワーク上で、現在利用可能なホームエージェ ントのリストを返さなければなりません。あるネットワー クに属しているホームエージェントの情報は、ネットワー ク・インターフェイスごとに管理されているインターフ ェイス情報 (hagent-ifinfo 構造体 ) に保持されています。 haif-findwithanycast() 関数は、引数で指定されたェニ キャスト・アドレスから、対応するインターフェイス情報を 検索します。以後、参照するコードは halist. c のものです。 901 struct hagent_ifinfo * 902 haif—findwithanycast (ha—addr , index) 903 904 struct in6_addr *ha—addr ; *index; 987 989 990 991 96 cm = CMSG_FIRSTHDR (&sndmhdr) ; IPPROTO_IPV6 ; cm—>cmsg—level IPV6_PKTINFO ; cm—>cmsg—type cm->cmsg—len = CMSG-LEN(sizeof (struct in6-pktinf0) ) ; 905 { haifffmdwithanycast ( ) は 2 つの引数をもちます。 ha -addr は検索に用いるェニーキャスト・アドレスです。ⅲー dex は、 hagent-ifinfo 構造体の haif-gavec 配列への インデックスを呼出し関数に返すための変数です。 haif- gavec 配列は、インターフェイスに割り当てられているェ UNIX MAGAZINE 2004.9

5. UNIX MAGAZINE 2004年9月号

v6 の実装 30 旧 v6 モビ リティ ( 9 ) Mobile IPv6 が RFC になり、 IPv6 における移動通信 動的ホームエーシェント探索メッセージの の基本才をはひとます完成しました。次は、 Mobile IPv6 処理 を基盤として、その上でどのようなサービスを提供するか が大きなテーマになります。 MobiIe IPv6 の仕様 (RFC 3775 ) で定義されているのは、技術的に最低限必要な部分 です。実際にユーザーカ俐用したり、他のサービスに応用 するには、周辺技術を充実させる必要があります。 これは Mobile IPv6 にかぎったことではありません。 IPv6 も同様で、 IPv6 の仕様を定めた RFC2460 を実装 しただけでは不十分です。たとえば、 IPv6 を家庭で利用 できるように、 PPP に IPv6 対応のための情報が追加さ れましたし、プロードバンド・ルータを簡単に設定するた めの手段として prefix DeIegation カ甘是案されたりして います。 902 現在、 IP ネットワークを用いた移動通信はほとんど普 903 及していません。しかしながら、今日の通信環境の発展状 904 905 況から考えて、いすれあらゆる場所で IP ネットワークを 906 907 { 利用できる時代カリ来することは間違いないと思われます。 haad-request-input() は 5 つの引数をもちます。 len IP の世界は実践と改良によって進化してきました。私た は受信した動的ホームエージェント探索要求メッセージの ちはきたるべき移動通信時代を見据えて、標準化カ院了し 長さ、 haad-req はメッセージが十内されたメモリ領域の先 た MobiIe IPv6 を積極的に運用しつつ、将来必要となる 頭アドレスです。 pi は受信したバケットに付属するバケッ 才翅の本寸と開発を続けていかなければなりません。 ト情報へのポインタ、 src は受信したバケットの始点アド 今回参照するファイル レスです。 type は動的ホームエージェント探索要求を示 す ICMPv6 のタイプ番号 ( 144 ) ですが、現在、この変数 は利用されていません。 動的ホームエージェント探索要求メッセージは mip6- dhaad•eq 構造体で定義されます ( 図 1 ) 。 動的ホームエージェント探索要求メッセージは ICMP v6 バケットの一種ですから、バケット形式は ICMPv6 ホームエージェントにおける動的ホームエージェント 探索の処理は、ユーザー空間で動作する had プログラム で実行されます。動的ホームエージェント探索要求メッ セージと動的ホームエージェント探索応答メッセージは ICMPv6 メッセージの一種として定義されており、その 処理は haad-request-input() と haad-reply-output() で実装されています。以下、ファイル名を明記していない コードは haadisc. c からの抜粋です。 900 static void 901 haad—request—input (len, haad—req, pi , src, type) int 1en ; struct mip6-dhaad-req *haad-req; struct in6—pktinf0 *pi ; struct sockaddr_in6 *src; int type ; 今回は、動的ホームエージェント探索に関係する以下の ファイルを参照します。 ・ kame/kame/had/haadisc. c ( 改訂番号 1.17 ) ・ kame/kame/had/halist. c ( 改訂番号 1.9 ) ・ kame/sys/netinet/icmp(). h ( 改訂番号 1.94 ) 93 UN 工 X MAGAZINE 2004.9

6. UNIX MAGAZINE 2004年9月号

連載 / v6 の実装ー 0 図 6 hagent-entry 構 1 制本のオ実索 820 if (haif—>linklocal) selfhalp = hal—find(haif , & ( (struct sockaddr—in6 * ) (haif—>linklocal—>ifa—addr) ) ー > 821 sin6—addr) ; 図 7 若メッセージに含めるリストの作成 824 825 826 827 828 829 830 831 832 833 834 835 836 837 839 for (naddr = 0 , hap = haif—>halist_pref . hagent_next_pref ; hap & & naddr く count ; hap = hap->hagent-next-pref) { fo て (ha—gaddr = hap->hagent-galist . hagent—next-gaddr ; (ha-gaddr ! = NULL) & & (naddr く count) ; ha—gaddr = ha-gaddr—>hagent-next-gaddr) { *hagent—addrs = ha—gaddr—>hagent—gaddr ; if (hap selfhalp & & found-src return naddr ・ naddr + + ; hagent—addrs + + ; found_src 十十 ; *hagent—addrs ; *src_addr ポインタで、このポインタを先頭とするメモリ領域にホー ムエージェント・リストを構築します。 src-addr は応答 メッセージを送信する際の始点アドレスへのポインタです。 hal-pick() 関数で適切な始点アドレスを定して、呼び出 した関数に返します。 haif は要求メッセージを受信したイ ンターフェイス情報へのポインタです。 count は IPv6 の 最小 MTU から計算された、リストに十内できるアドレス の最大個数です。 817 hal—shuffle(haif) ; 817 行目の hal-shuffle() は、同じ優先度をもつホー ムエージェントの川頁番をランダムに並べ替える関数です。 hal-shuffle() については次節で解説します。 各ホームエージェントの情報は、 hagent-entry 構造体 のかたちで保持されています。 820 ~ 821 行目 ( 図 6 ) で は、自分自身の情報カ当尉寺されている hagent-entry 構造 体を検索します。 haif—>linklocal は、ネットワーク・イ ンターフェイスに割り当てられているリンクローカル・ア ドレスを示します。 hal-find() で自分自身のリンクローカ ル・アドレスを検索し、対応する hagent-entry 構造体へ のポインタを取り出します。 図 7 の 824 ~ 837 行目のループで、応答メッセージに 含めるリストを作成します。各ホームエージェントの情報 は、それぞれのインターフェイス情報の halist-pref 変数 を先頭に、優先度の高い順に並べられています。よって、 基本的には halist-pref から始まるリストをたどって追 840 } 98 加していくだけです。 naddr はリストに挿入されたホー ムエージェントのアドレスの数をカウントします。これは hal-pick() の返り値として使われ ( 839 行目 ) 、最終的な応 答メッセージのサイズの計算に利用されます。ホームエー ジェントのリストを作成している過程で自分自身の情報を 発見したら ( 830 行目 ) 、そのホームエージェント・アド レスを応答メッセージの始点アドレスに設定します ( 831 行目 ) 。 ホームエーシェント情報の並べ替え 動的ホームエージェント探索応答メッセージには、現在 有効なホームエージェントのリストが優先度川頁に並べられ ます。 hal-pick() の解説で述べたとおり、そもそもインタ ーフェイス情報 (hagent-ifinfo 構造体 ) に優先度順に並 べられたホームエージェント情報 (hagent-entry 構造体 ) のリストが一尉寺されているので、応答メッセージの作成は、 基本的にはリストをたどりながらホームエージェントのア ドレスを取り出す作業になります。ただし、優先度が同じ ホームエージェントがある場合、応答メッセージを作成す るたびにランダムに並べ替える必要があります。 hal-shuffle() は、優先度が同じホームエージェント情報 をランダムに並べ替える関数です。 753 754 755 756 int hal-shuffle(haif) UNIX MAGAZINE 2004.9 struct hagent—ifinfo *haif ;

7. UNIX MAGAZINE 2004年9月号

連載 / Ⅲ v6 の実装ー 0 図 1 mip6-dhaad-req 構〕当本 (icmp6. h) struct mip6—dhaad—req { 420 struct icmp6—hdr 421 422 423 #define mip6-dhreq—type 424 #define mip6—dhreq—code 425 #define mip6-dhreq-cksum 426 #define mip6-dhreq-id 427 #define mip6—dhreq—reserved 428 図 2 応苔メッセージの選医 haad—reply—output (msgid, src , &(pi->ipi6—addr) , haif , type , ifga—index) ; / * HA Address Discovery Request * / mip6—dhreq-hdr ; mip6—dhreq—hdr . icmp6—type mip6—dhreq—hdr . icmp6- code mip6—dhreq— . icmp6— hdr cksum mip6—dhreq—hdr. icmp6—data16 [ 0 ] hdr. icmp6—data16 [ 1 ] mip6-dhreq- 923 / * anycast addr. 927 9 0 1 2 3 3 9 9 9 と同じ (icmp6-hdr 構造体 ) です。 mip6-dhreq-type と メンバー変数に保持されています。 この変数には、ェニ mip6-dhreq-code は、それぞれ ICMPv6 のタイプ番 キャスト・アドレスに対応する ( ェニーキャスト・アドレス 号とコード番号です。動的ホームエージェント探索要求 と同じプレフィックスをもっ ) グロ ーノヾル・ユニキャスト・ メッセージの場合、 144 と 0 が設定されます。 mip6- アドレスの情報も保持されています。動的ホームエージェ dhreq-cksum は ICMPv6 バケットのチェックサム値で ント探索要求はェニーキャスト・アドレスに向けて送信さ す。 mip6-dhreq-id は移動ノードが設定する任意の識別 れますが、応答メッセージの始点アドレスにェニーキャス 子です。ホームエージェントは、受信した要求メッセージ ト・アドレスを使うことはできません。 IP バケットの始 の識別子を、返送する応答メッセージにコピーします。移 点アドレスはユニキャスト・アドレスでなければならない 動ノードはこの識別子を調べることで、自分が送信した要 からです。そこで、動的ホームエージェント探索応答の始 求メッセージと受信した応答メッセージを対応付けること 点アドレスとして利用できるグローバル・ユニキャスト・ ができます。 アドレス情報を通知するために、 haif-findwithanycast() の第 2 引数に haif-gavec のインデックスを格納するポ 912 msgid = haad-req—>mip6—dhreq-id; インタ (ifga-index) を指定します。 ifga-index には、第 912 行目で識別子 (mip6-dhreq-id) を取り出します。 1 引数で指定されたェニーキャスト・アドレスに対応する 915 haif = haif—findwithanycast(&pi—> haif-gavec のインデックスが返ります。 ipi6—addr, &ifga—index) ; 917 if ( ! haif) { 915 行目で要求メッセージを受信したインターフェイス 情報 (hagent-ifinfo 構造体 ) を検索します。ホームエー goto err ; ジェントはネットワーク・インターフェイスごとに ha- 受信したェニーキャスト・アドレスが割り当てられてい gent ーⅲ nf 。構造体をもち、そのなかに各インターフェイス るインターフェイス情報カ療在しなければ ( 917 ~ 920 行 の情報をイ尉寺しています。 haif-findwithanycast() は、第 目 ) 、処理を中断します。 1 引数で指定されたホームエージェント・ェニーキャスト・ 図 2 の 923 ~ 929 行目の haad-reply-output() で応答 アドレスが割り当てられているインターフェイス情報を検 メッセージを返送します。 haad-reply-output() は、動的 索し、 hagent ーⅲ nf 。構造体のポインタを返します。ネット ホームエージェント探索応答メッセージを作成し、現時点 ワーク・インターフェイスには、複数のェニーキャスト・ア で利用可能なホームエージェントのリストを返します。続 ドレスが割り当てられている可能性があります。ネットワ いて、この haad-reply-output() を解説します。 ーク・インターフェイスに割り当てられているェニーキャ スト・アドレス情報は、 hagent-ifinfo 構造体の haif_gavec 936 static void 919 920 } 94 UN 工 X MAGAZINE 2004.9

8. UNIX MAGAZINE 2004年9月号

連載 / Ⅲ v6 の実装ー 0 グローノヾルアドレス・リストからのエントリの削除 図 17 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 653 654 655 if if if if (galp—>hagent—next—gaddr) { galp—>hagent—next—gaddr->hagent—prev—gaddr galp->hagent-prev-gaddr ; (galp—>hagent-prev—gaddr) { galp—>hagent-prev—gaddr->hagent-next-gaddr galp¯>hagent—next-gaddr ; (galp—>hagent—next-expire) { galp¯>hagent—next—expire—>hagent—prev—expire galp—>hagent—prev—expire ; (galp->hagent—prev—expire) { galp¯>hagent—prev—expire—>hagent—next—expire galp—>hagent—next-expire ; free(galp) ; グローバルアドレス情報の有効時間処理 624 hal-gaddr—expire(galp, now) 623 static void アドレス情報をリストから削除する関数です。 hal-gaddr-expire() は、有効時間の切れたグロ ーノヾ . ル 625 626 627 { struct hagent-gaddr *galp ; 10 Ⅱ g now; hal-gaddr-expire() は 2 つの引数をもちます。 galp は 効時間順に並べられた hagent-gaddr 構造体リストの先 頭工ントリへのポインタ、 now は現在時刻です。 630 fo て ( galp & & (galp->hagent—expire く 631 now) ; galp = tmp) { tmp = galp—>hagent—next—expire ; 630 ~ 631 行目のループでグローノヾルアドレス情報のリ ストをたどりながら、有効時間が切れたエントリを削除し ていきます。 633 if ( ! galp—>hagent—expire) 634 continue ; 633 ~ 634 行目は、肩勠時間に制限のないアドレスの処 理です。有効時間が切れる時刻として 0 が設定されてい る場合、そのアドレスカ陏効時間切れになることはありま せん。 図 17 の 636 ~ 651 行目で、グローノヾルアドレスのリスト からエントリを取り除きます。ホームエージェント情報と 同様に、グローバルアドレスも 2 つの異なるリストで管理 されています。 1 つはホームエージェント情報ごとに管理 されているリストで、あるホームエージェントが保持して 104 いるグローバルアドレスのリストを表します。もう 1 つは 効時間川頁に並べられたリストです。まず 636 ~ 643 行目 で、ホームエージェント情報ごとに管理されているリスト から有効時間が切れたエントリを取り除き、 644 ~ 648 行 目で有効時間順のリストからエントリを取り除きます。 最後に、 653 行目でグローバルアドレス情報をイ尉寺して いるメモリ領域を解放します。 次回はモバイル・プレフィックスの処理と、移動ノード ☆ の処理を解説します。 UNIX MAGAZINE 2004.9 ( しま・けいいち IIJ)

9. UNIX MAGAZINE 2004年9月号

0 プログラミンク・テクニック 多治見寿和 TCP Wrappers ( 3 ) 前回は、 inetd プログラムのソースコードを紹介し、お もに libwrap ライプラリで提供される関数群がどのように 使われているかを解説しました。ライプラリ関数を利用す れば、短いコードでもアクセス制御が実現できることが分 かったのではないでしようか。 今回は、これも inetd のソースコードのなかで使われて いる queue. h ヘッダファイルをとりあげます。 queue オンライン・マニュアル queue. h ヘッダファイルカ甘是供する機能は、 queue ( 3 ) オンライン・マニュアルとしてまとめられています。まず はこれをみておきましよう。 マニュアルを一見すると、そのタイトル ( 説明してい る項目 ) の多さに驚きます。しかしよくみると、 SLIST 、 STAILQ 、 LIST 、 TAILQ の 4 つに分類することができ ます。 SLIST で始まるものは、単方向リスト関連の関数 ( マク ロ ) です。ここで提供されている単方向リストでは、先頭 に要素を追加したり、特定の要素の次に新たに要素を追加 したり、リストの頁から要素を取り出したり、 ( 手間はか かりますが ) リストの任意の要素を取り出したりすること ができます。これらは、ほとんど削除操作をおこなわない データの集合を表したり、スタックを実現するために使わ れます。 STAILQ で始まるものは、単方向末尾キュー関連の関数 ( マクロ ) です。ここで提供されている単方向末尾キューで は、単方向リストでおこなえる操作に加え、末尾に要素を 追加したり、 2 つの単方向末尾キューを連結する操作など 60 が実行できます。これらの機能を実現するために、制限も いくつか増えています。たとえば、コードサイズは 15 % ほ ど大きくなりますし、実行速度も 20 % ほど遅くなってしま います。しかしこのコードを使えば、末尾にデータを追加 しながら先頭からデータを取り出していくことができるの で、キューの実現が可能になります。 単方向だけでなく、双方向のリンクをもっリストとキュ ーも用意されています。それが LIST と TAILQ です。 双方向のデータ構造では、ある要素の後ろに新しい要素を 追加するだけでなく、ある要素の前に要素を追加できるよ うになっており、任意の要素を削除する手間も改善されて います。 S 凵 ST UNIX MAGAZINE 2004.9 最初に定義しているデータ型は、それぞれの要素を表す SLIST_HEAD_INITIALIZER(head) ; SLIST_HEAD(1isthead, datatype) head elemp dl, d2, np, tmp; } listelem, *elemp; int va1 ; SLIST_ENTRY (datatype) next ; typedef struct datatype { うなプログラムとなります。 ENTRY マクロを使って指定します。この部分は、次のよ 連結するためのポインタを格納するメンバーは、 SLIST- のメンバーも追加しておく必要があります。このリストを おかなければなりません。さらに、リストを連結するため の各要素のデータ型は、あらかじめ構造体として宣言して SLIST ー HEAD マクロにより定義します。ただし、リスト 単方向リストを実現するための SLIST のデータ構造は、

10. UNIX MAGAZINE 2004年9月号

連載 / Ⅲ v6 の実装ー 0 図 10 優先度が 1 であるような hagent-entry 構〕本をタ里中の一日齡或の状態 一時配列 : tablep hagent_entry{} hagent_entry{} hagent_entry{} hagent_entry{} hagent_entry{} hagent_entry{} 図 11 793 794 795 796 797 798 図 12 741 742 743 744 745 747 748 2 つのホームエージェント情報の入替え for (i = 0 ; i く index; i + + ) hal—swap-preference—order(tablep[i] , tablep Crandom() % index] ) ; a—>hagent—prev—pref = b—>hagent—prev—pref ; t = a—>hagent—prev—pref ; if ()n ! = NULL) bn—>hagent_prev—pref = a; if ()n ! = NULL) an—>hagent_prev_pref = b ; ポインタの入替え return 1 ; free(tablep) ; b—>hagent-prev—pref を乱数で決定し、同じ優先度をもつホームエージェントを ランダムに並べなおします。 続いて、 hal-swap-preference-order() を解説します。 722 void 723 hal—swap—preference—order (), b) struct hagent—entry *a, *b; 724 725 { hal-swap-preference-order() は、 2 つの hagent-en- try 橢告体へのポインタを引数にとります。 728 if (a = = NULL Ⅱ b NULL) return; 728 行目は引数の正当性の確認です。引数が NULL の 場合は hagent-entry 構造体の入替えができないので、処 733 bn = b—>hagent—next—pref ; 732 bp = b—>hagent—prev—pref ; 731 an = a—>hagent—next—pref ; 730 ap = a->hagent—prev-pref ; 理を中断します。 いるため、自分の前の hagent-entry 構造体と、自分の後ろ hagent-entry 構造体は双方向リストとして実装されて 100 に続く構造体へのポインタをもっています。 ap 、 an 、 bp 、 bn に、引数として渡された 2 つの hagent-entry 構造体 がリストを構成するために保持しているポインタをコピー します。 735 736 737 738 739 ap—>hagent—next—pref = b ; bp->hagent—next—pref = a ; a—>hagent—next—pref ; t a—>hagent—next—pref = b—>hagent—next—pref ; b—>hagent—next—pref 735 ~ 739 行目で、 hagent-entry 構造体 a と b それぞ れの hagent-next-pref ( 後ろに続くエントリを示すポイ ンタ ) を入れ替えます。 同様に、図 12 の 741 ~ 745 行目で、 a と b の ha- gent-pref-pref ( 前のエントリへのポインタ ) を入れ替え ます。ただし、入替え対象のエントリ ( a もしくは b ) がリ ストの末尾だった場合、それぞれのエントリに続く構造体 を示すポインタ ()n もしくは (n) が NULL になるため、 741 行目と 742 行目でその例外条件を処理します。 図 13 に hal-swap-preference-order() の動作を示し UNIX MAGAZINE 2004.9