Transmettre et recevoir des files d’attente
Vue d’ensemble
Les files d’attente de paquets, ou files d’attente de chemin de données, sont des objets introduits dans NetAdapterCx pour permettre aux pilotes clients de modéliser leurs fonctionnalités matérielles, telles que les files d’attente de transmission et de réception matérielles, plus explicitement dans les pilotes logiciels. Cette rubrique explique comment utiliser les files d’attente de transmission et de réception dans NetAdapterCx.
Lorsque votre pilote client appelle NET_ADAPTER_DATAPATH_CALLBACKS_INIT, généralement à partir de sa fonction de rappel d’événement EVT_WDF_DRIVER_DEVICE_ADD , il fournit deux rappels de création de file d’attente : EVT_NET_ADAPTER_CREATE_TXQUEUE et EVT_NET_ADAPTER_CREATE_RXQUEUE. Le client crée respectivement des files d’attente de transmission et de réception dans ces rappels.
L’infrastructure vide les files d’attente avant de passer à un état d’alimentation faible et les supprime avant de supprimer l’adaptateur.
Création de files d’attente de paquets
Lors de la création d’une file d’attente de paquets, une file d’attente de transmission ou une file d’attente de réception, le client doit fournir des pointeurs vers les trois fonctions de rappel suivantes :
En outre, le client peut fournir ces fonctions de rappel facultatives après l’initialisation de la structure de configuration de la file d’attente :
Création d’une file d’attente de transmission
NetAdapterCx appelle EVT_NET_ADAPTER_CREATE_TXQUEUE à la toute fin de la séquence de mise sous tension. Pendant ce rappel, les pilotes clients effectuent généralement les opérations suivantes :
- Inscrivez éventuellement les rappels de début et d’arrêt pour la file d’attente.
- Appelez NetTxQueueInitGetQueueId pour récupérer l’identificateur de la file d’attente de transmission à configurer.
- Appelez NetTxQueueCreate pour allouer une file d’attente.
- Si NetTxQueueCreate échoue, la fonction de rappel EvtNetAdapterCreateTxQueue doit retourner un code d’erreur.
- Requête pour les décalages d’extension de paquets.
L’exemple suivant montre à quoi ces étapes peuvent ressembler dans le code. Le code de gestion des erreurs a été exclu de cet exemple pour plus de clarté.
NTSTATUS
EvtAdapterCreateTxQueue(
_In_ NETADAPTER Adapter,
_Inout_ NETTXQUEUE_INIT * TxQueueInit
)
{
NTSTATUS status = STATUS_SUCCESS;
// Prepare the configuration structure
NET_PACKET_QUEUE_CONFIG txConfig;
NET_PACKET_QUEUE_CONFIG_INIT(
&txConfig,
EvtTxQueueAdvance,
EvtTxQueueSetNotificationEnabled,
EvtTxQueueCancel);
// Optional: register the queue's start and stop callbacks
txConfig.EvtStart = EvtTxQueueStart;
txConfig.EvtStop = EvtTxQueueStop;
// Get the queue ID
const ULONG queueId = NetTxQueueInitGetQueueId(TxQueueInit);
// Create the transmit queue
NETPACKETQUEUE txQueue;
status = NetTxQueueCreate(
TxQueueInit,
&txAttributes,
&txConfig,
&txQueue);
// Get the queue context for storing the queue ID and packet extension offset info
PMY_TX_QUEUE_CONTEXT queueContext = GetMyTxQueueContext(txQueue);
// Store the queue ID in the context
queueContext->QueueId = queueId;
// Query checksum packet extension offset and store it in the context
NET_EXTENSION_QUERY extension;
NET_EXTENSION_QUERY_INIT(
&extension,
NET_PACKET_EXTENSION_CHECKSUM_NAME,
NET_PACKET_EXTENSION_CHECKSUM_VERSION_1);
NetTxQueueGetExtension(txQueue, &extension, &queueContext->ChecksumExtension);
// Query Large Send Offload packet extension offset and store it in the context
NET_EXTENSION_QUERY_INIT(
&extension,
NET_PACKET_EXTENSION_LSO_NAME,
NET_PACKET_EXTENSION_LSO_VERSION_1);
NetTxQueueGetExtension(txQueue, &extension, &queueContext->LsoExtension);
return status;
}
Création d’une file d’attente de réception
Pour créer une file d’attente de réception à partir de EVT_NET_ADAPTER_CREATE_RXQUEUE, utilisez le même modèle qu’une file d’attente de transmission et appelez NetRxQueueCreate.
L’exemple suivant montre à quoi peut ressembler la création d’une file d’attente de réception dans le code. Le code de gestion des erreurs a été exclu de cet exemple pour plus de clarté.
NTSTATUS
EvtAdapterCreateRxQueue(
_In_ NETADAPTER NetAdapter,
_Inout_ PNETRXQUEUE_INIT RxQueueInit
)
{
NTSTATUS status = STATUS_SUCCESS;
// Prepare the configuration structure
NET_PACKET_QUEUE_CONFIG rxConfig;
NET_PACKET_QUEUE_CONFIG_INIT(
&rxConfig,
EvtRxQueueAdvance,
EvtRxQueueSetNotificationEnabled,
EvtRxQueueCancel);
// Optional: register the queue's start and stop callbacks
rxConfig.EvtStart = EvtRxQueueStart;
rxConfig.EvtStop = EvtRxQueueStop;
// Get the queue ID
const ULONG queueId = NetRxQueueInitGetQueueId(RxQueueInit);
// Create the receive queue
NETPACKETQUEUE rxQueue;
status = NetRxQueueCreate(
RxQueueInit,
&rxAttributes,
&rxConfig,
&rxQueue);
// Get the queue context for storing the queue ID and packet extension offset info
PMY_RX_QUEUE_CONTEXT queueContext = GetMyRxQueueContext(rxQueue);
// Store the queue ID in the context
queueContext->QueueId = queueId;
// Query the checksum packet extension offset and store it in the context
NET_EXTENSION_QUERY extension;
NET_EXTENSION_QUERY_INIT(
&extension,
NET_PACKET_EXTENSION_CHECKSUM_NAME,
NET_PACKET_EXTENSION_CHECKSUM_VERSION_1);
NetRxQueueGetExtension(rxQueue, &extension, &queueContext->ChecksumExtension);
return status;
}
Modèle d’interrogation
Le chemin des données NetAdapter est un modèle d’interrogation, et l’opération d’interrogation sur une file d’attente de paquets est complètement indépendante des autres files d’attente. Le modèle d’interrogation est implémenté en appelant les rappels anticipés de file d’attente du pilote client, comme illustré dans la figure suivante :
Progression des files d’attente de paquets
La séquence d’une opération d’interrogation sur une file d’attente de paquets est la suivante :
- Le système d’exploitation fournit des mémoires tampons au pilote client pour la transmission ou la réception.
- Le pilote client programme les paquets sur le matériel.
- Le pilote client retourne les paquets terminés au système d’exploitation.
Les opérations d’interrogation se produisent dans la fonction de rappel EvtPacketQueueAdvance du pilote client. Chaque file d’attente de paquets dans un pilote client est soutenue par des structures de données sous-jacentes appelées anneaux net, qui contiennent ou sont liées aux mémoires tampons de données réseau réelles dans la mémoire système. Pendant EvtPacketQueueAdvance, les pilotes clients effectuent des opérations d’envoi et de réception sur les anneaux net en contrôlant les index au sein des anneaux, en transférant la propriété de la mémoire tampon entre le matériel et le système d’exploitation à mesure que les données sont transmises ou reçues.
Pour plus d’informations sur les anneaux nets, consultez Présentation des anneaux nets.
Pour obtenir un exemple d’implémentation d’EvtPacketQueueAdvance pour une file d’attente de transmission, consultez Envoi de données réseau avec des anneaux nets. Pour obtenir un exemple d’implémentation d’EvtPacketQueueAdvance pour une file d’attente de réception, consultez Réception de données réseau avec des anneaux net.
Activation et désactivation de la notification de file d’attente de paquets
Lorsqu’un pilote client reçoit de nouveaux paquets dans les anneaux nets d’une file d’attente de paquets, NetAdapterCx appelle la fonction de rappel EvtPacketQueueSetNotificationEnabled du pilote client. Ce rappel indique à un pilote client que l’interrogation ( evtPacketQueueAdvance ou EvtPacketQueueCancel) s’arrêtera et ne se poursuivra pas tant que le pilote client n’appellera pas NetTxQueueNotifyMoreCompletedPacketsAvailable ou NetRxQueueNotifyMoreReceivedPacketsAvailable. En règle générale, un appareil PCI utilise ce rappel pour activer les interruptions Tx ou Rx. Une fois qu’une interruption est reçue, les interruptions peuvent être à nouveau désactivées et le pilote client appelle NetTxQueueNotifyMoreCompletedPacketsAvailable ou NetRxQueueNotifyMoreReceivedPacketsAvailable pour déclencher l’infrastructure pour recommencer l’interrogation.
Activation et désactivation de la notification pour une file d’attente de transmission
Pour une carte réseau PCI, l’activation de la notification de file d’attente de transmission signifie généralement l’activation de l’interruption matérielle de la file d’attente de transmission. Lorsque l’interruption matérielle se déclenche, le client appelle NetTxQueueNotifyMoreCompletedPacketsAvailable à partir de son DPC.
De même, pour une carte réseau PCI, la désactivation de la notification de file d’attente signifie désactiver l’interruption associée à la file d’attente.
Pour un appareil qui a un modèle d’E/S asynchrone, le client utilise généralement un indicateur interne pour suivre l’état activé. Lorsqu’une opération asynchrone se termine, le gestionnaire d’achèvement vérifie cet indicateur et appelle NetTxQueueNotifyMoreCompletedPacketsAvailable s’il est défini.
Si NetAdapterCx appelle EvtPacketQueueSetNotificationEnabled avec NotificationEnabled défini sur FALSE, le client ne doit pas appeler NetTxQueueNotifyMoreCompletedPacketsAvailable jusqu’à ce que NetAdapterCx appelle ensuite cette fonction de rappel avec NotificationEnabled défini sur TRUE.
Par exemple :
VOID
MyEvtTxQueueSetNotificationEnabled(
_In_ NETPACKETQUEUE TxQueue,
_In_ BOOLEAN NotificationEnabled
)
{
// Optional: retrieve queue's WDF context
MY_TX_QUEUE_CONTEXT *txContext = GetTxQueueContext(TxQueue);
// If NotificationEnabled is TRUE, enable transmit queue's hardware interrupt
...
}
VOID
MyEvtTxInterruptDpc(
_In_ WDFINTERRUPT Interrupt,
_In_ WDFOBJECT AssociatedObject
)
{
MY_INTERRUPT_CONTEXT *interruptContext = GetInterruptContext(Interrupt);
NetTxQueueNotifyMoreCompletedPacketsAvailable(interruptContext->TxQueue);
}
Activation et désactivation de la notification pour une file d’attente de réception
Pour une carte réseau PCI, l’activation de la notification de réception de file d’attente ressemble beaucoup à une file d’attente Tx. Cela signifie généralement l’activation de l’interruption matérielle de la file d’attente de réception. Lorsque l’interruption matérielle se déclenche, le client appelle NetRxQueueNotifyMoreReceivedPacketsAvailable à partir de son DPC.
Par exemple :
VOID
MyEvtRxQueueSetNotificationEnabled(
_In_ NETPACKETQUEUE RxQueue,
_In_ BOOLEAN NotificationEnabled
)
{
// optional: retrieve queue's WDF Context
MY_RX_QUEUE_CONTEXT *rxContext = GetRxQueueContext(RxQueue);
// If NotificationEnabled is TRUE, enable receive queue's hardware interrupt
...
}
VOID
MyEvtRxInterruptDpc(
_In_ WDFINTERRUPT Interrupt,
_In_ WDFOBJECT AssociatedObject
)
{
MY_INTERRUPT_CONTEXT *interruptContext = GetInterruptContext(Interrupt);
NetRxQueueNotifyMoreReceivedPacketsAvailable(interruptContext->RxQueue);
}
Pour un périphérique USB ou toute autre file d’attente avec un mécanisme d’achèvement de réception logicielle, le pilote client doit suivre dans son propre contexte si la notification de la file d’attente est activée. À partir de la routine d’achèvement (déclenchée par exemple lorsqu’un message devient disponible dans le lecteur continu USB), appelez NetRxQueueNotifyMoreReceivedPacketsAvailable si la notification est activée. L’exemple suivant montre comment procéder.
VOID
UsbEvtReaderCompletionRoutine(
_In_ WDFUSBPIPE Pipe,
_In_ WDFMEMORY Buffer,
_In_ size_t NumBytesTransferred,
_In_ WDFCONTEXT Context
)
{
UNREFERENCED_PARAMETER(Pipe);
PUSB_RCB_POOL pRcbPool = *((PUSB_RCB_POOL*) Context);
PUSB_RCB pRcb = (PUSB_RCB) WdfMemoryGetBuffer(Buffer, NULL);
pRcb->DataOffsetCurrent = 0;
pRcb->DataWdfMemory = Buffer;
pRcb->DataValidSize = NumBytesTransferred;
WdfObjectReference(pRcb->DataWdfMemory);
ExInterlockedInsertTailList(&pRcbPool->ListHead,
&pRcb->Link,
&pRcbPool->ListSpinLock);
if (InterlockedExchange(&pRcbPool->NotificationEnabled, FALSE) == TRUE)
{
NetRxQueueNotifyMoreReceivedPacketsAvailable(pRcbPool->RxQueue);
}
}
Annulation des files d’attente de paquets
Lorsque le système d’exploitation arrête le chemin des données, il commence par appeler la fonction de rappel EvtPacketQueueCancel du pilote client. Ce rappel est l’endroit où les pilotes clients effectuent tout traitement nécessaire avant que l’infrastructure supprime les files d’attente de paquets. L’annulation d’une file d’attente de transmission est facultative et dépend si le matériel prend en charge l’annulation de transmission en cours d’exécution, mais l’annulation d’une file d’attente de réception est requise.
Pendant EvtPacketQueueCancel, les pilotes retournent les paquets au système d’exploitation en fonction des besoins. Pour obtenir des exemples de code d’annulation de file d’attente de transmission et de réception, consultez Annulation de données réseau avec des anneaux nets.
Après avoir appelé le rappel EvtPacketQueueCancel du pilote, l’infrastructure continue d’interroger le rappel EvtPacketQueueAdvance du pilote jusqu’à ce que tous les paquets et mémoires tampons aient été retournés au système d’exploitation.