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

📄 route.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 3 页
字号:
    // Salvage messages and (MB) packets.
    //
    SalvagePacketsFromMaintBuf(VA, NCE->VAddress,
                               NCE->LocIF, NCE->RemIF);

    //
    // Purge message queue of messages for this destination.
    //
    MsgFailLink(VA, NCE->VAddress, NCE->LocIF, NCE->RemIF);

    //
    // Safe to release memory.
    //
    ReleaseNCE(NCE);
    IoFreeWorkItem(Item);
    ExFreePool(RDDC);
}


//* RouteFailLink
//
//  Helper for failing a link associated with an NCE.
//
//  Caller must hold NC->Lock and therefore cannot take
//  RT->Lock to perform the downdate inline. Hence we 
//  queue an IoWorkQueueItem to do the work.
//
void
RouteFailLink(
    MiniportAdapter *VA,
    NeighborCacheEntry *NCE)
{
    PIO_WORKITEM Item;
    RouteFailLinkContext *RDDC;

    VRRASSERT(NCE != NULL);
    
    RDDC = ExAllocatePool(NonPagedPool, sizeof *RDDC);
    if (RDDC == NULL)
        return;
    
    Item = IoAllocateWorkItem(VA->DeviceObject);
    if (Item == NULL) {
        ExFreePool(RDDC);
        return;
    }
    
    //
    // Keep a ref on NCE so that locks can be released. The worker will
    // release the ref when done.
    //
    AddRefNCE(NCE);
    RDDC->NCE = NCE;
    RDDC->VA = VA;
    RDDC->Item = Item;
    IoQueueWorkItem(Item, RouteFailLinkWorker, DelayedWorkQueue, RDDC);
}

//* DistDirectLeftSR
//
// Helper for FindNextHop when directing SR around perimeter of ring.
// Given (ay,ax) returns Uint64DistanceLeft(ax,ay).
//
static unsigned __int64
DistDirectLeftSR(
    unsigned __int64 ay,
    unsigned __int64 ax)
{
    return Uint64DistanceLeft(ax,ay);
}

//* DistDirectRightSR
//
// Helper for FindNextHop when directing SR around perimeter of ring.
// Given (ay,ax) returns Uint64DistanceRight(ax,ay).
//
static unsigned __int64
DistDirectRightSR(
    unsigned __int64 ay,
    unsigned __int64 ax)
{
    return Uint64DistanceRight(ax,ay);
}

//* IsValidNextHop
//
//  Helper for FindNextHop.
//
//  Returns TRUE iff NCE for supplied Endpoint is valid for use.
//
static uint
IsValidNextHop(
    unsigned __int64 Dest,
    RouteTableEndpoint *EP,
    RTEFlags Flags)
{
    uint Result = FALSE;

    if (EP->Next==NULL)
        //
        // Common case: EP refers to self.
        //
        Result = TRUE;
    else if (EP->Next->State==VRR_NCE_STATE_ACTIVE)
        //
        // Common case: NextHop is on active link.
        //
        Result = TRUE;
    else if (EP->uint64Address==Dest && Flags.Hops1 == 1 &&
             (EP->Next->State & VRR_NCE_STATE_LINKED) != 0)
        //
        // Deliver via NCE(LINKED) if NCE==Dest.
        //
        Result = TRUE;
    else if (Flags.VSet == 1 &&
             (EP->Next->State & VRR_NCE_STATE_LINKED) != 0)
        //
        // Use VSet routes via NCE that is only LINKED.
        // Important when NCE is a major bridge - it may
        // know many usable routes even if missing some
        // VSet routes of its own.
        //
        Result = TRUE;
    else
        Result = FALSE;

    return Result;
}

//* RankEndpoint
//
// Helper for FindNextHop. Defines preference between endpoints.
//
static uint
RankEndpoint(
    MiniportAdapter *VA,
    RouteTableEndpoint *EP,
    RTEFlags Flags)
{
    if (VirtualAddressEqual(EP->Address,VA->Address))
        return 5;
    else if (Flags.Hops1 == 1)
        return 4;
    else if (Flags.Hops2 == 1)
        return 3;
    else if (Flags.Zero == 1)
        return 2;
    else
        return 1;
}

