TCP/IP セグメントの結合の規則
このセクションでは、受信セグメント結合 (RSC) 対応ミニポート ドライバーが特定の TCP 接続のセグメントを結合する必要がある場合を指定する規則を定義します。 いずれかの規則に違反すると、例外が生成され、ミニポート ドライバーはセグメントの結合を中止する必要があります。
ミニポート ドライバーは、単一の結合ユニット (SCU) の IP ヘッダーと TCP ヘッダーを更新する必要があります。 ミニポート ドライバーは、SCU 経由で TCP と IPv4 チェックサムを再計算し、TCP ペイロードをチェーンする必要があります。
次の 2 つのフローチャートの 1 つ目では、セグメントの結合と TCP ヘッダーの更新に関する規則について説明します。 このフローチャートは、有効な重複 ACL とウィンドウの更新を区別するためのメカニズムを指します。 2 番目のフローチャートでは、これらのメカニズムについて説明します。
これらのフローチャートは、RSC 規則を理解するためのリファレンスとして提供されています。 ハードウェアの実装では、正確性が維持されている限り、フローチャートを最適化できます。
フローチャートでは、次の用語が使用されます。
用語 | 説明 |
---|---|
SEG.SEQ | 受信セグメントのシーケンス番号。 |
H.SEQ | 現在追跡されている SCU のシーケンス番号。 |
SEG.ACK | 受信セグメントの受信確認番号。 |
H.ACK | 現在追跡されている SCU の受信確認番号。 |
SEG.WND | 受信セグメントによってアドバタイズされるウィンドウ。 |
H.WND | 現在追跡されている SCU によってアドバタイズされるウィンドウ。 |
SEG.LEN | 受信セグメントの TCP ペイロードの長さ。 |
H.LEN | 現在追跡されている SCU の TCP ペイロードの長さ。 |
SEG.NXT | SEG.SEQ と SEG.LEN の合計。 |
H.NXT | H.SEQ と H.LEN の合計。 |
H.DupAckCount | SCU に結合された重複する ACL の数。 この数値はゼロである必要があります。 |
SEG.Tsval | 現在の受信セグメントの Timestamp 値。 この値の形式は RFC 1323 で定義されています。 |
H.Tsval | 現在追跡されている SCU の Timestamp 値。 |
SEG.TSecr | 現在受信しているセグメントのタイムスタンプ エコー応答。 |
H.TSecr | 現在追跡されている SCU のタイムスタンプ エコー応答。 |
フローチャートは、ミニポート ドライバーが異なる ACK 番号でセグメントを結合する可能性があることを示しています。 ただし、ミニポート ドライバーは、上記の最初のフローチャートに示すように、ACK 番号に関する次の規則に従う必要があります。
シーケンス番号チェックを実行した後、受信した純粋 ACK は、次の条件のいずれかまたは両方を満たしている場合、現在追跡されている SCU に結合される可能性があります。
H.ACK == SEG.ACK.
追跡されている対象の結合セグメント内の重複 ACK カウントは 0 です。 つまり、 H.DupAckCount == 0 です。
つまり、重複 ACK またはウィンドウ更新ではない純粋な ACK は例外をトリガーし、結合してはなりません。 このような純粋な ACL はすべて、個々のセグメントとして示す必要があります。 この規則により、RSC が Windows TCP 輻輳制御アルゴリズムの動作やパフォーマンスに影響を与えないことを保証します。
次の両方の条件が満たされている場合、受信データ セグメント (SEG.ACK == H.ACK) または受信ピギーバック ACK (SEG.ACK>H.ACK) は、現在追跡されている SCU に結合される可能性があります。
- セグメントは、シーケンス スペース内の SCU に隣接しています。 つまり、SEG.SEQ == H.NXT です。
- 追跡されている対象の結合セグメント内の重複 ACK カウントは 0 です。 つまり、 H.DupAckCount == 0 です。
重複 ACK の結合に関する追加の注意事項
重複 ACK の動作
ミニポート ドライバーは、純粋な ACK と同等の重複する ACK セグメントを処理し、結合しないようにする必要があります。 この場合は、表示のために現在の SCU (ある場合) を最終処理し、重複 ACK セグメントを個々のセグメントとして示す必要があります。 Windows クライアントは既定で選択的確認応答 (SACK) を使用するため、重複 ACK セグメントによって例外が生成される可能性があります。 例については、「受信セグメント結合の例」を参照してください 。 DupAckCount> 0 のセグメントが示されている場合、NDIS はインターフェイスで RSC を無効にします。
データ セグメントで構成される SCU を追跡するときの重複 ACK の処理
H.LEN> 0 で SCU を追跡する場合 (つまり、データを含む結合セグメント)、重複 ACK が次に到着した場合は、次のように追跡 SCU を最終処理する必要があります。
重複 ACK から始めて、新しい SCU を追跡する必要があります。
新しい SCU の DupAckCount を 0 に設定する必要があります。
重複 ACK が追加で受信された場合は、DupAckCount をインクリメントする必要があります。
この場合、DupAckCount は重複 ACL の数より 1 少なくなります。 ホスト スタックはカウントを正しく処理します。
純粋な累積 ACK で構成される SCU を追跡するときの重複 ACK の処理
単一の純粋な累積 ACK で構成される SCU を追跡する場合 (複数の純粋な ACK の結合を禁止する規則) 、重複 ACK が次に到着した場合は、追跡 SCU の DupAckCount をインクリメントする必要があります。 また、重複 ACK が追加で受信された場合もインクリメントする必要があります。 この場合、DupAckCount は、結合された重複 ACK の数と等しくなります。
DPC で受信された最初のセグメントが重複 ACK である場合
この場合、NIC は、受信したセグメントが重複 ACK であるかどうかを判断できません。これは、状態が維持されないためです。 そのため、セグメントは次のように純粋な ACK として扱う必要があります。
このセグメントから始めて、新しい SCU を追跡する必要があります。
新しい SCU の DupAckCount を 0 に設定する必要があります。
DupAckCount は、重複 ACK を追加で受信するたびに 1 ずつインクリメントする必要があります。
この場合、DupAckCount は、重複 ACL の実際の数より 1 少ない数になります。 ホスト スタックはカウントを正しく処理します。
重複 ACK の除外
ミニポート ドライバーは、純粋な ACK と同等の重複 ACK セグメントを処理でき、結合しないようにする必要があります。 この場合は、表示のために現在の SCU (ある場合) を最終処理し、重複 ACK セグメントを個々のセグメントとして示す必要があります。 Windows クライアントは既定で SACK を使用するため、重複 ACK セグメントによって例外が生成される可能性があります。 例については、「受信セグメント結合の例」を参照してください 。 この除外は、ウィンドウ更新セグメントには適用されません。
タイムスタンプ オプションを使用したセグメントの結合
TCP タイムスタンプ オプションは、法的に結合できる唯一のオプションです。 このオプションを使用したセグメントの結合は、実装固有の決定として委ねられます。 ミニポート ドライバーがタイムスタンプ オプションでセグメントを結合する場合は、次のフローチャートに記載されている規則に従う必要があります。
Note
SEG.TSval>= H.TSval チェックは、TCP シーケンス番号に使用するものと同様の modulo-232 算術を使用して実行する必要があります。 「RFC 793、セクション 3.3」を参照してください。
結合セグメントを示す場合は、結合されたセグメントを記述する NET_BUFFER_LIST 構造体の NetBufferListInfo メンバーを設定することで、次のように以下の帯域外情報を示す必要があります。
結合されたセグメントの数は、NetBufferListInfo[TcpRecvSegCoalesceInfo].CoalescedSegCount メンバーに格納する必要があります。 この数値は、結合されたデータ セグメントのみを表します。 純粋 ACK の結合は禁止されており、ウィンドウ更新セグメントはこのフィールドの一部としてカウントしないでください。
重複 ACK 数は、NetBufferListInfo[TcpRecvSegCoalesceInfo].DupAckCount メンバーに格納する必要があります。 上記の最初のフローチャートでは、この値の計算方法について説明します。
TCP タイムスタンプ オプションを持つセグメントが結合されている場合、 NetBufferListInfo[RscTcpTimestampDelta] には、SCU を構成する結合されたセグメントのシーケンスに表示される最も早い TCP タイムスタンプ値と最新の TCP タイムスタンプ値の間の絶対差分が入る必要があります。 SCU 自体には、結合されたセグメントのシーケンスに表示される最新の TCP タイムスタンプ値が含まれている必要があります。
DupAckCount メンバーと RscTcpTimestampDelta メンバーは、CoalescedSegCount メンバーが 0 より大きい場合にのみ解釈されます。 CoalescedSegCount が 0 の場合、セグメントは結合されていない非 RSC セグメントとして扱われます。
NetBufferListInfo メンバーの情報については、NDIS_NET_BUFFER_LIST_INFO と NDIS_RSC_NBL_INFO を参照してください。
PSH ビットは、すべての結合セグメントに対して ORed にする必要があります。 つまり、PSH ビットが個々のセグメントのいずれかに設定されている場合、ミニポート ドライバーは SCU で PSH ビットを設定する必要があります。
SCU の最終処理には、次の処理が含まれます。
TCP を再計算し、該当する場合は IPv4 チェックサムを再計算します。
「結合されたセグメントの IP ヘッダーの更新」の説明に従って IP ヘッダーを更新します。
TCP ヘッダーと IP ヘッダーの ECN ビットおよび ECN フィールドを、個々のセグメントで設定されたものと同じ値に設定します。
TCP/IP IPsec セグメントの処理
ネットワーク カードは、RSC と IPsec タスク オフロード機能の両方を報告できます。 (「ネットワーク アダプターの RSC 機能の決定」を参照。)ただし、IPsec タスク オフロードをサポートしている場合は、IPsec によって保護されているセグメントの結合を試みてはなりません。