Mode d'interrogation NDIS
Vue d’ensemble du mode de sondage NDIS
Le mode de sondage NDIS est un modèle d’exécution d’interrogation contrôlé par le système d’exploitation qui pilote le chemin de données de l’interface réseau.
Auparavant, NDIS n’avait pas de définition formelle d’un contexte d’exécution de chemin de données. Les pilotes NDIS s’appuient généralement sur les appels de procédure différé (DPCs) pour implémenter leur modèle d’exécution. Toutefois, l’utilisation de DPCs peut surcharger le système lorsque de longues chaînes d’indication sont effectuées et éviter ce problème nécessite beaucoup de code difficile à obtenir correctement. Le mode de sondage NDIS offre une alternative aux CONTRÔLEURS de domaine et aux outils d’exécution similaires.
Le mode de sondage NDIS déplace la complexité des décisions de planification loin des pilotes de carte réseau et dans NDIS, où NDIS définit les limites de travail par itération. Pour atteindre ce mode d’interrogation, fournit les éléments suivants :
Mécanisme permettant au système d’exploitation d’exercer une pression arrière sur la carte réseau.
Mécanisme permettant au système d’exploitation de contrôler finement les interruptions.
Le mode de sondage NDIS est disponible pour les pilotes miniport NDIS 6.85 et ultérieurs.
Problèmes liés au modèle DPC
Le diagramme de séquence suivant illustre un exemple typique de la façon dont un pilote miniport NDIS gère une rafale de paquets Rx à l’aide d’un DPC. Dans cet exemple, le matériel est standard en termes de cartes réseau PCIe. Il a une file d’attente matérielle de réception et un masque d’interruption pour cette file d’attente.
En l’absence d’activité réseau, l’interruption Rx est activée. Quand un paquet Rx arrive :
Le matériel génère une interruption et NDIS appelle la fonction MiniportInterrupt du pilote (ISR).
Le pilote fait très peu de travail dans l’ISR parce qu’il s’exécute à un irQL très élevé. Le pilote désactive l’interruption de l’ISR et reporte le traitement matériel à une fonction MiniportInterruptDPC (DPC).
NDIS appelle finalement le DPC du pilote et le pilote vide toutes les achèvements de la file d’attente matérielle et les indique au système d’exploitation.
Deux points de douleur peuvent affecter la pile réseau lorsque le pilote reporte les opérations d’E/S à une DPC :
Le pilote ne sait pas si le système est capable de traiter toutes les données indiquées, de sorte que le pilote n’a pas le choix de vider autant d’éléments que possible de sa file d’attente matérielle et de les indiquer dans la pile.
Étant donné que le pilote utilise un DPC pour différer le travail de son ISR, toutes les indications sont faites à DISPATCH_LEVEL. Cela peut surcharger le système lorsque de longues chaînes d’indication sont effectuées et provoquent la vérification des bogues 0x133 DPC_WATCHDOG_VIOLATION.
Éviter ces points de douleur nécessite beaucoup de code difficile dans votre pilote. Bien que vous puissiez vérifier si le chien de surveillance DPC est proche de la limite avec la fonction KeQueryDpcWatchdogInformation et sortir de la DPC, vous devez toujours créer une infrastructure autour de cela dans votre pilote : vous avez besoin d’un moyen de suspendre un peu, puis de continuer à indiquer les paquets, et en même temps, vous devez synchroniser tout cela avec la durée de vie du chemin de données.
Introduction aux objets Poll
Le mode de sondage NDIS introduit l’objet Poll pour résoudre les points de douleur associés aux CONTRÔLEURS de domaine. Un objet Poll est une construction de contexte d’exécution. Les pilotes miniport peuvent utiliser un objet Poll à la place d’une DPC lors de la gestion des opérations de chemin de données.
Un objet Poll propose les éléments suivants :
Il permet à NDIS de définir des limites de travail par itération.
Il est étroitement lié à un mécanisme de notification. Cela permet au système d’exploitation et à la carte réseau de se synchroniser en ce qui concerne le moment où le travail doit être traité.
Il a un concept d’itération et d’interruptions intégrées. Lorsque vous utilisez des contrôleurs de domaine, les pilotes sont obligés de réactiver l’interruption chaque fois qu’ils terminent une DPC. Lors de l’utilisation d’objets Poll, les pilotes n’ont pas besoin de réactiver l’interruption de chaque itération d’interrogation, car le mode poll permet à votre pilote de savoir quand il a terminé l’interrogation et qu’il est temps de réactiver l’interruption.
Lorsque vous prenez des décisions de planification, le système peut être intelligent sur l’exécution à DISPATCH_LEVEL ou PASSIVE_LEVEL. Cela peut permettre une hiérarchisation affinée du trafic provenant de différentes cartes réseau et entraîner une distribution de charge de travail plus équitable sur l’ordinateur.
Elle offre des garanties de sérialisation. Une fois que vous exécutez du code à partir du contexte d’exécution d’un objet Poll, vous êtes assuré qu’aucun autre code lié au même contexte d’exécution ne s’exécutera. Cela permet à un pilote de carte réseau d’avoir une implémentation libre de verrou de son chemin de données.
Modèle mode de sondage NDIS
Le diagramme de séquence suivant illustre la façon dont le même pilote de carte réseau PCIe hypothétique gère une rafale de paquets Rx à l’aide d’un objet Poll au lieu d’un DPC.
Comme le modèle DPC, lorsqu’un paquet Rx arrive le matériel génère une interruption, NDIS appelle l’ISR du pilote et le pilote désactive l’interruption de l’ISR. À ce stade, le modèle mode sondage diffère :
Au lieu de mettre en file d’attente un DPC, le pilote met en file d’attente un objet Poll (qu’il a créé précédemment) à partir de l’ISR pour informer NDIS que le nouveau travail est prêt à être traité.
À un moment donné, dans le futur NDIS, le gestionnaire d’itérations de sondage du pilote appelle le gestionnaire d’itérations de sondage pour traiter le travail. Contrairement à un DPC, le pilote n’est pas autorisé à indiquer autant de NBL Rx qu’il existe des éléments prêts dans sa file d’attente matérielle. Le pilote doit à la place vérifier le paramètre de données de sondage du gestionnaire pour obtenir le nombre maximal de nbls qu’il peut indiquer.
Une fois que le pilote récupère jusqu’au nombre maximal de paquets Rx, il doit initialiser des listes NBL, les ajouter à la file d’attente NBL fournie par le gestionnaire de sondage et quitter le rappel. Le pilote ne doit pas activer l’interruption avant de quitter.
NDIS continue d’interroger le pilote jusqu’à ce qu’il évalue que le pilote ne progresse plus. À ce stade, NDIS arrête l’interrogation et demande au pilote de réactiver l’interruption.
Mot clé INF standardisé pour le mode de sondage NDIS
Le mot clé suivant doit être utilisé pour activer ou désactiver la prise en charge du mode de sondage NDIS :
*Les mots clés INF standardisés de l’énumération NdisPoll ont les attributs suivants :
Nom de sous-clé
Le nom du mot clé que vous devez spécifier dans le fichier INF et qui apparaît dans le registre.
ParamDesc
Le texte de l’affichage associé à SubkeyName.
Valeur
La valeur entière d’énumération associée à chaque option de la liste. Cette valeur est stockée dans NDI\params\ SubkeyName\Value.
EnumDesc
Le texte de l’affichage associé à chaque valeur qui apparaît dans le menu.
Par défaut
Valeur par défaut du menu.
Nom de sous-clé | ParamDesc | Valeur | EnumDesc |
---|---|---|---|
*NdisPoll | Mode de sondage Ndis | 0 | Désactivé |
1 (par défaut) | Activé(e) |
Pour en savoir plus sur l’utilisation des mots clés d’énumération, se reporter à Mots clés d'énumération.
Création d’un objet Poll
Pour créer un objet Poll, le pilote miniport effectue les opérations suivantes dans sa fonction de rappel MiniportInitializeEx :
- Alloue un contexte miniport privé.
- Alloue une structure NDIS_POLL_CHARACTERISTICS pour spécifier des points d’entrée pour les fonctions de rappel NdisPoll et NdisSetPollNotification.
- Appelle NdisRegisterPoll pour créer l’objet Poll et le stocker dans le contexte miniport.
L’exemple suivant montre comment un pilote miniport peut créer un objet Poll pour un flux de file d’attente de réception. La gestion des erreurs est omise par souci de simplicité.
NDIS_SET_POLL_NOTIFICATION NdisSetPollNotification;
NDIS_POLL NdisPoll;
NDIS_STATUS
MiniportInitialize(
_In_ NDIS_HANDLE NdisAdapterHandle,
_In_ NDIS_HANDLE MiniportDriverContext,
_In_ NDIS_MINIPORT_INIT_PARAMETERS * MiniportInitParameters
)
{
// Allocate a private miniport context
MINIPORT_CONTEXT * miniportContext = ...;
NDIS_POLL_CHARACTERISTICS pollCharacteristics;
pollCharacteristics.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
pollCharacteristics.Header.Revision = NDIS_POLL_CHARACTERISTICS_REVISION_1;
pollCharacteristics.Header.Size = NDIS_SIZEOF_NDIS_POLL_CHARACTERISTICS_REVISION_1;
pollCharacteristics.SetPollNotificationHandler = NdisSetPollNotification;
pollCharacteristics.PollHandler = NdisPoll;
// Create a Poll object and store it in the miniport context
NdisRegisterPoll(
NdisAdapterHandle,
miniportContext,
&pollCharacteristics,
&miniportContext->RxPoll);
return NDIS_STATUS_SUCCESS;
}
Mise en file d’attente d’un objet Poll pour l’exécution
À partir d’un ISR, les pilotes miniport appellent NdisRequestPoll pour mettre en file d’attente un objet Poll pour l’exécution. L’exemple suivant montre la gestion des réceptions, mais ignore le partage des lignes d’interruption par souci de simplicité.
BOOLEAN
MiniportIsr(
KINTERRUPT * Interrupt,
void * Context
)
{
auto miniportContext = static_cast<MINIPORT_CONTEXT *>(Context);
auto hardwareContext = miniportContext->HardwareContext;
// Check if this interrupt is due to a received packet
if (hardwareContext->ISR & RX_OK)
{
// Disable the receive interrupt and queue the Poll
hardwareContext->IMR &= ~RX_OK;
NdisRequestPoll(miniportContext->RxPoll, nullptr);
}
return TRUE;
}
Implémentation du gestionnaire d’itérations de sondage
NDIS appelle le rappel NdisPoll du pilote miniport pour interroger les indications de réception et envoyer des achèvements. NDIS appelle d’abord NdisPoll lorsque le pilote appelle NdisRequestPoll pour mettre en file d’attente un objet Poll. NDIS continue d’appeler NdisPoll pendant que le pilote avance sur les indications de réception ou les achèvements de transmission.
Pour les indications de réception, le pilote doit effectuer les opérations suivantes dans NdisPoll :
- Vérifiez le paramètre de réception de la structure NDIS_POLL_DATA pour obtenir le nombre maximal de nbls qu’il peut indiquer.
- Récupérez jusqu’au nombre maximal de paquets Rx.
- Initialisez les LISTES NBL.
- Ajoutez-les à la file d’attente NBL fournie par la structure NDIS_POLL_RECEIVE_DATA (située dans la structure NDIS_POLL_DATA du paramètre NdisPoll PollData).
- Quittez le rappel.
Pour les achèvements de transmission, le pilote doit effectuer les opérations suivantes dans NdisPoll :
- Vérifiez le paramètre de transmission de la structure NDIS_POLL_DATA pour obtenir le nombre maximal de nbls qu’il peut terminer.
- Récupérez jusqu’au nombre maximal de paquets Tx.
- Terminez les LISTES NBL.
- Ajoutez-les à la file d’attente NBL fournie par la structure NDIS_POLL_TRANSMIT_DATA (située dans la structure NDIS_POLL_DATA du paramètre NdisPoll PollData).
- Quittez le rappel.
Le pilote ne doit pas activer l’interruption de l’objet Poll avant de quitter la fonction NdisPoll . NDIS maintient l’interrogation du pilote jusqu’à ce qu’il évalue qu’aucune progression vers l’avant n’est effectuée. À ce stade, NDIS arrête l’interrogation et demande au pilote de réactiver l’interruption.
Voici comment un pilote peut implémenter NdisPoll pour un flux de file d’attente de réception.
_Use_decl_annotations_
void
NdisPoll(
void * Context,
NDIS_POLL_DATA * PollData
)
{
auto miniportContext = static_cast<MINIPORT_CONTEXT *>(Context);
auto hardwareContext = miniportContext->HardwareContext;
// Drain received frames
auto & receive = PollData->Receive;
receive.NumberOfRemainingNbls = NDIS_ANY_NUMBER_OF_NBLS;
receive.Flags = NDIS_RECEIVE_FLAGS_SHARED_MEMORY_VALID;
while (receive.NumberOfIndicatedNbls < receive.MaxNblsToIndicate)
{
auto rxDescriptor = HardwareQueueGetNextDescriptorToCheck(hardwareContext->RxQueue);
// If this descriptor is still owned by hardware stop draining packets
if ((rxDescriptor->Status & HW_OWN) != 0)
break;
auto nbl = MakeNblFromRxDescriptor(miniportContext->NblPool, rxDescriptor);
AppendNbl(&receive.IndicatedNblChain, nbl);
receive.NumberOfIndicatedNbls++;
// Move to next descriptor
HardwareQueueAdvanceNextDescriptorToCheck(hardwareContext->RxQueue);
}
}
Gestion des interruptions
Les pilotes miniport implémentent le rappel NdisSetPollNotification pour activer ou désactiver l’interruption associée à un objet Poll. NDIS appelle généralement le rappel NdisSetPollNotification lorsqu’il détecte que le pilote miniport n’effectue pas de progression vers l’avant dans NdisPoll. NDIS utilise NdisSetPollNotification pour indiquer au pilote qu’il arrêtera d’appeler NdisPoll. Le pilote doit appeler NdisRequestPoll lorsque le nouveau travail est prêt à être traité.
Voici comment un pilote peut implémenter NdisSetPollNotification pour un flux de file d’attente de réception.
_Use_decl_annotations_
void
NdisSetPollNotification(
void * Context,
NDIS_POLL_NOTIFICATION * Notification
)
{
auto miniportContext = static_cast<MINIPORT_CONTEXT *>(Context);
auto hardwareContext = miniportContext->HardwareContext;
if (Notification->Enabled)
{
hardwareContext->IMR |= RX_OK;
}
else
{
hardwareContext->IMR &= ~RX_OK;
}
}