⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 teardown.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 2 页
字号:
//
//  Receive a VRR TearDown message. Called from ReceiveSRPacket.
//
//  Note: basic packet parsing performd in ReceiveSRPacket, which
//  provides us the VrrSetup structure in an SRPacket option.
//
void
ReceiveTearDown(
    MiniportAdapter *VA,
    ProtocolAdapter *PA,
    InternalVrrTearDown *InternalTearDown)
{
    KIRQL OldIrql;
    RouteTable *RT = &VA->RT;
    Time Now = KeQueryInterruptTime(); 
    TeardownInformQueue *InformQueue = NULL;
    VrrGlobalPathId *FirstPPId;
    VrrGlobalPathId *PPId;
    VrrGlobalPathId *PTDBuff;
    NeighborCacheEntry *NCE;
    VrrTearDown *TearDown;
    uint NumPId;
    VirtualAddress *PVSET = NULL;
    VirtualAddress *MsgVSet = NULL;
    uint VSetLen;
    uint CountVSet;
    uint i;
    VSetRepairQueue *VSetRepair = NULL;

    //
    // Validate the VrrTearDown message.
    //
    VRRASSERT(InternalTearDown != NULL);
    TearDown = &InternalTearDown->Opt;
    VrrTrace(VA,2,"TD:TD=enter TD",TearDown->Source, NULL,TearDown->Dest,NULL,0,NULL,0);
    
    //
    // Ignore teardown messages not destined to self.
    // ref C# "// ignore teardown messages not destined to me"
    //
    if (! VirtualAddressEqual(VA->Address, TearDown->Dest)) {
        VrrTrace(VA,1,"TD:TD=drop TD self(s)!=TD->Dest(d)",TearDown->Source, NULL,TearDown->Dest,NULL,0,NULL,0);
        InterlockedIncrement((PLONG)&VA->CountMisroutedTearDown);
        return;
    }

    NumPId = RtlUlongByteSwap(TearDown->NumGlobalPathId);
    
    if (NumPId == 0) {
        VrrTrace(VA,1,"TD:TD=ignoring because NumPId==0",TearDown->Source, NULL,TearDown->Dest,NULL,0,NULL,0);
        return;
    }

    FirstPPId = TearDown->PId;
    MsgVSet = (VirtualAddress *)&FirstPPId[NumPId];
   
    VSetLen = (uint)InternalTearDown->Opt.OptDataLen
             - sizeof(TearDown->Source)
             - sizeof(TearDown->Dest)
             - sizeof(TearDown->Proxy)
             - sizeof(TearDown->Flags)
             - sizeof(TearDown->FrameSeqNo)
             - sizeof(TearDown->HopCount)
             - sizeof(TearDown->NumGlobalPathId)
             - (sizeof(VrrGlobalPathId) * NumPId);
             
    CountVSet = VSetLen / sizeof(VirtualAddress);

    UpdatePacketIndex(VA, TearDown->Source, RtlUlongByteSwap(TearDown->FrameSeqNo), TearDown->HopCount,
                  TearDown->Source, TearDown->Dest, (VRRIf)PA->Index, VRR_OPTION_TYPE_TEARDOWN);

    KeAcquireSpinLock(&VA->RT.Lock, &OldIrql);
    KeAcquireSpinLockAtDpcLevel(&VA->NC.Lock);
    KeAcquireSpinLockAtDpcLevel(&VA->TDC.Lock);

    //
    // Drop TD unless the sender is a physical neighbor.
    // Note TD->Source is the last node that forwarded the TD.
    // ref C# "// XXX do we really need the clause on physical neighbors"
    //
    if (FindNCE(&VA->NC,
                TearDown->Source, 
                VRR_IFID_UNSPECIFIED,
                VRR_IFID_UNSPECIFIED,
                VRR_NCE_STATE_LINKED) == NULL) {
        VrrTrace(VA,1,"TD:TD=drop TD sender(s) not a physn",TearDown->Source, NULL,TearDown->Dest,NULL,0,NULL,0);
        CountVSet = 0;
        goto ReleaseAndReturn;
    }

    //
    // Construct list of neighbors for fwd tailored image of this TearDown.
    //
    for (NCE = VA->NC.FirstNCE; NCE != SentinelNCE(&VA->NC); NCE = NCE->Next) {
        RouteTableEntry *RTE;
        TeardownInformQueue *TIQ;
        VirtualAddress *Inform;
        uint TearDownSize = 0;
        uint TearDownCount = 0;
        VrrGlobalPathId *TDBuff = NULL;
        uint NumPIdOut;
        
        //
        // Do not fwd the TD to the node that sent this TearDown.
        //
        if (VirtualAddressEqual(NCE->VAddress, TearDown->Source))
            continue;
    
        //
        // Count paths mentioned in TearDown for which the NCE is a NextHop.
        //
        PPId = FirstPPId;
        for (i = 0; i < NumPId; i++) {
            for (RTE = RT->FirstRTE; RTE != SentinelRTE(RT); RTE = RTE->Next) {
            
                //
                // Ignore TearDown elements that fail validation. 
                //
                if (! IsValidTearDownElement(TearDown->Source,PPId,RTE))
                    continue;
             
                //
                // Teardown is send in direction of NextA or Next B ref C#:
                // "Debug.Assert(fte.NextA == sender || fte.NextB == sender);"
                // "NodeId neighbor = (fte.NextA != sender) ? fte.NextA : fte.NextB;"
                //
                if (RTE->A.Next == NCE || RTE->B.Next == NCE) {
                    //
                    // Increment PathId count for this NCE.
                    //
                    if (++TearDownCount == VRRTEARDOWN_MAX_PID(VA)) {
                        VRRASSERT("RecvTD: overflowed TD buffer");
                        break;
                    }
                }
            }
            
            //
            // Proceed to next PathId in the TearDown message.
            //
            PPId++;
        }
        
        //
        // Proceed to next NCE if nothing to tell this NCE. 
        //
        if (TearDownCount == 0)
            continue;
        
        //
        // Add this NCE to list of TearDown recipients.
        //
        if ((TIQ = ExAllocatePool(NonPagedPool, sizeof *TIQ)) == NULL) {
            VrrTrace(VA,1,"TD:TD=failed to allocate TIQ",TearDown->Source, NULL,TearDown->Dest,NULL,0,NULL,0);
            continue;
        }
        RtlZeroMemory(TIQ, sizeof *TIQ);
        RtlCopyMemory(TIQ->SendTo, NCE->VAddress, sizeof(VirtualAddress));
        TIQ->Next = InformQueue;
        InformQueue = TIQ;

        //
        // Allocate memory to hold the flat PId[] buffer for this NCE.
        // N.B. allow space also for copy of originator's vset.
        //
        TearDownSize = TearDownCount * sizeof(VrrGlobalPathId);
        TearDownSize += VSetLen;
        TDBuff = ExAllocatePool(NonPagedPool, TearDownSize);
        if (TDBuff == NULL) {
            VrrTrace(VA,1,"TD:TD=failed to allocate TDBuff",TearDown->Source, NULL,TearDown->Dest,NULL,0,NULL,0);
            continue;
        }
        RtlZeroMemory(TDBuff,TearDownSize);
        PTDBuff = TDBuff;
        
        //
        // Populate the PId[] buffer for the tailored TearDown to this NCE.
        //
        NumPIdOut = TearDownCount;
        for (i = 0; i < NumPId && TearDownCount > 0; i++) {
            PPId = &FirstPPId[i];
            
            for (RTE = RT->FirstRTE; RTE != SentinelRTE(RT); RTE = RTE->Next) {
            
                //
                // Ignore TearDown elements that fail validation. 
                //
                if (! IsValidTearDownElement(TearDown->Source,PPId,RTE))
                    continue;
             
                if (RTE->A.Next == NCE || RTE->B.Next == NCE) {
                    //
                    // Include this PathId in TearDown sent to this NCE.
                    //
                    RtlCopyMemory(PTDBuff->Address, PPId->Address, sizeof(VirtualAddress));
                    PTDBuff->PathId = PPId->PathId;
                    PTDBuff++;
                    TearDownCount--;
                    VrrTrace(VA,3,"TD:TD=Fwd_",VA->Address,TearDown->Source,PPId->Address,"Pid",RtlUlongByteSwap(PPId->PathId),NULL,0);
                }
            }
        }
        
        //
        // Append the originator's vset onto TDBuff.
        //
        RtlCopyMemory(PTDBuff, MsgVSet, VSetLen);

        //
        // Encode the flat PId[] buffer in an InternalVrrTearDown encoding this TearDown.
        //
        TIQ->ITD = CreateTearDownOpt(VA,TIQ->SendTo, NumPIdOut, TearDownSize, TDBuff, FALSE, TRUE);
        ExFreePool(TDBuff);
    
    } // ForAllNCE.

    //
    // Apply the TearDown to our own RTE state and
    // add it to our TearDown cache.
    //
    PPId = FirstPPId;
    for (i = 0; i < NumPId; i++) {
        RouteTableEntry *RTE;

        VrrTrace(VA,3,"TD:TD=Exec",TearDown->Source,TearDown->Source,PPId->Address,"Pid",RtlUlongByteSwap(PPId->PathId),NULL,0);

        for (RTE = RT->FirstRTE; RTE != SentinelRTE(RT); RTE = RTE->Next) {
        
            //
            // Ignore TearDown elements that fail validation. 
            //
            if (! IsValidTearDownElement(TearDown->Source,PPId,RTE))
                continue;
                
            //
            // We know that this RTE matches (A,PathId) and that
            // TearDown was sent by NextA or NextB from the RTE.
            // On this basis we are prepared to retire this RTE. 
            //
            RTE->State = VRR_RTE_STATE_RETIRED;
            RTE->Timeout = RTERetireTimeout(RTE->Flags);
            VrrTrace(VA,2,"TD:TD=retired RTE(s=A,d=B)",RTE->A.Address, NULL,RTE->B.Address,"Pid",RTE->PathId,NULL,0);
            VSetRepair = ScheduleVSetRepair(VA,VSetRepair,RTE);
        }
        
        //
        // Cache copy of the TearDown in case it overtook 
        // the corresponding Setup while in flight.
        //
        FindOrCreateTDCE(&VA->TDC,
                         PPId->Address, 
                         RtlUlongByteSwap(PPId->PathId),
                         TearDown->Source);
        
        //
        // Proceed to next PathId in the TearDown message.
        //
        PPId++;
    }

ReleaseAndReturn:
    KeReleaseSpinLockFromDpcLevel(&VA->TDC.Lock);
    KeReleaseSpinLockFromDpcLevel(&VA->NC.Lock);
    KeReleaseSpinLock(&VA->RT.Lock, OldIrql);

    //
    // If the TearDown included a vset, process it now.
    //
    if (CountVSet > 0)
        ReceiveVSet(VA,CountVSet,MsgVSet);

    //
    // Schedule a TearDown message to each NCE in InformQueue.
    // Then free the InformQueue and InternalVrrTearDown memory.
    //
    while (NULL != InformQueue) {
        TeardownInformQueue *TIQ = InformQueue;
        
        InformQueue = InformQueue->Next;
        if (TIQ->ITD != NULL)
            MsgQueueMessage(VA, TIQ->SendTo, (InternalOption *) TIQ->ITD, VRR_IFID_UNSPECIFIED,VRR_IFID_UNSPECIFIED,TDOWN_DELAY,NULL);
        ExFreePool(TIQ);
    }
    
    //
    // Perform any required vset repair.
    //
    if (VSetRepair != NULL)
        ProcessVSetRepairQueue(VA,VSetRepair);
    
}


//* TearDownCacheTimeout
//
//  Housekeeping of the TearDown cache.
//
Time
TearDownCacheTimeout(
    MiniportAdapter *VA,
    Time Now)
{
    KIRQL OldIrql;
    Time NextTimeout = Now + TDOWN_MAX_HK_INTERVAL;
    TearDownCacheEntry *TDCE;
    TearDownCacheEntry *NextTDCE;

    KeAcquireSpinLock(&VA->TDC.Lock, &OldIrql);

    for (TDCE = VA->TDC.FirstTDCE; 
         TDCE != SentinelTDCE(&VA->TDC);
         TDCE = NextTDCE) {

        NextTDCE = TDCE->Next;
        if (TDCE->Timeout <= Now)
            RemoveTDCE(&VA->TDC,TDCE);
        else if (TDCE->Timeout < NextTimeout)
            NextTimeout = TDCE->Timeout;
    }

    KeReleaseSpinLock(&VA->TDC.Lock, OldIrql);

    return NextTimeout;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -