Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Síťové ovladače Systému Windows používají požadavky OID k odesílání řídicích zpráv ze zásobníku vazeb NDIS. Ovladače protokolu, například TCPIP nebo vSwitch, spoléhají na desítky identifikátorů OID ke konfiguraci jednotlivých funkcí základního ovladače síťové karty. Před Windows 10 verze 1709 byly požadavky OID odeslány dvěma způsoby: Regular a Direct.
Toto téma představuje třetí styl volání OID: Synchronní. Synchronní volání má být nízkolatenční, neblokující, škálovatelné a spolehlivé. Synchronní rozhraní požadavku OID je dostupné od verze NDIS 6.80, která je součástí Windows 10 verze 1709 a novější.
Porovnání s běžnými a přímými požadavky OID
U synchronních požadavků OID je datová část volání (samotného identifikátoru OID) úplně stejná jako u běžných a přímých požadavků OID. Jediným rozdílem je samotné volání. Proto to, co je stejné napříč všemi třemi typy identifikátorů OID; jenom to, jak se liší.
Následující tabulka popisuje rozdíly mezi běžnými identifikátory OID, přímými identifikátory OID a synchronními identifikátory OID.
| Vlastnost | Běžný identifikátor objektu | Přímý identifikátor OID | Synchronní identifikátor OID |
|---|---|---|---|
| Užitečný náklad | NDIS_OID_REQUEST | NDIS_OID_REQUEST | NDIS_OID_REQUEST |
| Typy OID | Statistiky, Dotaz, Sada, Metoda | Statistiky, Dotaz, Sada, Metoda | Statistiky, Dotaz, Nastavení, Metoda |
| Může být vydáno | Protokoly, filtry | Protokoly, filtry | Protokoly, filtry |
| Může být dokončeno | Miniporty, filtry | Miniporty, filtry | Miniporty, filtry |
| Filtry můžou upravovat | Ano | Ano | Ano |
| NDIS přiděluje paměť. | Pro každý filtr (klon OID) | Pro každý filtr (klon OID) | Pouze pokud je neobvykle velký počet filtrů (kontext volání) |
| Mohou být pozastaveny | Ano | Ano | Ne |
| Může blokovat | Ano | Ne | Ne |
| IRQL | == PASIVNÍ | <= DISPATCH | <= DISPATCH |
| Serializováno pomocí NDIS | Ano | Ne | Ne |
| Filtry jsou aktivovány. | Rekurzívně | Rekurzívně | Iterativně |
| Filtry klonují OID. | Ano | Ano | Ne |
Filtrování
Stejně jako u ostatních dvou typů volání OID mají ovladače filtru plnou kontrolu nad požadavkem OID v synchronním volání. Ovladače filtru můžou sledovat, zachycovat, upravovat a vydávat synchronní identifikátory OID. Kvůli efektivitě se ale mechanika synchronního identifikátoru OID poněkud liší.
Režim průchodu, zachytávání a vytváření
Koncepčně se všechny požadavky OID vydávají z vyššího ovladače a jsou dokončeny nižším ovladačem. Kromě toho může požadavek OID projít libovolným počtem ovladačů filtru.
Ve většině případů ovladač protokolu vydává požadavek OID a všechny filtry jednoduše předávají požadavek OID dále, neupravený. Tento běžný scénář znázorňuje následující obrázek.
Jakýkoli modul filtru ale může zachycovat požadavek OID a dokončit ho. V takovém případě požadavek neprojde nižšími ovladači, jak je znázorněno v následujícím diagramu.
V některých případech se může modul filtru rozhodnout vytvořit vlastní požadavek OID. Tento požadavek začíná na úrovni modulu filtru a prochází pouze nižšími ovladači, jak ukazuje následující diagram.
Všechny požadavky OID mají tento základní tok: vyšší ovladač (protokol nebo ovladač filtru) vydává požadavek a nižší ovladač (miniport nebo ovladač filtru) ho dokončí.
Jak fungují standardní a přímé požadavky OID
Pravidelné nebo přímé požadavky OID se odesílají rekurzivně. Následující diagram znázorňuje posloupnost volání funkce. Všimněte si, že samotná posloupnost je podobná sekvenci popsané v diagramech z předchozí části, ale je uspořádaná tak, aby zobrazovala rekurzivní povahu požadavků.
Pokud je nainstalovaných dostatek filtrů, bude rozhraní NDIS nuceno přidělit nový zásobník vláken, aby se mohlo dále zanořovat v rekurzi.
NDIS považuje strukturu NDIS_OID_REQUEST za platnou pouze pro jediný skok v rámci zásobníku. Pokud ovladač filtru chce předat požadavek následujícímu nižšímu ovladači (což je případ velké většiny OID), ovladač filtru musí vložit několik desítek řádků šablonového kódu pro klonování požadavku OID. Tato šablona má několik problémů:
- Vynutí přidělení paměti ke klonování OID. Dosažení fondu paměti je pomalé a znemožňuje zaručit průběh požadavku OID.
- Návrh struktury OID musí zůstat v průběhu času stejný, protože všechny ovladače filtru pevně kódují mechaniku kopírování obsahu jednoho NDIS_OID_REQUEST do druhého.
- Potřeba tak velkého množství šablonového kódu zakrývá, co filtr ve skutečnosti dělá.
Model filtrování pro synchronní požadavky OID
Model filtrování pro synchronní požadavky OID využívá synchronní povahu volání k řešení problémů probíraných v předchozí části.
Vyhotovení a dokončení obslužných rutin
Na rozdíl od běžných a přímých požadavků OID existují pro synchronní požadavky OID dva filtry: obslužná rutina pro vydávání a obslužná rutina pro dokončení. Ovladač filtru může zaregistrovat ani jeden nebo oba háky.
Volání událostí se vyvolávají pro každý ovladač filtru od vrcholu zásobníku k jeho spodní části. Jakékoli volání problému filtru může zastavit pokračování identifikátoru OID směrem dolů a dokončit identifikátor OID nějakým stavovým kódem. Pokud se žádný filtr nerozhodne zachytit OID, pak OID dosáhne ovladače síťové karty, který musí dokončit OID synchronně.
Po dokončení OID se pro každý ovladač filtru vyvolají volání Complete, počínaje místem, kde byl OID dokončen, až k horní části zásobníku. Úplné volání může zkontrolovat nebo upravit požadavek OID a zkontrolovat nebo upravit stavový kód dokončení identifikátoru.
Následující diagram znázorňuje typický případ, kdy protokol vydává synchronní požadavek OID a filtry nezachycují požadavek.
Všimněte si, že model volání pro synchronní identifikátory OID je iterativní. Díky tomu je využití zásobníku vázané konstantou a eliminuje nutnost kdykoli rozšířit zásobník.
Pokud ovladač filtru zachytí synchronní OID v obslužné rutině zpracování, OID se nepředá nižším filtrům nebo ovladači síťové karty. Kompletní obslužné rutiny pro vyšší úrovně filtrů jsou však stále vyvolány, jak je znázorněno v následujícím diagramu:
Minimální přidělení paměti
Běžné a přímé požadavky OID vyžadují, aby ovladač filtru klonoval NDIS_OID_REQUEST. Naproti tomu synchronní požadavky OID není povoleno klonovat. Výhodou tohoto návrhu je, že synchronní OID mají nižší latenci – požadavek OID se při průchodu filtrovacím zásobníkem neklonuje opakovaně – a existuje méně příležitostí k selhání.
To však vyvolává nový problém. Pokud identifikátor OID nejde naklonovat, kde ovladač filtru ukládá svůj stav podle požadavku? Předpokládejme například, že ovladač filtru přeloží jeden identifikátor OID na jiný. Na cestě dolů zásobníku musí filtr uložit starý identifikátor OID. Při zpětném postupu zásobníkem musí filtr obnovit starý OID.
Aby bylo možné tento problém vyřešit, NDIS přidělí slot velikosti ukazatele pro každý ovladač filtru pro každý požadavek synchronního identifikátoru OID v testovacím prostředí. NDIS zachová tento slot napříč voláním z obslužné rutiny pro vystavení filtru na jeho obslužnou rutinu pro dokončení. To umožňuje obslužné rutině Problému uložit stav, který je později spotřebován obslužnou rutinou Complete. Následující fragment kódu ukazuje příklad.
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 ukládá jeden PVOID na jeden filtr pro jedno volání. NDIS heuristicky přiděluje přiměřený počet slotů v zásobníku, aby v běžném případě nedocházelo k žádným přidělením fondu. Obvykle nedochází k více než sedmi filtrům. Pokud uživatel nastaví patologický případ, NDIS se vrátí k alokaci fondu.
Redukovaný šablonový kód
Vezměte v úvahu často používaný postup pro zpracování běžných nebo přímých požadavků OID na příkladu. Tento kód představuje náklady spojené pouze s registrací obslužné rutiny identifikátoru. Pokud chcete vydat vlastní identifikátory OID, musíte přidat další tucet řádků šablonového textu. U synchronních identifikátorů OID není nutné provádět další složitost zpracování asynchronního dokončování. Tak můžete odstranit většinu z toho standardního kódu.
Tady je minimální obslužná rutina problému s synchronními identifikátory OID:
NDIS_STATUS
MyFilterSynchronousOidRequest(
NDIS_HANDLE FilterModuleContext,
NDIS_OID_REQUEST *OidRequest,
PVOID *CallContext)
{
return NDIS_STATUS_SUCCESS;
}
Pokud chcete zachytit nebo upravit konkrétní identifikátor OID, můžete to udělat tak, že přidáte jenom několik řádků kódu. Minimální obslužná rutina Complete je ještě jednodušší:
VOID
MyFilterSynchronousOidRequestComplete(
NDIS_HANDLE FilterModuleContext,
NDIS_OID_REQUEST *OidRequest,
NDIS_STATUS *Status,
PVOID CallContext)
{
return;
}
Stejně tak může ovladač filtru vydat nový synchronní požadavek OID vlastní pomocí pouze jednoho řádku kódu:
status = NdisFSynchronousOidRequest(binding->NdisBindingHandle, &oid);
Naproti tomu ovladač filtru, který potřebuje vystavit běžný nebo přímý OID, musí nastavit asynchronní obslužnou rutinu dokončení a implementovat specifický kód, aby odlišil dokončení vlastních OID od dokončení OID, které právě naklonoval. Příklad této šablony je uveden v Příklad šablony pro podání běžné žádosti o OID.
Interoperabilita
I když styly pravidelného, přímého a synchronního volání používají stejné datové struktury, roury v miniportu nepřecházejí na stejnou obsluhu. Některé identifikátory OID se navíc nedají použít v některých kanálech. Například OID_PNP_SET_POWER vyžaduje pečlivou synchronizaci a často nutí miniport provádět blokující volání. To znesnadňuje zpracování zpětného volání Direct OID a brání jeho použití v synchronním zpětném volání OID.
Stejně jako u přímých požadavků OID je proto možné synchronní volání OID použít pouze s podmnožinou identifikátorů OID. Ve Windows 10, verze 1709, je ve synchronní OID cestě podporován pouze identifikátor OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES, použitý ve Škálování na straně příjmu verze 2 (RSSv2).
Implementace synchronních požadavků OID
Další informace o implementaci synchronního rozhraní žádosti OID v ovladačích najdete v následujících tématech: