連載 / 旧 v6 の実装ー① データリンク層バケットの出力 カルーチンに至るまでの処理の流れは、以下のようになり IP バケットの出力ルーチンから各データリンク層の出 じて個別に実装しています。 タリンク層アドレスの解決処理もデータリンクの不頁に応 を共通化することが可能になりました。 IPv4 では、デー リンク層アドレスの解決方法か統一されたため、この部分 層の出力ルーチンを呼び出すのですが、 IPv6 ではデータ 最糸勺には、近謝架索の出力ルーチンも各データリンク れた出力ルーチンを個別に呼び出す実装となっています。 れに対し、 IPv4 では、データリンクの不頁ごとに用意さ ーチンである nd6-output() を経由して送信されます。 ではすべての IP'S ケットが、近架索スタックの出力ル ク層アドレスの発見です。前回解説したとおり、 KAME 近ド架索の目的は、 IP アドレスに対応するデータリン 1. 次ノードの石忍 ます。 近隣探索スタックの出力ルーチンは nd6-output() で 次ノードの確認 3. データリンク層出力ルーチンの呼出し 2. 近隣キャッシュの伏軋寉認・更新 す。この関数は 5 つの引数をもちます。 m() は出力される IP バケットです。 dst には、次の中点となるノードのアドレスが入りま す。経路制徊ヘッダカ甘旨定されてい川ま、 dst は経路缶衂 ヘッダで指定された次ノードのアドレスに、指定されてい ない場合は単純に IP バケットの終点アドレスになります。 rt0 は dst , 、、の経路報です。 近謝架索プロトコルは ICMP を利用して実現されてい ます。近ド架索は、 IP で涌信するためには必頭です。し かし、 ICMP は IP の上位プロトコルとして : 見されてい ます。どちらが先かという鶏と卵の問題のようですが、 の連鎖を断ち切るのが 2 , 082 行目の処理てす。 2 , 082 行目 では、宛先アドレスがマルチキャストの場合に、近ド蝌架索 の手順を飛ひ越えてバケットを出力します。 2082 if (IN6-IS-ADDR MULTICAST(&dst—> 2083 sin6—addr) ) goto sendpkt ; 2062 2063 2064 2065 2066 2067 2068 2069 int nd6—output (ifp , struct struct struct struct st ruct origifp, mO, dst, て tO ) ifnet *ifp; ifnet *origifp; mbuf *mO ; sockaddr_in6 *dst ; rtentry *rtO; 2001 年 11 月号で解説したとおり、通イ目手のデータ リンク層アドレスを得るには、まず近隣要請を送信しなけ れはなりません。近隣要請は、通信したい相手ノードのア ドレスに対応する要請マルチキャスト・アドレスに対して 送信されます。 IP スタックからみれは、要請マルチキャ スト・アドレスはたんなるマルチキャスト・アドレスで すから、 2 , 082 行目の条件に従って即座にデータリンクに 出力されます。近隣要請を受信したノードは、近隣要請を 送ってきたノードに近隣通知を返信して、自分のデータリ ンク層アドレスを通知します。 近隣要請の送信と近隣通知の受信処理についてはあとで 角見することにして、こではバケットの出力処理の続き をみていきましよう。 2085 if (nd6—need—cache(ifp) = 0 ) 2086 goto sendpkt ; ifp と origifp は、出力先のアドレスに対応するインタ ーフェイスへのポインタです。この 2 つの違いは、自分自 身にループバックするときに意味をもちます。たとえは、 自分自身の Ethernet インターフェイスに出力する場合、 論理的な出力インターフェイスは Ethernet インターフェ イスですが、実際にはルーフ。バック・インターフェイスに 出力することになります。その際に、 ifp がループバック・ インターフェイスを指し、 origifp が Ethernet インター フェイスを指します。 64 nd6-need-cache() は、引数で指定されたネットワー ク・インターフェイスで近架索が必要かどうかを判断し ます。たとえは、ループバック・インターフェイスなど はそもそもデータリンク層アドレスをもたないため、近隣 探索をする必要がありません。そのような場合は、即座に バケットの出力を開始します。 if (rt) { 2091 2092 if ( (rt->rt—flags & RTF UP) UNIX MAGAZINE 2002.6
連載 / IPv6 の実装ー① 図 5 nd6-ns-output() の定義 385 void 386 nd6—ns—output (ifp , daddrO , taddr0, 1 Ⅱ , dad) 387 388 389 390 391 { struct ifnet *ifp; const struct sockaddr_in6 *daddr0 , *taddrO ; struct 11info—nd6 *1n; / * for source address determination * / int dad; / * duplicated address detection * / 図 6 ゾーンリ砌言聢 419 420 421 422 423 424 426 427 428 429 430 431 433 434 daddr6 = &daddr6_storage ; taddr6 = &taddr6-storage ; if (daddr の { * daddr6 = * daddrO ; if (in6—addr2zoneid(ifp , &daddr6—>sin6—addr , &daddr6—>sin6—scope—id) ) { return ・ } else daddr6 = NULL ; *taddr6 = *taddrO ; if (in6—addr2zoneid(ifp , &taddr6—>sin6_addr, 近隣要請バケットの構築 UNIX MAGAZINE 2002.6 指定します。 Detection) を実行するための近隣要請を送信する場合に 最後の dad は、重複アドレス検出 (Duplicate Address ln は、 taddrO に対応する近隣キャッシュを指します。 ます。 カま走わしい場合は近隣要請バケットを送信することがあり ため、データリンク層アドレスカ喇明していても、到達性 層アドレスの解決以外にノードの到達不能十鎹ロもおこなう のかと思うかもしれません。近ド蝌架索では、データリンク レスカ明しているのに、近隣要請を送信する必要がある をマルチキャストする場合などです。データリンク層アド リンク層アドレスがキャッシュされていたり、近隣要請 できません。たとえば、すでに近隣キャッシュにデータ するデータリンク層アドレスか判明しているときしカ甘旨定 daddrO は、この引数て指定される IP アドレスに対応 レス、 taddrO は角夬したい IP アドレスです。 イスを指します。 daddr0 は近隣要請バケットの終点アド ifp は近隣要請を出力するネットワーク・インターフェ nd6-ns-output() は 5 つの引数をもちます ( 図 5 ) 。 &taddr6—>sin6—scope—id) ) { ます、 sockaddr-in6 構造体で指定された daddr0 と taddr0 のゾーン識別子を設定します。もとのアドレス 情報を破壊しないように、それぞれ daddr6-storage と taddr6-storage という auto 変数を用意し、そこに孑日疋 されたデータをコピーしています ( 図 6 ) 。 if (IN6_IS_ADDR_MULTICAST (&taddr6-> 440 441 sin6-addr) ) return; マルチキャスト・アドレスに対応するデータリンク層ア ドレスを調べるために近隣要請する必要はありません。 IP アドレスを変換するだけで、簡単にデータリンク層アドレ スを引算することができます。 444 ~ 465 行目では、近ド蝌架索バケットのための mbuf を用意します。 444 maxlen = sizeof ( * 土 p6 ) + sizeof(*nd—ns) ; maxlen には近隣要請バケットの全体長を設定します。 近隣探索バケットは、基本的に IP ヘッダと近隣探索パ ケットのヘッダ (ICMP ヘッダと近隣要請のヘッ夘か ら構成されます。近隣探索 , 、、ツダは、 icmp6. h で以下の ように定義されています。 69
連載 / IPv6 の実装ー① 図 4 ループパック・インターフェイスへの出力ー里 2245 sendpkt : 2254 2264 2265 2266 if ((ifp—>if—flags & IFF—LOOPBACK) ! = 0 ) { return( (*ifp->if—output) (origifp, m, (struct sockaddr *)dst , ln-hold を解放していることから分かるとおり、 KAME の近隣キャッシュがデータリンク層アドレスの鮹夬処理の あいだに溜めておける IP バケットは 1 つだけです。 ln—>ln—expire く time—second) { nd6_mmaxtries & & if (ln—>ln—asked く (ln—>ln—expire) { 2 , 234 ~ 2 , 242 行目は、近隣要請バケットの送信処理で 2236 2235 2234 if す。 time_second 十 2238 ln—>ln_expire 2237 ln—>ln_asked 十十 ; トを送信します。 一定時間経過していたら ( 2 , 236 行目 ) 、近隣要請バケッ を超えておらす ( 2 , 235 行目 ) 、かつ以前の近隣要請から 近隣要請バケットの最大再送回数 (nd6-mmaxtries) 2239 nd—ifinfo [ifp—>if—index] . retrans / 1000 ; 近隣要請バケットの氾濫を防ぐために、最大再送回数と 再送間隔で蒲剏しています。 KAME では、再送間隔はイ ンターフェイスごとに設定可能で、初期値は 1 秒になっ ています。 2240 2241 2242 2243 nd6—ns-output (ifp , dst , NULL , 1 Ⅱ , 0 ) ; return(0) ; データリンク層アドレスがまだ判明していないので、 イスへの出力について特別な処理をおこなっています。出 図 4 の 2 , 254 行目では、ルーフ。バック・インターフェ る場合は、そのままバケットを送信することができます。 探索か不要なネットワーク・インターフェイスを使ってい データリンク層アドレスかすでに分かっていたり、近隣 データリンク層出力ルーチンの呼出し ケットを送信します。 2 , 240 行目で nd6-ns-output() を呼び出し、近隣要請パ 68 カ先のインターフェイスがルーフ。バック・インターフェイ スになるのは、以下の 2 つの場合です。 ルーフ。バック・インターフェイスのアドレスにバケット を出力する ( たとえは、終点アドレスが、、 : : 1 " のバケッ トを出力する場合 ) 。 ・自分自身のネットワーク・インターフェイスに設定され ているアドレスに出力する。 KAME では、自分自身のネットワーク・インターフェ イスがもつアドレスに対する経路が、ループバック・イン ターフェイスを向きます。経路情報での出力インターフェ イスはルーフ。バック・インターフェイスですが、実際に は別のネットワーク・インターフェイスです。この場合 は、茁妾ルーフ。バック・インターフェイスに出力するので はなく、実際のネットワーク・インターフェイスである origifp に出力しなければなりません ( 2 , 264 行目 ) 。 2276 return((*ifp—>if—output) (ifp, m, (struct sockaddr *)dst, (t)) ; そうでない場合は、出力インターフェイスとして指定さ れた i ゆに IP バケットを出力します。 の出力処理の手順は以下のようになります。 て送信先のデータリンク層アドレスを調べます。近隣要請 ク層アドレスか判明していない場合は、近隣要請を出力し なければ出力できません。バケットの出力時にデータリン IP バケットは、データリンク層アドレスが分かってい 近隣要請の出力処理 ものです。 以下、とくに明記しないかぎりコードは nd6-nbr. c の 3. 近隣要請バケットの送信 2. オプション処理 1. 近隣要請バケットの構築 UNIX MAGAZINE 2002.6
2194 if 2195 2196 2197 2198 } 連載 / IPv6 の実装ー① 図 3 バケットを送信できない場合はする #define ND6_LLINFO_STALE #define ND6_LLINFO_DELAY #define ND6_LLINFO_PROBE 2180 2181 2182 2187 2188 2190 2191 ります。 if ( ! ln Ⅱ ! (t) { ! (nd-ifinfo [ifp->if—index] . flags & ND6_IFF—PERFORMNUD) ) { if ((ifp—>if—flags & IFF_POINTOPOINT) senderr(EIO) ; goto sendpkt ; ( (ifp—>if—flags & IFF-POINTOPOINT) ln->ln—state く ND6—LLINFO-REACHABLE) ln—>ln_state = ND6_LLINFO_STALE ; ln—>ln—expire time_second 十 nd6—gctimer; る ND6-LLINFO-NOSTATE および ND6-LLINFO- INCOMPLETE になることはありえません。この場合 は即座に ND6-LLINFO-STALE 状態に遷移し、バケッ トの送受信ができるようにします。 2207 if (ln—>ln—state = = ND6—LLINFO—STALE) { 2208 2209 2210 2211 } ln->ln_asked ln—>ln_state ln—>ln—expire 2001 年 11 月号で解説したとおり、キャッシュは 次の 5 つの状態をもちます。 ・ INCOMPLETE ( データリンク層アドレスは角夬され ていない ) ・ REACHABLE ( 到達可能である ) ・ STALE ( データリンク層アドレスは判明しているが、 到達可能かどうか石忍できていない ) ・ DELAY 倒達可能性を石忍するための通信をおこなう までの待機伏態 ) ・ PROBE ( 到達可能であるかどうかを石忍中 ) これらの状態に対応して、 nd6. h で次のようなマクロが 定義されています。 nd6. h 0 ; ND6_LLINFO_DELAY ; time_second 十 nd6—deIay ; STALE は、相手のデータリンク層アドレスは判明して いるが、実際に相手と通信可能かどうかは確認できていな い状態です。この状態では、バケットの送信はできますが、 同時に通信相手の到達不能検知を開始する必要がありま す。そこで、 2 , 209 行目で近隣キャッシュの状態を ND6- LLINFO-DELAY に j 崟移します。 ND6-LLINFO-DE- LAY 状態が nd6-deIay て指定された時間 ( 初期設定では 5 秒 ) 続くと、近ド爾架索スタックは到達不能十剱日を開始し ます。 2218 if (ln—>ln-state > ND6—LLINFO—INCOMPLETE) 2219 goto sendpkt ; 68 69 70 71 72 #define ND6_LLINFO_INCOMPLETE #define ND6_LLINFO_REACHABLE 0 1 2 3 4 近隣キャッシュが ND6-LLINFO-INCOMPLETE 状態のときは、また相手のデータリンク層アドレスが解決 されていません。それ以タ ) 場合は 2 , 219 行目で送信処理 に進みます。 さらに、 KAME では j キャッシュカイ乍成された麦 の状態を示す値として、 ND6-LLINFO-NOSTATE を nd6. h 定義しています。 59 #define ND6_LLINFO_NOSTATE UNIX MAGAZINE 2002.6 ら、一データリンク層アドレスが半リ明していない状態であ こないます。対向リンクであれは近隣探索は不要ですか ます、 2 , 194 ~ 2 , 198 行目で対向リンクの伊外処理をお 2229 2230 if (ln—>ln—state = = ND6-LLINFO—NOSTATE) ln—>ln_state ND6_LLINFO_INCOMPLETE ; if ( ln ー > 1 Ⅱー hold ) m—freem(ln—>ln—hold) ; 1 Ⅱー > ln ー hold = m; データリンク層アドレスか解決されていない場合は、送 2233 2232 2231 ておき、近隣探索の処理に進みます。 2 , 232 行目で旧い 信しようとしているバケットをいったん ln-hold に溜め 67
図 10 734 735 736 737 649 650 651 652 658 連載 / IPv6 の実装ー① フラグ情報の抽出 1S_override ( (flags & ND—NA—FLAG_OVERRIDE) ! = 0 ) ; is—solicited = ( (flags & ND—NA—FLAG—SOLICITED) ! = 0 ) ; 1S_router ( (flags & ND—NA-FLAG_ROUTER) ! = 0 ) ; flags = nd—na—>nd—na—flags—reserved; ip6—>ip6—p1en = htons ( (u—short) icmp61en) ; nd—ns—>nd_ns_cksum = 0 ; nd_ns—>nd_ns_cksum in6—cksum(), IPPROTO—ICMPV6 , sizeof(*ip6) , icmp61en) ; ip6—output (m , NULL, &ro , dad ? IPV6_UNSPECSRC &im60 , NULL) ; icmp61en には ICMP バケットの長さかオ褓内されていま ます、ホップリミットをチェックします。 711 if (ip6—>ip6-h1im ! = 255 ) { す。 712 713 714 } goto bad; 近隣要請を送信すると、応答として近隣通知が医され てきます。近隣通知バケットには近隣通知を送信してきた ノードのデータリンク層アドレスが含まれているので、こ の情報を調べれは IP アドレスとデータリンク層アドレス を関連つ、けることができます。近隣通矢ロの受信処理は、以 651 ~ 652 行目で ICMP のチェックサムを計算し、 658 行目で送信します。重複アドレス検出の場合は、第 4 引数 で IPV6-UNSPECSRC を指定しています。このフラグ を指定しないと、 ip6-output() は始点アドレスが未定義 であるバケットをエラーとみなします。 近知の鄧言里 近虧甬知バケットの正当性チェック 4. 送イ寺ち IP?S ケットの送信 3. 近隣キャッシュの状態遷移 2. オプション処理 1. 近隣通知バケットの正当性チェック 下のような流れになります。 687 nd6—na—input (), off , icmp61en) 686 void put() を経由して呼び出されます。 icmp6 -in- おこなう nd6-na-input() は、 ip6-input() 、 近隣通知は ICMP の一種です。近隣通知の受信処理を 255 以外の値をもつバケットを破棄することで、他の リンクから近ド爾臻を装って送信されたバケットを除外し ます。 734 ~ 737 行目 ( 図 10 ) では近隣通知バケットからフラ ク 1 辭にを取り出しています。 is-router は、近隣通知を送っ てきたノードがルータであることを意味します。 is-solic- ited は、この近隣通知が近隣要請への応答として送信さ れたものであることを示します。近隣通知は、近隣要請ハ ケットを受信したとき以外にも、リンク上のすべてのノー ドに自分の存在を知らせる目的てマルチキャストされるこ とがあります。 is-override は、近隣キャッシュの情報を 明カ勺に上書きしたい場合に指定されます。 754 if (is—solicited & & IN6—IS—ADDR—MULTICAST 757 (&ip6->ip6-dst) ) { goto bad; 688 689 struct mbuf *m; int off , icmp61en; m には受信しオ丘隣通知バケットが、。仕には IP ヘッ ダの先頭から一 ICMP ヘッダの知頁までのオフセットが、 UNIX MAGAZINE 2002.6 近隣要請を受けて近隣通知する場合 (is-solicited が設 定されている場は、マルチキャストしてはいけません。 オプション里 近隣通知バケット構造体は icmp6. h で定義されていま す ( 図 11 ) 。 nd-na-target には、近隣要請て指定された IP アドレ スかオ絲勺されます。この構造体の後ろには、データリンク 層アドレスかオ勺されたオプションか読きます。近隣通知 では、近隣要請で要求された IP アドレスに対するデー タリンク層を示すターゲットリンク層アドレス (Target Link-layer Address) オプションと、近隣通知を送信し たノード自身のデータリンク層アドレスを示す送信元リン 758 } 73
図 13 769 770 771 772 図 14 0 0 1 792 793 連載 / IPv6 の実装ー① IIaddrIen = ndopts . nd_opts_tgt_lladdr—>nd—opt—len くく 3 ; lladdr = (char * ) (ndopts. nd_opts_tgt_lladdr + 1 ) ; if (ndopts. nd—opts—tgt—lladdr) { ターゲットリンク層アドレス・オプションが含まれている場合里 リンク層アドレス・オプションのフォーマット 1 9 0 1 2 3 4 5 6 7 8 Length 2 3 4 5 6 7 8 Type goto freeit; nd6—dad—na—input (ifa) ; 2 3 9 0 1 2 3 4 5 6 7 8 9 0 1 794 } Link-Layer Address . 820 819 rt ユ linfo) = = NULL) Ⅱ ( (sdl = SDL ()t → rt-gateway) ) = = NULL) ) goto freeit ; 重複アドレス検出をしているあいだ、アドレスには IN6 -IFF-TENTATIVE フラグが設定されます。この状態の アドレスは、通信に利用されることはありません。 IN6- IFF-TENTATIVE か設定されたアドレスに対する近隣 通知を受信した場合は、 nd6-dad-na-input() で重複アド レスの処理に進みます。重複アドレスの処理については別 の機会に角見します。 804 if (lladdr & & ( (ifp—>if—addrlen + 2 + 7 ) & 822 ~ 852 行目は、近隣キャッシュが ND6-LLINFO -INCOMPLETE 状態のときの処理です。 if (ln—>ln—state 822 827 828 ND6—LLI NFO ー I NC OMPLETE ) { if (ifp—>if—addrlen & & !lladdr) goto freeit; 809 810 } ~ 7 ) ! = lladdrlen) { goto bad; 804 ~ 810 行目では、送信されてきたデータリンク層ア ドレスの長さを検証します。 ifp には、受信したネットワ ーク・インターフェイスへのポインタかオ巒内されています。 if-addrlen にデータリンク層アドレスの長さかオ褓内されて いるので、これを lladdrlen と上交し、同しであることを 石忍します。さきはど述べたように、 lladdrlen は通架 索オプションの Type と Length フィールドの長さを含 みます。 804 行目では、 if-addrlen に 2 を加えることで そのぶん ( 2 オクテット ) を補正しています。 近隣キャッシュの状態 nd6-lookup() は近隣キャッシュの検索関数です。近 嵋凾知された IP アドレスに対応する近隣キャッシュカイ乍 られていなければ、その近隣通知を処理する必要がないの ND6-LLINFO-INCOMPLETE は、データリンク層 アドレスか解決されていない状態です。近隣通知にデータ リンク層アドレスカ哈まれていなければ、処理を続けるこ とかできないので中断します ( 827 行目 ) 。 受信した近隣通知バケットが、 j 要請バケットの応答 として返されたものなら (is-solicited が真 ) 、双方向の通 信カ蔀忍されたことになるので、近隣キャッシュの状態を ND6-LLINFO-REACHABLE に遷移します ( 図 15 ) 。 841 } else { 842 843 844 } ln—>ln_state ln—>ln—expire ND6_LLINFO_STALE; time_second 十 nd6—gctimer ; で中断します。 816 rt = nd6-100kup(&taddr6 , 817 if ( ()t = = NULL) Ⅱ 0 , ifp) ; 818 ( ()n = (struct 11inf0-nd6 *)rt UNIX MAGAZINE 2002.6 近隣要請に応答した近隣通知ではない場合 (issolic- ited カイ為 ) は、 ND6-LLINFO-STALE 状態に遷移しま す。これは、近隣通知の受信によって相手ノードから自ノ ード宛の通信カ蔀忍されただけで、自ノードから相手ノー ドへの通信は石薩忍されていないからです。 859 ~ 929 行目は、近隣キャッシュが ND6-LLINFO- INCOMPLETE 以外の状態のときの処理です。ここで は、文献 [ 1 ] のイ求 C に記載されている状態遷移表に従 って、近隣キャッシュの状態遷移をおこないます。条件 に従った単純な遷移カくので、コードの角見は省略しま 75
図 15 833 834 835 836 837 838 839 840 連載 / IPv6 の実装ー① is-solicited か真の場合 ~ 里 sdl—>sdl—alen = ifp—>if—addrlen; bcopy(lladdr, LLADDR(sd1) , ifp—>if—addrlen) ; if (is—solicited) { ln—>ln_state = ND6_LLINFO_REACHABLE; ln—>ln—byhint = 0 ; if (ln—>ln-expire) ln—>ln—explre = time_second 十 nd—ifinfo Crt->rt—ifp—>if—index] . reachable ; す。文献 [ 1 ] とコードを見くらべると、状斷多の牛が そのまま実装に反映されていることカ蔀忍できます。 931 if (ln—>ln—router & & ! is—router) { 931 ~ 966 行目は、以前は is-router フラグか設定され た近隣通知を送ってきたノードから、このフラグを設定し ない近隣通知が送信された場合の処理です。すなわち、 れまではルータとしてバケットを転送していたが、以後は バケットの転送ができないことを未します。 951 dr = defrouter—lookup ( (struct sockaddr—in6 970 ln->ln_asked = 0 ; 近隣通知を受信したので、近隣要請の再送カウンタ (ln- asked) をリセットします。 送信待ち IP バケットの送信 送イ富寺ちになっているバケットが近隣キャッシュに登 録されていたら、送信します。 971 if ( ln ー > ln ー五 01d ) { 978 976 977 nd6—output(ifp, ifp, 1 Ⅱー > ln ー五 01d , (struct sockaddr—in6 * ) rt—key(rt) , (t) ; 1 Ⅱー > 1 Ⅱー hold = NULL ; 952 953 if (dr) 954 *)rt-key(rt) , rt—>rt—ifp) ; defrtrlist—del (dr) ; 各ノードは、デフォルトルータ・リストと呼ばれるリス トにリンク上のルータの一覧をイ尉寺しています。 defrout- er 」 ookup() は、ノードのデフォルトルータ・リストの なかから、指定したアドレスをもつルータを検索する関数 です。 is-router カ為である近凾知を送信してきたノー ドは、ルータとして機能しなくなるので、 defrtrlist-del() を使ってデフォルトルータ・リストから外します。 955 else if ( ! ip6—forwarding & & 963 964 } ip6—accept—rtadv) { rt6—f1ush(saddr6, rt—>rt-ifp) ; rt6-flush() は、第 1 引数で指定されたアドレスが宛 先アドレスとして設定されている糸等清報を削除する関数 です。近隣通知を送信してきたノードがデフォルトルー タ・リストに登録されていない場合でも、向け直し (Re- direct) による経路修正の結果、バケットの転送先になっ ている可育生があります。 is-router カイ為の場合、以後の 車幻逶かできなくなるので経路表から削除します。 76 979 } この時点でデータリンク層アドレスは解決されています から、 nd6-output() を呼び出すことでデータリンク層に 向けてバケットが出力されます。 ☆ 次回はデータリンク層アドレスの解決処理の後半とし て、近隣要請の受信処理と近隣通知の送信処理について解 説します。 ( しま・けいいち IIJ) [ 1 ] Thomas Narten, Erik Nordmark and WiIIiam Allen Simpson, Ⅳ e 朝ん 60r D な co 眦 for IP レ s れ 6 (IP の , RFC2461 , December 1998 [ 2 ] David C. Plummer, スれ Ethernet Address eso ん 0 れ Protocol, RFC826, November 1982 [ 3 ] Richard Draves, DefauIt Address SeIection for / P 6 , draft-iet f-ipngwg-default-addr-select [ 赭文献 ] UNIX MAGAZINE 2002.6
旧 v6 の実装 島慶ー 近隲探索の処理 1 何かを作りだすときには 2 つのやり方があります。 1 っ は考えてから作るガ去、もう 1 つは作ってから考える方 法です。インターネットの世界は、どちらかといえば後者 のガ去によって構築されてきたように思います。気に入ら ないところがあれば自分で直す、動くコードは美しい、と いう考え方は、インターネット技術の進化の速さの象徴で す。しかしながら、このガ去はときとして将来性に問題の ある実装を生み出すこともあります。 もちろんいつの日にでも、将来を見据えた言 t をするの は困難なことです。そういった意味では、すくなくとも初 期のインターネットは、攵さと将来性を兼ね備えた絶妙 なバランスの上で技術開発がおこなわれていたように思い ます。 近年のインターネット技術は、仕様の本寸に何年もかか ることカしくなくなりました。インターネットの利用者 カえ、インターネット自身に課せられた責任か大きくな るにしたがい、細かな要求やさまざまな意見が出されるよ うになったことが原因です。もっと気楽に技ヤ硎目発できな いものか、と過去を顧みるようになったのは歳を重ねたせ いでしようか。 今回参照するファイル 今回は、 RFC2461 [ 1 ] で定義された近隣探索 (Neigh- bor Discovery) に関係する以下のファイルを参照します。 ・ kame/sys/netinet6/nd6. h ( 改訂番号 1.81 ) ・ kame/sys/netinet6/nd6. c ( 改訂番号 1.235 ) ・ kame/sys/netinet6/nd6-nbr. c ( 改訂番号 1.99 ) kame/sys/netinet/icmp6. h ( 改訂番号 1.68 ) UNIX MAGAZINE 2002.6 近隣探索の手順 2001 年 11 月号の「データリンク層アドレスの角たで も触れたように、近ド爾架索は IPv4 のアドレス角夬プロト コル (ARP : Address Resolution Protocol) [ 2 ] に代わ るものです。近隣探索では、単純なアドレス角共に加え、 ノードの到達性の石忍や重複アドレス検出、ルータの探索 などの機能も盛り込まれました。 今月からは、近ド爾架索でのアドレス解決の実装をみてい きます。近架索におけるアドレス鮹夬は、以下の手順で おこなわれます。 1. バケットを送り出すノードが、送信先アドレスのデー タリンク層アドレスを発見するために近隣要請 (Neigh- bor SoIicitation) を送信する。 2. j 要請を受信したノードは、自分のデータリンク層ア ドレスを近隣通知 (Neighbor Advertisement) に含め て返信する。 それぞれの処理は関数単位で実装されており、 nd6-ns- output() が近隣要請の送信、 nd6-ns-input() が近隣要 請の受信、 nd6-na-output() が近隣通知の送信、そして nd6-naänput ( ) が近隣通知の受信を受け持ちます。 今回は、近隣要請の送信処理と近隣通知の受信処理を解 説します。近隣要請の受信と近隣通知の送信については次 回にとりあげます。 近謝架索は、 IP バケットの出力を契機に実行されます。 前号で海見した IP'NO ケットの出力の続きから、コードを みていきましよう。なお、朝行でファイル名を明記してい ないコードは nd6. c のものです。 63
連載 / IPv6 の実装ー① 図 9 in6-selectsrc() による始点アドレスの央定 565 else { 576 577 581 583 bcopy(&dst—sa, &ro. ro—dst, sizeof(dst—sa)) ; srcO = in6—se1ectsrc(&dst—sa, NULL , NULL , &ro , NULL , 合に、もっともふさわしい始点アドレスを返す関数です。 始点アドレス窈尺は、ドラフト [ 3 ] で定義された規則に 従います。 601 ~ 610 行目は、重複アドレス検出時の始点アドレス 601 } else { 600 の言です。 ス ( すべて 0 のアドレス ) になります。 重複アドレス検出の場合、始点アドレスは未定義アドレ NULL , &error) ; 634 if ( !dad & & (mac = nd6—ifptomac(ifp))) { ただし、重複アドレス検出のための近隣要請バケットを 送信するときは、このオプションを付けてはいけません。 635 636 638 int optlen = sizeof (struct nd—opt—hdr) + ifp—>if—addrlen; struct nd—opt—hdr *nd—opt = (struct nd—opt—hdr * ) (nd-ns + 1 ) ; optlen = (optlen + 7 ) & ~ 7 ; 610 } 609 bzero(&src—sa. sin6—addr sizeof (src—sa. sin6-addr)) ; 始点アドレスの ) 尺処理カ鮗ったら、 611 行目で IP へ ッダの始点アドレスを設定します。 ip6—>ip6—src src_sa. sin6_addr; 615 ~ 620 行目では、近隣要請バケットの各フィールド を設定しています。 611 送信元リンク層アドレス・オプションの長さは、オプシ ョンヘッダ (nd-opt-hdr 構造体 ) とリンク層アドレスの 長さだけでよいのですが、オプションは 8 オクテット単位 に合わせる必要があるため長さを調整します ( 638 行目 ) 。 オプションを追加したことでバケット長が伸びますか ら、 640 ~ 642 行目て局します。 640 m—>m-pkthdr. len + = optlen ; 641 m¯>m_len 十 = optlen ; 642 icmp61en + = optlen; 続いて、オプションの各フィールドに値を代入します。 615 616 617 618 619 620 (struct nd_neighbor—solicit * ) nd_ns ( 土 p6 + 1 ) ; nd—ns—>nd—ns—type = ND—NEIGHBOR—SOLICIT ; nd_ns—>nd_ns_code = 0 ; nd_ns—>nd_ns_reserved = 0 ; nd—ns—>nd—ns—target taddr6—>sin6_addr ; in6—c1earscope (&nd—ns->nd—ns—target) ; 647 } 643 644 645 646 bzero ( (caddr—t)nd—opt , optlen) ; nd—opt—>nd—opt—type = ND_OPT_ SOURCE_L I NKADDR ; nd—opt—>nd—opt—len = optlen > > 3 ; bcopy (mac , (caddr—t) (nd—opt + 1 ) , ifp—>if—addrlen) ; 620 行目の in6-cIearscope() は、 IP アドレスに埋 め込まれたスコープ識別子の情報を消去する関数です。 KAME では、アドレスの一都にスコーフ識別子を埋め込 むコードがあるため、実際のバケットを作成する際にその 情報を消しておく必要があります。 オプション里 次に近隣要請バケットのオプションとして送信元リン ク層アドレス・オプションお助日します。 72 ifp->if-addrlen には、 ifp で指定されるネットワーク・ インターフェイスのデータリンク層アドレスかオ褓内されて いるので、その値を送信元データリンク層アドレス・オプ ションにコピーします。 近隣要請バケットの送信 これで、近隣要請バケットのすべての情報か設定されま した。近隣要請バケットは ICMP バケットですから、チェ ックサムの引算が必要です。 UNIX MAGAZINE 2002.6
連載 / IPv6 の実装ー① icmp6. h 254 struct nd_neighbor_solicit 255 256 struct icmp6—bdr struct in6_addr —target ; 言周査」・象 - nd ns_hdr ; nd_ns 近隣要請バケットは、 ICMP ヘッダの後ろに 495 if (daddr6 = = NULL Ⅱ ドレス宛に近隣要請バケットを送イ言する必要があります。 スカ喇明していない場合、最初は要請マルチキャスト・ア される場合の処理です。通イ目手のデータリンク層アドレ 495 ~ 500 行目は、近隣要請バケットがマルチキャスト す。 MGETHDR() で送イヤヾケット用の mbuf を石呆しま 455 MGETHDR (m , M_DONTWA I T , MT_DATA ) ; のビット操作で大きさを 8 の倍数に揃えています。 オクテット境界のアラインメントが必要なので、 445 行目 せています。近ド蝌架索バケットのオプションは、すべて 8 layer Address) オプションを追加するための余裕をもた 通知するため、送信元リンク層アドレス (Source Link- ンク層アドレスを、近隣要請バケットを受信したノードに 行目では、近隣要請バケットを送信したノードのデータリ さらに、必要に応じてオプションが追加されます。 445 ifp—>if—addrlen + 7 ) & ~ 7 ; 445 maxlen + = (sizeof (struct nd—opt—hdr) 十 の IP アドレスをオ褓内する領域か読きます ( 256 行目 ) 。 IN6_IS_ADDR_MULTICAST (&daddr6—> ルータを j 面過する際に 1 すっ減らされるので、受信したと きに 255 以外のホップリミットが設定されていれば、他 のリンクから不正に送られてきた近謝架索バケットである と判断できるわけです。 502 icmp61en = sizeof(*nd—ns) ; 503 m—>m-pkthdr. len = m—>m—len sizeof(*ip6) + icmp61en; icmp61en には、名前のとおり ICMP バケットのサイ ズが入ります。 502 行目で近隣要請バケットに最 f 邸具必要 な長さを設定し、オプションに応して長さをしていき ます。 507 行目から近ド蝌架索バケットの構築か始まります。 507 508 509 510 512 513 mtod(m , struct ip6—hdr * ) ; ip6—>ip6—fIow = 0 ; ip6->ip6—vfc & = -IPV6—VERSION_MASK ; ip6->ip6—vfc ー = IPV6—VERSION ; ip6—>ip6—nxt = IPPROTO—ICMPV6 ; ip6—>ip6-h1im = 255 ; ip6 507 ~ 513 行目で、基本的な IP ヘッダのフィールドを 埋めています。近隣要請がユニキャストされるときも、マ ルチキャストされる場合と同様にホップリミットを 255 に設定する必要があります。 496 497 498 499 500 } sin6-addr) ) { m—>m—flags ー = M—MCAST ; im60. im60—muIticast—ifp im60. im60_mu1ticast_h1im = 255 ; im60. im60_mu1ticast—100p = 0 ; ifp; 515 516 517 518 519 520 bzero(&src—sa, sizeof (src—sa) ) ; bzero(&dst—sa, sizeof (dst—sa) ) ; src—sa. sin6—fami1y =dst—sa. sin6—fami1y AF_INET6 ; src_sa. sin6_Ien =dst_sa. sin6_Ien sizeof (struct sockaddr—in6) ; if (daddr6) dst_sa = *daddr6 ; 496 行目で、 mbuf がマルチキャスト・バケットを含む ことを示すフラグを設定します。 497 ~ 499 行目はマルチ キャスト・オプションの設定です。前回説明したとおり、 このオプションは ip6-output() の呼出し時に引数て渡さ れます。 498 行目のホップリミットの設定は重要です。近窮架索 はリンク内て元結するプロトコルです。他のリンクから近 ド架索を装ったバケットか送信されることを防ぐため、す べての近ド架索バケットは 255 のホップリミットをもた なけれはならないことになっています。ホップリミットは 70 nd6-ns-output() の呼出し側で IP バケットの終点ア ドレスを指定していれば、 daddr6 に値か設定されていま す。この場合には、指定されたアドレスを終点アドレスと して設定します。 525 else { そうでなければ、データリンク層アドレスの検索対象 となっているアドレス (taddr6) から要請マルチキャス ト・アドレスを引算し、それを終点アドレスとして設定し ます。 2001 年 11 月号で解説したとおり、 IP アドレスが分 かっていれば、対応する要請マルチキャスト・アドレスは UNIX MAGAZINE 2002.6