アドレス - みる会図書館


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

1. UNIX MAGAZINE 2004年9月号

連載 /UNIX Communication Notes ーー 0 図 1 に示したように、負荷分散装置は複数のサーバー を接続するスイッチとして機能する。代表的な実装として は、 ・ Ethernet 中幻医型 ・レイヤ 3 NAT 型 の 2 つの方法がある。 Ethernet 医型の場合、クラスタを構成する各サーバー には同じ IP アドレスを割り当てる。負荷分散装置は、ク ライアント側の IP アドレスとポート番号をもとに、どの ーにバケットを転送すればよいかを管理する。もう すこし具体的にいえば、 IP アドレス 163.221.1.8 210.156.7.8 203.5.163.2 ポート番号 5684 3342 11635 サーバー 4 3 1 のような転送表を負荷分散装置が保持していて、クライア ント側の IP アドレスとポート番号に応じて、どのサーノヾー ( 接続ポート ) に Ethernet フレームを転送すればよいかを 決定する。この方式における負荷分散装置は Ethernet ス イッチのようにデータリンク・デバイスとしてみえるため、 TCP/IP での糸各制御に影響を与えることはない。 一方、レイヤ 3 NAT 型の場合は、負荷う攵装置のイン ターネット側ポートにイ反想的に 1 つにみえるサーバーの IP アドレスカ第殳定される。各サーバーには異なる IP アドレ スを割り当てているが、負荷分散装置の NAT 機能によっ て、外部との通信は整合性を保ったかたちでおこなうこと ができる。前者と同様、 IP アドレス 163.221.1.8 210.156.7.8 203.5.163.2 ポート番号 5684 3342 11635 サーバー 4 3 1 のような転送表を管理することになるが、レイヤ 3 NAT 型ではサーバーの指定に IP アドレスカ駛われる。レイヤ 3 NAT だから、負荷分散装置はもちろん IP 層でのゲート UN 工 X MAGAZ 工 NE 2004.9 ウェイとして機能する。 負荷分散装置には、各サーバーが機能しているかどうか をポーリングによって定期的にチェックする機能がある。 この機能を利用することでサーバーの障害を自動的に検知 し、障害が起きているサーバーに対しては、新たなコネク ションを割り当てないようにすることができる。 どのように負荷分散がおこなわれるかは、クライアント からサーバーに対して新たに接続する際のコネクションの 設定方法によって決められる。たとえば、負荷分散装置に よって管理されるサーバーが 2 台あったとすると、次のよ うになる。 新たなコネクションが設疋されようとするたびに、 2 台 のサーバーに対して交互にコネクション設疋要求を転送 するものとする。この場合には、いわゆるラウンドロビ ン型の負荷分散がおこなわれ、負荷に大きな変動がなけ れば 2 台のサーバーに負荷カ賻分に分散される。 通常は特定のサーバーにのみコネクションを設定し、そ のサーバーに障害が発生した場合は、もう 1 台のサー ノヾーにコネクション設定要求を転送する。これは、バッ クアップ・システムの考え方を具体化したものといって もよい。 ・やや特殊な使い方として、 2 台のサーバーに同じバケッ トを中幻去し、特定の 1 台のサーバーからの応答だけをク ライアントに送り返す手法もある。これによって、 2 台 のサーバーの状態を同期させることができる。これは、 ホットスタンバイ (hot standby) とも呼ばれる方法で ある。 副作用の管理 負荷分散装置によってサーバーをクラスタ化すると、ど うしても、、副作用の管理 " が必要になる。 複数のサーバーを仮想的に 1 台のシステムとしている 以上、あるサーバーの状態を変更する処理がおこなわれた ら、ほかのサーバーはそれを検知して適切な処理をおこな こで、サーバーの状態を変更する わなければならない。 処理を一般に、、副作用のある処理 " と呼ぶ。副作用のある 処理の代表的な例としては、ファイルのサーバーへのアッ プロードやデータベースの内容変更などがある。 副作用のある処理がおこなわれた場合には、サーバーの 状態変更を管理する必要がある、通常、サーバーが処理に 41

2. 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)

