UDP セグメント化オフロード (USO)
Windows 10 バージョン 2004 以降でサポートされている UDP セグメント化オフロード (USO) は、ネットワーク インターフェイス カード (NIC) がネットワーク メディアの最大伝送単位 (MTU) より大きい UDP データグラムのセグメント化をオフロードできるようにする機能です。 これにより、Windows はパケットごとの TCP/IP 処理に関連する CPU 使用率を下げます。 USO の要件は、TCP トランスポート プロトコルの LSOv2 に似ています。
USO の要件
このセクションでは、主に NDIS プロトコルとミニポート ドライバーについて説明します。 NDIS ライトウェイト フィルター ドライバー (LWF) は、パケットを変更または送信するときにプロトコル ドライバーの要件に従う必要があります。また、その FilterSendNetBufferLists ハンドラーに提供されるすべてのパケットはプロトコル ドライバーの要件を満たしていると想定することもできます。
ミニポート ドライバーは、ネットワーク メディアの MTU より大きな UDP パケットのセグメント化をオフロードできます。 大きな UDP パケットのセグメント化をサポートする NIC でも、次のことができる必要があります。
- IPv4 オプションを含む送信パケットの IP チェックサムを計算する
- 送信パケットの UDP チェックサムを計算する
USO をサポートするミニポート ドライバーは、 NET_BUFFER_LIST 構造体の帯域外 (OOB) 情報からオフロードのタイプを決定する必要があります。 NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO 構造体の値が 0 以外の場合、ミニポート ドライバーは USO を実行する必要があります。 USO OOB データを含む NET_BUFFER_LIST には、単一の NET_BUFFER 構造も含まれます。 ただし、ミニポート ドライバーが USO をオフにする OID_TCP_OFFLOAD_PARAMETERS を受け取った場合は、ミニポート ドライバーが OID を正常に完了した後、USO OOB フィールドが設定されている NET_BUFFER_LIST を返す必要があります。
TCP/IP トランスポートは、次の条件を満たす UDP パケットのみをオフロードします。
- パケットは UDP パケットです。
- パケット長は、最大セグメント サイズ (MSS) * (MinSegmentCount - 1) より大きい必要があります。
- ミニポート ドライバーが SubMssFinalSegmentSupported 機能を設定 していない場合、トランスポートによってオフロードされる大きな UDP パケット は、それぞれ Length % MSS == 0 を必要とします。 つまり、大きなパケットは N 個のパケットに分割可能であり、各パケット セグメントには正確に MSS ユーザー バイトが含まれます。 ミニポート ドライバーが SubMssFinalSegmentSupported 機能を設定する場合には、トランスポートのこのパケット長分割可能条件は適用されません。 つまり、最終セグメントは MSS より小さくなる場合があります。
- パケットはループバック パケットではありません。
- TCP/IP トランスポートがオフロードした大きな UDP パケットの IP ヘッダーの MF ビットはセットされず、IP ヘッダーの Fragment Offset は 0 になります。
- アプリケーションは、UDP_SEND_MSG_SIZE/WSASetUdpSendMessageSize を指定しています。
セグメント化のために大きな UDP パケットをオフロードする前に、TCP/IP トランスポートは次の処理を行います。
- NET_BUFFER_LIST 構造体に関連付けられている大きなパケットのセグメント化情報を更新します。 この情報は、 NET_BUFFER_LIST 構造体の OOB 情報の一部である NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO 構造体です。 TCP/IP トランスポートは、MSS 値を必要な MSS に設定します。
- UDP 擬似ヘッダーの 1 の補数の合計を計算し、この合計を UDP ヘッダーの Checksum フィールドに書き込みます。 TCP/IP トランスポートは、擬似ヘッダーの送信元 IP アドレス、宛先 IP アドレス、プロトコルの各フィールドの 1 の補数の合計を計算します。
TCP/IP トランスポートが提供する擬似ヘッダーの 1 の補数の合計により、NIC は IP ヘッダーを調べることなく、大きな UDP パケットから派生する各パケットの実際の UDP チェックサムの計算を早期に開始できます。
RFC 768 および RFC 2460 では、擬似ヘッダーは送信元 IP アドレス、宛先 IP アドレス、プロトコル、および UDP 長 (UDP ヘッダーの長さに UDP ペイロードの長さを加えた長さ、擬似ヘッダーの長さは含まない) で計算されると規定していることに注意してください。 ただし、基になるミニポート ドライバーと NIC は、TCP/IP トランスポートから渡される大きなパケットから UDP データグラムを生成するため、トランスポートは各 UDP データグラムの UDP ペイロードのサイズを認識しておらず、擬似ヘッダーの計算に UDP の長さを含めることはできません。 代わりに、次のセクションで説明するように、NIC は、TCP/IP トランスポートから渡された擬似ヘッダー チェックサムを拡張して、生成された各 UDP データグラムの UDP の長さを補います。
重要
TCP/IP トランスポートが提供する UDP ヘッダー チェックサム フィールドが 0 の場合、NIC は UDP チェックサム 計算を実行しないでください。
USO を使用したパケットの送信
ミニポート ドライバーは、その MiniportSendNetBufferLists コールバック関数で NET_BUFFER_LIST を取得した後、 NET_BUFFER_LIST_INFO マクロを UdpSegmentationOffloadInfo の _Id で呼び出し、MSS 値と IP プロトコルを取得できます。
ミニポート ドライバーは、最初の NET_BUFFER 構造体の長さから大きなパケットの全長を取得し、 MSS 値を使用して大きな UDP パケットを小さな UDP パケットに分割します。 小さいパケットそれぞれには、 MSS 以下のユーザー データ バイトが含まれます。 セグメント化された大きなパケットから生成された最後のパケットのみが、 MSS ユーザー データ バイト未満である可能性があることに注意してください。 セグメント化されたパケットから生成された他のすべてのパケットには、 MSS ユーザー データ バイトが含まれている必要があります。 ミニポート ドライバーがこの規則に準拠していない場合、UDP データグラムは正しく配信されません。 ミニポート ドライバーが SubMssFinalSegmentSupported 機能を設定していない場合、パケットの長さは MSS で分割され、セグメント化された各パケットには MSS ユーザー バイトが含まれます。
ミニポート ドライバーは、大きなパケットから派生した各セグメントに MAC、IP、UDP ヘッダーを付加します。 ミニポート ドライバーは、これらの派生パケットの IP と UDP チェックサムを計算する必要があります。 大きな UDP パケットから派生した各パケットの UDP チェックサムを計算するために、NIC は UDP チェックサム (UDP ヘッダーと UDP ペイロード) の可変部分を計算し、TCP/IP トランスポートが計算した擬似ヘッダーの 1 の補数の合計にこのチェックサム加えてから、チェックサム の 16 ビットの 1 の補数を計算します。 このようなチェックサムの計算の詳細については、 RFC 768 および RFC 2460を参照してください。
大きな UDP パケット内の UDP ユーザー データの長さは、ミニポート ドライバーが MaxOffLoadSize 値に割り当てる値以下である必要があります。
ドライバーが MaxOffLoadSize 値の変更を示す状態表示を発行した後、ドライバーは以前の MaxOffLoadSize 値を使用する LSO 送信要求を受信しても、バグ チェックを発生させてはなりません。 代わりに、ドライバーは送信要求を失敗させる必要があります。 ドライバー は、どのような理由 (サイズ、最小セグメント数、IP オプションなど) であっても、実行できない送信要求を失敗 させる必要があります。 ドライバーは、その機能に変更があった場合、できるだけ早く状態表示を送信する必要があります。
MaxOffLoadSize 値の変更を報告する状態表示を個別に発行する中間ドライバーは、状態表示を発行していない基になるミニポート アダプターが、ミニポート アダプターが報告した MaxOffLoadSize 値よりも大きいパケットを取得しないようにする必要があります。
USO サービスをオフにするために OID_TCP_OFFLOAD_PARAMETERS に応答するミニポート中間ドライバーは、USO 要求がミニポート ドライバーに到達する可能性のあるわずかな時間に備える必要があります。
大きな UDP パケットから派生したセグメンテーション パケットの数は、ミニポート ドライバーによって指定された MinSegmentCount 値以上である必要があります。
大きな UDP パケットを処理する場合、ミニポート ドライバーは、パケットをセグメント化し、大きな UDP パケットから派生したパケットに MAC、IP、UDP ヘッダーを不可することにのみ責任があります。 ミニポートが少なくとも 1 つのセグメント化されたパケットの送信に失敗した場合、NBL は最終的にエラー状態で完了する必要があります。 ミニポートは後続のパケットを送信し続けることができますが、送信する必要はありません。 セグメント化されたすべてのパケットが送信されるか失敗するまで、NBL を NDIS に戻すことはできません。
USO 対応ミニポート ドライバーでは、次の操作も行う必要があります。
- IPv4 と IPv6 の両方をサポートします。
- NIC が生成するセグメント化パケットで、大きなパケットからの IPv4 オプションの複製をサポートします。
- NET_BUFFER_LIST 構造の IP ヘッダーと UDP ヘッダーをテンプレートとして使用して、セグメント化された各パケットの UDP ヘッダーと IP ヘッダーを生成します。
- IP 識別 (IP ID) 値の範囲は、 0x0000 から 0xFFFFです。 たとえば、テンプレート IP ヘッダーが 0xFFFE の識別フィールド値で始まる場合、最初の UDP データグラム パケットの値は 0xFFFE である必要があり、 0xFFFF、 0x0000、 0x0001 と続きます。
- 大きな UDP パケットに IP オプションが含まれている場合、ミニポート ドライバーは、大きな UDP パケットから派生した各パケットに、これらのオプションを変更せずにコピーします。
- NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO の UdpHeaderOffset メンバーのバイト オフセットを使用して、パケットの最初のバイトからの UDP ヘッダーの位置を決定します。
- セグメント化されたパケットに基づいて送信統計をインクリメントします。 たとえば、各パケット セグメントのイーサネット、IP、UDP ヘッダーのバイト数を含め、パケット数は 1 ではなく MSS サイズのセグメント数です。
- セグメント化された各データグラム サイズに基づいて、UDP の合計長フィールドと IP 長フィールドを設定します。
NDIS インターフェイスの変更
このセクションでは、ミニポート ドライバーによって公開される USO 機能をホスト TCP/IP ドライバー スタック利用できるようにする NDIS 6.83 の変更内容について説明します。
NDIS とミニポート ドライバーは、次のことを行います。
- NIC が USO 機能をサポートしていることをアドバタイズする
- USO を有効または無効にする
- 現在の USO 機能の状態を取得する
USO 機能のアドバタイズ
ミニポート ドライバーは、 NdisMSetMiniportAttributes のパラメーターで渡される NDIS_OFFLOAD 構造体の UdpSegmentation フィールドへの入力によって USO 機能をアドバタイズします。 NDIS_OFFLOAD 構造体の Header.Revision フィールドを NDIS_OFFLOAD_REVISION_6 に、 Header.Size フィールドを NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_6 にそれぞれ設定する必要があります。
USO 状態の照会
現在の USO 状態は、 OID_TCP_OFFLOAD_CURRENT_CONFIG を使用して照会できます。 NDIS は、この OID を処理し、ミニポート ドライバーには渡しません。
USO 状態の変更
USO は、 OID_TCP_OFFLOAD_PARAMETERS を使用して有効または無効にできます。 OID を処理したミニポート ドライバーは、更新されたオフロード状態で NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG 状態を送信する必要があります。
USO のキーワード
USO リスト キーワードは次のとおりです。
- *UsoIPv4
- *UsoIPv6
これらの値は、特定の IP プロトコルで USO が有効か無効かを示します。 USO 設定は、 NDIS_TCP_IP_CHECKSUM_OFFLOAD 構成に依存しません。 たとえば、 *UDPChecksumOffloadIPv4 を無効にしても、 *UsoIPv4 が暗黙のうちに無効にはなりません。
サブキー名 | パラメーターの説明 | Value | 列挙型の説明 |
---|---|---|---|
*UsoIPv4 | UDP セグメント化オフロード (IPv4) | 0 | 無効 |
1 | Enabled | ||
*UsoIPv6 | UDP セグメント化オフロード (IPV6) | 0 | 無効 |
1 | Enabled |