Compartilhar via


Gerenciamento de buffer de dados de rede

O gerenciamento de buffer é um recurso que permite que os drivers de cliente de adaptador de rede (NIC) e o sistema operacional trabalhem juntos na alocação de buffers de dados de pacote da memória do sistema para os caminhos de dados de transmissão (Tx) e de recebimento (Rx). Isso pode levar a um desempenho mais rápido do NIC, ao gerenciamento facilitado da vida útil da memória para o driver de cliente do NIC e a mais controle do sistema sobre a memória.

Benefícios do gerenciamento de buffer na NetAdapterCx

Escolher onde os buffers de dados são alocados da memória do sistema para os conteúdos de pacotes é um aspecto crítico para o desempenho do caminho de dados. Na NetAdapterCx, o modelo de gerenciamento de buffer é otimizado para hardware de NIC compatível com DMA, e a melhor maneira de os drivers de cliente aproveitarem isso é permitir que o sistema aloque buffers de dados em nome deles para os caminhos Tx e Rx. No entanto, os drivers de cliente ainda podem influenciar onde e como o sistema aloca os buffers de dados para que possam ser facilmente consumidos pelo hardware do cliente.

Considere, por exemplo, um NIC típico compatível com DMA. Essa abordagem traz vários benefícios:

  1. Os buffers de dados são alocados e liberados pelo sistema. Assim, o driver do cliente é liberado da carga de gerenciamento da vida útil da memória.
  2. O sistema garante que os buffers de dados alocados estejam prontos para DMA para o hardware do NIC com base nos recursos declarados pelo driver do cliente. Em seguida, o driver do cliente pode simplesmente programar os buffers de dados em seu hardware como estão, sem executar quaisquer operações adicionais de mapeamento de DMA.
  3. O sistema pode levar em consideração as necessidades dos aplicativos de camada superior ao alocar os buffers de dados, para que possa decidir otimizar o desempenho global descentralizado, em vez de apenas o desempenho local descentralizado.

No caso de NICs não compatíveis com DMA, como um dongle de rede baseado em USB, ou de outros NICs avançados/de software, o modelo de gerenciamento de buffer também oferece uma opção para deixar o gerenciamento de buffer de dados completamente para o driver do cliente.

Como aproveitar o gerenciamento de buffer

Importante

Se o hardware for compatível com DMA, você precisará criar um objeto WDFDMAENABLER antes de definir os recursos de Rx e Tx. Ao configurar o objeto WDFDMAENABLER com a estrutura WDF_DMA_ENABLER_CONFIG, certifique-se de definir o membro WdmDmaVersionOverride como 3 para especificar o DMA versão 3.

Para aceitar o gerenciamento de buffer, siga estas etapas:

  1. Ao iniciar o adaptador de rede, mas antes de chamar NetAdapterStart, informe ao sistema sobre os recursos de buffer de dados do hardware e as limitações de uso da estrutura de dados NET_ADAPTER_RX_CAPABILITIES e NET_ADAPTER_TX_CAPABILITIES para o caminho de Rx e Tx, respectivamente.
  2. Inicialize as duas estruturas de recursos chamando uma das funções de inicialização. Por exemplo, um driver de cliente de NIC compatível com DMA usaria NET_ADAPTER_TX_CAPABILITIES_INIT_FOR_DMA e NET_ADAPTER_RX_CAPABILITIES_INIT_SYSTEM_MANAGED_DMA para declarar os recursos de DMA de hardware e para instruir o sistema a gerenciar os buffers de dados integralmente em seu nome.
  3. Passe as estruturas de recursos de Tx e Rx inicializadas para o método NetAdapterSetDatapathCapabilities.

Exemplo

O exemplo a seguir ilustra as etapas básicas descritas na seção anterior sobre como começar a usar o gerenciador de buffer no driver do cliente de NIC. O exemplo usa DMA para Tx e Rx, pois anteriormente ele criou um objeto WDFDMAENABLER que armazenou no espaço de contexto do dispositivo.

O exemplo também define algumas dicas sobre os buffers de fragmento depois de inicializar as estruturas de recursos de Tx e Rx. Essas dicas podem ser usadas pela NetAdapterCx e por drivers de protocolo para melhorar o desempenho.

O tratamento de erro foi deixado de fora por questões de clareza.

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