3. UNIX MAGAZINE 2004年9月号

連載 / ネットワークとセキュリティ 図 1 iptables の言綻例 # /sbin/iptables —A OUTPUT -p tcp # /sbin/iptables —A OUTPUT —p tcp # /sbin/iptables —A OUTPUT —p tcp ネットワーク上で未使用の IP アドレスを dumnet 用に 割り当てる 運よく囀吏用の IP アドレスがある場合に、それを dum- net 専用として割り当てます。この方法は、すべてのポート —tcp-flags RST RST -s 192.168.12.34 ¯j DROP —sport 80 -s 192 . 168 . 12 . 34 -j ACCEPT —sport 22 -s 192 . 168 . 12 . 34 -j ACCEPT 宛のバケットの内容を入手でき、通常発生するトラフィッ クの景彡響を受けないため、本格的に運用するのであれば、 ちらがお勧めです。 dumnet がバケットを収集する場合には、 dumnet に割 り当てた IP アドレス宛のトラフィックがホストまで到達 する必要があります。そのため、 dumnet を運用するネッ トワーク上のルータで、スタティックな ARP 工ントリを 追加する必要があります。 こでは、 dumnet に割り当てる IP アドレスが 192. 168.12.34 、 dumnet を動かすホストの NIC の MAC ア ドレスが 00 ー 00 ー 01 ー 29 ー be ー ef だと仮定して、ルータ上での ARP 工ントリの設定方法を説明します。 Cisco IOS の搭載されたルータやレイヤ 3 スイッチを 利用している場合には、次のコマンドを入力します ( 誌面 # arp —s 192.168.12.34 00 : 00 : 01 : 29 : be : ef のコマンドを入力します。 *BSD や Linux をルータとして使っているのなら、次 0000.0129. beef arpa router(config)# arp 192 . 168.12.34 - router# configure terminal の都合上、で折り返しています。以下同様 ) 。 56 http://www.insecure.org/sploits/arp ・ games. html 3 ARP and ICMP redirection games 必要です。 arp poisoning を使うのは、その他の手段カ駛 るトリッキーな手法なので、利用する際には十分な注意が poisoning は Man ⅲ the Middle 攻撃の一種ともいえ ス宛のトラフィックを誘導することができます。なお、 arp ⅲ g3 をおこなうことで、 dumnet に割り当てた IP アドレ る arpredir コマンドを使い、ルータに対して arp poison- す。そのような場合には、 dumnet のパッケージに含まれ タティックな ARP 工ントリか轂定できないことがありま 一部のプロードバンド・ルータなどでは、どうしてもス えない場合に限定すべきです。 既存のホストの dumnet を動かす すでに動いているホスト上の、サービスを提供していな いポートで dumnet を動作させる方法です。この方法は dumnet 専用の IP アドレスカ坏要で、すでにサービスを 動かしているホスト上で空いているポートに対するアクセ スを確認したい場合に便利です。 この方法を利用するときは、以下の 2 点に注意する必要 があります。 ・ dumnet が OS の TCP/IP スタックに代わって ACK フラグの付いた TCP バケットを返さないように設定す る dumnet には -N という引数があり、 TCP 接続をエミ ュレートしないポート番号を指定できます。また、 -I 引 数を用いて ICMP ECHO Request に dumnet 自体 カ答しないように設定します。たとえば、 SSH (TCP 22 番ポート ) と HTTP (TCP 80 番ポート ) カ働いて いるホスト上で dumnet を稼動させる場合は、次のよ うにコマンドライン引数を設定します。 # dumnet -N 22 , 80 ーエその他の引数 ・閉じられたポートへのアクセスを受けたとき、 OS の TCP/IP スタックが RST フラグの付いた TCP パ ケットを送信しないように設疋する 通常、サービスを提供していないポートに対してアクセ スがあった場合、 OS の TCP/IP スタックが RST フ ラグ付きの TCP 応答を返します。しかし、 RST が返 されると TCP セッションが切断されてしまう可能性が あります。サービスを提供していないポートが開かれて いるかのようにみせかけるには、そのポートに SYN パ ケットが送られてきても、 RST を返さないようにする 必要があります。 図 1 に、 Linux 上で動くバケットフィルタ iptables の 設定例を示します。このホストの IP アドレスは 192.168. 12.34 で、さきほどの例と同様に SSH と HTTP のトラ フィックは通常どおり扱い、その他のポート宛のトラフィ UNIX MAGAZINE 2004.9

