大きな 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 構造体の 型 メンバーを使用して、ドライバー スタックが 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 情報へのアクセス」を参照してください。
ただし、ミニポートがミニポートの LSO 機能をオフにする OID_TCP_OFFLOAD_PARAMETERS を受け取った場合、ミニポートが 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-Packet-Segmentation 機能の の報告と、NIC の LSOv2 TCP-Packet-Segmentation 機能の報告 を参照してください。
パケットはループバック パケットではありません。
パケットはトンネルを介して送信されません。
セグメント化のために大きな 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 値を最大セグメント サイズに設定します。
LSOv1 の場合、パケットの IP ヘッダーの
Total Length
フィールドに、大きな TCP パケットの合計長を書き込みます。 合計長には、IP ヘッダーの長さ、IP オプションが存在する場合の IP オプションの長さ、TCP ヘッダーの長さ、存在する場合の TCP オプションの長さ、および TCP ペイロードの長さが含まれます。 LSOv2 の場合、パケットの IP ヘッダーのTotal Length
フィールドを 0 に設定します。 ミニポート ドライバーは、NET_BUFFER_LIST 構造体の最初の NET_BUFFER 構造体の長さからパケットの長さを決定する必要があります。TCP 擬似ヘッダー 1 の補数の合計 を計算し、この合計を TCP ヘッダーの
Checksum
フィールドに書き込みます。 TCP/IP トランスポートは、擬似ヘッダーの次のフィールドに対する 1 の補数の合計を計算します。Source IP Address
、Destination IP Address
、およびProtocol
。 TCP/IP トランスポートによって提供される擬似ヘッダーの補数の合計により、NIC は、IP ヘッダーを調べることなく、NIC が大きな 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 セグメントの TCP 長さをカバーするように、TCP/IP トランスポートによって提供された擬似ヘッダー チェックサムを拡張します。TCP ヘッダーの
Sequence Number
フィールドに正しいシーケンス番号を書き込みます。 シーケンス番号は、TCP ペイロードの最初のバイトを識別します。
ミニポート ドライバーは、MiniportSendNetBufferLists または MiniportCoSendNetBufferLists 関数内で NET_BUFFER_LIST 構造体を取得した後、TCP/IP トランスポートによって書き込まれた MSS 値を取得するために、TcpLargeSendNetBufferListInfo
の _Id
で NET_BUFFER_LIST_INFO マクロを呼び出すことができます。
ミニポート ドライバーは、パケットの IP ヘッダーから大きなパケットの合計の長さを取得し、MSS 値を使用して、大きな TCP パケットをより小さなパケットに分割します。 小さい各パケットには、MSS 以下のユーザー データ バイトが含まれます。 セグメント化された大きなパケットから作成された最後のパケットにのみ、MSS ユーザー データ バイト未満を含める必要があります。 セグメント化されたパケットから作成された他のすべてのパケットには、MSS ユーザー データ バイトが含まれている必要があります。 この規則に従わないと、不要な余分なパケットの作成と送信によってパフォーマンスが低下する可能性があります。
ミニポート ドライバーは、大きなパケットから派生した各セグメントに MAC、IP、および TCP ヘッダーを添付します。 ミニポート ドライバーは、これらの派生パケットの IP チェックサムと TCP チェックサムを計算する必要があります。 大きな TCP パケットから派生した各パケットの TCP チェックサムを計算するために、NIC は TCP チェックサムの可変部分 (TCP ヘッダーと TCP ペイロード) を計算し、TCP/IP トランスポートによって計算される擬似ヘッダーの補数の合計にこのチェックサムを追加し、チェックサムの 16 ビットの補数を計算します。 このようなチェックサムの計算の詳細については、RFC 793 および RFC 1122 を参照してください。
次の図は、大きなパケットのセグメント化を示しています。
大きな TCP パケット内の TCP ユーザー データの長さは、ミニポート ドライバーが MaxOffLoadSize
値に割り当てる値以下にする必要があります。 MaxOffLoadSize
値の詳細については、「NIC の LSOv1 TCP-Packet-Segmentation 機能 と NIC の LSOv2 TCP-Packet-Segmentation 機能の報告」を参照してください。
ドライバーが MaxOffLoadSize
値の変更を示す状態表示を発行した後、前の MaxOffLoadSize
値を使用する LSO 送信要求を受け取った場合、ドライバーはクラッシュしないようにする必要があります。 代わりに、ドライバーは送信要求を失敗させることができます。
MaxOffLoadSize
値の変更を報告する状態表示を個別に発行する中間ドライバーは、ステータス表示を発行していない基になるミニポート アダプターが、ミニポート アダプターが報告した MaxOffLoadSize
値よりも大きいパケットを取得しないようにする必要があります。
LSO サービスをオフにする OID_TCP_OFFLOAD_PARAMETERS に応答するミニポート中間ドライバーは、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 ヘッダーでこのビットを設定する必要があります。
PSH 大きな TCP パケットの TCP ヘッダー内のビットが設定されている場合、ミニポート ドライバーは、大きな TCP パケットから作成する最後のパケットの TCP ヘッダーでこのビットを設定する必要があります。
CWR 大きな TCP パケットの TCP ヘッダーにビットが設定されている場合、ミニポート ドライバーは、大きな 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 ヘッダーを生成します。
0x0000 から 0x7FFFまでの範囲で IP 識別 (IP ID) 値を使用します。 (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 に制限します。
手記
これは、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
する必要があります。