Freigeben über


Verwaltung des Netzwerkdatenpuffers

Die Pufferverwaltung ist ein Feature, über das NIC-Clienttreiber (Network Interface Card, Netzwerkschnittstellenkarten) und das Betriebssystem zusammenarbeiten können, wenn Paketdatenpuffer aus den Datenpfaden zum Übertragen (Tx) und Empfangen (Rx) zugeordnet werden. Das kann zu einer schnelleren Leistung der NIC, einer einfacheren Speicherlebensdauerverwaltung des NIC-Clienttreibers und mehr Kontrolle des System über den Speicher führen.

Die Vorteile der Pufferverwaltung in NetAdapterCx

An welcher Stelle Datenpuffer aus dem Systemspeicher für Paketnutzlasten zugeordnet werden, ist für die Leistung des Datenpfads von entscheidender Bedeutung. In NetAdapterCx ist das Pufferverwaltungsmodell für DMA-fähige NIC-Hardware optimiert. Die beste Nutzungsmöglichkeit des Modells besteht für Clienttreiber darin, dem System die Zuweisung der Datenpuffer für ihre Tx- und Rx-Pfade zu überlassen. Clienttreiber können jedoch weiterhin beeinflussen, wo und wie das System die Datenpuffer zuordnet, damit sie problemlos von der Hardware des Clients genutzt werden können.

Stellen Sie sich beispielsweise eine typische DMA-fähige NIC vor. Dieser Ansatz hat mehrere Vorteile:

  1. Die Datenpuffer werden vom System zugewiesen und freigegeben. Daher wird der Clienttreiber von der Last der Speicherlebensdauerverwaltung befreit.
  2. Das System stellt sicher, dass die zugeordneten Datenpuffer für die NIC-Hardware DMA-bereit sind, basierend auf den vom Clienttreiber deklarierten Funktionen. Anschließend kann der Clienttreiber die Datenpuffer einfach unverändert in das Programm ihrer Hardware aufnehmen und muss keine weiteren DMA-Zuordnungsvorgänge ausführen.
  3. Das System kann beim Zuordnen der Datenpuffer die Anforderungen von Anwendungen der oberen Ebene berücksichtigen, um festzustellen, ob eine Optimierung für eine globale End-to-End-Leistung anstelle der lokalen End-to-End-Leistung vorzunehmen ist.

Nicht DMA-fähigen NICs wie einem USB-basierten Netzwerk-Dongle oder anderen erweiterten/softwarebasierten NICs ermöglicht das Pufferverwaltungsmodell auch, die Datenpufferverwaltung vollständig dem Clienttreiber zu überlassen.

So nutzen Sie die Pufferverwaltung

Wichtig

Wenn Ihre Hardware DMA-fähig ist, müssen Sie ein WDFDMAENABLER-Objekt erstellen, bevor Sie die Rx- und Tx-Funktionen festlegen. Wenn Sie das WDFDMAENABLER-Objekt mit der WDF_DMA_ENABLER_CONFIG-Struktur konfigurieren, stellen Sie sicher, dass Sie den WdmDmaVersionOverride-Member auf 3 festlegen, um DMA Version 3 anzugeben.

Führen Sie die folgenden Schritte aus, um mit der Pufferverwaltung zu beginnen:

  1. Informieren Sie das System beim Starten des Netzadapters, aber vor dem Aufrufen von NetAdapterStart, über die Datenpufferfunktionen und -einschränkungen Ihrer Hardware. Verwenden Sie hierfür jeweils die NET_ADAPTER_RX_CAPABILITIES- und die NET_ADAPTER_TX_CAPABILITIES-Datenstruktur für den Rx- und den Tx-Pfad.
  2. Initialisieren Sie die beiden Funktionsstrukturen, indem Sie eine der Initialisierungsfunktionen aufrufen. Beispielsweise würde ein DMA-fähiger NIC-Clienttreiber NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA und NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA verwenden, um die DMA-Funktionen seiner Hardware zu deklarieren und das System anzuweisen, die Datenpuffer in seinem Auftrag vollständig zu verwalten.
  3. Übergeben Sie die initialisierten Tx- und Rx-Funktionsstrukturen an die NetAdapterSetDatapathCapabilities-Methode.

Beispiel

Das folgende Beispiel veranschaulicht die grundlegenden Schritte des vorherigen Abschnitts, wie Sie mit der Pufferverwaltung in Ihrem NIC-Clienttreiber beginnen können. Im Beispiel wird DMA sowohl für Tx als auch für Rx verwendet. Zuvor wurde ein WDFDMAENABLER-Objekt erstellt und im Kontextbereich des Gerätes gespeichert.

Das Beispiel enthält auch einige Hinweise zu den Fragmentpuffern, nachdem die Tx- und Rx-Funktionsstrukturen initialisiert wurden. Anhand dieser Hinweise können NetAdapterCx- und Protokolltreibern die Leistung verbessern.

Fehlerbehandlungscode wurde aus Gründen der Übersichtlichkeit ausgelassen.

VOID
MyAdapterSetDatapathCapabilities(
    _In_ NETADAPTER Adapter
)
{
    // Get the device context
    PMY_DEVICE_CONTEXT deviceContext = GetMyContextFromDevice(Adapter);

    // Set various capabilities such as link layer MTU size, link layer capabilities, and power capabilities
    ...   

    // Initialize the Tx DMA capabilities structure
    NET_ADAPTER_DMA_CAPABILITIES txDmaCapabilities;
    NET_ADAPTER_DMA_CAPABILITIES_INIT(&txDmaCapabilities,
                                      deviceContext->dmaEnabler);

    // Set Tx capabilities
    NET_ADAPTER_TX_CAPABILITIES txCapabilities;
    NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA(&txCapabilities,
                                             &txDmaCapabilities,
                                             1);
    txCapabilities.FragmentRingNumberOfElementsHint = deviceContext->NumTransmitControlBlocks * MAX_PHYS_BUF_COUNT;
    txCapabilities.MaximumNumberOfFragments = MAX_PHYS_BUF_COUNT;

    // Initialize the Rx DMA capabilities structure
    NET_ADAPTER_DMA_CAPABILITIES rxDmaCapabilities;
    NET_ADAPTER_DMA_CAPABILITIES_INIT(&rxDmaCapabilities,
                                      deviceContext->dmaEnabler);

    // Set Rx capabilities
    NET_ADAPTER_RX_CAPABILITIES rxCapabilities;
    NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA(&rxCapabilities,
                                                        &rxDmaCapabilities,
                                                        MAX_PACKET_SIZE + FRAME_CRC_SIZE + RSVD_BUF_SIZE,
                                                        1);
    rxCapabilities.FragmentBufferAlignment = 64;
    rxCapabilities.FragmentRingNumberOfElementsHint = deviceContext->NumReceiveBuffers;

    // Set the adapter's datapath capabilities
    NetAdapterSetDatapathCapabilities(Adapter, 
                                      &txCapabilities, 
                                      &rxCapabilities);
}