//* FindNextHop  // FNH:
//
//  Selects next hop towards destination by inspecting Route Table.
//
//  Updates the callers TxToken with sufficient state for
//  the packet be transmitted without further reference to 
//  the Route Table.
//
//  Note the special-case support for routing SetupReq when the 
//  virtual ring is being initialized or somehow inconsistent. In
//  particular the SRcAntiRoute and SRFlags arguments are used when
//  routing to a target destination is failing.
//
//  Returns:
//    SuccessFwd iff the next hop is elsewhere
//    SuccessRcvSelf iff self exactly matches self
//    SuccessRcvNearest iff self is closest match to destination
//    Error: internal error occurred.
//
//  Caller must not hold the RT->Lock.
//  Caller must not hold the NC->Lock.
//  Caller must not hold the VA->Lock.
//
FindNextHopResult
FindNextHop(
    MiniportAdapter *VA,
    VirtualAddress Dest,
    VRRIf LocIF,
    VRRIf RemIF,
    TxToken *Tok,
    AddressList *SRcAntiRoute,
    uchar SRFlags)
{
    KIRQL OldIrql;
    RouteTable *RT = &VA->RT;
    RouteTableEntry *RTE;
    RouteTableEntry *BestRTE;
    RouteTableEndpoint *BestEndpoint = NULL;
    unsigned __int64 uint64Dest = VirtualAddressToUint64(Dest);
    pFuncUi64Distance *pDistanceFunc = Uint64VirtualAddressDistance;
    
    FindNextHopResult Result = Error;

    //
    // If this is an attempt to route to self then we are done.
    //
    if (VirtualAddressEqual(VA->Address,Dest)) {
        return SuccessRcvSelf;
    }

    //
    // There will be no routing state if we are the boot node.
    // In that case we receive everything in order that other
    // nodes may join the ring.
    //
    if (RT->FirstRTE == SentinelRTE(RT)) {
        VrrKdPrint("FNH(d): no RT state - return SuccessRcvNearest (boot node?)",NULL,Dest);
        return SuccessRcvNearest;
    }

    //
    // Special case for SetupReq.
    //
    // Force a SetupReq around the perimeter of the virtual ring in
    // a direction specified by the SRFlags argument. 
    //
    if (SRFlags == VRR_SR_DIRECT_LHS) {
        InterlockedIncrement(&VA->CountFNHsendSRleft);
        VrrTrace(VA,3,"RT:**=FNH_(SendSRleft)",VA->Address,NULL,Dest,NULL,0,NULL,0);
        pDistanceFunc = DistDirectLeftSR;
    }
    else if (SRFlags == VRR_SR_DIRECT_RHS) {
        InterlockedIncrement(&VA->CountFNHsendSRright);
        VrrTrace(VA,3,"RT:**=FNH_(SendSRright)",VA->Address,NULL,Dest,NULL,0,NULL,0);
        pDistanceFunc = DistDirectRightSR;
    }

    //
    // Search for the best endpoint given Dest.
    //
    KeAcquireSpinLock(&VA->RT.Lock, &OldIrql);
    KeAcquireSpinLockAtDpcLevel(&VA->NC.Lock);

    for (RTE = RT->FirstRTE; RTE != SentinelRTE(RT); RTE = RTE->Next) {
        RouteTableEndpoint *Endpoint;

        //
        // Consider only ACTIVE routes.
        //
        if (RTE->State != VRR_RTE_STATE_ACTIVE)
            continue;

        //
        // Consider both endpoints in the RTE.
        //
        Endpoint = NULL;
        while (Endpoint != &RTE->B) {
        
            Endpoint = (NULL == Endpoint) ? &RTE->A : &RTE->B;

            //
            // Consider only Endpoints on valid (usable) next hop links.
            //
            if (IsValidNextHop(uint64Dest,Endpoint,RTE->Flags) == FALSE)
                continue;

            //
            // SetupReq (SR) uses SRcAntiRoute to prevent an SR being
            // routed to a node that recently Nacked the SR.
            //
            if (AddressListContains(SRcAntiRoute,Endpoint->Address)) {
                InterlockedIncrement(&VA->CountFNHSRcAntiRoute);
                VrrTrace(VA,4,"RT:**=FNH_(SRcAntiRouteEP)",VA->Address,NULL,Endpoint->Address,NULL,0,NULL,0);
                continue;
            }

            //
            // If we are on the SR SRcAntiRoute then we must override the
            // standard logic for receiving if we have the closest known
            // address to the destination, so that the SR can progress
            // beyond us via the next nearest address that we known.
            //
            if (AddressListContains(SRcAntiRoute,VA->Address) &&
                Endpoint->Next == NULL) {
                InterlockedIncrement(&VA->CountFNHSRcAntiRoute);
                VrrTrace(VA,4,"RT:**=FNH_(SRcAntiRouteSelfNearest)",VA->Address,NULL,Dest,NULL,0,NULL,0);
                continue;
            }

            //
            // Endpoint must satisfy our caller's IF arguments,
            //
            if (LocIF != VRR_IFID_UNSPECIFIED && 
                Endpoint->Next != NULL &&
                LocIF != Endpoint->Next->LocIF)
                continue;
            if (RemIF != VRR_IFID_UNSPECIFIED && 
                Endpoint->Next != NULL &&
                RemIF != Endpoint->Next->RemIF)
                continue;

            //
            // Ignore routes created by the partition repair protocol unless
            // they exactly match the intended destination.
            //
            if (RTE->Flags.Zero == 1 &&
                ! VirtualAddressEqual(Endpoint->Address, Dest))
                continue;

            //
            // Endpoint is on an active route via acceptable interface(s).
            // At the outset it makes a reasonable starting point for search.
            //
            if (BestEndpoint == NULL) {
                BestEndpoint = Endpoint;
                BestRTE = RTE;
                continue;
            }
            
            //
            // We want the closest endpoint(s) to Dest.
            // Endpoint address must be at least as close to dest as
            // BestEndpoint.
            //
            if ((*pDistanceFunc)(Endpoint->uint64Address, uint64Dest) >
                (*pDistanceFunc)(BestEndpoint->uint64Address, uint64Dest))
                continue;

            //
            // Endpoint may beat BestEndpoint on name distance.  
            //
            if ((*pDistanceFunc)(Endpoint->uint64Address, uint64Dest) <
                (*pDistanceFunc)(BestEndpoint->uint64Address, uint64Dest)) {
                
                BestEndpoint = Endpoint;
                BestRTE = RTE;
                continue;
            }

            //
            // Endpoint and BestEndpoint are same name distance from Dest.
            //
            VRRASSERT((*pDistanceFunc)(Endpoint->uint64Address, uint64Dest) == 
                      (*pDistanceFunc)(BestEndpoint->uint64Address, uint64Dest));

            //
            // Given two equidistant endpoints, choose the one closest
            // to our right hand side.
            //
            if (IsCloserRight(BestEndpoint->Address , Endpoint->Address, Dest))
                continue;
            if (IsCloserRight(Endpoint->Address , BestEndpoint->Address, Dest)) {
                BestEndpoint = Endpoint;
                BestRTE = RTE;
                continue;
            }

            //
            // At this point it must be that Endpoint and BestEndpoint have the same address.
            //
            VRRASSERT(VirtualAddressEqual(Endpoint->Address, BestEndpoint->Address));

            //
            // The endpoint is fixed for the remainder of this iteration.
            // It remains to choose between alternate routes to endpoint.
            //
            // Route to Endpoint may beat route to BestEndpoint on rank.  
            //
            if (RankEndpoint(VA,Endpoint,RTE->Flags) < RankEndpoint(VA,BestEndpoint,BestRTE->Flags))
                continue;
            if (RankEndpoint(VA,Endpoint,RTE->Flags) > RankEndpoint(VA,BestEndpoint,BestRTE->Flags)) {
                BestEndpoint = Endpoint;
                BestRTE = RTE;
                continue;
            }
            
            //
            // The route to Endpoint and the route to BestEndpoint have equal rank.
            //
            VRRASSERT(RankEndpoint(VA,Endpoint,RTE->Flags) == 
                      RankEndpoint(VA,BestEndpoint,BestRTE->Flags));
            
            //
            // For Hops1 and Hops2 prefer route with lowest ETT.
            //
            if (RTE->Flags.Hops1 == 1 || RTE->Flags.Hops2 == 1)
            if (RTE->ETT < BestRTE->ETT) {
                BestEndpoint = Endpoint;
                BestRTE = RTE;
                continue;
            }
            
            //
            // Prefer the route with the higher value of PathId.
            //
            if (RTE->PathId > BestRTE->PathId) {
                BestEndpoint = Endpoint;
                BestRTE = RTE;
                continue;
            }
        }
    }
    
    //
    // Finished searching route table.
    //
    if (NULL == BestEndpoint) {
        //
        // Unable to determine route.
        //
        Result = Error;
        
    }
    else if (NULL == BestEndpoint->Next) {
        //
        // Having a null next hop means we are receiving locally.
        //
        VRRASSERT(VirtualAddressEqual(VA->Address,BestEndpoint->Address));
        if (VirtualAddressEqual(VA->Address,Dest))
            Result = SuccessRcvSelf;
        else
            Result = SuccessRcvNearest;

    }
    else {
        //
        // We are forwarding.
        //
        ProtocolAdapter *PA;
        Result = SuccessFwd;
        
        PA=FindPhysicalAdapterFromIndex(VA, BestEndpoint->Next->LocIF);
        
        if (NULL == PA) {
            //
            // Error. We are forwarding but cannot get the Protocol Adapter address.
            //
            KdPrint(("FNH: error in FindPhysicalAdapterFromIndex(%u)\n",BestEndpoint->Next->LocIF));
            Result = Error;
            
        }
        else if (NULL != Tok) {
            //
            // Initialize the caller's TxToken.
            //
            NeighborCacheEntry *NCE = BestEndpoint->Next;

            RtlZeroMemory(Tok, sizeof(TxToken));
            RtlCopyMemory(Tok->Source, VA->Address, sizeof(VirtualAddress));
            RtlCopyMemory(Tok->Dest, Dest, sizeof(VirtualAddress));
            RtlCopyMemory(Tok->NextVAddress, NCE->VAddress, sizeof(VirtualAddress));
            RtlCopyMemory(Tok->NextPAddress, NCE->PAddress, sizeof(PhysicalAddress));
            Tok->LocIF = NCE->LocIF;
            Tok->RemIF = NCE->RemIF;
            Tok->PA = PA;
        }
    }

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

    return Result;
}

