Управление сетевым буфером данных

Управление буферами — это функция, которая позволяет клиентским драйверам сетевой карты (NIC) и операционной системе работать вместе при выделении буферов данных пакетов из системной памяти для путей передачи (Tx) и получения (Rx). Это может привести к повышению производительности сетевого адаптера, упрощению управления временем существования памяти для драйвера клиента сетевой карты и большему контролю за памятью для системы.

Преимущества управления буферами в NetAdapterCx

Выбор места выделения буферов данных из системной памяти для полезных данных пакетов имеет решающее значение для производительности пути к данным. В NetAdapterCx модель управления буферами оптимизирована для оборудования сетевого адаптера с поддержкой DMA, и лучший способ воспользоваться преимуществами клиентских драйверов — позволить системе выделять буферы данных от их имени для путей Tx и Rx. Однако клиентские драйверы по-прежнему могут влиять на то, где и как система выделяет буферы данных, чтобы их можно было легко использовать на клиентском оборудовании.

Рассмотрим, например, типичный сетевой адаптер с поддержкой DMA. Этот подход имеет ряд преимуществ:

  1. Буферы данных выделяются и освобождаются системой. Таким образом, драйвер клиента освобождается от бремени управления жизненным циклом памяти.
  2. Система гарантирует, что выделенные буферы данных готовы к DMA для оборудования сетевого адаптера на основе возможностей, объявленных драйвером клиента. Затем драйвер клиента может просто запрограммить буферы данных в оборудование без выполнения дополнительных операций сопоставления DMA.
  3. Система может учитывать потребности приложений верхнего уровня при выделении буферов данных, чтобы решить оптимизировать глобальную сквозную производительность, а не только локальную сквозную производительность.

Для сетевых адаптеров, не относящихся к DMA, таких как сетевой аппаратный ключ на основе USB, или для других расширенных и программных сетевых адаптеров модель управления буферами также предоставляет возможность полностью оставить управление буфером данных драйверу клиента.

Использование управления буфером

Важно!

Если оборудование поддерживает DMA, необходимо создать объект WDFDMAENABLER перед настройкой возможностей Rx и Tx. При настройке объекта WDFDMAENABLER со структурой WDF_DMA_ENABLER_CONFIG обязательно установите для элемента WdmDmaVersionOverride значение 3 , чтобы указать DMA версии 3.

Чтобы согласиться на управление буферами, выполните следующие действия.

  1. При запуске сетевого адаптера, но перед вызовом NetAdapterStart, сообщите системе о возможностях и ограничениях буфера данных оборудования, используя структуру данных NET_ADAPTER_RX_CAPABILITIES и NET_ADAPTER_TX_CAPABILITIES для пути Rx и Tx соответственно.
  2. Инициализируйте две структуры возможностей, вызвав одну из функций инициализации. Например, драйвер клиента сетевого адаптера с поддержкой DMA будет использовать NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA и NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA для объявления аппаратных емкостей DMA и для указания системе полностью управлять буферами данных от ее имени.
  3. Передайте инициализированные структуры возможностей Tx и Rx в метод NetAdapterSetDatapathCapabilities .

Пример

В следующем примере показаны основные шаги, описанные в предыдущем разделе для начала работы с диспетчером буферов в драйвере клиента сетевой карты. В примере используется DMA для Tx и Rx, поэтому он ранее создал объект WDFDMAENABLER, который он сохранил в пространстве контекста устройства.

Обратите внимание, что в примере также задаются некоторые указания о буферах фрагментов после инициализации структур возможностей Tx и Rx. Эти указания могут использоваться NetAdapterCx и драйверами протоколов для повышения производительности.

Обработка ошибок была оставлена без ясности.

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