連載 / 旧 v6 の実装ー 0 図 4 hagent-ifinfo 構 ; 本 151 struct hagent—ifinfo { 152 153 154 155 156 157 158 159 } ; struct hagent—entry int char struct ifaddrs struct hagent—ifa_pair int int 図 5 hagent-entry 構〕当本 138 139 140 141 142 143 144 145 146 740 741 struct hagent—entry { struct hagent—gaddr 1 ong u_int 16 ー t u_int 16 ー t struct in6_addr struct hagent—entry halist-pref ; ifindex ; ifname CIF-NAMESIZE] ; *linklocal; *haif-gavec; gavec_used; gavec_S1ze; *hagent—next—expire , *hagent_prev_expire , *hagent—next—pref , *hagent—prev—pref ; hagent ー addr ; hagent-pref ; hagent—lifetime ; hagent—expire ; hagent—galist ; 737 ~ 741 行目で、プレフィックス情報に含まれている ホームエージェントのグローバルアドレスを newgaddrs (lastp) 変数に追加します。プレフィックス情報にホーム 工ージェントのグローバルアドレスが含まれているかどう かは、 MobiIe IPv6 で拡張された ND-OPT-PI-FLAG- ROUTER フラグによって判断できます。 743 744 750 if (newgaddrs . hagent—next—gaddr NULL) goto done ; hal—gaddr—last (halp , newgaddrs . hagent—next—gaddr) ; 751 done : 752 } すべてのプレフィックス情報の処理が終了したら、ル ープの過程で作成されたホームエージェントのグローバル アドレスのリスト (newgaddrs 、 lastp) を、 hal_gaddr- last() 関数で hagent-entry 構造体に追加します ( 743 ~ 744 行目 ) 。 ホームエーシェント↑侵の管理構造 ホームエージェントの情報は、下記の 4 つの構造体で管 理されます。これらは halist. h で定義されています。 72 ・ hagent-gaddr 構造体 ・ hagent-entry 構造イ本 ・ hagent-ifinfo 構造体 ・ hagent-ifa-pair 構造体 hagent-ifinfo 構造体は、ホームエージェントがもつネ ットワーク・インターフェイスを表す構造体です。ホーム 工ージェントのリストはネットワーク・インターフェイス ごとに管理されるため、ホームエージェントは自分カ甘是供 しているホーム・ネットワークの数だけ hagent-ifinfo 構 造体をイ寺しています。図 4 に hagent-ifinfo 構造体の定 義を示します。 halist-pref は hagent-entry 構造体の変 数で、各ホームエージェントの情報を保持するリストを格 納するために利用されます。 ifindex は、各インターフェ イスのインデックス、 ifname はインターフェイス名です。 linklocal はインターフェイスに割り当てられているリン クローカル・アドレス、 haif_gavec は動的ホームエージェ ント探索に利用されるホームエージェント・ェニーキャス ト・アドレスの配列です。 gavec_used は haif_gavec に登 録されているェニーキャスト・アドレスの数、 gavec-size は haif-gavec 配列の大きさです。 hagent-entry 構造体は、ある 1 つのホームエージェン トに関連する情報を表す構造体です。図 5 に hagent-en- try 構造体の定義を示します。 hagent-next-expire と hagent-prev-expire は hagent-entry 構造イ本一のポイ ンタで、有効時間順に並べたリストを構成するために使 われます。 hagent-next-pref と hagent-prev-pref は 優先度順に並べたリストを構成するために使われます。な お、有効時間順のリストはノード全体で 1 つのリストと して管理されますが、優先度順のリストはインターフェイ UNIX MAGAZINE 2004.8
0 v6 の実装 29 旧 v6 モビリティ ( 8 ) 2004 年 6 月 10 日、 MobiIe IPv6 関係者が百を長く して待ち望んでいたニュースが流れました。 Mobile IPv6 仕様の編集者から IETF の MIP6 分科会に対し、 Mo- bile IPv6 の基本仕様が RFC3775 として、ホームエー ジェントと移動ノード間の制御信号を保護するための仕様 が RFC3776 として発行されたことカ斗及告されたのです。 Mobile IPv6 の最初の仕様カ甘是案されたのが 1996 年で すから、 8 年越しの標準化ということになります。 MobiIe IPv6 にかかわるエンジニアとして、なによりもます標準化 作業に尽力した著者、編集者、分科会のメンバーに感謝し たいと思います。 ある仕様が RFC になるということは、利用者に安こ、を もたらします。すなわち、今後はすくなくとも 6 カ月ごと に仕様カ敏訂されたり 1 、過去の実装との互換性がなくなっ てしまうかもしれないという心配をしなくてもよくなりま す。とくに、商用製品の実装やサービスの運用を考えてい る人にとって、 RFC 化は一種の安定性の保証でもありま す。これらの RFC の発行を機に、 MobiIe IPv6 がさま ざまな移動通信サービスの基本技術として浸透していくこ とを期待します。 今回参照するファイル 今回は、動的ホームエージェント探索 (Dynamic Home Agent Address Discovery) に関する以下のファイルを 参照します。 ・ kame/kame/had/haadisc. c ( 改訂番号 1.17 ) ・ kame/kame/had/halist. h ( 改訂番号 1.7 ) ・ kame/kame/had/halist. c ( 改訂番号 1.9 ) 1 インターネット・ドラフトの有効期間は発行から 6 カ月。 UNIX MAGAZINE 2004.8 動的ホームエージェント探索 動的ホームエージェント探索は MobiIe IPv6 の自動設 定手段の 1 つです。 Mobile IPv6 では、移動ノードはつ ねに自分の位置 ( 気付アドレス ) をホームエージェントに 登録して移動透過性を確保する必要があります。そのため には、あらかじめ移動ノードにホームエージェントのアド レスを設疋しておくか、今回解説する動的ホームエージェ ント探索を用いてホームエージェントのアドレスを取得し なければなりません。 移動ノードは、ホーム・ネットワークのプレフィックス情 報をもとに、特別なアドレス ( ホームエージェント・ェニ キャスト・アドレス ) を言 t 算します。移動ノードカ起動し、 最初のホーム登録を実行する時点でホームエージェントの アドレスが未知の場合、ホームエージェント・ェニーキャ スト・アドレスに向けて探索要求を送信します。これは、 ホーム・ネットワークで稼動しているホームエージェント ( 複数のホームエージェントカ材家動している場合は、ェニ キャストの特性によりいずれか 1 台 ) に届きます。探索要 求を受信したホームエージェントは、現在のホームエージ ェントの一覧を移動ノードに返します。ホームエージェン トは、拡張されたルータ通知メッセージを利用して、同じ ホーム・ネットワークで稼動しているホームエージェント のリストを動的に作成しています。移動ノードは、受信し たリストに含まれるホームエージェントのアドレスをもと ホームエージェント・リストは、ホーム・ネットワークで ICMPv6 メッセージの受信 に、ホーム登録を完了します。 67
連載 / 旧 v6 の実装ー 0 図 2 ホームエージェントの有交加罰と優先度の取得 654 ha—lifetime = ntohs(ra—>nd_ra—router—lifetime) ; if (ndopts . nd_opts—hai) { 655 ha—lifetime = ntohs (ndopts . nd—opts—hai—>nd—opt—hai—lifetime) ; 656 ha—pref = nt0hs (ndopts . nd—opts—hai—>nd—opt—hai—preference) ; 658 659 } 図 3 プレフィックス情報の正当性 Di 忍 690 fo て (pt (struct nd—opt—hdr * ) ndopts . nd—opts—pi ; 691 692 693 pt く = (struct nd—opt—hdr * ) ndopts . nd—opts—pi—end ; (struct nd—opt—hdr * ) ( (caddr—t)pt + pt ()t → nd-opt-len くく 3 ) ) ) { してきたルータがホームエージェントではない場合 ( 642 行目 ) 、ホームエージェント・リストから該当するアドレス を削除します ( 648 行目 ) 。 hal-delete() は、 hagent-ifinfo 構造体に内されてい るホームエージェント・リストから、指定されたアドレス をもつ工ントリを削除します。 654 ~ 659 行目 ( 図 2 ) ではホームエージェントの有効 時間と優先度を取得します。 MobiIe IPv6 では、ホーム 工ージェントの有効時間と優先度をルータ通知の一部とし て送信できるように、近隣探索のオプションにホームエー ジェント情報 (Home Agent lnformation) オプショ ンが追加されています。ルータ通知にホームエージェン ト情報オプションが含まれていると、 nd-options 共用体 の nd-opts-hai にオプションへのポインタが設疋される ので、 656 行目と 658 行目で、オプションに指定された 有効時間と優先度を取り出します。ホームエージェント情 報オプションが指定されていない場合、ホームエージェン トの有効時間は、ルータとしての有効時間を示す nd-ra- router 」 ifetime と同じになり ( 654 行目 ) 、優先度は標準 値の 0 が指定されたとみなされます。 662 664 668 669 halp = ha1—update(pinf0->ipi6-ifindex, &from—>sin6_addr , ha_lifetime , ha—pref ) ; if (!halp) { goto done ; 有効時間、第 4 引数は優先度です。有効時間が 0 の場合 は、該当するエントリがリストから削除されます。リスト の更新に失敗したり、エントリカ哨リ除された場合は NULL カ隧され、処理を中断します ( 664 ~ 669 行目 ) 。 if (ndopts . nd-opts-pi) { 675 675 行目以降では、ホームエージェント・リストに十絲タさ れたグローバルアドレスの情報を更新します。ホームエー ジェントのグローバルアドレスは、近隣探索のプレフィッ クス情報オプションとして配布されています。近隣探索の 仕様 ( RFC2461 ) で定義されたプレフィックス情報オプシ ョンには、リンクのプレフィックスの情報しか含まれてい ません。 MobiIe IPv6 では、プレフィックス情報オプショ ンを拡張し、プレフィックス情報と同時にホームエージェ ントのグローバルアドレスを含められるようにしています。 686 newgaddrs ・ hagent—next—gaddr = NULL ; 687 lastp = &newgaddrs ; newgaddrs は、ホームエージェントのグローバルアド レスを格納する hagent-gaddr 構造体の変数です。 ha- gent-gaddr 構造体はリストを構成できるように定義され ており、以下に続くプレフィックス情報の処理の過程で、受 信したグローバルアドレスが newgaddrs に追加されてい きます。 図 3 の 690 行目の for ループでは、ルータ通知に含まれ ているプレフィックス情報の正当性を確認します。これは カーネル内での正当性の確認と同じ処理なので、解説を省 略します。 662 ~ 669 行目でホームエージェント・リストを更新し ます。 hal-update() は 4 つの引数をもちます。第 1 引 数は更新するホームエージェント・リストに対応するイン ターフェイス、第 2 引数はホームエージェントのリンク ローカル・アドレス、第 3 引数はホームエージェントの UNIX MAGAZINE 2004.8 737 739 if ( (pi—>nd—opt-pi—flags-reserved & ND_OPT_PI_FLAG_ROUTER) ! = 0 ) { lastp = hal—gaddr-add(halp , lastp, (i) ; 71
連載 / 旧 v6 の実装ー 0 図 6 hagent-gaddr 構〕本 121 135 134 133 132 131 130 129 128 127 126 125 124 123 122 struct hagent-gaddr { 1 ong 10 Ⅱ g u_int32_t u_int32_t } hagent—flags ; U_Char u_ Char u_ Char struct hagent—flags u_int8_t struct in6_addr struct hagent—gaddr struct hagent—gaddr *hagent-next-gaddr , *hagent-prev-gaddr ; *hagent—next—expire, *hagent—prev—expire ; hagent—preferred; hagent—expire; hagent—pltime ; hagent—vltime ; router : 1 ; autonomous onlink : 1 ; hagent—prefixlen ; hagent—gaddr ; スごと (hagentäfinfo 構造体ごと ) に管理されます。 ha- UNIX MAGAZINE 2004.8 gentäfa-pair 構造体の定義を示します。 ーキャスト・アドレスの組を保持します。以下に ha- バルアドレスと、それに対応するホームエージェント・エ hagent-ifa-pair 構造体はホームエージェントのグロー 時間が切れる時刻を表します。 と hagent-pltime から計算された、有勠時間と推奨有効 hagent-expire と hagent-preferred は hagent-vltime それぞれ、プレフィックスの有効時間と推奨有効時間です。 情報のコピーです。 hagent-vltime と hagent-pltime は hagent-flags はプレフィックス情報に付随していたフラグ ルアドレス、 hagent-prefixlen はプレフィックス長です。 gaddr はプレフィックス情報から取り出されたグローバ ード全体で 1 つのリストとして管理されます。 hagent- 効時間川頁のリストを構成します。有効時間順のリストはノ pire と hagent-prev-expire はグローバルアドレスの有 entry 構造体ごと ) に管理されます。 hagent-next-ex- します。このリストはホームエージェントごと (hagent- ントに割り当てられたグローバルアドレスのリストを構成 gent-gaddr 構造体へのポインタで、あるホームエージェ す。 hagent-next-gaddr と hagent-prev-gaddr は ha- バルアドレスを保持する構造体です。図 6 に定義を示しま hagent-gaddr 構造体はホームエージェントのグロー るグローバルアドレスのリストがイ尉寺されます。 体の変数で、このホームエージェントに割り当てられてい が切れる時刻です。 hagent-galist は hagent-gaddr 構造 優先度と有効時間を表します。 hagent-expire は肩効時間 レスです。 hagent-pref と hagent 」 ifetime はそれぞれ、 gent ー addr はホームエージェントのリンクローカル・アド 164 165 167 166 struct hagent—ifa—pair { struct ifaddrs struct ifaddrs *global; *anycast ; global はホームエージェントのグローバルアドレスを、 す。この情報を間違いなく操作するため、いくつかの関数 ホームエージェントの情報を表す構造はたいへん複雑で ホームエーシェント・リストのキ乍 りを示す矢印は省略しています。 に実装できます。なお、図では肩効時間順リストのつなが 別にもっことで、有効期限切れ工ントリの削除処理が簡単 トごとに管理されるリストに加え、有効時間順のリストを ます。インターフェイスごと、あるいはホームエージェン gent-entry 構造体と hagent-gaddr 構造体をイ尉寺してい のリストは、ホームエージェント上に存在するすべての ha ー prev-expire 変数を用いてリストが構成されます。これら gent-gaddr 構造体の hagent-next-expire と hagent- gaddr 構造体が有効時間順に並べられたリストです。 ha- リストが構成されます。 gaddr-expire-head は hagent- gent-next-expire と hagent-prev-expire 変数を使って に並べられたリストです。 hagent-entry 構造体の ha- list-expire-head は hagent-entry 構造体が有効時間順 expire-head の 2 つのリストが定義されています。 ha- 効時間を管理するために、 halist-expire-head と gaddr- ホームエージェントの情報や、グローバルアドレスの有 これらの構造体は、図 7 のような関係で管理されます。 工ージェント・ェニーキャスト・アドレスを表します。 anycast は、 global で示されるアドレスに対応するホーム 73
593 連載 / 旧 v6 の実装ー 0 break; MIP6-HA-DISCOVERY-REQUEST は、動的ホー ムエージェント探索要求メッセージです。コード番号は 0 でなければなりません。さらに、受信したデータが動 的ホームエージェント探索要求メッセージを示す mip6- dhaad-req 構造体の大きさに満たない場合は、処理を中 断します。 メッセージに問題がなければ、処理関数である haad-re- quest-input() を呼び出します。 594 case MIP6_PREFIX_SOLICIT: 595 596 mpi—solicit—input ()i , &from, (struct mip6-prefix-s01icit *)icp) ; break; MIP6-PREFIX-SOLICIT はモノヾイル・プレフィック ス要求メッセージです。処理関数である mpi-solicit-in- put() を呼び出しています。本来ならばここでメッセージ サイズの正当性とコード番号 ( 0 でなければならない ) の確 諢をすべきですが、現在のところ暫定的に書かれたコード のままになっています。 モバイル・プレフィックス要求 / 応答の処理については、 別の機会に説明します。 構造体へのポインタで、ルータ通知メッセージの先頭アド レスを示します。 pinfo は in6-pktinfo 構造体のポイン タで、受信したバケットに関する情報を格納しています。 from は sockaddr-in6 構造体のポインタで、ルータ通知 の始点アドレスを示します。 623 haif = haif—find(pinfo—>ipi6—ifindex) ; 624 if (haif = NULL ) { goto done ; 630 631 } ホームエージェントは、ネットワーク・インターフェイス ごとに別個のホーム・ネットワークをもっことができます。 そのため、ホームエージェントのリストもインターフェイ スごとに管理されます。 haif-find() は、インターフェイ スのインデックスに対応するホームエージェント管理情報 (hagent-ifinfo 構造体 ) へのポインタを返します。この構 造体についてはのちほと群しく解説します。 hagent-ifinfo 構造体は、各インターフェイスに 1 つず つ、 had プログラムの起動時に作成されます。対応するイ ンターフェイスの hagent-ifinfo 構造体がない場合は、処 理を中断します ( 630 行目 ) 。 597 599 600 default : break ; 634 635 636 638 639 bzero(&ndopts , sizeof (union nd—opts) ) ; nd6—option—init ()a + 1 , Ien sizeof (struct nd—router—advert) , &ndopts) ; if (nd6-options (&ndopts) く 0 ) { goto done ; 602 } had プログラムで処理しないメッセージを受信した場合 は、何もせすに終了します ( 597 行目 ) 。 ルータロの処理 608 ra—input(len, ra, pinfo, from) 607 static void に従ってホームエージェント・リストを更新します。 ルータ通知を受信したホームエージェントは、その内容 634 ~ 639 行目は近隣探索のオプション解析です。 nd- opts は nd-opts 共用体の変数です。 636 行目の nd6-op- tions() 関数で、受信した ICMPv6 メッセージに含ま れる近隣探索オプションを解析し、共用体の各変数にオ プションへのポインタを設疋します。 nd6-option-init() 、 nd6-options() は、カーネル内で利用されていた同名の関 数と同じ動作なので、解説は省略します。 if ( 0 (ra—>nd—ra—flags—reserved & 642 609 610 611 612 int 1en ; struct nd_router_advert *ra ; struct in6—pktinf0 *pinfo ; struct sockaddr_in6 *from; 648 649 ND_RA_FLAG_HOME_AGENT) ) { hal-delete (haif , &(from->sin6-addr) ) ; goto done ; 613 { ra-input() は 4 つの引数をもちます。 len は受信した メッセージのサイズで、 ICMPv6 ヘッダの先頭からデー タの末尾までの長さを表します。 ra は nd-router-advert 70 650 } nd-ra-flags-reserved に ND-RA-FLAG-HOME- AGENT カ第ス疋されていない、すなわちルータ通知を送信 UN 工 X MAGAZINE 2004.8
連載 / v6 の実装ー 0 図 8 リストからのエントリの肖郎余 if (halp) { 160 176 177 178 179 180 181 182 183 184 165 166 167 168 169 170 171 172 173 if (halp->hagent-next-pref) { halp—>hagent—next—pref—>hagent—prev—pref halp—>hagent—prev—pref ; if (halp->hagent-prev—pref) { halp—>hagent—prev—pref—>hagent—next—pref halp—>hagent—next—pref ; halp—>hagent—next—pref = halp—>hagent—prev—pref if (halp->hagent—next—expire) { halp—>hagent—next—expire—>hagent—prev—expire halp—>hagent—prev—expire ; if (halp->hagent—prev—expire) { halp—>hagent—prev—expire—>hagent—next—expire halp—>hagent—next—expire ; NULL ; halp—>hagent—next—expire = halp—>hagent—prev—expire NULL ; 185 } 図 9 新しいリストエントリの作成 187 if (ha_lifetime > 0 ) { 189 192 193 194 195 197 198 200 201 202 if ( ! halp) { halp = malloc(sizeof (struct hagent-entry) ) ; if (halp) { bzero(halp, sizeof (struct hagent—entry) ) ; bcopy(ha—addr, &halp—>hagent—addr, sizeof (struct in6—addr) ) ; goto err; else { hagent-entry 構造体が追加されるインターフェイスのイ ンデックスです。 ha-addr 、 ha 」 ifetime 、 ha-pref はそれ ぞれ、追加されるホームエージェントのリンクローカル・ア ドレス、効時間、優先度を示します。 149 153 154 151 haif = haif—find(ifindex) ; if (!haif) { goto err; 149 行目でインターフェイスのインデックスに対応する hagentäfinfo 構造体を検索します。 hagentäfinfo 構造 体はインターフェイスごとにかならす存在しなければなり ません。検索に失敗したら処理を中断します。 157 halp = hal-find(haif , ha-addr) ; 157 行目で、 hal-update() の引数に指定されたリンク ローカル・アドレスをもつ工ントリが、すでにリストにあ UNIX MAGAZINE 2004.8 るかどうかを調べます。 hal-find() 関数は第 1 引数で指定 された hagent-ifinfo 構造体のホームエージェント・リス トから、第 2 引数で指定されたアドレスをもつ工ントリを 検索する関数です。 該当するエントリがすでにリストにあれば、図 8 の 165 ~ 185 行目でリストからエントリを削除します。前述した とおり、 hagent-entry 構造体は 2 種類のリストで管理さ れています。 1 つは優先度順に並べられたインターフェイ スごとのホームエージェント・リスト、もう 1 つは有効時 間順に並べられた全体のホームエージェントを保持するリ ストです。この 2 つのリストからエントリを削除します。 187 ~ 202 行目 ( 図 9 ) で新しいリストエントリを作成 します。ホームエージェントの有効時間 ()a 」 ifetime) が 0 より大きい値に設定されており、該当するエントリがま だリストにない (halp が NULL の ) 場合、新しいエント リを作成します。 75
連載 / Ⅲ v6 の実装ー 0 ホームエージェント情報のリストへの挿入 図 10 fO て (prevp = curp = haif—>halist—pref . hagent_next_pref ; 211 curp ; curp = curp¯>hagent—next—pref ) { 212 if (halp—>hagent-pref > curp->hagent_pref) { 213 halp—>hagent—prev—pref = curp—>hagent_prev_pref ; 214 halp—>hagent—next—pref = curp ; 215 if (curp->hagent—prev-pref) { 216 curp—>hagent—prev—pref->hagent—next—pref = halp ; 217 218 curp—>hagent—prev—pref halp ; 219 220 break; 221 222 223 prevp = curp ; 224 if ( ! curp) { 225 if (prevp) { 226 / * append tail * / 227 prevp—>hagent—next—pref halp ; 228 halp—>hagent-prev—pref 229 prevp ; 230 else { 231 / * insert head * / 232 haif—>halist-pref . hagent—next-pref = halp ; 233 halp—>hagent-prev-pref &haif—>halist—pref ; 234 235 236 べられます。リストの操作は 211 ~ 236 行目と同じです 有効時間川頁のリストは、優先度順のリストと異なり、すミ てのインターフェイスのホームエージェントの情報が 1 つ のリストに保持されています。リストの先頭は halist-ex- pire-head なので、 halist-expire-head に保持されてい る hagent-entry 構造体のポインタをたどってエントリを 挿入します。 266 } 267 else if (halp) { halp—>hagent—pref = ha—pref ; 206 halp—>hagent—lifetime = ha—lifetime ; 207 halp—>hagent—expire = no + ha—lifetime ; 208 206 ~ 208 行目で、エントリの情報を hal-update() に 渡された引数で更新します。 now には現在時刻が格納さ れています。 now にホームエージェントの有効時間 (ha- lifetime) を加えたものが、有効時間が切れる時刻になり ます。 211 ~ 236 行目 ( 図 10 ) で、新しく作成された、あるいは 更新されたホームエージェントの情報を、優先度に従って リストに挿入します。ホームエージェントの優先度は ha ー gent-pref に設疋されており、値が小さいほど優先度カ皜 くなります。新しく作成されたエントリがリストの途中に 275 } 挿入される場合、 211 ~ 224 行目で処理が完了しますが、リ 267 ~ 275 行目は有効時間として 0 ( あるいは負の値 ) が ストの頁 ( もっとも優先度カ皜い ) に挿入される場合と、 指定された場合の処理です。これは対応するエントリの削 空のリストに挿入される場合 ( 最初の挿入時 ) は 225 ~ 236 除を未します。すでに 165 ~ 185 行目でエントリはリス 行目で処理されます。 トから取り除かれているので、グローバルアドレスを保持 優先度川頁のリストは、インターフェイスごとに個別に管 しているメモリを hal-gaddr-clean() 関数で解放し、続い 理されます。リストの先頭は hagent-ifinfo 構造体の ha- て hagent-entry 構造体自体をイ尉寺しているメモリを解放 list-pref 変数になるので、 halist-pref に保持されている します ( 271 行目 ) 。 hagent-entry 構造体のポインタをたどって適切な位置に done : 277 工ントリを挿入します。 239 ~ 264 行目 ( 図 11 ) は有効時間順に並んだリストへ の挿入です。リストは為効時間が切れる時刻の早い順に並 hal-gaddr-clean(halp) ; free(halp) ; halp = NULL ; 270 271 2 72 return halp ; 284 285 76 UNIX MAGAZINE 2004.8
図 18 473 474 475 476 477 478 479 480 図 19 526 527 528 531 532 533 534 535 536 537 538 連載 / v6 の実装ー 0 グローバルアドレスのオ for (galp = halp—>hagent—galist . hagent—next—gaddr ; galp ; galp = galp->hagent-next-gaddr) { if ( (galp—>hagent—prefixlen ha—prefixlen) & & IN6_ARE_ADDR_EQUAL ( & (galp->hagent_gaddr) , ha_addr) ) break ; return galp ; グローバルアドレス・リストの角攵 while (halp—>hagent—galist . hagent—next—gaddr) { tmp = halp—>hagent—galist . hagent—next—gaddr ; halp—>hagent—galist . hagent—next—gaddr = tmp—>hagent—next—gaddr ; if (tmp—>hagent—next—expire) { tmp¯>hagent—next—expire—>hagent—prev—expire tmp—>hagent—prev—expire ; if (tmp—>hagent—prev—expire) { tmp—>hagent—prev—expire—>hagent—next—expire tmp¯>hagent—next—expire ; ルアドレスの重複登録カ吮生することはありません。 グローバルアドレスの検索 あるホームエージェントのグローバルアドレス情報を検 索するには hal-gaddr-find() 関数を使います。 465 static struct hagent_gaddr * 466 hal—gaddr—f ind(halp , ha—addr , 467 468 469 ha—prefixlen) struct hagent—entry *halp ; struct in6_addr *ha_addr ; u—int8—t ha—prefixlen ; gaddr-clean() 関数で実装されます。 519 void 520 hal—gaddr—clean (halp) struct hagent—entry *halp ; 521 522 { hal-gaddr-clean() 関数は解放したいグローバルアドレ ス・リストをイ尉寺している hagent-entry 構造体へのポイ ンタを引数にとります。 グローバルアドレスのリストは hagent-entry 構造体の hagent-galist メンバー変数に保持されています。グロー バルアドレスは、インターフェイスごとのリストとノード 全体で管理されている有効時間川頁のリストの 2 つのリスト で管理されています。図 19 の 526 行目のループで、リス トのエントリを 1 つずったどりながら、効時間順のリス トからエントリを削除します。 470 { hal-gaddr-find() 関数は 3 つの引数をもちます。 halp は検索対象となるホームエージェントの情報を保持した hagent-entry 構造体へのポインタ、 ha-addr は検索した いホームエージェントのグローバルアドレス、 ha-prefix- len はグローバルアドレスのプレフィックス長です。 グローバルアドレスは hagent-gaddr 構造体リストのか たちで hagent-entry 構造体の hagent-galist 変数に保持 されています。リストを順番にたどりながら、指定された プレフィックス長をもち、 hal-gaddr-find() の引数で指定 されたグローバルアドレスと同じ値をもつ hagent-gaddr 構造体のポインタを返します ( 図 18 ) 。 グローバルアドレス・リストの解放 グローバルアドレスを保持するリストは、 hagent-en- try 構造体が解放されるときに同時に解放されなければな りません。グローバルアドレス・リストの解放処理は hal- UNIX MAGAZINE 2004.8 540 541 free(tmp) ; 542 } ノード全体のリストからエントリを取り除いたあと、 540 行目で情報をイ尉寺しているメモリを解放します。 ☆ 次回も引き続き、動的ホームエージェント探索処理を解 説します。 81 ( しま・けいいち IIJ)
図 11 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 256 257 258 259 261 262 263 264 288 289 290 連載 / 旧 v6 の実装 for (prevp = curp = halist—expire—head. hagent—next—expire; 有咬加頁に並べられたリストへの挿入 curp—>hagent—prev—expire—>hagent—next—expire = halp ; if (curp->hagent-prev-expire) { curp ; halp—>hagent—next—expire halp—>hagent—prev-expire curp—>hagent—prev—expire ; if (curp—>hagent-expire > halp—>hagent—expire) { curp ; curp = curp¯>hagent—next—expire) { if curp—>hagent—prev—expire break; prevp = curp ; ( ! curp) { if (prevp) { prevp¯>hagent—next—expire halp->hagent-prev—expire else { halp ; halp ; prevp ; halist—expire—head. hagent—next—expire = halp ; halp—>hagent—prev—expire = &halist—expire—head ; halp = NULL ; goto done ; 索します。指定されたアドレスをもつ工ントリがリストに ない場合は処理を中断します ( 686 ~ 689 行目 ) 。 図 12 の 692 ~ 699 行目で優先度順のリストから、 700 ~ 707 行目で有効時間順のリストからエントリを取り除き リストの更新が正常に終了したら、 284 行目で対応する ホームエージェント情報へのポインタを返します。処理が 中断される場合は、 288 ~ 289 行目で NULL を返します。 ホームエーシェント情報の削除 ホームエージェント情報の削除には hal-delete() 関数 を使います。 674 int 675 hal_delete(haif , ha—addr) ます。 710 712 714 716 717 hal-gaddr-clean (halp) ; free(halp) ; done : return ret ; 676 677 struct hagent—ifinfo *haif ; struct in6_addr *ha—addr ; 678 { hal-delete() は 2 つの引数をとります。 haif は削除対 象のリストを保持している hagent-ifinfo 構造体へのポイ ンタ、 ha-addr は削除するホームエージェントのアドレス へのポインタです。 684 686 687 688 689 halp = hal-find(haif , ha—addr) ; if ( !halp) { ret goto done ; 最後に 710 行目でエントリに対応するグローバルアドレ スを保持するメモリを解放し、 712 行目でエントリ自身の メモリを解放します。 ホームエーシェント情報の検索 あるリンクローカル・アドレスをもつホームエージェン トをリストから検索するには hal-find() 関数を使います。 295 struct hagent_entry * 296 hal-find (haif , ha-addr) 297 298 struct hagent—ifinfo *haif ; struct in6_addr *ha—addr ; 684 ~ 689 行目で削除対象の hagent-entry 構造体を検 UNIX MAGAZINE 2004.8 299 { halffmd() は 2 つの引数をもちます。 haif は検索対象 77
連載 / v6 の実装ー 0 図 12 優先偵 / 有交加蔀頁のリストからのエントリの肖畭 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 図 13 321 322 図 14 324 326 327 329 330 galp->hagent—flags . router 332 333 334 335 336 337 338 339 340 341 342 343 351 352 353 sizeof (struct in6—addr) ) ; bcopy(&(pi->nd-opt-pi-prefix) , &(galp->hagent—gaddr) , bzero(galp, sizeof (struct hagent-gaddr)) ; goto err; = NULL) { if (galp galp = malloc(sizeof (struct hagent—gaddr) ) ; if ( ! galp) { メモリび )i 寉保とメンバー変数のネ騏用ヒ pi—>nd—opt—pi—prefix—len) ; galp = hal-gaddr—find (halp , &pi—>nd-opt-pi—prefix , 〕ロするアドレスがリストにあるか C)E 忍 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—prev-expire) { halp¯>hagent—prev—expire—>hagent—next—expire halp—>hagent—next—expire ; (halp¯>hagent—next—expire) { halp¯>hagent—next—expire—>hagent—prev—expire halp—>hagent—prev—expire ; galp¯>hagent—pref ixlen = pi¯>nd—opt—pi—prefix—len; galp—>hagent—flags . onlink = (pi->nd-opt—pi-flags-reserved & ND_OPT_PI_FLAG_ONLINK) ? 1 (pi—>nd—opt—pi—flags—reserved & galp¯>hagent—flags . autonomous ND_OPT_PI_FLAG_AUTO) ? 1 (pi—>nd—opt—pi—flags—reserved & ND_OPT_PI_FLAG_ROUTER) ? 1 galp¯>hagent—vltime = ntOh1 (pi¯>nd—opt—pi—valid—time) ; galp¯>hagent—pltime = ntOhl (pi¯>nd—opt—pi—preferred—time) ; if (hal-gaddr—init—prefix—ltimes(galp) ) goto err ; のリストを保持している hagent-ifinfo 構造体へのポイン 夕、 ha-addr は検索したいホームエージェントのアドレス へのポインタです。 305 306 307 302 303 304 for (halp = haif—>halist—pref . hagent-next-pref ; halp ; halp = halp->hagent-next-pref ) if (IN6_ARE_ADDR_EQUAL ( & (halp—> hagent—addr) , ha—addr) ) return halp ; break; レスをもつ工ントリを探します。みつかればそのエントリ が、みつからなければ NULL が返されます。 グローバルアドレスの追加 ホームエージェント情報を保持する hagent-entry 構 造体には、ホームエージェントのグローバルアドレスを 示すリストへのポインタが含まれます。あるホームエージ ェント情報にグローノヾルアドレスを追加する場合は hal- gaddr-add() 関数を使います。 313 struct hagent—gaddr * 314 hal-gaddr-add(halp, lastp, pi) 308 } インターフェイスごとに管理されているホー ント・リストをたどりながら、同じリンクローカル・アド ンエ 78 315 316 struct hagent—entry *halp ; struct hagent—gaddr *lastp ; UNIX MAGAZINE 2004.8