Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les pilotes réseau Windows utilisent des requêtes OID pour envoyer des messages de contrôle vers le bas de la pile de liaison NDIS. Les pilotes de protocole, tels que TCPIP ou vSwitch, s’appuient sur des dizaines d’OID pour configurer chaque fonctionnalité du pilote de carte réseau sous-jacente. Avant Windows 10, version 1709, les demandes OID ont été envoyées de deux manières : standard et direct.
Cette rubrique présente un troisième style d’appel OID : synchrone. Un appel synchrone est destiné à être faible latence, non bloquant, scalable et fiable. L’interface de requête OID synchrone est disponible à partir de NDIS 6.80, qui est incluse dans Windows 10, version 1709 et ultérieure.
Comparaison avec les requêtes OID standard et directes
Avec les requêtes OID synchrones, la charge utile de l’appel (l’OID lui-même) est exactement la même qu’avec les requêtes OID régulières et directes. La seule différence est dans l’appel lui-même. Par conséquent, ce qui est le même pour les trois types d’OID ; c’est seulement la façon dont il est différent.
Le tableau suivant décrit les différences entre les OID standard, les OID directs et les OID synchrones.
| Caractéristique | OID standard | Direct OID | OID synchrone |
|---|---|---|---|
| Charge utile | NDIS_OID_REQUEST | NDIS_OID_REQUEST | NDIS_OID_REQUEST |
| Types d'OID | Statistiques, Requête, Ensemble, Méthode | Statistiques, Requête, Ensemble, Méthode | Statistiques, Requête, Ensemble, Méthode |
| Peut être émis par | Protocoles, filtres | Protocoles, filtres | Protocoles, filtres |
| Peut être effectué par | Miniports, filtres | Miniports, filtres | Miniports, filtres |
| Les filtres peuvent modifier | Oui | Oui | Oui |
| NDIS alloue de la mémoire | Pour chacun des filtres (clone OID) | Pour chaque filtre (clone OID) | Uniquement si un nombre inhabituellement élevé de filtres (dans le contexte d’appel) |
| Peut pender | Oui | Oui | Non |
| Peut bloquer | Oui | Non | Non |
| IRQL | == PASSIF | <= EXPÉDITION | <= DISPATCH |
| Sérialisé par NDIS | Oui | Non | Non |
| Les filtres sont appelés | Récursivement | Récursivement | Itérativement |
| Filtres clonent l’OID | Oui | Oui | Non |
Filtrage
Comme les deux autres types d’appels OID, les pilotes de filtre ont un contrôle total sur la requête OID dans un appel synchrone. Les pilotes de filtre peuvent observer, intercepter, modifier et émettre des OID synchrones. Toutefois, pour une efficacité, les mécanismes d’un OID synchrone sont quelque peu différents.
Passthrough, interception et origination
Conceptuellement, toutes les demandes OID sont émises à partir d’un pilote plus élevé et sont effectuées par un pilote inférieur. Le long du chemin, la requête OID peut passer par n’importe quel nombre de pilotes de filtre.
Dans le cas le plus courant, un pilote de protocole émet une requête OID et tous les filtres transmettent simplement la requête OID, non modifiée. La figure suivante illustre ce scénario courant.
Toutefois, tout module de filtre est autorisé à intercepter la requête OID et à la terminer. Dans ce cas, la requête ne passe pas à des pilotes inférieurs, comme illustré dans le diagramme suivant.
Dans certains cas, un module de filtre peut décider de générer sa propre requête OID. Cette requête commence au niveau du module de filtre et traverse uniquement les pilotes inférieurs, comme le montre le diagramme suivant.
Toutes les requêtes OID ont ce flux de base : un pilote plus élevé (un protocole ou un pilote de filtre) émet une requête et un pilote inférieur (un miniport ou un pilote de filtre) le termine.
Fonctionnement des requêtes OID régulières et directes
Les requêtes OID régulières ou directes sont distribuées de manière récursive. Le diagramme suivant montre la séquence d’appels de fonction. Notez que la séquence elle-même est similaire à la séquence décrite dans les diagrammes de la section précédente, mais est organisée pour afficher la nature récursive des requêtes.
S’il existe suffisamment de filtres installés, NDIS est obligé d’allouer une nouvelle pile de fil d'exécution pour permettre une récursion plus profonde.
NDIS considère qu’une structure NDIS_OID_REQUEST est valide pour une seule étape dans la pile. Si un pilote de filtre souhaite transmettre la requête au pilote inférieur suivant (qui est le cas pour la grande majorité des OID), le pilote de filtre doit insérer plusieurs dizaines de lignes de code réutilisable pour cloner la requête OID. Ce modèle standard présente plusieurs problèmes :
- Elle force une allocation de mémoire pour cloner l’OID. L’accès au pool de mémoire est à la fois lent et il est impossible de garantir la progression vers l’avant de la requête OID.
- La conception de la structure OID doit rester la même au fil du temps, car tous les pilotes de filtre codent en dur la mécanique de copie du contenu d’une NDIS_OID_REQUEST vers une autre.
- Exiger tant de code standard rend difficile de voir ce que le filtre fait vraiment.
Modèle de filtrage pour les requêtes OID synchrones
Le modèle de filtrage des requêtes OID synchrones tire parti de la nature synchrone de l’appel pour résoudre les problèmes abordés dans la section précédente.
Émetteurs et gestionnaires de complétion
Contrairement aux requêtes OID régulières et directes, il existe deux crochets de filtre pour les requêtes OID synchrones : un gestionnaire de problèmes et un gestionnaire complet. Un pilote de filtre ne peut inscrire ni l’un ni l’autre, ni les deux crochets.
Les appels de problème sont appelés pour chaque pilote de filtre, en commençant du haut de la pile vers le bas de la pile. Tout appel de problème de filtre peut empêcher l’OID de continuer vers le bas et de terminer l’OID avec un code d’état. Si aucun filtre ne décide d’intercepter l’OID, l’OID atteint le pilote de carte réseau, qui doit effectuer l’OID de manière synchrone.
Une fois qu’un OID est terminé, les appels complets sont appelés pour chaque pilote de filtre, à partir de n’importe où dans la pile où l’OID a été terminé, jusqu’au haut de la pile. Un appel complet peut inspecter ou modifier la requête OID, et inspecter ou modifier le code d’état d’achèvement de l’OID.
Le diagramme suivant illustre le cas classique, où un protocole émet une requête OID synchrone et les filtres n’interceptent pas la requête.
Notez que le modèle d’appel pour les OID synchrones est itératif. Cela maintient l’utilisation de la pile limitée par une constante, éliminant ainsi la nécessité d'agrandir la pile.
Si un pilote de filtre intercepte un OID synchrone dans son gestionnaire de problèmes, l’OID n’est pas donné aux filtres inférieurs ou au pilote de carte réseau. Toutefois, les gestionnaires complets pour les filtres de niveau supérieur sont toujours appelés, comme illustré dans le diagramme suivant :
Allocations de mémoire minimales
Les requêtes OID régulières et directes nécessitent un pilote de filtre pour cloner un NDIS_OID_REQUEST. En revanche, les requêtes OID synchrones ne sont pas autorisées à être clonées. L’avantage de cette conception est que les OID synchrones ont une latence inférieure ( la requête OID n’est pas cloné à plusieurs reprises, car elle se déplace vers le bas de la pile de filtres) et il y a moins d’opportunités d’échec.
Toutefois, cela soulève un nouveau problème. Si l’OID ne peut pas être cloné, où un pilote de filtre stocke-t-il son état par requête ? Par exemple, supposons qu’un pilote de filtre traduit un OID en un autre. Lors de la descente dans la pile, le filtre doit sauvegarder l’ancien OID. Lors de la remontée de la pile, le filtre doit restaurer l’ancien OID.
Pour résoudre ce problème, NDIS alloue un emplacement de la taille d'un pointeur pour chaque pilote de filtre, pour chaque requête OID synchrone en cours. NDIS conserve cet emplacement dans l’appel à partir du gestionnaire de problèmes d’un filtre vers son gestionnaire Complet. Cela permet au gestionnaire de problèmes d’enregistrer l’état qui est consommé ultérieurement par le gestionnaire Complete. L’extrait de code suivant montre un exemple.
NDIS_STATUS
MyFilterSynchronousOidRequest(
_In_ NDIS_HANDLE FilterModuleContext,
_Inout_ NDIS_OID_REQUEST *OidRequest,
_Outptr_result_maybenull_ PVOID *CallContext)
{
if ( . . . should intercept this OID . . . )
{
// preserve the original buffer in the CallContext
*CallContext = OidRequest->DATA.SET_INFORMATION.InformationBuffer;
// replace the buffer with a new one
OidRequest->DATA.SET_INFORMATION.InformationBuffer = . . . something . . .;
}
return NDIS_STATUS_SUCCESS;
}
VOID
MyFilterSynchronousOidRequestComplete(
_In_ NDIS_HANDLE FilterModuleContext,
_Inout_ NDIS_OID_REQUEST *OidRequest,
_Inout_ NDIS_STATUS *Status,
_In_ PVOID CallContext)
{
// if the context is not null, we must have replaced the buffer.
if (CallContext != null)
{
// Copy the data from the miniport back into the protocol’s original buffer.
RtlCopyMemory(CallContext, OidRequest->DATA.SET_INFORMATION.InformationBuffer,...);
// restore the original buffer into the OID request
OidRequest->DATA.SET_INFORMATION.InformationBuffer = CallContext;
}
}
NDIS enregistre un PVOID par filtre par appel. NDIS alloue un nombre raisonnable d'emplacements sur la pile de manière heuristique, afin qu'il n'y ait pas d'allocations de pool dans les cas habituels. Il s'agit généralement de pas plus de sept filtres. Si l'utilisateur configure un scénario pathologique, NDIS retourne à une allocation de pool.
Réduction du code standard
Prenons l’exemple de modèle standard sur exemple de modèle standard pour gérer les requêtes OID régulières ou directes. Ce code est le coût d'entrée pour simplement enregistrer un gestionnaire d'OID. Si vous souhaitez émettre vos propres OID, vous devez ajouter une douzaine de lignes de code standard. Avec les OID synchrones, il n’est pas nécessaire d’ajouter une complexité supplémentaire à la gestion de l’achèvement asynchrone. Ainsi, vous pouvez supprimer une grande partie de ce code standard.
Voici un gestionnaire de problèmes minimal avec des OID synchrones :
NDIS_STATUS
MyFilterSynchronousOidRequest(
NDIS_HANDLE FilterModuleContext,
NDIS_OID_REQUEST *OidRequest,
PVOID *CallContext)
{
return NDIS_STATUS_SUCCESS;
}
Si vous souhaitez intercepter ou modifier un OID particulier, vous pouvez le faire en ajoutant seulement quelques lignes de code. Le gestionnaire complet minimal est encore plus simple :
VOID
MyFilterSynchronousOidRequestComplete(
NDIS_HANDLE FilterModuleContext,
NDIS_OID_REQUEST *OidRequest,
NDIS_STATUS *Status,
PVOID CallContext)
{
return;
}
De même, un pilote de filtre peut émettre une nouvelle requête OID synchrone propre à l’aide d’une seule ligne de code :
status = NdisFSynchronousOidRequest(binding->NdisBindingHandle, &oid);
En revanche, un pilote de filtre qui doit émettre un OID normal ou direct doit configurer un gestionnaire d’achèvement asynchrone et implémenter un code pour distinguer ses propres achèvements d’OID par rapport aux achèvements des OID qu’il vient de cloner. Un exemple de ce texte standard s’affiche sur Exemple de modèle standard pour émettre une demande d’OID régulière.
Interopérabilité
Bien que les styles d'appel régulier, direct et synchrone utilisent tous les mêmes structures de données, les pipelines ne vont pas au même gestionnaire dans le miniport. En outre, certains OID ne peuvent pas être utilisés dans certains des pipelines. Par exemple, OID_PNP_SET_POWER nécessite une synchronisation minutieuse et force souvent le miniport à effectuer des appels bloquants. Cela rend la gestion difficile dans un rappel OID direct et empêche son utilisation dans un rappel OID synchrone.
Par conséquent, comme avec les requêtes OID directes, les appels OID synchrones ne peuvent être utilisés qu’avec un sous-ensemble d’OID. Dans Windows 10, version 1709, seul le OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES OID utilisé dans la version de mise à l’échelle côté réception version 2 (RSSv2) est pris en charge dans le chemin d’accès OID synchrone.
Implémentation de requêtes OID synchrones
Pour plus d’informations sur l’implémentation de l’interface de requête OID synchrone dans les pilotes, consultez les rubriques suivantes :