Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Os drivers de cliente NetAdapterCx enviam os dados de rede quando a estrutura invoca sua função de retorno de chamada de EvtPacketQueueAdvance para uma fila de transmissão. Durante esse retorno de chamada, os drivers de cliente lançam buffers do anel de fragmento da fila para o hardware e, em seguida, esvaziam os pacotes e fragmentos concluídos de volta para o sistema operacional.
Visão geral da pós-operação e operação de envio e esvaziamento de transmissão (Tx)
A animação a seguir ilustra como um driver de cliente para uma NIC, um cartão de adaptador de rede PCI simples, executa operações de envio e esvaziamento para uma fila de transmissão (Tx).
Nesta animação, os pacotes pertencentes ao driver cliente são realçados em azul claro e azul escuro, e os fragmentos pertencentes ao driver cliente são realçados em amarelo e laranja. As cores mais claras representam a subseção esvaziamento dos elementos do driver, enquanto as cores mais escuras representam a subseção envio dos elementos do driver.
Como enviar os dados em ordem
Aqui está uma típica sequência de envio e esvaziamento típica para um driver cujo dispositivo transmite dados em ordem, como uma NIC PCI simples.
- Chame NetTxQueueGetRingCollection para recuperar a estrutura de coleção de anéis da fila de transmissão. Você pode armazenar isso no espaço de contexto da fila para reduzir as chamadas do driver. Use a coleção de anéis para acessar o anel de pacotes da fila de transmissão.
- Postar dados no hardware:
- Aloque uma variável UINT32 para o índice de pacotes e defina-a como NextIndex do anel de pacotes, que é o início da subseção de pós do anel.
- Faça o seguinte em um loop:
- Obtenha um pacote chamando NetRingGetPacketAtIndex com o índice de pacotes.
- Verifique se esse pacote deve ser ignorado. Se ele tiver de ser ignorado, pule para a etapa 6 deste loop. Caso contrário, continue.
- Obtenha os fragmentos desse pacote de dados. Recupere o anel de fragmentos da fila de transmissão da coleção de anéis, recupere o início dos fragmentos do pacote do membro FragmentIndex do pacote e, em seguida, recupere o final dos fragmentos do pacote chamando NetRingIncrementIndex com a FragmentCount do pacote.
- Execute o seguinte em um loop:
- Chame NetRingGetFragmentAtIndex para obter um fragmento.
- Traduza o descritor NET_FRAGMENT para o descritor associado de fragmento de hardware.
- Avance o índice de fragmentos ao chamar NetRingIncrementIndex.
- Atualize o índice Próximo do anel de fragmentos para corresponder ao índice atual do iterador de fragmentos, indicando que o envio para o hardware foi concluído.
- Avance o índice de pacote ao chamar NetRingIncrementIndex.
- Atualize o NextIndex do anel de pacotes para o índice de pacotes, finalizando o envio deles para o hardware.
- Esvazie os pacotes de transmissão concluídos para o sistema operacional:
- Defina o índice de pacotes para o BeginIndex do anel de pacotes, que é o começo da subseção de esvaziamento do anel.
- Faça o seguinte em um loop:
- Obtenha um pacote chamando NetRingGetPacketAtIndex com o índice de pacotes.
- Verifique se o pacote terminou de transmitir. Se não tiver, saia do loop.
- Avance o índice de pacote ao chamar NetRingIncrementIndex.
- Atualize o BeginIndex do anel de pacotes para o índice de pacotes, finalizando o envio deles para o hardware.
Essas etapas podem ter esta aparência no código. Observe que os detalhes específicos do hardware, como a forma de enviar descritores para o hardware ou liberar uma pós-transação bem-sucedida, são deixados de fora para maior clareza.
void
MyEvtTxQueueAdvance(
NETPACKETQUEUE TxQueue
)
{
//
// Retrieve the transmit queue's ring collection and packet ring.
// This example stores the Tx queue's ring collection in its queue context space.
//
PMY_TX_QUEUE_CONTEXT txQueueContext = MyGetTxQueueContext(TxQueue);
NET_RING_COLLECTION const * ringCollection = txQueueContext->RingCollection;
NET_RING * packetRing = ringCollection->Rings[NET_RING_TYPE_PACKET];
UINT32 currentPacketIndex = 0;
//
// Post data to hardware
//
currentPacketIndex = packetRing->NextIndex;
while(currentPacketIndex != packetRing->EndIndex)
{
NET_PACKET * packet = NetRingGetPacketAtIndex(packetRing, currentPacketIndex);
if(!packet->Ignore)
{
NET_RING * fragmentRing = ringCollection->Rings[NET_RING_TYPE_FRAGMENT];
UINT32 currentFragmentIndex = packet->FragmentIndex;
UINT32 fragmentEndIndex = NetRingIncrementIndex(fragmentRing, currentFragmentIndex + packet->FragmentCount - 1);
for(txQueueContext->PacketTransmitControlBlocks[packetIndex]->numTxDescriptors = 0;
currentFragmentIndex != fragmentEndIndex;
txQueueContext->PacketTransmitControlBlocks[packetIndex]->numTxDescriptors++)
{
NET_FRAGMENT * fragment = NetRingGetFragmentAtIndex(fragmentRing, currentFragmentIndex);
// Post fragment descriptor to hardware
...
//
currentFragmentIndex = NetRingIncrementIndex(fragmentRing, currentFragmentIndex);
}
//
// Update the fragment ring's Next index to indicate that posting is complete and prepare for draining
//
fragmentRing->NextIndex = currentFragmentIndex;
}
currentPacketIndex = NetRingIncrementIndex(packetRing, currentPacketIndex);
}
packetRing->NextIndex = currentPacketIndex;
//
// Drain packets if completed
//
currentPacketIndex = packetRing->BeginIndex;
while(currentPacketIndex != packetRing->NextIndex)
{
NET_PACKET * packet = NetRingGetPacketAtIndex(packetRing, currentPacketIndex);
// Test packet for transmit completion by checking hardware ownership flags in the packet's last fragment
// Break if transmit is not complete
...
//
currentPacketIndex = NetRingIncrementIndex(packetRing, currentPacketIndex);
}
packetRing->BeginIndex = currentPacketIndex;
}
Enviando dados fora de ordem
Para drivers cujos dispositivos podem concluir transmissões fora de ordem, a principal diferença em relação aos dispositivos em ordem está em quem aloca os buffers de transmissão e como o driver gerencia o teste de conclusão das transmissões. Para transmissões em ordem com uma NIC PCI compatível com DMA, o sistema operacional normalmente aloca, anexa e, por fim, controla os buffers de fragmentos. Em seguida, em ordem, o driver cliente pode testar o sinalizador de propriedade de hardware correspondente de cada fragmento durante EvtPacketQueueAdvance.
Ao contrário desse modelo, considere uma NIC típica baseada em USB. Nessa situação, a pilha USB possui os buffers de memória para transmissão e esses buffers podem estar localizados em outro lugar na memória do sistema. A pilha USB indica finalizações para o driver cliente fora de ordem, então o driver cliente precisa registrar o status de conclusão de um pacote separadamente durante sua rotina de retorno de chamada de conclusão. Para fazer isso, o driver cliente pode usar o campo Scratch do pacote, ou pode empregar outra metodologia, como armazenar informações em seu espaço de contexto da fila. Em seguida, na chamada para EvtPacketQueueAdvance, o driver cliente verifica essas informações para testes de conclusão de pacote.