Udostępnij przez


Zarządzanie buforem danych sieciowych

Zarządzanie buforem to funkcja umożliwiająca współdziałanie sterowników klienta karty interfejsu sieciowego (NIC) i systemu operacyjnego podczas przydzielania buforów danych pakietów z pamięci systemowej dla ścieżek danych transmisji (Tx) i odbierania (Rx). Może to spowodować skrócenie czasu operacji dla karty sieciowej, łatwiejsze zarządzanie okresem istnienia pamięci dla sterownika klienta oraz większą kontrolę systemu nad pamięcią.

Zalety zarządzania buforem w NetAdapterCx

Wybór alokacji buforów danych z pamięci systemowej dla ładunków pakietów ma kluczowe znaczenie dla wydajności ścieżki danych. W systemie NetAdapterCx model zarządzania buforem jest zoptymalizowany pod kątem sprzętu karty sieciowej z obsługą DMA, a najlepszym sposobem dla sterowników klienta, aby to wykorzystać, jest umożliwienie systemowi przydzielania buforów danych w ich imieniu zarówno dla ścieżki nadawczej (Tx), jak i odbiorczej (Rx). Jednak sterowniki klienta nadal mogą mieć wpływ na to, gdzie i w jaki sposób system przydziela bufory danych, żeby mogły być łatwo konsumowane przez sprzęt klienta.

Rozważmy na przykład typową kartę sieciową z obsługą DMA. To podejście ma kilka korzyści:

  1. Bufory danych są przydzielane i zwalniane przez system. W związku z tym sterownik klienta jest zwalniany z obciążenia zarządzania okresem istnienia pamięci.
  2. System zapewnia, że przydzielone bufory danych są gotowe do pracy w celu obsługi DMA dla sprzętu karty sieciowej, zgodnie z możliwościami zadeklarowanymi przez sterownik klienta. Następnie sterownik klienta może po prostu programować bufory danych do jego sprzętu as-is bez wykonywania jakichkolwiek dodatkowych operacji mapowania DMA.
  3. System może wziąć pod uwagę potrzeby aplikacji wyższej warstwy podczas przydzielania buforów danych, dzięki czemu może zdecydować się na optymalizację pod kątem globalnej wydajności końcowej, a nie tylko lokalnej wydajności końcowej.

W przypadku kart sieciowych, które nie obsługują DMA, takich jak adapter sieciowy oparty na USB, lub w przypadku innych zaawansowanych lub programowych kart sieciowych, model zarządzania buforem zapewnia również możliwość całkowitego powierzenia zarządzania buforem danych sterownikowi klienta.

Jak wykorzystać zarządzanie buforem

Ważny

Jeśli Twój sprzęt obsługuje DMA, należy utworzyć obiekt WDFDMAENABLER, zanim ustawisz możliwości Rx i Tx. Podczas konfigurowania obiektu WDFDMAENABLER za pomocą struktury WDF_DMA_ENABLER_CONFIG upewnij się, że ustawiono element członkowski WdmDmaVersionOverride3, aby określić wersję DMA 3.

Aby włączyć zarządzanie buforem, wykonaj następujące kroki:

  1. Podczas uruchamiania karty sieciowej, ale przed wywołaniem NetAdapterStart, poinformuj system o możliwościach i ograniczeniach buforu danych sprzętu, używając odpowiednio struktury danych NET_ADAPTER_RX_CAPABILITIES i NET_ADAPTER_TX_CAPABILITIES dla ścieżki Rx i Tx.
  2. Zainicjuj dwie struktury możliwości, wywołując jedną z funkcji inicjowania. Na przykład sterownik klienta karty sieciowej z obsługą DMA używa NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA i NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA do deklarowania sprzętowych możliwości DMA oraz poinstruowania systemu, aby w pełni zarządzał danymi w jego zastępstwie.
  3. Przekaż zainicjowane struktury możliwości Tx i Rx do metody NetAdapterSetDatapathCapabilities.

Przykład

Poniższy przykład ilustruje podstawowe kroki opisane w poprzedniej sekcji, aby zacząć używać menedżera bufora w sterowniku klienta karty sieciowej. W przykładzie użyto DMA zarówno dla Tx, jak i Rx, wcześniej stworzono obiekt WDFDMAENABLER, który został przechowany w przestrzeni kontekstowej urządzenia.

Należy pamiętać, że w przykładzie po zainicjowaniu struktur możliwości Tx i Rx przedstawiono również pewną wskazówkę dotyczącą buforów fragmentów. Te wskazówki mogą być używane przez sterowniki NetAdapterCx i protokołów w celu zwiększenia wydajności.

Obsługa błędów została pominięta w celu zapewnienia przejrzystości.

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);
}