//* FindVSetRoute
//
//  Returns RTE(A,B) or RTE(B,A) if one exist, else returns NULL.
//
//  Caller must hold RT->Lock.
//
RouteTableEntry *
FindVSetRoute(
    MiniportAdapter *VA,
    const VirtualAddress EndpointA,
    const VirtualAddress EndpointB)
{
    RouteTableEntry *RTE;
    RTEFlags Flags;

    Flags.Flags = 0;
    Flags.VSet = 1;
    RTE = FindRTE(VA, EndpointA, EndpointB, VRR_PATHID_UNSPECIFIED, // (A,B,PathId).
                       VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED, // NextA.
                       VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED, // NextB.
                       Flags);
    if (RTE == NULL)
        RTE = FindRTE(VA, EndpointB, EndpointA, VRR_PATHID_UNSPECIFIED, // (B,A,PathId).
                           VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED, // NextA.
                           VRR_ADDRESS_UNSPECIFIED, VRR_IFID_UNSPECIFIED, VRR_IFID_UNSPECIFIED, // NextB.
                           Flags);

    return RTE;

}

//* IsNullTxToken
//
//  Returns TRUE iff given TxToken is all zeros.
//
boolint
IsNullTxToken(TxToken *Token)
{
    TxToken NullToken;
    RtlZeroMemory(&NullToken,sizeof(NullToken));

    return RtlEqualMemory(Token, &NullToken, sizeof(NullToken));
}

⌨️ 快捷键说明

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