UDP 受信セグメント結合オフロード (URO)
Windows 11 バージョン 24H2 以降では、UDP 受信セグメント結合オフロード (URO) により、ネットワーク インターフェイス カード (NIC) が UDP 受信セグメントを結合できるようになりました。 NIC は、一連のルールに一致する同じフローの UDP データグラムを論理的に連続したバッファに結合することができます。 これらの結合されたデータグラムは、1 つの大きなパケットとして Windows ネットワーク スタックに示されます。
UDP データグラムを結合すると、高帯域幅フローでパケットを処理するための CPU コストが削減され、スループットが向上し、バイトあたりのサイクル数が減少します。
次のセクションでは、UDP パケットを結合するためのルールと、URO ミニポート ドライバーの作成方法について説明します。
UDPパケットを結合するためのルール
URO 結合は、次のすべての条件を満たすパケットに対してのみ試行できます。
- IpHeader.Version はすべてのパケットで同一です。
- IpHeader.SourceAddress と IpHeader.DestinationAddress はすべてのパケットで同一です。
- UdpHeader.SourcePort と UdpHeader.DestinationPort はすべてのパケットで同一です。
- UdpHeader.Length は、最後のパケットを除くすべてのパケットで同一ですが、最後のパケットは短くなる場合があります。
- UdpHeader.Length はゼロ以外である必要があります。
- UdpHeader.Checksum がゼロ以外の場合、すべてのパケットで正確である必要があります。 つまり、受信チェックサムオフロードではパケットを検証する必要があるということです。
- レイヤー2ヘッダーはすべてのパケットで同一である必要があります。
パケットが IPv4 の場合、次の基準も満たす必要があります。
- すべてのパケットに対して IPv4Header.Protocol == 17 (UDP) です。
- EthernetHeader.EtherType == すべてのパケットに対して 0x0800 です。
- 受信したパケットの IPv4Header.HeaderChecksum は正確でなければなりません。 つまり、受信チェックサムオフロードではヘッダーを検証する必要があるということです。
- すべてのパケットに対して IPv4Header.HeaderLength == 5 (IPv4 オプション ヘッダーなし)。
- IPv4Header.ToSはすべてのパケットで同一です。
- IPv4Header.ECNはすべてのパケットで同一です。
- IPv4Header.DontFragment はすべてのパケットで同一です。
- IPv4Header.TTLはすべてのパケットに対して同一です。
- すべてのパケットで、IPv4Header.TotalLength == UdpHeader.Length + length(IPv4Header) です。
パケットが IPv6 の場合、次の基準も満たす必要があります。
- IPv6Header.NextHeader == すべてのパケット(拡張ヘッダーなし)の 17 (UDP)。
- すべてのパケットで、EthernetHeader.EtherType == 0x86dd (IPv6) です。
- IPv6Header.TrafficClass と IPv6Header.ECN はすべてのパケットに対して同一です。
- IPv6Header.FlowLabel はすべてのパケットで同一です。
- IPv6Header.HopLimit はすべてのパケットに対して同一です。
- すべてのパケットのIPv6Header.PayloadLength == UdpHeader.Length。
UROパケット構造
結果として得られる単一結合ユニット (SCU) には、単一の IP ヘッダーと UDP ヘッダーがあり、その後に連結されたすべての結合データグラムの UDP ペイロードが続く必要があります。
URO 指示では、IPv4Header.TotalLength フィールドを SCU の合計長に設定するか、IPv6Header.PayloadLength フィールドを UDP ペイロードの長さに設定し、UdpHeader.Length フィールドを結合されたペイロードの長さに設定する必要があります。
結合されたデータグラムにレイヤー 2 (L2) ヘッダーが存在する場合、SCU には有効な L2 ヘッダーが含まれている必要があります。 SCU の L2 ヘッダーは、結合されたデータグラムの L2 ヘッダーに似ている必要があります。
チェックサムの検証と表示
URO 通知では、IPv4Header.HeaderChecksum フィールドと UdpHeader.Checksum フィールドをゼロに設定し、IPv4 および UDP チェックサムの成功を示すチェックサム オフロード アウトオブバンド情報を SCU に入力する必要があります。
結合されるすべての条件に一致するが、チェックサム検証に失敗したパケットは、個別に示される必要があります。 その後に受信されたパケットは、それ以前に受信されたパケットと結合してはなりません。
たとえば、パケット 1、2、3、4、5 が同じフローから受信されたが、パケット 3 がチェックサム検証に失敗したとします。 パケット 1 と 2 は結合でき、パケット 4 と 5 も結合できますが、パケット 3 はどちらの SCU とも結合できません。 パケット 1 と 2 は、パケット 4 と 5 と結合してはなりません。 パケット 2 は SCU 内の最後のパケットであり、パケット 4 は新しい SCU を開始します。 さらに、パケット 1 と 2 を含む SCU はパケット 3 を示す前に示す必要があり、パケット 3 はパケット 4 と 5 を含む SCU を示す前に示す必要があります。
パケットの合体とフローの分離
ハードウェアとメモリが許す限り、複数のフローからのパケットを並列に結合できます。 異なるフローのパケットを結合してはなりません。
インターリーブされた複数の受信からのパケットは、それぞれのフローに分離され、結合される場合があります。 たとえば、フロー A、B、C があり、パケットが A、A、B、C、B、A の順序で到着した場合、A フローのパケットは AAA に統合され、B フローのパケットは BB に統合される可能性がありますが、C フローのパケットは通常どおりに示されるか、フロー C の保留中の SCU と統合される可能性があります。
特定のフロー内のパケットは、相互に順序を変更してはなりません。 たとえば、A フローからのパケットは、その間に受信された B フローおよび C フローからのパケットに関係なく、受信順に結合される必要があります。
UROを制御するためのINFキーワード
次のキーワードを使用すると、レジストリ キー設定で URO を有効/無効にすることができます。
*UdpRsc
列挙標準化 INF キーワードには、次の属性があります。
SubkeyName
INF ファイルで指定する必要があり、レジストリに表示されるキーワードの名前。
ParamDesc
SubkeyName に関連付けられている表示テキスト。
Value
リスト内の各オプションに関連付けられている列挙整数値。 この値は、NDI\params\ SubkeyName\Value に格納されます。
EnumDesc
メニューに表示される各値に関連付けられている表示テキスト。
既定値
このメニューの既定値。
SubkeyName | ParamDesc | Value | EnumDesc |
---|---|---|---|
*UdpRsc | URO | 0 | 無効 |
1 (既定値) | Enabled |
列挙キーワードの使用について詳しくは、「列挙キーワード」をご覧ください。
UROミニポートドライバーを書く
NDIS 6.89 以降では、URO の NDIS インターフェイスにより、TCP/IP と NDIS ミニポート ドライバー間の通信が容易になります。
URO機能のレポート
ミニポート ドライバーは、NDIS_OFFLOAD 構造体の UdpRsc メンバーで URO のサポートをアドバタイズし、これを NdisMSetMiniportAttributes 関数に渡します。
URO 機能のクエリ
ミニポート ドライバーが URO をサポートしているかどうかを確認するには、NDIS ドライバーおよびその他のアプリケーションで OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES OID を照会し、NDIS_OFFLOAD 構造を返します。
URO の状態を照会する
現在の URO 状態を確認するために、NDIS ドライバーおよびその他のアプリケーションは、OID_TCP_OFFLOAD_CURRENT_CONFIG OID 要求を照会できます。 NDIS はこの OID を処理し、ミニポートに渡しません。
URO状態の変更
URO は、OID_TCP_OFFLOAD_PARAMETERS OID 要求を発行することによって有効または無効にできます。 この OID は、NDIS_OFFLOAD_PARAMETERS 構造を使用します。 この構造体では、UdpRsc.Enabled メンバーは次の値を持つことができます。
Value | 意味 |
---|---|
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_NO_CHANGE 0 |
ミニポート ドライバーは現在の設定を変更しません。 |
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_DISABLED 1 |
URO は無効です。 |
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_ENABLED 2 |
URO は有効です。 |
ドライバーが NDIS_OFFLOAD_PARAMETERS_UDP_RSC_DISABLED
フラグが設定された OID_TCP_OFFLOAD_PARAMETERS OID 要求を処理する場合、NIC は、既存の結合セグメントと未処理の URO 表示がすべて示されるまで、要求の完了を待機する必要があります。 これにより、NDIS コンポーネント間で URO の有効化/無効化イベントが同期されます。
ミニポート ドライバーは、OID_TCP_OFFLOAD_PARAMETERS OID 要求を処理した後、更新されたオフロード状態を含む NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG ステータス表示を発行する必要があります。
NDIS_OFFLOAD_PARAMETERS の NDIS_OFFLOAD_PARAMETERS_SKIP_REGISTRY_UPDATE
フラグを使用すると、URO を実行時のみ無効にすることができます。 このフラグを使用して行われた変更はレジストリに保存されません。
NDIS 6.89 以降での URO のオプトアウト
NDIS 6.89 以降をターゲットとするドライバーは、URO パケットを理解し、適切に処理する必要があります。 URO をオプトアウトするには:
- 軽量フィルター (LWF) ドライバーは、NDIS_FILTER_DRIVER_CHARACTERISTICS 構造に
NDIS_FILTER_DRIVER_UDP_RSC_NOT_SUPPORTED
フラグを設定します。 - プロトコル ドライバーは、NDIS_PROTOCOL_DRIVER_CHARACTERISTICS 構造に
NDIS_PROTOCOL_DRIVER_UDP_RSC_NOT_SUPPORTED
フラグを設定します。
このアプローチにより、URO に精通していないコンポーネントが URO NBL を受信しないようにすることができます。 URO をサポートしていない LWF またはプロトコル ドライバーが存在する場合、NDIS はバインド中にミニポート上の URO を無効にします。
URO ドライバーのプログラミングに関する考慮事項
URO 対応ミニポート ドライバーを実装する場合は、次の問題を考慮してください。
Winsock URO API
Winsock URO API の詳細については、IPPROTO_UDP ソケット オプション を参照してください。 UDP_RECV_MAX_COALESCED_SIZEおよびUDP_COALESCED_INFOの情報を参照してください。
Windows TCP/IP スタックの更新
Microsoft TCP/IP トランスポートは、構成によって禁止されていない限り、NDIS とのバインド時に URO を有効にします。
WFP コールアウトは、FWPS_CALLOUT2 の FWP_CALLOUT_FLAG_ALLOW_URO
を使用して、URO のサポートをアドバタイズできます。 URO に敏感なレイヤーに互換性のない WFP コールアウトが登録されている場合、コールアウトが登録されている間、OS は URO を無効にします。
ソケットが、最大結合サイズがハードウェア オフロード サイズ以上である URO にオプトインする場合、スタックはハードウェアから NBL を変更せずにソケットに配信します。 ソケットが小さい最大結合サイズを選択した場合、スタックは結合受信をソケットの小さいサイズに分割します。
ソケットが URO を選択しない場合、スタックはそのソケットの受信を再セグメント化します。 ハードウェア URO がない場合でも、既存のソフトウェア URO 機能は引き続き利用できます。