大きな TCP パケットのセグメント化のオフロード
ネットワーク ドライバー インターフェイス使用 (NDIS) ミニポート ドライバーは、ネットワーク メディアの最大伝送単位 (MTU) を超える大きな TCP パケットのセグメント化をオフロードできます。 大きな TCP パケットのセグメント化をサポートする NIC では、以下のことが可能である必要があります。
IP オプションを含む送信パケットの IP チェックサムを計算する。
TCP オプションを含む送信パケットの TCP チェックサムを計算する。
NDISバージョン6.0以降では、NDIS 5における大きな送信オフロード(LSO)に類似したバージョン1(LSOv1)をサポートしています。x。 NDIS バージョン 6.0 以降では、IPv6 のサポートを含む拡張された大きなパケット セグメント化サービスを提供する大きな送信オフロード バージョン 2 (LSOv2) もサポートされています。
LSOv2 と LSOv1 をサポートするミニポート ドライバーは、NET_BUFFER_LIST 構造体の対域外 (OOB) 情報からオフロードの型を決定する必要があります。 ドライバーは、NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO 構造体の Type メンバーを使用して、ドライバー スタックが LSOv2 または LSOv1 のどちらを使用しているかを判断し、適切なオフロード サービスを実行できます。 LSOv1 または LSOv2 の OOB データを含む NET_BUFFER_LIST 構造体にも、1 つの NET_BUFFER 構造体が含まれています。 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO の詳細については、 「TCP/IP オフロード NET_BUFFER_LIST 情報へのアクセス」を参照してください。
ただし、ミニポートが OID_TCP_OFFLOAD_PARAMETERS を受信してミニポート上の LSO 機能をオフにした場合、ミニポートが OID を正常に完了した後、ミニポートでは、0 以外の LSOv1 または LSOv2 の OOB データ (NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO) を含むすべての NET_BUFFER_LIST を削除する必要があります。
TCP/IP トランスポートは、以下の条件を満たす 大きな TCP パケットのみをオフロードします。
パケットは TCP パケットです。 TCP/IP トランスポートは、セグメント化のために大きな UDP パケットをオフロードしません。
パケットは、少なくともミニポート ドライバーによって指定されたセグメントの最小数以上で分割可能である必要があります。 詳細については、 「NIC の LSOv1 TCP パケット セグメント化機能の報告」 および 「NIC の LSOv2 TCP パケット セグメント化機能の報告」を参照してください。
パケットはループバック パケットではありません。
パケットはトンネル経由で送信されません。
セグメント化のために大きな TCP パケットをオフロードする前に、TCP/IP トランスポートは、
- NET_BUFFER_LIST 構造体に関連付けられている大きなパケットのセグメント化情報を更新します。 この情報は、NET_BUFFER_LIST 構造体に関連付けられた NET_BUFFER_LIST 情報の一部である NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO 構造体です。 NET_BUFFER_LIST 情報の詳細については、 「TCP/IP オフロード NET_BUFFER_LIST 情報へのアクセス」を参照してください。 TCP/IP トランスポートは、MSS 値を最大セグメント サイズ (MSS) に設定します。
LSOv1 の場合、大きな TCP パケットの合計長をパケットの IP ヘッダーの
Total Length
フィールドに書き込みます。 合計長には、IP ヘッダーの長さ、IP オプションが存在する場合はその長さ、TCP ヘッダーの長さ、TCP オプションが存在する場合はその長さ、および TCP ペイロードの長さが含まれます。 LSOv2 の場合、パケットの IP ヘッダーのTotal Length
フィールドを 0 に設定します。 ミニポート ドライバーは、NET_BUFFER_LIST 構造体の最初の NET_BUFFER 構造体の長さからパケットの長さを決定する必要があります。TCP 疑似ヘッダーの 1 の補数の合計を計算し、この合計を TCP ヘッダーの
Checksum
フィールドに書き込みます。 TCP/IP トランスポートは、擬似ヘッダーのSource IP Address
、Destination IP Address
、およびProtocol
フィールドに対して 1 の補数の合計を計算します。 TCP/IP トランスポートが提供する擬似ヘッダーの 1 の補数の合計により、NIC は IP ヘッダーを調べることなく、大きな TCP パケットから派生する各パケットの実際の TCP チェックサムの計算を早期に開始できます。 RFC 793 では、擬似ヘッダー チェックサムは、Source IP Address
、Destination IP Address
、Protocol
、およびTCP Length
に対して計算されることに注意してください。 (TCP 長とは、TCP ヘッダーの長さに TCP ペイロードの長さを加えたものです。TCP 長には、擬似ヘッダーの長さは含まれません)。ただし、下位のミニポート ドライバーと NIC は、TCP/IP トランスポートによって渡される大きなパケットから TCP セグメントを生成するため、トランスポートは各 TCP セグメントの TCP ペイロードのサイズを認識しないため、擬似ヘッダーに TCP 長を含めることはできません。 その代わりに、以下で説明するように、NIC は、TCP/IP トランスポートによって提供された擬似ヘッダーのチェックサムを拡張して、生成された各 TCP セグメントの TCP 長さをカバーします。TCP ヘッダーの
Sequence Number
フィールドに正しいシーケンス番号を書き込みます。 シーケンス番号は、TCP ペイロードの最初のバイトを識別します。
ミニポート ドライバーは、MiniportSendNetBufferLists または MiniportCoSendNetBufferLists 関数内で NET_BUFFER_LIST 構造体を取得した後、TCP/IP トランスポートによって書き込まれた MSS 値を取得するために、 の _Id
で TcpLargeSendNetBufferListInfo
マクロを呼び出すことができます。
ミニポート ドライバーは、パケットの IP ヘッダーから大きなパケットの合計の長さを取得し、MSS 値を使用して、大きな TCP パケットをより小さなパケットに分割します。 小さいパケットそれぞれには、MSS 以下のユーザー データ バイトが含まれます。 セグメント化された大きなパケットから作成された最後のパケットのみに、MSS ユーザー データ未満のバイト数が含まれている必要があります。 セグメント化されたパケットから生成された他のすべてのパケットには、MSS ユーザー データ バイトが含まれている必要があります。 この規則に従わない場合、不要な追加パケットの作成と送信によってパフォーマンスが低下する可能性があります。
ミニポート ドライバーは、大きなパケットから派生した各セグメントに MAC、IP、TCP ヘッダーを付加します。 ミニポート ドライバーは、これらの派生パケットの IP と TCP チェックサムを計算する必要があります。 大きな TCP パケットから派生した各パケットの TCP チェックサムを計算するために、NIC は TCP チェックサムの可変部分 (TCP ヘッダーと TCP ペイロード)を計算し、TCP/IP トランスポートが計算した擬似ヘッダーの 1 の補数の合計にこのチェックサムを加えてから、チェックサム の 16 ビットの 1 の補数を計算します。 このようなチェックサムの計算の詳細については、RFC 793 および RFC 1122 を参照してください。
以下の図は、大きなパケットのセグメント化を示しています。
大きな TCP パケット内の TCP ユーザー データの長さは、ミニポート ドライバーが MaxOffLoadSize
値に割り当てる値以下である必要があります。 MaxOffLoadSize
値の詳細については、「NIC の LSOv1 TCP-Packet-Segmentation 機能 と NIC の LSOv2 TCP-Packet-Segmentation 機能の報告」を参照してください。
ドライバーが MaxOffLoadSize
値の変更を示すステータス表示を発行した後、ドライバーは以前の MaxOffLoadSize
値を使用する LSO 送信要求を受信しても、クラッシュしてはなりません。 その代わりに、ドライバーは送信要求を失敗させることができます。
MaxOffLoadSize
値の変更を報告する状態表示を個別に発行する中間ドライバーは、状態表示を発行していない基になるミニポート アダプターが、ミニポート アダプターが報告した MaxOffLoadSize
値よりも大きいパケットを取得しないようにする必要があります。
OID_TCP_OFFLOAD_PARAMETERS に応答して LSO サービスを停止するミニポート中間ドライバーは、LSO 送信要求がミニポート ドライバーに到達する可能性のあるわずかな時間に備える必要があります。
セグメント パケット内の TCP ユーザー データの長さは、MSS 以下である必要があります。 MSS は、NET_BUFFER_LIST 構造体に関連付けられた LSO NET_BUFFER_LIST 情報を使用して TCP トランスポートが渡す ULONG 値です。 セグメント化された大きなパケットから作成された最後のパケットのみに、MSS ユーザー データ未満のバイト数が含まれている必要があります。 セグメント化されたパケットから生成された他のすべてのパケットには、MSS ユーザー データ バイトが含まれている必要があります。 この規則に従わない場合、不要な追加パケットの作成と送信によってパフォーマンスが低下する可能性があります。
大きな TCP パケットから派生したセグメント化パケットの数は、ミニポート ドライバーが指定する MinSegmentCount
値以上である必要があります。 MinSegmentCount
値の詳細については、「NIC の LSOv1 TCP-Packet-Segmentation 機能 と NIC の LSOv2 TCP-Packet-Segmentation 機能の報告」を参照してください。
バージョンに関係なく、LSO 対応ミニポート ドライバーの IP ヘッダーと TCP ヘッダーの処理には、以下の前提条件と制限が適用されます。
TCP/IP トランスポートがオフロードした大きな TCP パケットの IP ヘッダーの MF ビットはセットされず、IP ヘッダーのフラグメント オフセットは 0 になります。
URG、RST、および SYN フラグは、大きな TCP パケットの TCP ヘッダーでは設定されず、TCP ヘッダー内の緊急オフセット(ポインター)は 0 になります。
大きなパケットの TCP ヘッダーの FIN ビットが設定されている場合、ミニポート ドライバーは、大きな TCP パケットから作成される最後のパケットの TCP ヘッダーにこのビットを設定する必要があります。
大きな TCP パケットの TCP ヘッダーの PSH ビットが設定されている場合、ミニポート ドライバーは、大きな TCP パケットから作成される最後のパケットの TCP ヘッダーにこのビットを設定する必要があります。
大きな TCP パケットの TCP ヘッダーの CWR ビットが設定されている場合、ミニポート ドライバーは、大きな TCP パケットから作成される最初のパケットの TCP ヘッダーにこのビットを設定する必要があります。 ミニポート ドライバーは、大きな TCP パケットから作成する最後のパケットの TCP ヘッダーにこのビットを設定することもできますが、これはあまり望ましくありません。
大きな TCP パケットに IP オプションまたは TCP オプション (またはその両方) が含まれている場合、ミニポート ドライバーは、大きな TCP パケットから派生した各パケットに、これらのオプションを変更せずにコピーします。 具体的には、NIC はタイム スタンプ オプションを増分しません。
すべてのパケット ヘッダー (イーサネット、IP、TCP) は、パケットの最初の MDL に含まれます。 ヘッダーは複数の MDL に分割されません。
ヒント
この前提条件は、LSO が有効な場合に有効です。 そうでないと、LSO が有効になっていない場合、ミニポート ドライバーは、IP ヘッダーがイーサネット ヘッダーと同じ MDL 内にあることを想定できません。
ミニポート ドライバーは、TCP/IP トランスポートから NET_BUFFER_LIST 構造体を受信する順序で NET_BUFFER_LIST 構造体のパケットを送信する必要があります。
大きな TCP パケットを処理する場合、ミニポート アダプターは、パケットをセグメント化し、大きな TCP パケットから派生したパケットに MAC、IP、TCP ヘッダーを付加することだけを担当します。 TCP/IP トランスポートは、他のすべてのタスク (リモート ホストの受信ウィンドウ サイズに基づいて送信ウィンドウ のサイズを調整するなど) を実行します。
大きなパケットの送信操作を (NdisMSendNetBufferListsComplete または NdisMCoSendNetBufferListsComplete などにより) 完了する前に、ミニポート ドライバーは、大きな TCP パケットから作成されたすべてのパケットで正常に送信された TCP ユーザー データ バイトの合計数を NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO 値 (大きな送信オフロードの場合は NET_BUFFER_LIST 情報) に書き込みます。
以前の LSO 要件に加えて、LSOv2 対応ミニポート ドライバーには以下の要件があります:
IPv4 か IPv6、もしくは IPv4 と IPv6 の両方をサポートします。
ネットワーク インターフェイス カード (NIC) によって作成される各セグメント パケットで、大きなパケットからの IPv4 オプションの複製をサポートします。
各 TCP セグメント パケットで、大きな TCP パケットからの IPv6 拡張ヘッダーの複製をサポートします。
ミニポート ドライバーが作成する各 TCP セグメント パケットの TCP オプションの複製をサポートします。
NET_BUFFER_LIST 構造体の IP ヘッダーと TCP ヘッダーをテンプレートとして使用して、セグメント化された各パケットの TCP/IP ヘッダーを作成します。
IP 識別 (IP ID) 値の範囲は、0x0000 から 0x7FFF です。 (0x8000 から 0xFFFF までの範囲は、TCP チムニー オフロード対応デバイス用に予約されています) たとえば、テンプレート IP ヘッダーが 0x7FFE の識別フィールド値で始まる場合、最初の TCP セグメント パケットの IP ID 値は 0x7FFE、次に 0x7FFF、0x0000、0x0001 と続く必要があります。
NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO の TcpHeaderOffset メンバーのバイト オフセットを使用して、パケットの先頭バイトから TCP ヘッダーの位置を決定します。
各 LSOv2 の NET_BUFFER_LIST 構造体に関連付けられた NET_BUFFER 構造体の数を 1 に制限します。
Note
これは、LSOv2 対応ミニポート ドライバーの新しい要件です。 LSOv1 ミニポート ドライバーでは、この規則は明示的に適用されませんが、推奨されます。
NET_BUFFER_LIST
構造体の最初のNET_BUFFER
構造体の長さからパケットの合計長を決定します。 これは、LSOv1 のメソッド ドライバーとは異なります。TCP オプション、IP オプション、および IP 拡張機能ヘッダーをサポートします。
送信操作が完了すると、ミニポート ドライバーは、NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO 構造体の
LsoV2TransmitComplete.Reserved
メンバーを 0 に、そしてLsoV2TransmitComplete.Type
メンバーをNDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE
に設定する必要があります。