📄 teardown.c
字号:
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
//
// (c) Microsoft Corporation. All rights reserved.
//
// This file is part of the Microsoft Virtual Ring Routing distribution.
// You should have received a copy of the Microsoft Research Shared Source
// license agreement (MSR-SSLA) for this software; see the file "license.txt".
// If not, please see http://research.microsoft.com/vrr/license.htm,
// or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
//
#include "headers.h"
//* TearDownCacheInit
void
TearDownCacheInit(TearDownCache *TDC)
{
KeInitializeSpinLock(&TDC->Lock);
TDC->FirstTDCE = TDC->LastTDCE = SentinelTDCE(TDC);
}
//* RemoveTDCE
void
RemoveTDCE(
TearDownCache *TDC,
TearDownCacheEntry *TDCE)
{
//
// Sanity checks.
//
VRRASSERT(TDCE != (TearDownCacheEntry *)TDC);
//
// Adjust pointers and free memory.
//
TDCE->Next->Prev = TDCE->Prev;
TDCE->Prev->Next = TDCE->Next;
ExFreePool(TDCE);
}
//* InsertTDCE
//
// Insert TDCE into TearDown cache.
//
// Caller must hold the TDC->Lock.
//
void
InsertTDCE(
TearDownCache *TDC,
TearDownCacheEntry *TDCE)
{
TearDownCacheEntry *NextTDCE;
VRRASSERT(TDC != NULL);
VRRASSERT(TDCE != NULL);
//
// Find insertion point for new TDCE in the TearDown cache.
//
for (NextTDCE = TDC->FirstTDCE;
NextTDCE != SentinelTDCE(TDC);
NextTDCE = NextTDCE->Next) {
if (VirtualAddressLessThan(TDCE->Address, NextTDCE->Address))
continue;
if (VirtualAddressLessThan(NextTDCE->Address, TDCE->Address))
break;
if (TDCE->PathId < NextTDCE->PathId)
continue;
break;
}
//
// Insert the new TDCE immediately prior to NextTDCE.
//
TDCE->Prev = NextTDCE->Prev;
TDCE->Prev->Next = TDCE;
TDCE->Next = NextTDCE;
TDCE->Next->Prev = TDCE;
}
//* CreateTDCE
//
//
TearDownCacheEntry *
CreateTDCE(
VirtualAddress Address,
uint PathId,
VirtualAddress ReportedBy)
{
TearDownCacheEntry *TDCE;
TDCE = ExAllocatePool(NonPagedPool, sizeof *TDCE);
if (TDCE == NULL)
return NULL;
//
// Initialize the TDCE.
//
RtlZeroMemory(TDCE, sizeof *TDCE);
RtlCopyMemory(TDCE->Address,Address,sizeof(VirtualAddress));
TDCE->PathId = PathId;
TDCE->Timeout = KeQueryInterruptTime() + TDOWN_CACHE_LIFETIME;
RtlCopyMemory(TDCE->ReportedBy,ReportedBy,sizeof(VirtualAddress));
return TDCE;
}
//* FindTDCE
//
// Returns TDCE iff in Teardown cache, else NULL.
//
// Caller must hold the TDC->Lock.
//
TearDownCacheEntry *
FindTDCE(
TearDownCache *TDC,
VirtualAddress Address,
uint PathId,
VirtualAddress ReportedBy)
{
TearDownCacheEntry *TDCE;
VRRASSERT(TDC != NULL);
for (TDCE = TDC->FirstTDCE;
TDCE != SentinelTDCE(TDC);
TDCE = TDCE->Next) {
if (VirtualAddressEqual(TDCE->Address, Address) &&
TDCE->PathId == PathId) {
if (IsUnspecified(ReportedBy) ||
VirtualAddressEqual(TDCE->ReportedBy, ReportedBy))
return TDCE;
}
}
return NULL;
}
//* FindOrCreateTDCE
//
// Returns TDCE if match found in TearDown cache, else
// tries to create a matching TDCE.
//
// A return value of NULL means failure.
//
// Caller must hold the TDC->Lock.
//
TearDownCacheEntry *
FindOrCreateTDCE(
TearDownCache *TDC,
VirtualAddress Address,
uint PathId,
VirtualAddress ReportedBy)
{
TearDownCacheEntry *TDCE;
TDCE = FindTDCE(TDC, Address, PathId, ReportedBy);
if (TDCE == NULL)
if ((TDCE=CreateTDCE(Address, PathId, ReportedBy)) != NULL)
InsertTDCE(TDC, TDCE);
return TDCE;
}
//* TearDownCacheCleanup
//
// Flush the TearDown cache.
//
void
TearDownCacheCleanup(
TearDownCache *TDC)
{
TearDownCacheEntry *TDCE;
KIRQL OldIrql;
KeAcquireSpinLock(&TDC->Lock, &OldIrql);
while ((TDCE = TDC->FirstTDCE) != SentinelTDCE(TDC))
RemoveTDCE(TDC, TDCE);
KeReleaseSpinLock(&TDC->Lock, OldIrql);
}
//* CreateTearDownOpt
//
// Creates an SRP Opt encoding a TearDown.
//
// Note that PidBuf and SizeOfPIdBuff args may cover
// both a list of SizeofPidBuff PathIds *plus* a
// trailing vset (e.g. in case that caller wants to
// fwd a copy of someone else's vset rather than
// include a copy of this node's vset). In such
// cases the caller must supply IncludeVSet=FALSE.
//
// Caller must not hold the NT->Lock.
//
InternalVrrTearDown *
CreateTearDownOpt(
MiniportAdapter *VA,
VirtualAddress Dest,
uint NumPId,
uint SizeOfPIdBuff,
VrrGlobalPathId PidBuf[],
uint IncludeVSet,
uint Forwarding)
{
uint OptSize;
NodeTableEntry *NTE;
KIRQL OldIrql;
uint NTECount = 0;
uint i;
InternalVrrTearDown *ITD;
uint FrameSeqNo = 0;
VirtualAddress FlatVSet[VRR_MAX_VSET_SIZE];
//
// Maintain counters.
//
if (Forwarding)
InterlockedIncrement((PLONG)&VA->CountFwdTearDown);
else
InterlockedIncrement((PLONG)&VA->CountSendTearDown);
//
// Lock the Node Table during our traversals.
//
KeAcquireSpinLock(&VA->NT.Lock, &OldIrql);
//
// Obtain memory for VrrTearDown option.
//
if (IncludeVSet)
NTECount = VSetToFlatBuffer(VA,FlatVSet);
OptSize = sizeof *ITD // Internal option linkage.
+ sizeof(VrrTearDown) // Preamble.
+ SizeOfPIdBuff // Supplied by caller.
+ (NTECount * sizeof(VirtualAddress)); // vset, iff generating inline.
if ((ITD=ExAllocatePool(NonPagedPool, OptSize)) == NULL) {
goto UnlockReleaseAndReturn;
}
//
// Format the TearDown header.
//
RtlZeroMemory(ITD, OptSize);
ITD->Opt.OptionType = VRR_OPTION_TYPE_TEARDOWN;
ITD->Opt.OptDataLen = OptSize - sizeof(*ITD) - sizeof(VRROption);
RtlCopyMemory(ITD->Opt.Source, VA->NT.Self->Address, sizeof(VirtualAddress));
RtlCopyMemory(ITD->Opt.Dest, Dest, sizeof(VirtualAddress));
RtlCopyMemory(ITD->Opt.Proxy, Dest, sizeof(VirtualAddress));
ITD->Opt.Flags = 0;
ITD->Opt.NumGlobalPathId = RtlUlongByteSwap(NumPId);
RtlCopyMemory(ITD->Opt.PId, PidBuf, SizeOfPIdBuff);
FrameSeqNo = InterlockedIncrement((unsigned long *)&VrrGlobal.NextFrameSeqNo);
ITD->Opt.FrameSeqNo = RtlUlongByteSwap(FrameSeqNo);
//
// Append list of VSet addresses.
//
if (IncludeVSet)
RtlCopyMemory(&ITD->Opt.PId[NumPId],FlatVSet,NTECount*sizeof(VirtualAddress));
for (i = 0; i < NumPId; i++)
VrrTrace(VA,3,"TD:TD=New_",VA->Address,Dest,PidBuf[i].Address,"Pid",RtlUlongByteSwap(PidBuf[i].PathId),"FrameSeqNo",FrameSeqNo);
UnlockReleaseAndReturn:
//
// Finished with Node Table. Release its lock.
//
KeReleaseSpinLock(&VA->NT.Lock, OldIrql);
return ITD;
}
//* IsValidTearDownElement
//
// Helper for ReceiveTearDown.
// Given element=(EndpointA,PathId) from a TearDown buffer and an RTE
// returns TRUE if, and only if, the element should be accepted.
//
// Caller must hold the RT->Lock.
//
uint
IsValidTearDownElement(
VirtualAddress Sender,
VrrGlobalPathId *GPId,
RouteTableEntry *RTE)
{
//
// The RTE must be in state Active.
//
if (RTE->State != VRR_RTE_STATE_ACTIVE)
return FALSE;
//
// GPId and RTE must match on EndpointA and PathId.
//
if (RTE->PathId != RtlUlongByteSwap(GPId->PathId))
return FALSE;
if (! VirtualAddressEqual(RTE->A.Address,GPId->Address))
return FALSE;
//
// Ignore TD sent by node other than RTE->NextA or RTE->NextB.
//
if (RTE->A.Next != NULL &&
VirtualAddressEqual(Sender,RTE->A.Next->VAddress))
return TRUE;
if (RTE->B.Next != NULL &&
VirtualAddressEqual(Sender,RTE->B.Next->VAddress))
return TRUE;
return FALSE;
}
//* ReceiveTearDown
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -