This document is a translation of `Why TCP Over TCP Is A Bad Idea', which was written by Olaf Titz.
この文書は、Olaf Titz氏による `Why TCP Over TCP Is A Bad Idea'の翻訳です。
IPトンネリングアプリケーションにしばしば用いられるアイデア は、IPパケットを(モデムラインのような)ストリーム転送に適した フォーマットにカプセル化する、PPPのようなプロトコルをTCPベー スの接続上で実行することです。これは、すでにいくつかの推奨 (Linux HOWTOや、私自身のウェブサイトや、もちろん他にもいく つか)がある、PPP over SSHの実行により、容易なソリューション となるでしょう。それは、データグラムベースの圧縮が効率的な 制約で困難となる一方で、任意のIPトラフィックを圧縮する容易 な方法となります。
しかし、不運にも、それは上手くいきません。長い遅延や頻繁な接続の中 断が予想されます。ここにその理由を述べます。
TCPはデータストリームを、個々のIPデータグラムとして送信される セグメントに分割します。セグメントは、ストリーム 中のバイトに番号を付けるシーケンス番号(sequence number)と、他方に最後に受信されたシーケンス番号を伝え る受領番号(acknowledge number)を搬送します。[RFC793]
IPデータグラムは、失われたり、重複したり、順番が変わってしまう かもしれないため、シーケンス番号がストリームの再組み立てに利用 されます。受領番号は送信者に間接的にセグメントが失われたかどうかを 伝えます。つまり、ある一定の時間に最近送信されたセグメントに対する 受領番号が届かなかった場合、送信者はパケットが失われたと仮定し、 セグメントを再送します。
同様のアプローチを利用した他の多くのプロトコル(ほとんどが比較的一定な 帯域幅のラインで利用されるように設計されています)が、固定されているか 設定可能な「一定の時間」を持っています。しかし、インターネット上では、 帯域幅や遅延や損失率のようなパラメータは、一つの接続と他の接続で、 あるいは一つの接続でさえ違う時間で比較すると、非常に異なっています。 秒単位のある一定のタイムアウトは高速なLANでは不適切になるでしょうし、 また、輻輳した国をまたぐようなリンクでも不適切でしょう。実際、 それは輻輳を増大し「メルトダウン」として知られる効果を引き起こします。
このため、TCPはタイミング関係のパラメータのために適応性のあるタイムアウトを 利用しています。TCPでは保守的な見積りからスタートし、受信した各セグメント毎に 動的にパラメータを変化させます。実際に利用されているアルゴリズムは[RFC2001] で説明されています。詳細はここでは重要ではありませんが、一つだけ重要なことが あります。あるセグメントがタイムアウトした場合、次のタイムアウトは増加 されます。(タイムアウトは指数関数的に増加されます。これはメルトダウンを 避けるためのものです。)
TCPのタイムアウトポリシーはインターネット上で多様な接続の特性に対して有効に 機能しています。なぜならTCPは接続を切らないように非常によく努力し、タイムアウト は数分の単位にまで増加されるからです。これは、無人の大量のデータ転送に対して、 何と気のきいたことでしょう。(対話的なアプリケーションに対しては、このような 遅い接続はもちろん望ましくないもので、たぶんユーザは接続を切断するでしょう。)
この信頼性のための最適化はTCP接続を他のTCP接続の上に積み重ねると破綻します。 それはTCPの設計者たちが予期したものではありません。しかし、そのような状況は PPP over SSHやその他のTCPベースのプロトコルを実行すると発生します。 なぜならPPPでカプセル化されたIPデータグラムがこのようにTCPベースのペイロード を搬送するからです。
上位のレイヤーと下位レイヤーではTCPは異なるタイマーを持つことに注意して ください。上位のレイヤーの接続が高速にスタートした時、そのタイマーも高速 です。その際、下位レイヤーがより遅いタイマーを持っているかもしれません。 おそらく、低速であるか信頼性の低いベースとなる接続の時からの痕跡として。
この状況でベースとなる接続がパケットを失い始めた時、どんなことが起こるか 想像してみましょう。下位レイヤーのTCPは、再送パケットをキューに入れ、タイム アウトを増加させます。接続はこの間ブロックするため、上記のレイヤーの TCPは適時にACKを受信できず、同様に再送パケットをキューに入れます。タイムアウト は依然として下位のレイヤーよりも小さいため、上位レイヤーは下位レイヤーが 処理するよりも早く再送パケットをキューに入れます。これは上位レイヤーの 接続を非常に早く失速させ、再送は問題 - 内部的なメルトダウン効果 - を増加させる だけです。
TCPの信頼性のための用意はここでは逆効果となります。上位のレイヤーの再送は まったく不要です。なぜならキャリアが配送を保証するからです。しかし、上位レイヤー のTCPはそれを知ることができません。なぜならTCPは常に信頼できないキャリアを 仮定するからです。
このすべての問題がCIPE プロジェクトを始める最初の動機となりました。なぜなら私はしばらくの間 PPP over SSHソリューションを使って、それがまったく役に立たないことが 明らかになったからです。当時はしばしばパケットロスが起こる光リンク上で 実行していて、時々10-20%の時間の延長がありました。素のTCPでは、 これは我慢できました。(なぜならリンクは輻輳していたわけではなからです。) しかし、積み重ねられたプロトコルでは、接続は実に遅くなり、とてもよく 切断されました。
これがCIPEがデータグラムキャリアを採用している詳細な理由です。 (IPsecのような他のIPレベルのプロトコルではなくUDPを採用しているのには いくつかの理由があります: UDPを使うと、トンネルをポート番号によって識別 することができ、SOCKS上で実行することも可能です。) データグラムキャリアは素のIPとちょうど同じような特性を持っており、それは TCPがその上で実行されるように設計されたものです。