📄 partition.c
字号:
KeReleaseSpinLock(&VA->ZL.Lock, OldIrql);
return NextTimeout;
}
//* UpdateLocalZeroListEntry
//
// Refresh ZLE representing self.
//
void
UpdateLocalZeroListEntry(
MiniportAdapter *VA)
{
KIRQL OldIrql;
KeAcquireSpinLock(&VA->ZL.Lock, &OldIrql);
UpdateZLE(VA,VA->Address,GetZeroSeqNo());
KeReleaseSpinLock(&VA->ZL.Lock, OldIrql);
}
//* EmitHelloZeroList
//
// Emit list of partition representatives (Zero List) in
// format expected by Hello message.
//
void
EmitHelloZeroList(
MiniportAdapter *VA,
VrrHello *Hello)
{
KIRQL OldIrql;
NodeTable *NT = &VA->NT;
ZeroList *ZL = &VA->ZL;
NodeTableEntry *NTE;
ZeroListEntry *ZLE;
uint AmActive = FALSE;
uint AmClosestZero = TRUE;
//
// Decide if we're the representative node for this partition.
//
KeAcquireSpinLock(&NT->Lock, &OldIrql);
AmActive = IsDriverActive(VA);
for (NTE = NT->FirstNTE; NTE != SentinelNTE(NT); NTE = NTE->Next) {
if (VirtualAddressIsCloser(NTE->Address, VA->Address, NullAddress)) {
AmClosestZero = FALSE;
break;
}
}
KeReleaseSpinLock(&NT->Lock, OldIrql);
//
// If we are representative, refresh our Zero List entry.
//
if (AmActive && AmClosestZero)
UpdateLocalZeroListEntry(VA);
//
// Dump first two ACTIVE entries from Zero List to caller's
// buffer.
//
KeAcquireSpinLock(&ZL->Lock, &OldIrql);
ZLE = ZL->FirstZLE;
if (ZLE != SentinelZLE(ZL) && ZLE->State == ZLE_STATE_ACTIVE) {
Hello->ZeroCount++;
RtlCopyMemory(Hello->Zero1Addr,ZLE->Address,sizeof(VirtualAddress));
Hello->Zero1SeqNo = RtlUlongByteSwap(ZLE->SeqNo);
if ((ZLE=ZLE->Next) != SentinelZLE(ZL) && ZLE->State == ZLE_STATE_ACTIVE) {
Hello->ZeroCount++;
RtlCopyMemory(Hello->Zero2Addr,ZLE->Address,sizeof(VirtualAddress));
Hello->Zero2SeqNo = RtlUlongByteSwap(ZLE->SeqNo);
}
}
KeReleaseSpinLock(&ZL->Lock, OldIrql);
}
//* ReceiveHelloZeroList
//
// Receive the Zero List from an incoming Hello message.
//
// Caller must not hold ZL->Lock;
// Caller must not hold NC->Lock;
// Caller must not hold RT->Lock;
// Caller must not hold NT->Lock;
// Caller must not hold PCache->Lock;
//
void
ReceiveHelloZeroList(
MiniportAdapter *VA,
VrrHello *Hello,
VirtualAddress NextHop,
VRRIf LocIF,
Time Now)
{
KIRQL OldIrql;
ZeroList *ZL = &VA->ZL;
ZeroListEntry *ZLE;
NeighborCacheEntry *NCE;
VRRIf RemIF = Hello->SentFromIF;
RouteTableEntry *RTE1;
RTEFlags Flags1;
Time RTETimeout = Now + HelloLifetime;
VirtualAddress *ZeroAddress;
uint Zero2PathId = 0;
uint i;
//
// Sanity test on ZeroCount.
//
if (Hello->ZeroCount == 0)
return;
if (Hello->ZeroCount > VRRHELLO_MAX_ZERO_LIST_ENTRIES) {
VrrKdPrint("RcvZList: drop hello from s, ZeroCount too large",
Hello->source, NULL);
return;
}
//
// Update our Zero List with max two hosts per Hello message.
//
KeAcquireSpinLock(&ZL->Lock, &OldIrql);
UpdateZLE(VA,Hello->Zero1Addr,RtlUlongByteSwap(Hello->Zero1SeqNo));
if (Hello->ZeroCount == VRRHELLO_MAX_ZERO_LIST_ENTRIES)
UpdateZLE(VA,Hello->Zero2Addr,RtlUlongByteSwap(Hello->Zero2SeqNo));
KeReleaseSpinLock(&ZL->Lock, OldIrql);
//
// Partition repair may be disabled.
//
if (IsPartitionRepairEnabled(VA) == FALSE)
return;
//
// There may be some delay before a new NCE becomes LINKED.
//
KeAcquireSpinLock(&VA->NC.Lock, &OldIrql);
NCE = FindNCE(&VA->NC,NextHop,LocIF, RemIF, VRR_NCE_STATE_LINKED);
KeReleaseSpinLock(&VA->NC.Lock, OldIrql);
if (NCE == NULL)
return;
//
// Ensure we have routes of type zero for each partition
// representative via the node that sent us this hello,
// taking ETT from the corresponding Hops1 route.
//
// The Z routes have short lifetimes and are soon garbage
// collected by the route module unless frequently renewed.
//
Flags1.Flags = 0;
Flags1.Hops1 = 1;
KeAcquireSpinLock(&VA->RT.Lock, &OldIrql);
RTE1 = FindRTE(VA, VA->Address, Hello->source, VRR_PATHID_UNSPECIFIED,
VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED,
NextHop, LocIF, Hello->SentFromIF, Flags1);
ZeroAddress = &Hello->Zero1Addr;
for (i=0; i<Hello->ZeroCount; i++) {
if (! VirtualAddressEqual(*ZeroAddress, VA->Address)) {
//
// Removing old route for ZeroAddress is easier than updating it,
// as it saves messing with NCE ref counts etc.
//
RouteTableEntry *RTE;
RTEFlags FlagsZ;
FlagsZ.Flags = 0;
FlagsZ.Zero = 1;
RTE = FindRTE(VA, VA->Address, *ZeroAddress, VRR_PATHID_UNSPECIFIED,
VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED,
VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED,
FlagsZ);
if (RTE != NULL) {
RTE->State = VRR_RTE_STATE_RETIRED;
RTE->Timeout = Now + RTE_RETIRE_IMMEDIATE;
}
//
// Update existing, or create new, route for the zero address.
//
RTE = FindOrCreateRTE(VA, VA->Address, *ZeroAddress, VRR_PATHID_UNSPECIFIED,
VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED,
NextHop, LocIF, RemIF, NullAddress, FlagsZ);
if (RTE != NULL) {
RTE->Timeout = RTETimeout;
if (RTE1 != NULL)
RTE->ETT = RTE1->ETT;
if (i != 0)
Zero2PathId = RTE->PathId;
}
}
ZeroAddress++;
}
KeReleaseSpinLock(&VA->RT.Lock, OldIrql);
//
// Assume that the ring breaks into partions A and B,
// and that we are in A. If A and B meet again then
// all it takes is one vset message between A and B
// for vset repair to start, and once started it will
// ripple throughout both partitions.
//
// Assume that A is much larger than B, hence it is
// likely that closest(zero,A) is closer to zero than
// closest(zero,B), hence any hello featuring both
// will have Zero2Addr=closest(zero,B).
//
// Assume we are in A, that fresh information about
// closest(zero,B) reaches us. If closest(zero,B) belongs
// in our vset then we are the node that will start the
// process by sending a Setup to closest(zero,B).
//
if (Hello->ZeroCount > 1 &&
IsDriverActive(VA) &&
IsCandidateNeighbor(VA,Hello->Zero2Addr,1,&Hello->Zero2Addr) &&
FindVSetRoute(VA, VA->Address, Hello->Zero2Addr) == NULL) {
NodeTableEntry *NTE = NULL;
InternalVrrSetup *Setup = NULL;
RouteTableEntry *RTE = NULL;
uint PathId;
KeAcquireSpinLock(&VA->NT.Lock, &OldIrql);
NTE = FindNTE(&VA->NT,Hello->Zero2Addr);
KeReleaseSpinLock(&VA->NT.Lock, OldIrql);
//
// Create setup message before updating our VSet,
// obtaining snapshot of current state of VSet.
//
if (NTE == NULL) {
Setup = CreateSetupOpt(VA,
Hello->Zero2Addr, // Dest.
VA->Address, // Endpoint A.
Hello->Zero2Addr, // Endpoint B.
0, // PathId - inserted later.
Hello->Zero2Addr, // Proxy.
NullAddress, // Prev wrt NextNextA local path repair.
VA->Address);
}
//
// Create an RTE type V for Zero2Addr.
//
if (Setup != NULL) {
RTEFlags FlagsV;
FlagsV.Flags = 0;
FlagsV.VSet = 1;
KeAcquireSpinLock(&VA->RT.Lock, &OldIrql);
VrrKdPrint("RcvZList: send setup(d)",NULL,Hello->Zero2Addr);
RTE = FindOrCreateRTE(VA,
VA->Address, // VirtualAddress EndpointA,
Hello->Zero2Addr, // VirtualAddress EndpointB,
VRR_PATHID_UNSPECIFIED, // PathId,
VRR_ADDRESS_UNSPECIFIED, // VirtualAddress NextA,
VRR_IFID_UNSPECIFIED, // LocIFa,
VRR_IFID_UNSPECIFIED, // RemIFa,
NextHop, // VirtualAddress NextB,
LocIF, // LocIFb,
RemIF, // RemIFb,
NullAddress, // NextNextA.
FlagsV);
if (RTE != NULL)
PathId = RTE->PathId;
KeReleaseSpinLock(&VA->RT.Lock, OldIrql);
}
//
// Add Zero2Addr to local VSet and send Setup.
//
if (RTE != NULL) {
VirtualAddress *ZeroVSet = &Hello->Zero2Addr;
VrrKdPrint("RcvZList: VSetAdd(d) & SendSetup(d)",NULL,Hello->Zero2Addr);
VSetAddNode(VA,Hello->Zero2Addr,1,ZeroVSet);
Setup->Opt.PathId = RtlUlongByteSwap(PathId);
Setup->Opt.LocIF = LocIF;
Setup->Opt.RemIF = RemIF;
InterlockedIncrement((PLONG)&VA->CountPnRepairSendSetup);
MsgQueueMessage(VA, NextHop, (InternalOption *) Setup, LocIF, RemIF, SETUP_DELAY, NULL);
Setup = NULL;
}
if (Setup != NULL) {
//
// Allocated but never sent message.
//
ExFreePool(Setup);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -