要約

  • 累積ACKは連続して届いた末端を示すが、一つの送信窓で複数の損失が起きたとき、穴の先に残るデータの形までは伝えない。
  • RFC 2018は受信済みの不連続なバイト範囲を通知できるようにした一方、その通知を助言的な情報にとどめ、累積ACKを最終確認として維持した。
  • RFC 3517とRFC 6675は、スコアボード、飛行中データ量の推定、そしてACKクロックを守るための限定的な救済再送へと発展させた。

二番目のセグメントだけが落ち、三番目以降は受信側に並んでいるとする。受信側は大半を保持していても、通常のACK番号は最初の穴を越えられない。同じ番号が繰り返されれば異常は分かる。しかし送信側には、後続部分が届いているのか、まとめて再送すべきなのかが十分には分からない。

RFC 2018は1996年10月、この情報の不足に新しい表現を与えた。原型はRFC 1072にもあったが、ウィンドウ拡張との組み合わせをめぐる意見の相違などから広く配備されなかった。新しい仕様では、接続開始時のSYNでSACK-Permittedを交換し、許可された接続だけが、その後のACKにSACKブロックを載せる。

各ブロックは受信済み連続範囲の左端と右端を32ビットのシーケンス番号で表す。ただし、累積ACKの意味は変えない。累積ACKより前はすべて届いたという強い確認であり、SACKは穴の先にある島を示す補助情報である。受信側はメモリ不足なら、SACKで知らせたデータを後に捨てることも許される。送信側は通常のACKが進むまで、自分の再送用コピーを解放できない。

地図の大きさにも上限がある。TCPオプションは40バイトしかなく、SACKブロックは最大四つ、タイムスタンプも使えば通常三つになる。RFC 2018は最新到着分を最初のブロックに置き、過去のブロックを繰り返すよう勧めた。新しい状態を優先しつつ、戻りのACKが失われても情報が残るようにするためだ。完全な受信キューではなく、限られた欄に最も有用な断片を詰める設計だった。

RFC 2018は信号の形式を定めたが、詳細な回復手順までは固定しなかった。SACKを使っても既存の輻輳制御を守る必要があるとした。2003年4月のRFC 3517は、送信側がその情報を使う保守的な手順を示した。送信側は累積ACKとSACKの範囲をスコアボードに記録し、どの穴が損失とみなせるかを判断し、Pipeでネットワーク内に残るバイト数を見積もり、輻輳窓の範囲で次の送信を選ぶ。

この分業は重要だった。受信側は観測を返すが、送信の決定権は持たない。送信側はより良い地図を得るが、誤認の責任、データ保持、速度制限を引き受け続ける。複数損失を一つの回復期間で処理できても、SACKは輻輳窓を無視する免許ではない。

2012年8月のRFC 6675はRFC 3517を廃止し、現実の隅に合わせて手順を修正した。新しいSACK情報を使って重複ACKを定義し、最大セグメントサイズより小さい送信でも損失を判断しやすくした。またRescueRxtを加えた。窓の末尾で損失が起き、新しいデータもないためACKクロックが止まりそうな場合、回復期間ごとに一度だけ楽観的な再送を許す仕組みである。大きさも送信側最大セグメント一個までに制限される。

SACKの歩みは、単にTCPが速くなった物語ではない。分散した証拠を誰がどこまで信じるかを決めた歴史である。受信側は現在のキューを知るが、永続保持は約束しない。送信側は再送を制御するが、経路を見る手段は遅れた報告しかない。ヘッダーは状態を圧縮し、タイムアウトは過去の判断を疑わせる。

長く残った発明は、ACKを一本の境界から部分的な地図へ変えつつ、その地図を命令にはしなかったことだ。無駄な再送を減らす情報と、共有経路を守る責任を同時に置いた。その均衡が、互換性を保った小さなオプションを損失回復の基盤にした。

出典