IP-インターネットを支える基本技術

 インターネットのプロトコルはTCP/IPといいます。これはいくつものプロトコルの集合体で、TCP/IPプロトコルスイートなどと呼ばれることもあります。スイート(suite)ですから、インターネットを支えるプロトコル一式というような意味でしょうか。日本語ではプロトコル群などと呼ばれることもあります。プロトコル群をTCP/IPと呼ぶのは、インターネットを支えるプロトコル群のうちの代表的なプロトコルとして、TCPとIPを取り上げたからです。つまり、IPというプロトコルがインターネットを代表するようなプロトコルだというわけですね。とっても重要なプロトコルという意味になります。





1 IPはパケットの送受信を行う

 TCP/IPではIPが処理するデータユニット(データのかたまり)はデータグラムと呼びますが、OSI参照モデルではパケットと呼びます。そのため、IPパケットとか、パケットという言葉も一般的です。次にIPデータグラムのヘッダフォーマットを示します。

 3  7  15  19  31
Ver IHL ToS パケット長
識別子 フラグ フラグメントオフセット
TTL プロトコル番号 ヘッダチェックサム
SA(送信元アドレス)
DA(宛先アドレス)
オプション群                /  パディング

 Ver(Version、4ビット)はIPのVersionを示します。IPv4の場合は4が入ります。

 IHL(Internet Header Length、4ビット)はIPパケットのヘッダ長です。4ビット幅ですので、0~15までしか表現できません。これでどうやってヘッダ長を表現できるのでしょうか。上の表を見て下さい。Verからパケット長までで32ビットあります。IPv4の時代は32ビット仕様CPU(32ビットずつ処理)が一般的ですので、それに合わせて幅を32ビットにしてあります。オプション群の次にパディングが入っていることにも注目です。これは、無理やりヘッダ長を32ビット(つまり、4バイト)の倍数にしたいためです。もうわかったと思いますが、4バイトの何倍かでヘッダ長は表されます。上の表で言えば、何行かということですね。上の例は6行(4バイト×6)ですので、ここには「6」という値が入ります。

 ToS(Type of Service、8ビット)はサービスタイプを示しますが、現実にはほとんど使用されていません。しかし、このフィールドは最近業界の注目を集めています。ISPやベンダーなどでネットワーク内の様々なCoS(Class of Service)レベルを提供する必要に迫られているのです。例えば、映像データや音声データをリアルタイムで送信することを求めるサービスが盛んになっていることが原因です。そこで、ToSフィールドをDS(Differentiated Services、略してDiff-serv)として再定義するRFC2474、RFC2475などの規定も出てきています。

 DS規格によると、ビット8~13はDSCP(Differentiated Services Code Point)となり、残り2ビット(14-15)は引き続き未使用です。フィールドの利用方法はToSでもDSCPでもあまり変わりませんので、区別できるようにルータを設定しておけば、このフィールドを目印にして、パケットごとに処遇を切り替えることができます。

 ところがRFC3168によってToSはまたしても変更されることになります。それは、以前に不使用だった14-15の2つのビットがECN(Explicit Congestion Notification、明示的輻輳通知)に利用されるようになったことです。ECNは、ルータが輻輳を起こした際に、末端ノードにそのことを知らせる役目を持ちます。このおかげで末端のノードは、ルータが実際にデータを取りこぼす前にデータの送信速度を落とすことができます。2つのビットはECT(ECNCapable Transport)コールドポイントとCE(Congestion Experienced)コールドポイントと呼ばれます。

 ECN規格ができるまでは、ルータには過負荷を末端のノードに知らせる手段がありませんでした。そこでルータはやむなくデータを破棄していました。末端のノードはACKが返らずにタイムアウトするなどの状況を見て、いったん送信速度をがくんと落とし、破棄されたデータをおもむろに送り直して、様子を見ながら元のスピードまで上げていくという職人技のような手法に頼っていました。

 パケット長(16ビット)はバイト単位で表現します(IHLと数え方が違います)。16ビット幅ですので65,535バイト(64Kバイト)まで表現することが可能です。

 TTL(Time To Live)はパケットがルータを越えるたびにルータによって1ずつ引かれていきます。これによってパケットがインターネット上に永久的に存続しないようにしています。初期値は最大で255に設定できますが、大半のシステムでは比較的小さな初期値を使っているようです。このフィールドは元々は秒数を表していました。最長時間は255秒前後とされていました(フィールドの長さが8ビット表なので、秒だとすると最大で255秒となります)。これは、1980年代の回線速度とソフトウェアベースのルータを使った場合、1台のルータが1つのパケットを受信・転送するために約1秒の時間を必要としたということに由来しています。現在は回線速度も格段に上がり、ルータの処理速度も向上しているので、時間をミリ秒単位で測る必要があるのですが、8ビットフィールドでは、ミリ秒時間は扱いにくいということだと思います。TTLは現在はポップ(ルータを越える動作)カウントとみなされています。
 TTLはポップ毎にルータによって書き換えられますので(-1)、ヘッダチェックサムはその都度再計算して書き換えられています。

 ヘッダチェックサムはヘッダ部分の整合性を検査するためのフィールドです。チェックサム計算には「1の補数演算」という特別なアルゴリズムが使われています。データ部分はフラグメント化される場合があるので、チェックの対象になっていません。

 送信元アドレスと宛先アドレスはインターネット上の住所表示のようなものです。具体的な説明はIPアドレスの章を参照してください。

 フラグ、フラグメントオフセット、プロトコル番号についてはこの後説明します。