4. UNIX MAGAZINE 2004年9月号

出しはテキスト領域に置かれます。プログラムを実行する と、このテキストの部分が図 1 のようにアドレス空間の 先頭にある、、テキスト・セグメント " の部分に置かれるこ とになります。テキスト領域は、たいていの OS ではア ドレス空間のもっとも先頭に近いところに置かれるようで す。しかし、かならす 0 から始まるアドレス空間に配置さ れるとはかぎらず、頁にすこし空きがあることもありま す。この部分は、プログラムを実行しているときでも変更 する必要はありません。変更が必要な部分、つまりデータ 領域 ( データセグメント ) は別の部分に割り当てられるか らです。そのため、 OS によって謝奐え不叮能 (read only) な領域として保護されています。したがって、プログラム のバグなどでこのテキスト領域のアドレスに値を書き込も うとすると、 OS はセグメンテーション・フォルト ( セグメ ンテーションの違反 ) というエラーを返し、たいていのプ ログラムは異常終了してしまいます。 もう 1 つのデータ領域 ( データセグメント ) には、プロ グラムの残りの部分のうち、実行時に変更の必要があるデ ータ、すなわちプログラムの変数 ( グローバル変数、スタ ティック変数 ) が入っています。この部分はプログラムの 実行中にも割奐えが必要なわけですから、もちろん読取り や書込みカ可能な領域として割り当てられます。したがっ て、たとえプログラムのバグによってこの領域のアドレス への書込みがおこなわれたとしても、セグメンテーション・ フォルトは発生せず、そのアドレスのデータが間違った値 になってしまうだけです。もし、そのアドレスがなんらか の変数に割り当てられていたとしたら、その変数の値がい つの間にカき換わっているという現象に遭遇することに なります。俗に、、メモリを壊す " といわれるのは、このよ うなことカ起こっている状態を指しています。 、、ヒープ " とは、メモリを動的に割り当てるときに確保され る領域です。 C 言語の場合は、 malloc などのメモリ割当て 関数を呼び出したときに、この領域から必要な量カ保さ れ、そのアドレスが mall 。 c の戻り値として返ってきます。 、、スタック " とはプログラムの実行時の作業領域のような もので、関数呼出し時の引数やプログラムの自動変数が置 かれる領域です。スタックは、プログラムの実行中に大き さが頻繁に変わるため、ほかの領域とは違ってアドレス空 間の一番後ろに置かれています。そして、必要に応じてア ドレスの小さいほうへ向かって伸びていきます。 26 図 2 Solaris のアドレス (64bit) OxFFFFFFFFFFFFFFFF OXFFFFFFFFFFBFOOOO 0XFFFFF7FF00000000 0X801000000000 予約済み スタック 共有ライブラリ 予約済み ヒープ テータセグメント あいだにある、、共有ライプラリ " の部分には、プログラム がリンクしている共有ライプラリ ( ダイナミック・リンク されているライプラリ ) のテキスト領域とデータ領域が置 かれています。 もう 1 つ、 64bit のコンピュータの場合のアドレス空間 もみてみましよう。同じく solaris の 64bit のアドレス空 間は、図 2 のようになっています。 64bit のアドレス空間でも、各アドレスの割り当てられ方 は 32bit の場合とほば同じようなものです。ただし、さき ほども述べたようにアドレス空間の広さが異なります。ひ と昔前だったら、 4GB のアドレス空間はたいへん広大に思 えたものですが、現在はこの程度のアドレス空間では足り ないというプログラムもたくさんあります。たとえば、大 量のデータをやりとりするデータベースを扱うプログラム や、 CAD/CAE などのシミュレーションやモデリングを 実行するプログラム、あるいは科・学支術引・算のプログラム などカそうです。 32bit のコンピュータ環境では、このようなプログラム は、データの一部をディスクに書き出すといった工夫をす テキスト・セグメント OX10000000 UN 工 X MAGAZINE 2004.9

5. 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

6. 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

7. UNIX MAGAZINE 2004年9月号

特集プログラミンクの次の一歩 といった、プログラミングの初こ、者から一歩抜け出して、次 図 1 SoIaris のアドレス (32bit) のステップに進みたい人を想定しています。 4G B OXFFFFFFFF 今回は、例としておもに OS は Solaris を、プログラミ ング言語としては C 言語を使って説明します。ただし、お およその概念はほかの OS や言語の場合にも共通するとこ ろがあるはずです。 アドレス空間 メモリ管理の具体的な話に入る前に、、、 UNIX のアプリ ケーション " がどのような環境で動いているかをみておき ましよう。 言でいってしまえば、 イ磨誤メモリとは、 実際の物理メモリ空間以上のイ反想アドレス空間を作りだ 複数のイ反想アドレス空間を作りだす 技術といえるでしよう。 アプリケーション・プログラムを書いているときに、物 は、各プロセスごとにこの 4GB の仮想アドレス空間カ吏 理メモリと仮想メモリがどのように関連づけられているか えます。とはいっても、この 4GB の空間を自由気ままに を気にすることはあまりないと思います。この種の技術の 利用できるわけではなく、プログラムの部分ごとに割り当 細については、書籍や Web サイトで解説されているの てられる場所が決まっています。どのように割り当てられ で、卿未のある人はそちらを参照してください。 こでは、 るのかは OS によって若干異なりますが、こでは Solaris アプリケーション ( プログラム ) を書く立場から仮想メモ の場合を例に説明します。 リを眺めてみましよう。 Solaris のアドレス空間は、図 1 のようになっています。 この場合に重要なのは、アプリケーションカ働いている まずは、この図の未からみていきましよう。 アドレス空間についての知識でしよう。もちろん、プログ ラミングを勉強し始めたばかりのころは言語そのものを学 私たちがプログラムを書くときは、通常は C や Java ぶので手一杯だと思います。しかし、その次の段階として、 などのいわゆる高級言語と呼ばれる言語を使います。そし 自分の作成したプログラムがどのような環境で動いている て、これをコンパイル、リンクすることによって、、実行形 かを理解することはたいへん重要です。なによりも、この 式 " という実行可能なファイルに変換します。この実行形 ようなことを理解しているのといないのとでは、プログラ 式ファイルのフォーマットも OS によっていくつか種類が ありますが 2 、大雑把にいってしまうと、プログラムの、、テ ムの言気 t やデバッグ作業の効率が大きく違ってきます。 キスト領域 " と、、データ領域 " カ陬められています。 UNIX のアドレス空間 プログラムのテキスト領域 ( テキスト・セグメント ) と 仮想メモリ技術のおかげで、私たちが書くアプリケー はプログラム本体のことで、たとえばプログラムのなかで ション・プログラムは 4GB (0—OxFFFFFFFF=232) printf 関数を呼び出していれば、この printf 関数への呼 の広さのアドレス空間 1 を使うことができます。 UNIX で 2 以前は a. out 廾なにとよれるものが主流でしたが、丘は ELF 丿方にのほ うが多くなってきました。これらがどのようなフォーマットなのか興床があ 1 "4GB の広さのアドレス空間 " というのは、 32bit のコンピュータの場合 で。 64bit コンピュータでは、 264 ぶんのアドレス空間があります。 る方は、 man a. out または man elf などとしてみてください。 スタック 共有ライブラリ ( テータ ) 共有ライブラリ ( テキスト ) 共有ライブラリ ( テータ ) 共有ライブラリ ( テキスト ) ヒープ テータセグメント テキスト・セグメント す 1 三ロ 25 UNIX MAGAZINE 2004.9

8. 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

9. UNIX MAGAZINE 2004年9月号

