連載 / 旧 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
連載 / 旧 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
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
連載 / 旧 v6 の実装 560 561 562 563 図 15 565 566 567 568 574 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 図 14 hagent-entry 構〕本の有咬加び忍 if (halist—expire—head. hagent—next-expire & & (halist—expire—head. hagent-next—expire—>hagent—expire く now) ) { hal—expire(halist—expire—head. hagent—next_expire, now) ; ホームエージェントのグローバルアドレスの有交加び )i 砡忍 if (gaddr—expire—head ・ hagent—next—expire & & (gaddr—expire—head. hagent—next—expire—>hagent—expire く now) ) { hal-gaddr—expire (gaddr—expire—head. hagent-next—expire , now) ; 図 16 有交加寺間切れのホームエージェント↑黼 & の肖畭 if if if if (halp—>hagent—prev-pref ) { halp—>hagent—prev—pref—>hagent—next—pref halp—>hagent—next—pref ; (halp—>hagent—next—pref) { halp—>hagent—next-pref—>hagent-prev—pref halp—>hagent-prev—pref ; (halp—>hagent—next—expire) { halp¯>hagent—next—expire—>hagent—prev—expire halp—>hagent—prev—expire ; (halp—>hagent-prev—expire) { halp—>hagent—prev—expire—>hagent—next—expire halp—>hagent—next—expire ; に最新のリストカ叩」用されます。 547 void 548 hal—check—expire ( ) 549 { 555 556 gettimeofday(&tv, NULL) ; now = tV . tv_sec; 555 ~ 556 行目で現在時刻を取得します。ホームエージ ェント情報には、ホームエージェントの有効時間が切れる 時刻カ第己録されているので、現在時刻と比較することで無 効なホームエージェント情報を検出できます。 560 ~ 563 行目 ( 図 14 ) は、 hagent-entry 構造体の有 効時間の確認処理です。前回解説したとおり、ホームエー ジェント情報は 2 種類のリストで管理されています。 1 つ はインターフェイス情報ごとにまとめられたリストで、動 的ホームエージェント探索応答メッセージを作成しやすい ように、ホームエージェント情報が優先度川頁に並べられて います。もう 1 つはノード全体で 1 つだけ管理されてい るリストです。こちらは、ホームエージェント情報が有効 時間順 ( 有効時間が切れる時刻が早い順 ) に並べられてい ます。 hal-check-expire() では後者のリストを用います。 まず、 560 ~ 561 行目で、リストの先頭に配置されている 102 工ントリの有効時間を確認します。このエントリの有効時 間がまだ切れていなければ、それに続く残りのエントリは すべて有効です。先頭のエントリの有効時間が切れていた ら、 hal-expire() 関数で有効時間にもとづいた削除処理を おこないます。 UNIX MAGAZINE 2004.9 ら hal-gaddr-expire() を呼び出し、有効時間にもとづい の処理と同様に、頁のエントリの有効時間が切れていた が早い川頁 ) に並べられたリストです。 halist-expire-head gent-gaddr 構造体が有効時間順 ( 有効時間が切れる時刻 体として管理されています。 gaddr-expire-head は ha- 告されており、 had プログラムでは hagent-gaddr 構造 レスは、ルータ通知のプレフィックス情報の一部として広 無効になります。各ホームエージェントのグローバルアド 生したアドレスは、プレフィックスが無効になると同時に に有効時間の概念があるため、あるプレフィックスから派 アドレスを構成しているネットワーク・プレフィックス は有効時間があります。より正確にいうと、グローバル 工ージェントに割り当てられているグローバルアドレスに ローバルアドレスの有効時間の確認処理です。各ホーム 図 15 の 565 ~ 568 行目は、ホームエージェントのグ
連載 / 旧 v6 の実装ー 0 図 13 hal-swap-preference-order() の重が乍 UNIX MAGAZINE 2004.9 レス情報の有効時間管理 ホームエージェント情報とグローバルアド ます。 各ホームエージェントが構築するホームエージェント・リ ータ通知を使って他のホームエージェントに通知されます。 トとして機能できる時間を管理しています。この時間はル 各ホームエージェントは、自分自身がホー hagent_pref_prev hagent_pref_next hagent_entry{} hagent_pref_prev hagent_pref_next hagent_entry{}: a hagent_pref_prev hagent_pref_next hagent_entry{} ・交換後 hagent_pref_prev hagent_pref_next hagent_entry{} hagent_pref_prev h ag e nt_p ref_n ext hagent_entry{}: a hagent_pref_prev hagent_pref_next hagent_entry{} ・交換前 ムエージェン hagent_entry{} hagent_pref_next hagent_pref_prev hagent_entry{}: b hagent_pref_next hagent_pref_prev hagent_entry{} hagent_pref_next hagent_pref_prev hagent_entry{} hagent_pref_next hagent_pref_prev hagent_entry{}: b hagent_pref_next hagent_pref_prev hagent_entry{} hagent_pref_next hage nt_pref_p rev ストは、かならずこの肩勠時間を参照し、利用できないホー ムエージェントがリストに含まれないように更新しなけれ ばなりません。 hal-check-expire() は、有効時間が切れたホームエー ジェントの情報を、ホームエージェント・リストから削除 する関数です。この関数は、 had プログラムが入力バケッ トを処理する直前に呼び出されます。動的ホームエージェ ント探索応答メッセージを返信する場合、返信処理の前に かならず要求メッセージが入力されるので、返信にはつね 101
連載 / 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 ;
SC 翡 好評発売中 ! Linux ブートプロセス みる 連載 / 旧 v6 の実装ー 0 た削除処理をおこないます。 ホームエージェント情報の有効時間処理 hal-expire() は、有効時間の切れたホームエー ジェント 情報をリストから削除する関数です。 579 static void 580 hal_expire (halp , now) struct hagent—entry *halp ; 581 10 Ⅱ g now ; 582 583 { Linux の プートプロセスをみる hal-expire() は 2 つの引数をもちます。 halp は肩効時 白物博生 間川頁に並べられたホームエージェント情報リストの先頭工 ントリへのポインタ、 now は現在時刻です。 メ、一ドウアあ - リのメモリ響宿 慣 2Cpu の■・蠍みと外 CPu の VO アク物ス、 PC ′ AT アーキテクチャ 589 for ( ; halp & & (halp->hagent-expire く フッビからのプロラムの 0 ー Ⅱ 0 ) ; halp = tmp) { ト叡響 32 ルチン 、ⅲ一銀物を、一物 tmp = halp—>hagent—next—expire ; " 0 から一ネルスレ ・白崎博生著 ュサプ 0 セス′ 1 ′ーー = カ”ネデバッ 589 ~ 590 行目の for ループで、ホームエージェント情 ・ B5 判、 204 ページ 報のリストをたどりながら、有効時間が切れているエント ・旧 BN4-7561-4451-9 リを削除していきます。 ・ 2 , 940 円 ( 税込み ) ホームエージェント情報 (hagent-entry 構造体 ) は双 Linux カーネルがプートする仕組みを、コ 方向リストとして実装されているので、エントリを削除す ードを見ながら詳細に解説する。 CPU の る場合は自分の前のエントリのポインタと、後ろのエント 構造から、 Linux のプートローダとカーネ リのポインタを修正する必要があります。また、ホームエ ルの動作、 init プロセスの起動までの道筋 をみていく。カーネルの「敷居」を低く ージェント情報は有効時間順と優先度順の 2 つのリストで する一冊。 管理されているので、それぞれのリストのポインタを修正 します。図 16 の 594 ~ 601 行目で、優先度順に並べられ 目次から ハードウェアの制御ーー CPU のメモリ管理 たリストから有効時間が切れたホームエージェント情報を IA -32 CPU の保護機能、割込みと例外 取り除き、 602 ~ 609 行目で有効時間順に並べられたリス CPU のレ O アクセス、 PC / AT アーキテクチャ トから同じホームエージェント情報を取り除いています。 フロッピーからのプログラムのロード 612 hal-gaddr—clean(halp) ; セットアップ・ルーチン、圧縮カーネルの展開 sta 「 tup ー 32 丿レーチン 612 行目は削除されるホームエージェントに割り当てら sta 「 t_ke 「 nel() と setup_a 「 ch() れているグローバルアドレス情報の削除です。各ホームエ t 「 ap_init() 、 init_ 旧 Q() 、 time_init() 、 mem init() ージェント情報は、ホームエージェントに割り当てられて 「 est ー init ( ) からカーネ丿レスレッドの生成まで いるグローバルアドレスの情報をもっています。ホームエ init() と do_basic_setup() ージェント情報を削除する際は、同時にグローバルアドレ ユーザープロセス / sbin / init の起動 カーネルデバッガ ス情報も削除しなければなりません。 free (halp) ; 614 615 の を 晴 * 0 0 第。 N 学幸学第電第第 590 株式会社アスキー 618 } 最後に 614 行目でホームエージェント情報をイ尉寺してい たメモリ領域を解放し、リストからの削除を完了します。 〒 1 60 ー 8584 東京都新宿区信濃町 34 J 日信濃町ビル 出版営業局電話 (03) 5362 ー 3300 103 UNIX MAGAZ 工 NE 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
連載 / 旧 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
連載 / Ⅲ 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