Поделиться через


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

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

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

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

Рассмотрим типичный сетевой адаптер, поддерживающий DMA, например. Существуют преимущества сервала для этого подхода:

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

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

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

Внимание

Если оборудование поддерживает DMA, перед настройкой возможностей Rx и Tx необходимо создать объект WDFDMAENABLER. При настройке объекта 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);
}