特集プログラミンクの次の一歩 図 3 pmap で csh のプロセスをる砡忍 144K r x 16K rwx 1184K r——s— ることで実行していましたが、そのぶん、プログラム自体 T IME CMD PID TTY csh 4160 : % pmap 4160 00010000 00044000 00048000 FF080000 FF200000 FF214000 FF220000 FF252000 FF260000 FF280000 FF33C000 FF342000 FF350000 FF360000 FF39A000 FF3A2000 FF3B0000 FF3C0000 FF3F6000 FFBEEOOO tota1 176K 24K 8K 144K 16K 16K 688K 24K 8K 8K 168K 32K 8K 8K 160K 16K 72K 2920K rWX— rWX— rWX— rWX ー rWX ー rWX ー rWX ー rWX ー rWX— /usr/bin/csh /usr/bin/csh [ heap ] dev: 85 , 30 ino : 665692 /usr/1ib/10ca1e/ja-JP. eucJP/meth0ds-ja—JP . eucJP . so . 2 /usr/1ib/10ca1e/ja-JP. eucJP/methods—ja—JP . eucJP . so . 2 /usr/1ib/10ca1e/ja-JP. eucJP/ja-JP. eucJP . so . 2 /usr/1ib/10ca1e/ja-JP. eucJP/ja—JP. eucJP . so . 2 /usr/p1atform/sun4u/1ib/1ibc—psr. so. 1 [ stack ] /usr/lib/ld. so . 1 /usr/lib/ld. so . 1 /usr/lib/libdl . so . 1 /usr/lib/libcurses . SO . 1 /usr/lib/libcurses . so . 1 /usr/lib/libcurses . so . 1 [ 。Ⅱ ] /usr/lib/libc . so . 1 /usr/lib/libc . so . 1 /usr/lib/libc . SO . 1 がいくっか用意されていますが、現在動いているプロセス はネ礬隹になっていました。もちろん、、、工夫 " をしたぶんの よけいな処理が増えるわけですから、処理時間にも大きく 影響します。これが、 64bit のコンピュータ環境になると、 18EB ( 工クサバイト ) のアドレス空間にひろがります。 れなら、データをひとまとめにして ( イ反想的な ) メモリ上に 置いておくこともできますし、プログラミングもかなり楽 になり、もちろん高速な処理も可能になります。このよう に、 64bit のアドレス空間を使うと大きなプログラムも作 りやすくなります。ただし、アドレス空間の基本的な構造 は 32bit の環境ととくに変わりありません。 pmap によるアドレスマップの確認 UNIX のプロセスは、実行されるとこのような空間内 のアドレスマップをみるには pmap を使います。 pmap コマンドの引数にプロセスの番号を指定すると、そのプロ セスのアドレスマップを確認することができます。 まず、プロセス番号を調べるために ps コマンドを実行 します。 % ps 4212 4160 4188 4189 pts/3 pts/3 pts/3 pts/3 0 : 00 0 : 00 0 : 00 more 0 : 00 diff a . c b . c csh PS に配置されて動くことになります。 ・・と言葉で説明した だけでは、いまひとっ具体的なイメージが思い浮かばない かもしれないので、実際に動いているプロセスのアドレス マップをみてみましよう。アドレスマップとは、プロセス がアドレス空間にどのように配置されているかを示すもの です。 最近の SoIaris には、実行中のプロセスのアドレスマッ プを簡単に見られるコマンドがあるので、これを使います。 SoIaris には、プロセスのた態を確認するためのコマンド UN 工 X MAGAZ 工 NE 2004.9 どのプロセスを確認してもかまいませんが、ここでは csh プロセスについてみてみましよう。プロセス番号は、 ps コ マンドの出力の、、 PID " の欄を見れば分かります。 csh の プロセス番号は 4160 ですから、これを引数にして pmap コマンドを実行します ( 図 3 ) 。 pmap コマンドでは、図 1 とは逆にアドレスは小さいほ うから表示されています。これを図 1 と同じアドレス順で 示すと、図 4 のようになります。 アドレスのもっとも先頭に近い部分 0X00010000 から の領域が /usr/bin/csh のテキスト領域、次の 0X000440 00 からの領域がデータ領域です。その次に続く領域 0X00 048000 には、ヒープが割り当てられています ( 実際には、 27

10. 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