📄 setupreq.c
字号:
goto ReleaseAndReturn;
}
}
//
// Optimistic Lightweight Transaction (like) rules ex C# SetupProbeEvent::Deliver
// ref "don't know how to route message or message looped; drop it but send an ack"
//
RtlZeroMemory(&Token, sizeof(TxToken));
Result = FindNextHop(VA,
SetupReq->Dest,
VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,
&Token,
SRcAntiRoute,
SR_DIRECTION_BITS(SetupReq->Type));
//
// We are acting as a proxy and are closest(originator).
// Ref C# "(nextB == node.nodeid && !passedProxy && dest != node.nodeid)"
//
if (Result == SuccessRcvSelf)
if (! (SetupReq->Flags & VRR_MSG_FLAG_PASTPROXY))
if (!VirtualAddressEqual(SetupReq->Dest,VA->Address)) {
VrrTrace(VA,2,"SR:SR=Drop(BadFwd1)",SetupReq->Source,SetupReq->Source,SetupReq->Dest,NULL,0,"SeqNo",FrameSeqNo);
goto ReleaseAndReturn;
}
//
// Do not fwd SR straight back to the node that created it.
// Ref C# "sender == nextB // subsumed by next but removes one message"
//
if (VirtualAddressEqual(Token.NextVAddress, srp->Source)) {
VrrTrace(VA,2,"SR:SR=Drop(BadFwd2)",SetupReq->Source,SetupReq->Source,SetupReq->Dest,NULL,0,"SeqNo",FrameSeqNo);
goto ReleaseAndReturn;
}
//
// Ref C# "nextB == node.nodeid && !node.Active && dest != node.nodeid"
// where "!node.Active" is true if left or right wing of vset is empty.
//
if (Result == SuccessRcvSelf)
if (!VirtualAddressEqual(SetupReq->Dest,VA->Address))
if (InterlockedCompareExchange(&VA->NT.CountLeft,0,0) == 0 ||
InterlockedCompareExchange(&VA->NT.CountRight,0,0) == 0) {
VrrTrace(VA,2,"SR:SR=Drop(BadFwd3)",SetupReq->Source,SetupReq->Source,SetupReq->Dest,NULL,0,"SeqNo",FrameSeqNo);
goto ReleaseAndReturn;
}
//
// Done with Optimistic Lightweight Transaction (like) rules ex C# SetupProbeEvent::Deliver
//
//
// Special case when acting as proxy for a node attempting to join ring.
// We insist that the joining node be (known to be) LINKED (or ACTIVE).
//
if (VirtualAddressEqual(VA->Address, SetupReq->Dest))
if (SetupReq->Flags & VRR_MSG_FLAG_JOIN_ATTEMPT)
if (! (SetupReq->Flags & VRR_MSG_FLAG_PASTPROXY)) {
//
// We are the proxy in a join attempt.
// Check the originator's NCE.
//
NeighborCacheEntry *NCE;
KeAcquireSpinLock(&VA->NC.Lock, &OldIrql);
NCE = FindNCE(&VA->NC,
SetupReq->Source,
VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,
VRR_NCE_STATE_LINKED);
if (NULL == NCE) {
VrrTrace(VA,2,"SR:SR=Drop(BadProxy)",SetupReq->Source,SetupReq->Source,SetupReq->Dest,NULL,0,"SeqNo",FrameSeqNo);
KeReleaseSpinLock(&VA->NC.Lock, OldIrql);
goto ReleaseAndReturn;
}
KeReleaseSpinLock(&VA->NC.Lock, OldIrql);
}
//
// Forward the message if we are not the destination node.
// Actions that we must perform if acting as a proxy are done at this point.
// This includes swapping (Dest,Proxy) addresses.
//
if (ForwardSR(VA, (InternalOption*)InternalSetupReq, SRcAntiRoute)) {
InterlockedIncrement((PLONG)&VA->CountFwdSetupReq);
goto ReleaseAndReturn;
}
//
// The message is ours to receive.
//
// Deal with SetupReq of type VRR_SR_TYPE_NACK.
// Basically these indicate that the sender is rejecting
// a SetupReq of type VRR_SR_TYPE_REQUEST that we
// sent earlier. We add the sender to the SRcAntiRoute for
// the address we're probing and receive the sender's
// vset in case it tells us a closer neighbour.
//
if (SetupReq->Type & VRR_SR_TYPE_NACK) {
ProbeListEntry *PLE;
uint CountPLESRcAntiRoute;
KeAcquireSpinLock(&VA->NT.Lock,&OldIrql);
if ((PLE=FindPLE(&VA->PL,SetupReq->Target)) == NULL) {
//
// We have no PLE for target.
//
VrrTrace(VA,2,"SR:SR=Drop(NoPLE)",SetupReq->Source,SetupReq->Source,SetupReq->Target,
NULL,0,"SeqNo",FrameSeqNo);
}
else if (PLE->FrameSeqNo != FrameSeqNo) {
VrrTrace(VA,2,"SR:SR=Drop(BadSeqNo)",SetupReq->Source,SetupReq->Source,SetupReq->Target,
NULL,0,"SeqNo",FrameSeqNo);
}
else if (VirtualAddressEqual(SetupReq->Source,SetupReq->Target)) {
//
// If we knew no better and sent to a node that knows we're not in
// its VSet then it will Nack us, but its VSet will tell us a better
// destination(s) for later attempts, and restrictions on probe list
// length will stop us probing that node again.
//
// However, during periods of instability, such as initialization, we
// may get a Nack from a node that has made an incorrect decision
// about whether we should be admitted to its VSet. This most often
// happens when we are advertizing a wrapped VSet, and a later retry
// with an evolved VSet will succeed. Therefore allow retries iff the
// sender is the target of original SR.
//
InterlockedIncrement(&VA->CountSRNackSeqT);
VrrTrace(VA,2,"SR:SR=noop(Sender=target)",SetupReq->Source,SetupReq->Target,SetupReq->Dest,
NULL,0,"SeqNo",FrameSeqNo);
}
else if ((CountPLESRcAntiRoute=AddressListCount(PLE->SRcAntiRoute)) <= PLE_MAX_REXMITS) {
//
// Our SR was routed along a path leading to a node that has closer
// nodes than us in its vset. This can happen when routing state and
// vset membership is inconsistent e.g. during initialization. Add
// sender to SRcAntiRoute so that next attempt gets routed elsewhere.
//
if (! VirtualAddressEqual(SetupReq->Target, SetupReq->Source))
PLE->SRcAntiRoute = AddressListAdd(PLE->SRcAntiRoute,SetupReq->Source);
PLE->SRcAntiRoute = AddressListTrim(PLE->SRcAntiRoute,MAX_SRCANTIROUTE_SIZE);
if (++CountPLESRcAntiRoute > (uint)InterlockedCompareExchange((PLONG)&VA->MaxPLESRcAntiRoute,0,0))
VA->MaxPLESRcAntiRoute = CountPLESRcAntiRoute;
VrrTrace(VA,2,"SR:SR=Rcv_(NackTgt)",SetupReq->Source,SetupReq->Source,SetupReq->Target,
"CountPLESRcAntiRoute",CountPLESRcAntiRoute, "SeqNo",FrameSeqNo);
}
KeReleaseSpinLock(&VA->NT.Lock,OldIrql);
ReceiveVSet(VA,CountVSet,MsgVSet);
goto ReleaseAndReturn;
}
//
// Handle a SetupReq of type VRR_SR_TYPE_REQUEST.
//
//
// We are going to reply with Setup(A=self,B,PathId).
// First we send TearDown for, and remove, any old routes RTE=(A,B,*).
// Ref C# "// There should be at most one fte except in rare cases"
//
while (TRUE) {
RouteTableEntry *RTE;
InternalVrrTearDown *TDO;
VrrGlobalPathId PId;
uint PathId = VRR_PATHID_UNSPECIFIED;
RTEFlags Flags;
Flags.Flags = 0;
Flags.VSet = 1;
KeAcquireSpinLock(&VA->RT.Lock, &OldIrql);
RTE = FindRTE(VA,
VA->Address, //const VirtualAddress EndpointA,
SetupReq->Source, //const VirtualAddress EndpointB,
VRR_PATHID_UNSPECIFIED, //PathId,
VRR_ADDRESS_UNSPECIFIED, //const VirtualAddress NextA,
VRR_IFID_UNSPECIFIED, //VRRIf LocIFa,
VRR_IFID_UNSPECIFIED, //VRRIf RemIFa,
VRR_ADDRESS_UNSPECIFIED, //const VirtualAddress NextB,
VRR_IFID_UNSPECIFIED, //VRRIf LocIFb,
VRR_IFID_UNSPECIFIED, //VRRIf RemIFb,
Flags);
if (RTE != NULL) {
PId.PathId = RtlUlongByteSwap(RTE->PathId);
AddRefRTE(RTE);
}
KeReleaseSpinLock(&VA->RT.Lock, OldIrql);
//
// Finished tearing down old routes?
//
if (RTE == NULL)
break;
//
// An old RTE for this (A,B) pair exists and must be torn down.
//
// Construct and send a TearDown message for the old RTE to the
// NextHop in direction of endpoint B per the old RTE.
//
VRRASSERT(RTE->B.Next != NULL);
RtlCopyMemory(&PId.Address, VA->Address, sizeof(VirtualAddress));
TDO=CreateTearDownOpt(VA, RTE->B.Next->VAddress, 1, sizeof(PId), &PId, TRUE, FALSE);
MsgQueueMessage(VA, RTE->B.Next->VAddress, (InternalOption *) TDO, VRR_IFID_UNSPECIFIED,VRR_IFID_UNSPECIFIED,TDOWN_DELAY,NULL);
VrrKdPrint("RcvSR: send Teardown old RTE(self,s=B) to d",RTE->B.Address,RTE->B.Next->VAddress);
//
// Retire the old RTE.
//
KeAcquireSpinLock(&VA->RT.Lock, &OldIrql);
RTE->State = VRR_RTE_STATE_RETIRED;
RTE->Timeout = RTERetireTimeout(RTE->Flags);
VrrKdPrint("RcvSR: retired old RTE(s=A,d=B,*)",VA->Address,SetupReq->Source);
KeReleaseSpinLock(&VA->RT.Lock, OldIrql);
ReleaseRTE(RTE);
}
//
// Consider whether sender is a candidate for our virtual neighbor set.
//
if (IsCandidateNeighbor(VA,*source,CountVSet,MsgVSet)) {
//
// The sender should be admitted to our virtual neighbor set, but
// not until we have constructed a Setup featuring our vset
// as it stands prior to admitting the new neighbor.
//
RouteTableEntry *RTE;
uint PathId = 0;
TxToken Tok;
RTEFlags Flags;
Flags.Flags = 0;
Flags.VSet = 1;
//
// Create setup message before updating our VSet,
// obtaining snapshot of current state of VSet.
//
Setup = CreateSetupOpt(VA,
SetupReq->Proxy, // Dest.
VA->Address, // Endpoint A.
*source, // Endpoint B.
0, // PathId: inserted later.
*source, // Proxy.
NullAddress, // Prev wrt NextNextA local path repair.
SetupReq->Target); // Enable RemovePLE() when SR->Target==AddressDec!=A
if (Setup == NULL) {
VrrKdPrint("RcvSetup: ERROR! NULL==CreateSetupOpt()",NULL, SetupReq->Proxy);
goto ReleaseAndReturn;
}
//
// ForwardInternal option has adjusted SR addresses wrt proxy handling.
//
// Find the next hop towards the new neighbor. May bypass proxy.
//
if (VirtualAddressEqual(VA->NT.Self->Address, SetupReq->Proxy) ||
GetPhysNeighborTxToken(VA, SetupReq->Source, VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,&Tok, VRR_NCE_STATE_LINKED)) {
//
// We are the proxy, or we can bypass the proxy because joiner is a linked
// physical neighbor. Get next hop info from the physical neighbor set.
//
if (GetPhysNeighborTxToken(VA,SetupReq->Source,VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,&Tok,VRR_NCE_STATE_LINKED)==FALSE) {
VrrTrace(VA,2,"SR:SR=Drop(BadPhysNCE)",SetupReq->Source,SetupReq->Source,SetupReq->Dest,NULL,0,"SeqNo",FrameSeqNo);
goto ReleaseAndReturn;
}
IsProxy = TRUE;
}
else {
//
// Use the proxy as the next hop towards the sender. Get next hop info
// from RT state.
//
Result = FindNextHop(VA,
SetupReq->Proxy,
VRR_IFID_UNSPECIFIED,
VRR_IFID_UNSPECIFIED,
&Tok,
NULL,
NULL_SR_FLAGS);
if (SuccessFwd != Result) {
VrrTrace(VA,2,"SR:SR=Drop(BadFNHProxy)",SetupReq->Source,SetupReq->Source,SetupReq->Dest,NULL,0,"SeqNo",FrameSeqNo);
goto ReleaseAndReturn;
}
}
//
// Add a route for the sender to our Route Table.
//
KeAcquireSpinLock(&VA->RT.Lock, &OldIrql);
RTE = FindOrCreateRTE(VA,
VA->Address, //const VirtualAddress EndpointA,
*source, //const VirtualAddress EndpointB,
VRR_PATHID_UNSPECIFIED, //PathId,
VRR_ADDRESS_UNSPECIFIED, //const VirtualAddress NextA,
VRR_IFID_UNSPECIFIED, //VRRIf LocIFa,
VRR_IFID_UNSPECIFIED, //VRRIf RemIFa,
Tok.NextVAddress, //const VirtualAddress NextB,
Tok.LocIF, //VRRIf LocIFb,
Tok.RemIF, //VRRIf RemIFb,
NullAddress, //NextNextA.
Flags);
if (NULL != RTE)
PathId = RTE->PathId;
KeReleaseSpinLock(&VA->RT.Lock, OldIrql);
//
// We must have an RTE in order to proceed.
//
if (RTE == NULL) {
VrrKdPrint("RcvSetup: ERROR! cannot send Setup - FindRTE(d)==NULL",NULL, *source);
goto ReleaseAndReturn;
}
//
// Update PathId in our Setup option.
//
Setup->Opt.PathId = RtlUlongByteSwap(PathId);
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -