要約

  • RFC 791 の例では reassembly timer を 15 秒から始め、到着した fragment の残存 TTL が大きければ待ち時間を延ばした。
  • RFC 1122 は TTL が秒ではなく hop count として扱われる現実を認め、60〜120 秒の固定 timer を推奨した。期限切れの不完全 datagram は必ず破棄する。
  • ICMP Time Exceeded Code 1 を必ず送るのは fragment zero を受け取った場合である。破棄はローカルな資源保護、通知は原 datagram の先頭を必要とする別の証拠行為だった。

同じ数字に二つの時間を任せる

RFC 791 の Time to Live は名前どおり秒を単位としたが、各 module は処理時間が一秒未満でも少なくとも一つ減らす必要があった。したがって TTL は最初から純粋な時計ではない。経路を進むたびに消費される budget と、経過時間の上限が一つの byte に同居していた。

初期の reassembly 手順は、この TTL を受信側の待ち時間にも利用した。新しい reassembly context を作ると timer を 15 秒の下限に設定する。次の fragment が到着したとき、その残存 TTL が現在の timer より大きければ timer を延長する。小さな値は待ち時間を短縮しない。

発想には連続性がある。datagram が Internet に残ってよい時間を fragment が持っているなら、宛先もその値を参考に待てばよい。しかし forwarding node が TTL を hop ごとに一つ減らし、滞在秒数を正確に差し引かないなら、受信時の値は経過時間を表さない。近い経路を長時間かけて届いた fragment と、多数の hop を高速で越えた fragment が、timer に逆の印象を与えることさえある。

この矛盾は名称の問題ではない。reassembly buffer をいつ解放するかという、有限メモリの決定だった。

先頭がなくても context は始まる

IPv4 は source、destination、protocol、Identification の組で fragment をまとめる。Fragment Offset は data の位置を示す。offset zero が先頭、MF が zero の fragment が末尾である。先頭と末尾は別の packet であり、到着順も保証されない。

RFC 791 の例は、どの offset の fragment でも対応する buffer がなければ資源を確保する。data を所定の位置に置き、受け取った block を記録する。末尾が来れば全体の data length を計算できる。だが header buffer に原 datagram の header を保存するのは FO = 0 の場合だけである。

そのため、timer は「fragment zero を受け取ってから」の時計ではない。途中の一片だけでも context は生まれる。末尾が先に来れば完成時の長ささえ分かる。それでも offset zero の穴が埋まらなければ上位層へ渡せない。

この非対称性を理解しないと、timeout を単なる packet loss counter と誤解する。実際には、受信済み data、未充足の穴、保存した header、判明した末尾、経過時間が一つの期限付き object を構成する。

穴を数える方法

RFC 815 は reassembly の bookkeeping を「受信した場所」ではなく「まだ空いている場所」で表した。fragment が来るたびに hole descriptor を短くし、二つに分け、または消す。hole がなくなれば完成である。

これは順不同の到着に向いた方法だった。しかし header は data と同じではない。IPv4 option にはすべての fragment に複製されるものと、最初の fragment だけに残るものがある。fragment zero が来るまでは、元の header の最終的な長さと内容を確定できない。最大長の領域を予約するか、後で data を移動する必要がある。

アルゴリズムは少ない管理情報で完成を判定できる。けれども、失われた先頭を推論で作り出すことはできない。後に RFC 1122 が「RFC 815 と異なり、最初の fragment header を timeout ICMP 用に保存する必要がある」と明記したのは、この差を示している。成功の組立てだけでなく、失敗を説明するためにも先頭は state だった。

Code 1 が引用するもの

RFC 792 の Time Exceeded は Type 11 である。Code 0 は transit 中の TTL expiry、Code 1 は fragment reassembly time exceeded を表す。error message には原 IP header と原 datagram の最初の 64 data bits が含まれる。当時の上位 protocol なら、その範囲に port などの照合材料があると想定された。

非 zero fragment にも source address と IP header はある。そうでなければ reassembly key を作れない。問題は返信先を知らないことではなく、error format が約束する「原 datagram の先頭」を持っているかどうかである。

