UDP 分割卸載 (USO)
Windows 10 版本 2004 和更新版本中支援的 UDP 分割卸除 (USO)是一項功能,可讓網路適配器 (NIC) 卸除大於網路媒體最大傳輸單位 (MTU) 的 UDP 數據報分割。 如此一來,Windows 會減少與每個封包 TCP/IP 處理相關聯的 CPU 使用率。 USO 的需求類似於 LSOv2,也就是 TCP 傳輸通訊協定。
USO 的需求
本節主要是指 NDIS 通訊協定和迷你埠驅動程式。 修改或傳送封包時,NDIS 輕量型篩選驅動程式 (LFS) 必須遵循通訊協定驅動程式需求,也可以假設提供給其 FilterSendNetBufferLists 處理程式的任何封包都符合通訊協定驅動程式需求。
迷你埠驅動程式可以卸除大於網路媒體 MTU 的大型 UDP 封包分割。 支援分割大型 UDP 封包的 NIC 也必須能夠執行下列動作:
- 計算包含 IPv4 選項之已傳送封包的 IP 總和檢查碼
- 計算已傳送封包的 UDP 總和檢查碼
支援 USO 的迷你埠驅動程式必須從NET_BUFFER_LIST結構的頻外 (OOB) 資訊判斷卸除類型。 如果NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO結構的值不是零,則迷你埠驅動程序必須執行 USO。 任何 包含 USO OOB 資料的NET_BUFFER_LIST 也都包含單 一NET_BUFFER 結構。 不過,在迷你埠驅動程式收到 OID_TCP_OFFLOAD_PARAMETERS 關閉 USO 的情況下,在迷你埠驅動程式成功完成 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 將會是零。
- 應用程式已指定 UDP_SEND_MSG_SIZE/WSASetUdpSendMessageSize。
卸除大型 UDP 封包以進行分割之前,TCP/IP 傳輸會執行下列動作:
- 更新與 相關聯的大型封包分割資訊 NET_BUFFER_LIST結構。 這項資訊是 NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO 結構,屬於 NET_BUFFER_LIST 結構的 OOB 資訊。 TCP/IP 傳輸會將 MSS 值設定為所需的 MSS。
- 計算 UDP 虛擬標頭的補碼總和,並將此總和 寫入 UDP 標頭的 Checksum 字段。 TCP/IP 傳輸會計算虛擬標題器中下列欄位的補碼加總:來源 IP 位址、目的地 IP 位址和通訊協定。
TCP/IP 傳輸所提供虛擬標頭的補碼加總,讓 NIC 在計算 NIC 衍生自大型 UDP 封包的每個封包的實際 UDP 總和時,早日開始計算 NIC 衍生自大型 UDP 封包的實際 UDP 總和,而不需要檢查 IP 標頭。
請注意, RFC 768 和 RFC 2460 規定虛擬標頭是透過來源 IP 位址、目的地 IP 位址、通訊協定和 UDP 長度計算的(UDP 標頭的長度加上 UDP 承載的長度,不包括虛擬標頭的長度)。 不過,由於基礎迷你埠驅動程式和 NIC 會從 TCP/IP 傳輸所傳遞的大型封包產生 UDP 數據報,因此傳輸不知道每個 UDP 數據報的 UDP 承載大小,因此無法在虛擬header 計算中包含 UDP 長度。 相反地,如下一節所述,NIC 會擴充 TCP/IP 傳輸所提供的虛擬頭檢查碼,以涵蓋每個產生的 UDP 數據報的 UDP 長度。
重要
如果 TCP/IP 傳輸所提供的 UDP 標頭總和檢查碼欄位為零,NIC 不應該執行 UDP 總和檢查碼計算。
使用USO傳送封包
迷你埠驅動程式在其 MiniportSendNetBufferLists 回呼函式中取得NET_BUFFER_LIST之後,可以使用 UdpSegmentationOffloadInfo 的_Id呼叫 NET_BUFFER_LIST_INFO 宏,以取得 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 傳輸所計算之虛擬標頭的補碼總和,然後計算總和檢查碼的 16 位補碼。 如需計算這類總和檢查碼的詳細資訊,請參閱 RFC 768 和 RFC 2460。
大型 UDP 封包中的 UDP 用戶數據長度必須小於或等於迷你埠驅動程式指派給 MaxOffLoadSize 值的值。
在驅動程式發出狀態指示以指出 MaxOffLoadSize 值的變更之後,驅動程式在收到使用先前 MaxOffLoadSize 值的 LSO 傳送要求時,不得造成錯誤檢查。 相反地,驅動程式必須失敗傳送要求。 驅動程式 必須 因為任何原因而無法執行的任何傳送要求失敗(包括大小、最社區段計數、IP 選項等等)。 如果驅動程式的功能變更,則必須儘快傳送狀態指示。
獨立發出狀態指示以報告 MaxOffLoadSize 值變更的中繼驅動程式,必須確保尚未發出狀態指示的基礎迷你埠適配卡不會取得任何大於迷你埠配接器所報告 MaxOffLoadSize 值的封包。
回應OID_TCP_OFFLOAD_PARAMETERS關閉 USO 服務的迷你埠中繼驅動程式,必須針對 USO 要求仍可連線到迷你埠驅動程式的小型時段做好準備。
衍生自大型 UDP 封包的分割封包數目必須等於或大於 迷你埠驅動程式所指定的 MinSegmentCount 值。
處理大型 UDP 封包時,迷你埠驅動程式只負責分割封包,並將 MAC、IP 和 UDP 標頭貼到衍生自大型 UDP 封包的封包。 如果迷你埠無法傳送至少一個區段封包,NBL 最終必須以失敗狀態完成。 迷你埠可以繼續傳送後續封包,但不需要這麼做。 NBL 無法完成回到 NDIS,直到所有分段封包都傳輸或失敗為止。
支援 USO 的迷你連接埠驅動程式也必須執行下列動作:
- 支援 IPv4 和 IPv6。
- 支援從 NIC 產生之每個區段封包中大型封包的 IPv4 選項複寫。
- 使用 NET_BUFFER_LIST 結構中的IP和UDP標頭作為範本,為每個區段封包產生UDP和IP標頭。
- 使用範圍 從 0x0000 到 0xFFFF的IP識別 (IP ID) 值。 例如,如果範本IP標頭以識別域值開頭為 0xFFFE,則第一個UDP數據報封包的值必須是0xFFFE,後面接著0xFFFF、0x0000、0x0001等等。
- 如果大型 UDP 封包包含 IP 選項,迷你埠驅動程式會將這些選項從大型 UDP 封包衍生的每個封包中複製。
- 使用 NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO UdpHeaderOffset 成員中的位元組位移來判斷 UDP 標頭的位置,從封包的第一個字節開始。
- 根據分段封包遞增傳輸統計數據。 例如,包含每個封包區段的乙太網路、IP 和 UDP 標頭位元組計數,而封包計數是 MSS 大小的區段數目,而不是 1。
- 根據每個分割的數據報大小,設定 UDP 總長度和 IP 長度字段。
NDIS 介面變更
本節說明 NDIS 6.83 中的變更,可讓主機 TCP/IP 驅動程式堆棧利用迷你埠驅動程序公開的 USO 功能。
NDIS 和迷你埠驅動程序會執行下列動作:
- 公告 NIC 支援 USO 功能
- 啟用或停用 USO
- 取得目前的 USO 功能狀態
廣告 USO 功能
迷你埠驅動程式會填入 NDIS_OFFLOAD 結構的 UdpSegmentation 欄位來公告 USO 功能,其會傳入 NdisMSetMiniportAttributes 的參數中。 NDIS_OFFLOAD 結構中的Header.Revision字段必須設定為 NDIS_OFFLOAD_REVISION_6,而且Header.Size字段必須設定為 NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_6。
查詢 USO 狀態
您可以使用 OID_TCP_OFFLOAD_CURRENT_CONFIG 查詢目前的 USO 狀態。 NDIS 會處理此 OID,且不會將其傳遞至迷你埠驅動程式。
變更 USO 狀態
您可以使用 OID_TCP_OFFLOAD_PARAMETERS 來啟用或停用 USO。 迷你埠驅動程序處理 OID 之後,它必須傳送 具有更新卸除狀態的NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG 狀態指示。
USO 關鍵詞
USO 列舉關鍵詞如下所示:
- *UsoIPv4
- *UsoIPv6
這些值描述是否為該特定IP通訊協定啟用或停用USO。 USO 設定不相依於 NDIS_TCP_IP_CHECKSUM_OFFLOAD 組態。 例如,停用 *UDPChecksumOffloadIPv4 並不會隱含停用 *UsoIPv4。
子機碼名稱 | 參數描述 | 值 | 列舉描述 |
---|---|---|---|
*UsoIPv4 | UDP 分割卸除 (IPv4) | 0 | 已停用 |
1 | 啟用 | ||
*UsoIPv6 | UDP 分割卸除 (IPV6) | 0 | 已停用 |
1 | 啟用 |