UDP 接收區段合併卸載 (URO)
從 Windows 11 版本 24H2 開始,UDP 接收區段聯合卸載 (URO) 可讓網路適配器 (NIC) 聯合 UDP 接收區段。 NIC 可以將符合一組規則的相同資料流中的 UDP 封包合併成邏輯上連續的緩衝區。 然後,這些合併的數據報會以單一大型封包的形式向 Windows 網路堆疊表示。
合併 UDP 數據報可降低在高頻寬流量中處理封包的 CPU 成本,進而提高吞吐量並降低每個位元組的處理循環次數。
下列各節說明聯合 UDP 封包的規則,以及如何撰寫 URO 迷你埠驅動程式。
- 聯合 UDP 封包 的
規則 - 撰寫 URO 迷你埠驅動程式
- URO 驅動程式的程式設計考慮
UDP封包合併的規則
URO 結合只能在符合下列所有準則的封包上才能夠嘗試:
- 所有封包的
IpHeader.Version
都相同。 - 所有封包的
IpHeader.SourceAddress
和IpHeader.DestinationAddress
都相同。 - 所有封包的
UdpHeader.SourcePort
和UdpHeader.DestinationPort
都相同。 - 所有封包的
UdpHeader.Length
都相同,除了最後一個封包,其可能較小。 -
UdpHeader.Length
必須是非零。 -
UdpHeader.Checksum
,如果不是零,則必須在所有封包上都正確。 這表示接收總和檢查碼卸除必須驗證封包。 - 所有封包的
Layer 2 headers
必須相同。
如果封包是 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
* + 所有封包的長度 (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
欄位設定為零,並在 SCU 上填寫校驗和卸載的帶外資訊,表示 IPv4 和 UDP 校驗和驗證成功。
符合合併之所有條件但總和檢查碼驗證失敗的封包必須個別指出。 接收後的封包不得與接收前的封包合併。
例如,假設封包 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 | 價值 | EnumDesc |
---|---|---|---|
*UdpRsc |
URO | 0 | 禁用 |
1 (預設值) | 啟用 |
如需使用列舉關鍵詞的詳細資訊,請參閱 列舉關鍵詞。
撰寫 URO 迷你埠驅動程式
從 NDIS 6.89 開始,URO 的 NDIS 介面有助於 TCP/IP 與 NDIS 迷你埠驅動程式之間的通訊。
報告 URO 功能
迷你埠驅動程式會在 NDIS_OFFLOAD 結構 UdpRsc
成員中公告 URO 的支援,其會傳遞給 NdisMSetMiniportAttributes 函式。
查詢URO功能
若要檢查迷你埠驅動程式是否支援 URO,NDIS 驅動程式和其他應用程式可以查詢 OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES OID,該 OID 會傳回 NDIS_OFFLOAD
結構。
查詢URO狀態
若要判斷目前的 URO 狀態,NDIS 驅動程式和其他應用程式可以查詢 OID_TCP_OFFLOAD_CURRENT_CONFIG OID 要求。 NDIS 會處理此 OID,且不會將其傳遞至迷你埠。
變更URO狀態
您可以發出 OID_TCP_OFFLOAD_PARAMETERS OID 要求來啟用或停用 URO。 此 OID 使用 NDIS_OFFLOAD_PARAMETERS 結構。 在此結構中,UdpRsc.Enabled
成員可以有下列值:
價值 | 意義 |
---|---|
NDIS卸載參數_UDP_RSC_未變更 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,除非配置阻止它這樣做。
糧食計劃署的圖說文字可以在 FWPS_CALLOUT2 中使用 FWP_CALLOUT_FLAG_ALLOW_URO
來宣傳他們對 URO 的支援。 如果在 URO 敏感層上註冊不相容的 WFP 呼出,則 OS 會在該呼出註冊期間停用 URO。
如果套接字選擇加入URO,且合併最大大小大於或等於硬體卸載大小,那麼堆疊會將來自硬體的NBLs原封不動地傳遞到套接字。 如果套接字選擇較小的合併最大大小,堆疊會將合併的接收數據分成適合該套接字的較小大小。
如果套接字未選擇加入URO(接收重組選項),則協議棧會重新分段該套接字的接收。 如果沒有硬體 URO,現有的軟體 URO 功能仍可繼續使用。