2 パケットのフラグメント化

 IPパケットが宛先までの経路の途中で大きすぎるという場合があります。宛先までには様々な物理ネットワークを経由しなくてはなりませんが、それぞれの物理ネットワークは処理できるパケットの大きさの最大限を定めています。これをMTU(Maximum Transmission Unit:最大伝送ユニット)と言います。パケット長が1500バイトのパケットがMTU512バイトのネットワークに到達した場合ルータはパケットがその狭いリンクを通り抜けることができるようフラグメント(fragment、破片)に分割することが出来ます。分割はデータフィールドを分割し、それぞれにパケットヘッダを追加することによって行います。この分割パケットのヘッダは必要がある場合は書き直され、使えるものはコピーされます。パケット長はフラグメント化された後のパケット長になります。識別子はIPパケットを識別するものです。各フラグメントは同じIDを持っていますので、宛先では、同じIDのフラグメントを集めることで再構成できます。フラグメントオフセットはそのフラグメントが元のIPパケットのどこの部分かを示すための値です。オプションはそのまま、コピーする場合と、コピーの必要がない場合があります。その後、各パケットのフラグメントは個別に宛先への経路上に転送され、最終的に宛先のIPによって再構成されます。

 フラグフィールドはこのフラグメントの動作を制御するために使います。3ビットのうち最上位ビットは常に0です。2番目のビットは「Don't Fragment」ビットで、フラグメントを禁止するときにセットします。3番目は「More Fragment」で後ろにフラグメントが続く場合にセットします。2ビット目の「Don't Fragment」がセットされているパケットが転送不能な狭いネットワークに遭遇するとその直前のルータはそのパケットを破棄してパケットの送信元にエラーメッセージを送ります。このときに利用されるプロトコルがICMPです。

 パケットの全てのフラグメントが宛先アドレスに到着すると、各パケットのフラグメントオフセット値に従って再構成されます。再構成するのは最終宛先のIPで、途中のルータで再構成されることはありません。全てのフラグが同じ経路を通るという保証はありません。全てのフラグメントが集まるのは最終宛先以外にはありません。例え可能だとしても、非効率です。途中で再構成しても、再度分割せざるを得ない狭いネットワークを通るかもしれないからです。

 全てのフラグメントが到着するまで、受信済みのフラグメントは受信側でバッファリング(一時保存)されなくてはなりません。全てのフラグメントが有効時間内に到着しない場合は、既に到着しているフラグメント全てが廃棄されます。



