UDP 接收區段聯合卸載 (URO)
從 Windows 11 版本 24H2 開始,UDP 接收區段聯合卸載 (URO) 可讓網路適配器 (NIC) 聯合 UDP 接收區段。 NIC 可以從符合一組規則的相同流程,將 UDP 數據報合併成邏輯連續緩衝區。 然後,這些合併的數據報會以單一大型封包的形式向 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 字段設定為零,並填寫 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,而且必須在包含封包 4 和 5 的 SCU 之前指出封包 3。
封包聯合和流程分離
多個流程的封包可能會平行合併,因為硬體和記憶體允許。 來自不同流程的封包不得合併在一起。
從多個接收交錯的封包可以分開,並結合其各自的流程。 例如,假設流量 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 相關聯的顯示文字。
值
與清單中每個選項相關聯的列舉整數值。 此值會儲存在 NDI\params\ SubkeyName\值中。
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驅動程式和其他應用程式可以查詢傳回NDIS_OFFLOAD結構的 OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES OID。
查詢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_OFFLOAD_PARAMETERS_UDP_RSC_NO_CHANGE 0 |
迷你埠驅動程序不應該變更目前的設定。 |
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_DISABLED 1 |
URO 已停用。 |
NDIS_OFFLOAD_PARAMETERS_UDP_RSC_ENABLED 2 |
已啟用URO。 |
當驅動程式處理 已設定旗標的 OID_TCP_OFFLOAD_PARAMETERS OID 要求 NDIS_OFFLOAD_PARAMETERS_UDP_RSC_DISABLED
時,NIC 必須等候完成要求,直到指出所有現有的聯合區段和未完成的 URO 指示為止。 這可確保跨 NDIS 元件同步處理 URO 啟用/停用事件。
迷你埠驅動程序處理 OID_TCP_OFFLOAD_PARAMETERS OID 要求之後,迷你埠驅動程式必須發出 NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG 狀態指示,並顯示更新的卸除狀態。
NDIS_OFFLOAD_PARAMETERS_SKIP_REGISTRY_UPDATE
NDIS_OFFLOAD_PARAMETERS中的旗標允許只停用 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_UDP_RSC_NOT_SUPPORTED
NDIS_PROTOCOL_DRIVER_CHARACTERISTICS 結構中設定旗標。
此方法可確保不熟悉URO的元件不會收到URO NBL。 如果 LWF 或不支援 URO 的通訊協定驅動程式存在,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 傳輸會在系結時啟用 URO 與 NDIS,除非設定可防止它這樣做。
糧食計劃署的圖說文字可以在FWPS_CALLOUT2中用來FWP_CALLOUT_FLAG_ALLOW_URO
宣傳他們對URO的支援。 如果在 URO 敏感層註冊不相容的 WFP 圖說文字,則操作系統會在註冊圖說時停用 URO。
如果套接字選擇加入URO,且大小上限大於或等於硬體卸除大小,則堆疊會將NCL從未修改的硬體傳遞到套接字。 如果套接字選擇加入較小的最大聯合大小,堆疊會將聯合接收分成較小的套接字大小。
如果套接字未選擇加入URO,則堆疊會重新分配該套接字的接收。 如果沒有硬體 URO,現有的軟體 URO 功能將繼續提供。