何のために抽象化、モデル化するかというと、ごちゃごちゃと複雑な現実を整理し、理解し易く、設計・開発・保守し易く、また再利用しやすくするためである。コンピュータ通信の分野で言うと、レイヤ化がその一例である。
レイヤ化モデルで代表的なものはOSIの7階層モデルであろう。ここで書くまでもないが、同一ノード間では、あるレイヤnはn+1レイヤおよびn-1レイヤのみとインタラクションし、対向ノードとは同じレイヤ同士のみ(peer)がコミュニケーションする。下位レイヤはカプセル化され、上位レイヤに対して下位レイヤの機能は隠ぺいされる。整然としているが、実際には、今日OSIモデルのサブセットが断片的に使用されているだけで、そのフルスタックの実装が普及したことはなかった。必要以上に機能分化され、必要以上にオーヴァヘッドが大きいためだと思う。
TCP/IPプロトコルスタックも、一応はレイヤモデルに基づくが、理論後付け的なところがあり、あまり整然とした階層にはなっていない。例えば、IP(ネットワーク層)を補完する機能としてARPやICMPがあるが、ARPはEthernet専用の機能でEthernet Frameを使用する一方、ICMPはIPにカプセル化される、等、図に書いてもきれいなレイヤ構造にならない。(rfc3439では、"Layering Considered Harmful"とさえ言ってる:))トップダウンで設計されたOSIと、時とともに漸次進化してきたTCP/IPの違いである。
レイヤによる抽象化は、モジュール化に加えて相対化という側面を持つので、いろいろ面白いことが起こる。ある問題を解決したつもりになっていても、実は、単に新たなレイヤを追加しただけだったり、他のレイヤの問題を増やしただけだったり。“Any problem in computer science can be solved with another layer of indirection.” “But that usually will create another problem.”という箴言もある。(これを言ったのは誰か、というのは、どうも諸説あるらしい。David Wheelerだと思っていたが、WikipediaによるとButler Lampsonと書いてあった。 )
ところで、IPv6では、OSIモデルのような必要以上の機能分化は行わず、しかしIPv4の時よりは、もう少し整然とした抽象化を行おうとした。まず、ARPやIGMPに相当するIPレイヤを補完する機能(Neighbor DiscoveryやMLD)を、ICMPの拡張メッセージとして統合し、また、ヘッダを階層化した。前者は、「ICMPへの統合によるメディア非依存」、という抽象化であり、後者は、「再帰」による抽象化である。
これは結構素敵である。IPv4の時よりもすっきり整然とするとともに、OSIよりも実践的だし、実際のプロトコルスタック実装にも適性が高い。
しかし、しかし。特にハードウェアに近くなればなるほど、やはり実装と抽象化は相容れにくくなる。
まずメディア非依存。Neighbor Discoveryに関するメカニズムは実際はメディア種別に依存するが、rfc4861(IPv6 Neighbor Discovery)は、メディア非依存であらゆるリンク属性{point-to-point, multicast, NBMA, shared media}を対象とする。属性によって適用するメカニズムを取捨選択することになるのだが、これは実装に任されるところになる。point-to-point linkではNS/NA(Neighbor Solicitation, Neighbor Advertisement)は行わない。ではDAD(Duplicate Address Detection)はどうか。これもpoint-to-pointでは無くてもよいのではと思うが、rfc4862(IPv6 Stateless Address Configuration)では、特にlink種別の記述はない。また、subnet-router anycast address(interface-id = 0)も、point-to-pointに必要とは思えないが(shared linkであっても使ってないのでは)、rfc4291(IPv6 Addressing Architecture)は、実際のinterface-id生成アルゴリズムについてリンク依存性(EUI64など)を言及しているに留まる。
そして再帰。Fragment処理に関しては、エンドに委ねたのはよいと思う。ただ、ヘッダ階層化による柔軟性・拡張性は、ついそれを有効利用したくなってしまうというところが悩ましい。Routing Header 0 は廃止されたが、1(Nimrod), 2(MobileIP)は残っており、これからも追加される可能性がある。再帰処理によるオーヴァヘッドやリスクと、得られる効用をよく見極めたい。
一番悩ましいのは、これらがセキュリティホールになることだ。pingpong問題(*)は、point-to-point linkではNS/NAが行われず、同一サブネット上のアドレスで自身のアドレス以外のものは着信したインタフェースへと送り返す動作に起因する。さらにsubnet長を一律/64にするというガイドラインもあるため、リスクの確率が大きくなる。
(*)
http://atm.tut.fi/list-archive/ipng/msg00163.html
http://www.apnic.net/meetings/26/program/apops/matsuzaki-ipv6-p2p.pdf
/127が使えればこの問題を防げるが、rfc3627(Use of /127 Prefix Length Between Routers Considered Harmful)にDADやAddressingとの不整合が記述されている。但し、ここに記述されている点は、point-to-point linkには適用外だと思う。下位メディアは、概念としては抽象化されていても、現実の実装の際はl属性を個別に考えた方が良い。
rfc4443(ICMP for IPv6)には、このpingpong問題を回避するためのソリューションが記述されているが、これもハードウェアフォワーディングにとってはかなりハードルが高い。抽象化のためにパフォーマンスを劣化させるのはあまりぱっとしない。
Routing Headerのセキュリティリスクについては言うまでもない。itojunさんのことが思い出され、今も胸が痛む。抽象化と実装が背反するような場合があれば、私だったら実装面を優先させるだろう。たぶんitojunさんも賛成してくれるのではないだろうか。
最近のコメント