3 到着パケットの処理

 IPの開発当時のうたい文句は「IP over Everything」でした。IPは初めから物理ネットワークは既存のものを借りるように設計されています。このキャッチは、IPはどんな物理ネットワーク上でもインストールできますという意味になります。イーサネット上でも使えます。また、イーサネットもその上に何を乗せてもいいように設計されています。従って、イーサネットにしてみれば、上に何を載せているかを識別できる印のようなものが必要になります。イーサネットとインターネット(TCP/IP)の間を結びつける何らかの楔のようなものが必要です。これがタイプ番号です。

 宛先に到着したフレームはイーサネットのNICのハードウエアによって受信され、ソフトウエア(NICのドライバー)によって受信処理されます。この受信処理は主として、宛先MACアドレスと、自身のMACアドレスの照合と、それがマッチした時の上位層プロトコル(の実装)へのパケットの配達です。イーサネットは多くのプロトコルスタックを載せることが出来ますので、実際にどのようなプロトコルスタックが乗っているか分かりません。TCP/IPのことが多いでしょうが、上に載っているのがNovellのIPX(最近あまり見かけなくなっていますが)であるかも知れませんし、MicrosoftのNetBEUIかも知れません、あるいはApple独自のApple Talk(最近ほとんど使われていないようです)かも知れません。イーサネットはこのときフレームのタイプ番号フィールドの値を確認して、0x0800ならIP(ipd)に渡します。渡すのは、フレームのデータフィールドに格納されているパケット(データグラム)です。
※NetBEUI:Windows OSが小規模のLANでファイル共有やプリンタ共有を実現するためのプロトコル

 IPはパケットの宛先IPアドレスが自身(と言ってもNICにつけられた識別子ですが)のIPアドレスとマッチするか確認し、マッチしていればパケットのプロトコル番号フィールドの値に従ってパケットのデータフィールドに格納されたデータを渡します。上位層がTCP(プロトコル番号=6、実装はtcpd)なら、そのデータはセグメントと呼ばれ、UDP(プロトコル番号=17、実装はudpd)の場合はデータグラムと呼ばれます。ICMP(プロトコル番号=1、実装はicmpd)に渡す場合もあります。

※プロトコル番号はWindowsのC:\Windows\system32\drivers\etcというフォルダの中のprotocolというファイルに記載されています。powershellで閲覧できますので、是非確認してください(コマンドはcdとtypeだけで大丈夫です)。64bit仕様のCPUを使っている場合は、system32はsystem64と読み替えて下さい。

※更にトランスポート層のプロトコル実装はセグメント、あるいはデータグラムヘッダのポート番号に従ってアプリケーションの実装にデータ(メッセージ)を渡します(HTTPなら、実装はhttpd)。


4 送信パケットの処理

 前節の到着パケットの処理で説明した通りの処理が行われるためには、当然それに対応した処理が送信元で行われていなくてはなりません。アプリケーション層の実装から依頼されたトランスポート層の実装は、セグメントヘッダのポート番号フィールドに依頼主(の相手側、クライアントに依頼されたらその相手側のサーバ、サーバに依頼されたらその相手側のクライアント)のポート番号を格納し、トランスポート層の実装から依頼されたネットワーク層の実装は依頼主のプロトコル番号をデータグラムヘッダのプロトコル番号フィールドに格納し、更にネットワーク層の実装から依頼を受けたイーサネットのNICドライバは、依頼主のタイプ番号をフレームヘッダのタイプ番号フィールドに格納します。


5 ルーティング

 送信元と宛先での処理については理解できたと思いますが、では途中の処理はどのように行われるでしょうか。これを行うのがルータと呼ばれる装置です。ルータ(Router)はパケットを指定された宛先に転送する目的で設計された特殊用途のコンピュータです。コンピュータはルーティングテーブルと呼ばれるデータベースを持ち、それに従ってパケットの転送を行います。ルーティングテーブルはネットワークアドレス(IPアドレスのプレフィックス)毎に転送先を指定したファイルです。このファイルはネットワーク管理者によって手書きされることもありますが、大きなネットワークでは自動的に作成されます。ルーティングテーブルの自動作成をするプロトコルをルーティングプロトコルと言います。代表的なものとしてはRIP(ripd)やOSPF(ospfd)などがあります。ルーティングプロトコルの実装はお互いに情報を交換しながら宛先ごとの最適ルートを求めていきます。

 ルータのIP実装であるipdはルーティングテーブルに従って受信パケットを転送します。






更新履歴

2016/08/24 「1 IPはパケットの送受信を行う」のECNの説明を追加しました。
2016/03/01 作成












































 ページの先頭