UDP Segmentation Offload (USO)
Mit dem Feature UDP Segmentation Offload (USO) in Windows 10, Version 2004 und höher können Netzwerkschnittstellenkarten (NICs) die Segmentierung von UDP-Datagrammen auslagern, die größer als die maximale Übertragungseinheit (MTU) des Netzwerkmediums sind. Dadurch reduziert Windows die CPU-Auslastung pro Paket bei der TCP/IP-Verarbeitung. Die Anforderungen für USO ähneln LSOv2, das für das TCP-Transportprotokoll bestimmt ist.
Anforderungen für USO
Dieser Abschnitt bezieht sich hauptsächlich auf NDIS-Protokoll- und Miniporttreiber. NDIS-LWF-Treiber (Lightweight Filter) müssen die Protokolltreiberanforderungen beim Ändern oder Senden von Paketen erfüllen und können auch davon ausgehen, dass die an ihren FilterSendNetBufferLists-Handler übergebenen Pakte, den Protokolltreiberanforderungen entsprechen.
Miniporttreiber können die Segmentierung großer UDP-Pakete auslagern, die größer als die MTU des Netzwerkmediums sind. Eine NIC, die die Segmentierung großer UDP-Pakete unterstützt, muss auch Folgendes ausführen können:
- IP-Prüfsummen für gesendete Pakete berechnen, die IPv4-Optionen enthalten
- UDP-Prüfsummen für gesendete Pakete berechnen
Ein Miniporttreiber, der USO unterstützt, muss den Auslagerungstyp anhand der OOB-Informationen (Out of Band) der NET_BUFFER_LIST-Struktur bestimmen. Wenn der Wert der NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO-Struktur ungleich null ist, muss der Miniporttreiber USO ausführen. Jede NET_BUFFER_LIST, die USO-OOB-Daten enthält, enthält auch eine einzelne NET_BUFFER-Struktur. Wenn der Miniporttreiber jedoch OID_TCP_OFFLOAD_PARAMETERS zum Deaktivieren von USO empfängt, nachdem er die OID erfolgreich abgeschlossen hat, sollte er jede NET_BUFFER_LIST ablehnen und zurückgeben, in der das USO-OOB-Feld festgelegt ist.
Der TCP/IP-Transport lagert nur die UDP-Pakete aus, die die folgenden Kriterien erfüllen:
- Das Paket ist ein UDP-Paket.
- Die Paketlänge muss größer als die maximale Segmentgröße (MSS) * (MinSegmentCount - 1) sein.
- Wenn der Miniporttreiber die SubMssFinalSegmentSupported-Funktion nicht festlegt, muss jedes große UDP-Paket, das vom Transport ausgelagert wird, Länge % MSS == 0 aufweisen. Das große Paket ist also in N-Pakete mit jedem Paketsegment teilbar, das genau MSS-Benutzerbytes enthält. Wenn der Miniporttreiber die SubMssFinalSegmentSupported-Funktion festlegt, gilt diese Bedingung zur Teilbarkeit der Paketlänge für den Transport nicht. Das letzte Segment kann also kleiner als MSS sein.
- Das Paket ist kein Loopbackpaket.
- Das MF-Bit im IP-Header des großen UDP-Pakets, das vom TCP/IP-Transport ausgelagert wurde, wird nicht festgelegt, und der Fragmentoffset im IP-Header ist null.
- Die Anwendung hat UDP_SEND_MSG_SIZE/WSASetUdpSendMessageSize angegeben.
Vor dem Auslagern eines großen UDP-Pakets für die Segmentierung führt der TCP/IP-Transport Folgendes aus:
- Die Segmentierungsinformationen für große Pakete, die der NET_BUFFER_LIST-Struktur zugeordnet sind werden aktualisiert. Diese Informationen sind eine NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO-Struktur, die zu den OOB-Informationen der NET_BUFFER_LIST-Struktur gehört. Der TCP/IP-Transport legt den MSS-Wert auf die gewünschte MSS fest.
- Die Einerkomplementsumme für den UDP-Pseudoheader wird berechnet und diese Summe in das Feld Checksum des UDP-Headers geschrieben. Der TCP/IP-Transport berechnet die Einerkomplementsumme über die folgenden Felder im Pseudoheader: Quell-IP-Adresse, Ziel-IP-Adresse und Protokoll.
Die Einerkomplementsumme für den vom TCP/IP-Transport bereitgestellten Pseudoheader ermöglicht der NIC eine frühzeitige Berechnung der tatsächlichen UDP-Prüfsumme für jedes Paket, das die NIC vom großen UDP-Paket ableitet, ohne dass der IP-Header untersucht werden muss.
Beachten Sie, dass RFC 768 und RFC 2460 festlegen, dass der Pseudoheader über die Quell-IP-Adresse, die Ziel-IP-Adresse, das Protokoll und UDP-Länge (die Länge des UDP-Headers plus die Länge der UDP-Nutzlast, nicht einschließlich der Länge des Pseudoheaders) berechnet wird. Da jedoch der zugrunde liegende Miniporttreiber und die NIC UDP-Datagramme aus dem vom TCP/IP-Transport übergebenen großen Paket generieren, kennt der Transport die Größe der UDP-Nutzlast für jedes UDP-Datagramm nicht und kann daher die UDP-Länge nicht in die Pseudoheaderberechnung aufnehmen. Stattdessen erweitert die NIC, wie im Folgenden beschrieben, die vom TCP/IP-Transport bereitgestellte Pseudoheaderprüfsumme, um die UDP-Länge jedes generierten UDP-Datagramms einzubeziehen.
Wichtig
Wenn das vom TCP/IP-Transport bereitgestellte UDP-Header-Prüfsummenfeld 0 ist, sollte die NIC keine UDP-Prüfsummenberechnung ausführen.
Senden von Paketen mit USO
Nachdem der Miniporttreiber die NET_BUFFER_LIST in seiner MiniportSendNetBufferLists-Rückruffunktion abgerufen hat, kann er das NET_BUFFER_LIST_INFO-Makro mit einer _Id von UdpSegmentationOffloadInfo aufrufen, um den MSS-Wert und das IP-Protokoll abzurufen.
Der Miniporttreiber ruft die Gesamtlänge des großen Pakets aus der Länge der ersten NET_BUFFER-Struktur ab und verwendet den MSS-Wert, um das große UDP-Paket in kleinere UDP-Pakete zu unterteilen. Jedes der kleineren Pakete enthält Benutzerdatenbytes der MSS oder weniger. Nur das letzte Paket, das aus dem segmentierten großen Paket erstellt wurde, sollte weniger Benutzerdatenbytes enthalten als die MSS. In allen anderen Pakete, die aus dem segmentierten Paket erstellt wurden, müssen die Benutzerdatenbytes der MSS entsprechen. Wenn ein Miniporttreiber diese Regel nicht einhält, werden die UDP-Datagramme falsch übermittelt. Wenn der Miniporttreiber die SubMssFinalSegmentSupported-Funktion nicht festlegt, wird die Paketlänge durch MSS geteilt, und jedes segmentierte Paket enthält Benutzerdatenbytes der MSS.
Der Miniporttreiber bringt MAC-, IP- und UDP-Header für jedes Segment an, das vom großen Paket abgeleitet wird. Der Miniporttreiber muss die IP- und UDP-Prüfsummen für diese abgeleiteten Pakete berechnen. Um die UDP-Prüfsumme für jedes Paket zu berechnen, das vom großen UDP-Paket abgeleitet wurde, berechnet die NIC den variablen Teil der UDP-Prüfsumme (für den UDP-Header und die UDP-Nutzlast), fügt diese Prüfsumme der Einerkomplementsumme für den vom TCP/IP-Transport berechneten Pseudoheader hinzu und berechnet dann das 16-Bit-Einerkomplement für die Prüfsumme. Weitere Informationen zum Berechnen solcher Prüfsummen finden Sie unter RFC 768 und RFC 2460.
Die Länge der UDP-Benutzerdaten im großen UDP-Paket muss kleiner oder gleich dem Wert sein, den der Miniporttreiber dem MaxOffLoadSize-Wert zuweist.
Nachdem ein Treiber eine Statusanzeige ausgegeben hat, um eine Änderung des MaxOffLoadSize-Werts anzuzeigen, darf der Treiber keine Fehlerüberprüfung verursachen, wenn er eine LSO-Sendeanforderung empfängt, die den vorherigen MaxOffLoadSize-Wert verwendet. Der Treiber muss stattdessen die Sendeanforderung unterlassen. Treiber müssen jede Sendeanforderung unterlassen, die sie nicht ausführen können (z. B. aufgrund von Größe, Mindestsegmentanzahl, IP-Optionen usw.). Treiber müssen bei Funktionsänderungen so schnell wie möglich eine Statusanzeige senden.
Ein Zwischentreiber, der unabhängig Statusanzeigen zu Änderungen am MaxOffLoadSize-Wert ausgibt, muss sicherstellen, dass der zugrunde liegende Miniportadapter, der keine Statusanzeige ausgegeben hat, keine Pakete erhält, die größer als der MaxOffLoadSize-Wert sind, den der Miniportadapter gemeldet hat.
Ein Miniport-Zwischentreiber, der auf OID_TCP_OFFLOAD_PARAMETERS reagiert, um USO-Dienste zu deaktivieren, muss für ein kleines Zeitfenster vorbereitet sein, in dem USO-Sendeanforderungen weiterhin den Miniporttreiber erreichen können.
Die Anzahl der Segmentierungspakete, die vom großen UDP-Paket abgeleitet wurden, muss gleich oder größer als der MinSegmentCount-Wert sein, der vom Miniporttreiber angegeben wird.
Bei der Verarbeitung eines großen UDP-Pakets ist der Miniporttreiber nur für das Segmentieren des Pakets und das Anbringen von MAC-, IP- und UDP-Headern an die Pakete verantwortlich, die vom großen UDP-Paket abgeleitet werden. Wenn der Miniport mindestens ein segmentiertes Paket nicht sendet, muss die NBL mit einem Fehlerstatus abgeschlossen werden. Der Miniport kann weiterhin nachfolgende Pakete senden, muss jedoch nicht. Die NBL kann erst als abgeschlossen an NDIS zurückgegeben werden, wenn alle segmentierten Pakete übertragen oder fehlgeschlagen sind.
Für USO-fähige Miniporttreiber gilt außerdem:
- IPv4 und IPv6 werden unterstützt.
- Die Replikation der IPv4-Optionen aus dem großen Paket in jedem segmentierten Paket, das die NIC generiert, wird unterstützt.
- Der IP- und UDP-Header in der NET_BUFFER_LIST-Struktur wird als Vorlage verwendet, um UDP- und IP-Header für jedes segmentierte Paket zu generieren.
- IP-Identifikationswerte (IP-ID) im Bereich von 0x0000 bis 0x7FFF werden verwendet. Wenn beispielsweise der IP-Header der Vorlage mit einem Identifikationsfeldwert 0xFFFE beginnt, muss das erste UDP-Datagrammpaket einen Wert 0xFFFE aufweisen, gefolgt von 0xFFFF, 0x0000, 0x0001 usw.
- Wenn das große UDP-Paket IP-Optionen enthält, kopiert der Miniporttreiber diese Optionen unverändert in jedes Paket, das er vom großen UDP-Paket abgeleitet hat.
- Der Byteoffset im UdpHeaderOffset-Element von NDIS_UDP_SEGMENTATION_OFFLOAD_NET_BUFFER_LIST_INFO wird verwendet, um den Speicherort des UDP-Headers zu bestimmen, beginnend mit dem ersten Byte des Pakets.
- Übertragungsstatistiken werden basierend auf den segmentierten Paketen erhöht. Beispielsweise wird die Anzahl der Ethernet-, IP- und UDP-Headerbytes für jedes Paketsegment aufgenommen, und die Paketanzahl ist die Anzahl der Segmente entsprechend der Größe von MSS, nicht 1.
- Die Felder der UDP-Gesamtlänge und IP-Länge werden nach der jeweiligen Größe der segmentierten Datendiagramme festgelegt.
Änderungen der NDIS-Schnittstelle
In diesem Abschnitt werden die Änderungen in NDIS 6.83 beschrieben, mit denen der TCP/IP-Treiberstapel des Hosts die von Miniporttreibern bereitgestellten USO-Funktionen nutzen kann.
NDIS und der Miniporttreiber führen Folgendes aus:
- Ankündigen, dass die NIC die USO-Funktion unterstützt
- USO aktivieren oder deaktivieren
- Aktuellen USO-Funktionsstatus abrufen
Ankündigen der USO-Funktion
Miniporttreiber kündigen die USO-Funktion an, indem sie das UdpSegmentation-Feld der NDIS_OFFLOAD-Struktur ausfüllen, die in den Parametern von NdisMSetMiniportAttributes übergeben wird. Das Header.Revision-Feld in der NDIS_OFFLOAD-Struktur muss auf NDIS_OFFLOAD_REVISION_6 und das Header.Size-Feld muss auf NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_6 festgelegt werden.
Abfragen des USO-Zustand
Der aktuelle USO-Zustand kann mit OID_TCP_OFFLOAD_CURRENT_CONFIG abgefragt werden. NDIS verarbeitet diese OID und gibt sie nicht an den Miniporttreiber weiter.
Ändern des USO-Zustands
USO kann mithilfe von OID_TCP_OFFLOAD_PARAMETERS aktiviert oder deaktiviert werden. Nachdem der Miniporttreiber die OID verarbeitet hat, muss er eine NDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG-Statusanzeige mit dem aktualisierten Auslagerungszustand senden.
USO-Schlüsselwörter
Schlüsselwörter der Enumeration:
- *UsoIPv4
- *UsoIPv6
Diese Werte beschreiben, ob USO für dieses IP-Protokoll aktiviert oder deaktiviert ist. Die USO-Einstellungen sind nicht von der NDIS_TCP_IP_CHECKSUM_OFFLOAD-Konfiguration abhängig. Das Deaktivieren von *UDPChecksumOffloadIPv4 deaktiviert z. B. nicht implizit *UsoIPv4.
Name des Unterschlüssels | Parameterbeschreibung | Wert | Enum-Beschreibung |
---|---|---|---|
*UsoIPv4 | UDP Segmentation Offload (IPv4) | 0 | Disabled |
1 | Aktiviert | ||
*UsoIPv6 | UDP Segmentation Offload (IPV6) | 0 | Disabled |
1 | Aktiviert |