Управление буфером сетевых данных
Управление буферами — это функция, которая позволяет клиентским драйверам сетевой карты (NIC) и операционной системе совместно работать при выделении буферов данных пакетов из системной памяти для путей передачи (Tx) и получения (Rx). Это может привести к более быстрой производительности сетевого адаптера, упрощению управления временем существования памяти для клиентского драйвера сетевого адаптера и большему управлению системой над памятью.
Преимущества управления буферами в NetAdapterCx
Выбор места, в котором буферы данных выделяются из системной памяти для полезных данных пакетов, критически важны для производительности пути к данным. В NetAdapterCx модель управления буферами оптимизирована для оборудования сетевого адаптера, поддерживающего DMA, и лучший способ использования клиентских драйверов — разрешить системе выделять буферы данных от их имени как для путей Tx, так и для Rx. Однако драйверы клиентов по-прежнему могут влиять на то, где и как система выделяет буферы данных, чтобы их можно было легко использовать оборудованием клиента.
Рассмотрим типичный сетевой адаптер, поддерживающий DMA, например. Существуют преимущества сервала для этого подхода:
- Буферы данных выделяются и освобождаются системой. Таким образом, драйвер клиента освобождается от бремени управления временем существования памяти.
- Система гарантирует, что выделенные буферы данных готовы для оборудования сетевого адаптера на основе возможностей, объявленных драйвером клиента. Затем драйвер клиента может просто программирует буферы данных в аппаратное состояние без выполнения дополнительных операций сопоставления DMA.
- Система может учитывать потребности приложений верхнего уровня при выделении буферов данных, поэтому она может решить оптимизироваться для глобальной сквозной производительности, а не только локальной сквозной производительности.
Для сетевых адаптеров, отличных от DMA, таких как сетевой адаптер на основе USB, или для других расширенных и программных сетевых адаптеров, модель управления буферами также предоставляет возможность полностью оставить управление буферами данных драйверу клиента.
Использование управления буферами
Внимание
Если оборудование поддерживает DMA, перед настройкой возможностей Rx и Tx необходимо создать объект WDFDMAENABLER. При настройке объекта WDFDMAENABLER со структурой WDF_DMA_ENABLER_CONFIG обязательно установите для члена WdmDmaVersionOverride значение 3 , чтобы указать DMA версии 3.
Чтобы войти в систему управления буферами, выполните следующие действия.
- При запуске сетевого адаптера, но перед вызовом NetAdapterStart сообщите системе о возможностях и ограничениях буфера данных оборудования с помощью NET_ADAPTER_RX_CAPABILITIES и NET_ADAPTER_TX_CAPABILITIES структуры данных для пути Rx и Tx соответственно.
- Инициализировать две структуры возможностей путем вызова одной из функций инициализации. Например, драйвер клиента сетевого адаптера, поддерживающий DMA, будет использовать NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA и NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA для объявления аппаратных ограничений DMA и указания системе полностью управлять буферами данных от его имени.
- Передайте структуры инициализированных возможностей 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);
}