RFC 792 は ICMP error を fragment zero の処理に関する error に限定した。reassembly が期限内に終わらなければ host は datagram を捨て、Time Exceeded を送ってよい。ただし fragment zero がなければ送らなくてもよい。失敗の存在と、外部に提示できる引用は一致しない。

Host Requirements の修正

RFC 1122 は reassembly timeout を必須にし、その値を残存 TTL ではなく固定値とするよう求めた。推奨は 60〜120 秒である。短すぎれば遅延した正当な datagram を不要に破棄し、長すぎれば buffer を長時間拘束する。文書は二分という TCP の MSL との関係にも触れ、有限の Identification 空間をどれだけ速く再利用できるかにも待ち時間が影響すると説明した。

ここで規範文は二段階になる。timeout が切れた部分 datagram は必ず破棄する。そして fragment zero を受け取っていれば、source host に ICMP Time Exceeded を送る。

破棄に括弧はない。通知にはある。受信 host は外部へ説明できない場合でも、自分の memory を守らなければならない。反対に、buffer を使ったという事実だけでは、原先頭を引用する error を生成する条件にならない。

60〜120 秒は現在の全実装に共通する default ではない。本稿の閉じた RFC 集合は現代の kernel 設定を測定していない。重要なのは、仕様が二つの時計を分け、reassembly の resource policy を destination に戻したことだ。

router が host になる境界

RFC 1812 は transit router が普通の転送のために datagram を再構成するとはしない。router 自身を宛先とする packet を reassemble するとき、その router は Internet host として host requirements に従う。

また、非 first fragment に対する ICMP error は送ってはならず、この制限は他の送信要求より優先する。したがって path 上のどこかで fragment を見た device と、実際に timeout context を所有した destination を区別しなければならない。

待ち時間は ID の寿命でもある

RFC 6864 は reassembly timeout と maximum datagram lifetime を IPv4 Identification の一意性期間に関連づける。古い fragment が有効な間に同じ source、destination、protocol、ID が別の datagram に使われれば、異なる世代が同じ箱に見える危険がある。

これは ID field 全体の歴史ではない。timer の影響範囲を示す補助線である。長く待つ判断は、memory だけでなく「この識別子がまだ過去を指しうる時間」も延ばす。

error がない経路を健康と呼べない

Code 1 を受信した source は、destination が fragment zero を含む不完全 context を期限まで保持した、と限定的に理解できる。どの fragment がどこで消えたか、誰に責任があるか、同じ現象が再現するかまでは分からない。

何も受信しなければ候補は増える。fragment zero が destination に来なかった。ICMP が rate-limit された。return path で失われた。filter が落とした。実装または観測が異なった。沈黙は一つの outcome だが、一つの cause ではない。

末尾 fragment の到着も代替にはならない。MF zero は expected length を確定し、hole の範囲を閉じるが、ICMP が引用する original beginning を提供しない。end_knownzero_received は別の state である。

Code 1 自体も MTU 値や loss point を報告しない。RFC 1122 は将来の discovery procedure への利用可能性に触れたが、一件の expiry から narrow link や責任主体を断定することはできない。packet size、送信記録、path change と反復観測が必要になる。

仕様が保証するのは cause の判定ではなく、destination で一つの不完全 context が期限を迎えたという狭い事実である。この狭さを保つことが、誤った path verdict を避ける。

不明を不明のまま記録することも、interoperability を守る設計判断である。

二つの時計を分けた歴史は、二つの証拠も分ける。local timer の expiry は destination 内部の事実である。ICMP の到着は、zero fragment、生成処理、出力制御、return path をすべて通過した結果である。後者だけを数えれば、最も重要な先頭を失った failure ほど統計から消える。

出典と限界

これらは仕様、algorithm、当時記された trade-off を示す。現在の OS default、fragment traffic の割合、ICMP 到達率、filter、vendor compliance は測っていない。個別の現行実装については別の一次証拠が必要である。