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

📄 pback.c

📁 Vitual Ring Routing 管你知不知道
💻 C
📖 第 1 页 / 共 2 页
字号:
// -*- 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.
//
// This file is derived from the Microsoft Research Mesh Connectivity Layer,
// available under the MSR-SSLA license, and downloadable from
// http://research.microsoft.com/mesh/.
//
// Abstract:
//
// Piggy-backing module. General mechanism for sending VRR options
// at a later time, hopefully by piggy-backing on another packet
// that is going in the right direction.
//

#include "headers.h"

//* PbackInit
//
//  Initializes the piggy-back data structures.
//
void
PbackInit(MiniportAdapter *VA)
{
    PbackCache *PCache = &VA->PCache;

    KeInitializeSpinLock(&PCache->Lock);
    VRRASSERT(PCache->List == NULL);
}

//* PbackCleanup
//
//  Cleans up the piggy-back data structures.
//
void
PbackCleanup(MiniportAdapter *VA)
{
    PbackCache *PCache = &VA->PCache;
    PbackOption *PO;

    while ((PO = PCache->List) != NULL) {
        PCache->List = PO->Next;
        VrrKdPrint("PbackCleanup: free pcache entry",NULL,NULL);
        ExFreePool(PO->Opt);
        ExFreePool(PO);
    }
}

//* PbackResetStatistics
//
//  Resets all counters and statistics gathering for the piggy-backing module.
//
void
PbackResetStatistics(MiniportAdapter *VA)
{
    PbackCache *PCache = &VA->PCache;
    KIRQL OldIrql;

    KeAcquireSpinLock(&PCache->Lock, &OldIrql);
    PCache->HighWater = PCache->Number;
    PCache->AckMaxDupTime = 0;
    PCache->CountPbackReply = 0;
    PCache->CountAloneReply = 0;
    PCache->CountPbackError = 0;
    PCache->CountAloneError = 0;
    PCache->CountPbackInfo = 0;
    PCache->CountAloneInfo = 0;
    KeReleaseSpinLock(&PCache->Lock, OldIrql);
}

//* MsgQueueMessage
//
//  Enqueue a message with a specified transmission deadline.
//  Takes ownership of the message memory.
//
void
MsgQueueMessage(
    MiniportAdapter *VA,
    VirtualAddress Dest,       // May point into the option.
    InternalOption *Opt,
    VRRIf LocIF,
    VRRIf RemIF,
    Time Timeout,              // Relative.
    TxToken *SRToken)
{
    PbackCache *PCache = &VA->PCache;
    PbackOption *PO, *NewPO, **PrevPO;
    Time Now = KeQueryInterruptTime();
    KIRQL OldIrql;
    TxToken TokenBuff;
    TxToken *Token = &TokenBuff;
    uint DelayMS = TIME_TO_MS(Timeout);

    //
    // If you add another option type that can be piggy-backed,
    // you must also update PbackAddOptionToPacket.
    //

    //
    // Obtain TxToken to store in PO.
    //
    switch (Opt->Opt.optionType) {

    case VRR_OPTION_TYPE_SETUPREQ:
        {
            //
            // Caller supplies TxToken, ref possible SRcAntiRoute.
            //
            VRRASSERT(SRToken != NULL);
            VRRASSERT(! IsNullTxToken(SRToken));
            Token = SRToken;
            break;
        }
    case VRR_OPTION_TYPE_ACK:
    case VRR_OPTION_TYPE_SETUP:
    case VRR_OPTION_TYPE_TEARDOWN:
        //
        // The NextHop is fixed and must not be changed by FNH.
        //
        VRRASSERT(SRToken == NULL);
        if (GetPhysNeighborTxToken(VA,Dest,LocIF,RemIF,Token,VRR_NCE_STATE_LINKED)==FALSE) {
            //
            // Dest was selected because it was a physical neighbor
            // en route to Setup->Dest (i.e. EndpointB or its proxy).
            // It must be that Dest is no longer a physical neighbor.
            //
            // If message is a Setup our own neighbor detection should 
            // detect a link failure and initiate TD with respect to the
            // trail of RTE that saw this Setup, so we can just drop it.
            //
#if DBG
            if (Opt->Opt.optionType == VRR_OPTION_TYPE_ACK) {
                Acknowledgement *Ack = (Acknowledgement *)&Opt->Opt;
                InterlockedIncrement((PLONG)&VA->CountMsQDropCritical);
                VrrTrace(VA,3,"MQ:AK=Drop",Ack->from,Token->NextVAddress,Ack->to,"id",Ack->identification,NULL,0);
            }
            if (Opt->Opt.optionType == VRR_OPTION_TYPE_SETUP) {
                VrrSetup *Setup = (VrrSetup *)&Opt->Opt;
                InterlockedIncrement((PLONG)&VA->CountMsQDropCritical);
                VrrTrace(VA,3,"MQ:SU=Drop",Setup->A,Token->NextVAddress,Setup->B,
                       "Pid",RtlUlongByteSwap(Setup->PathId),"FrameSeqNo",RtlUlongByteSwap(Setup->FrameSeqNo));
            }
            if (Opt->Opt.optionType == VRR_OPTION_TYPE_TEARDOWN) {
                VrrTearDown *TD = (VrrTearDown *)&Opt->Opt;
                int NumPId = RtlUlongByteSwap(TD->NumGlobalPathId);
                int i;
                InterlockedIncrement((PLONG)&VA->CountMsQDropCritical);
                for (i = 0; i < NumPId; i++) {
                    VrrTrace(VA,3,"MQ:TD=Drop",TD->Source,Token->NextVAddress,TD->PId[i].Address,
                           "Pid",RtlUlongByteSwap(TD->PId[i].PathId),NULL,0);
                }
            }
#endif
            ExFreePool(Opt);
            Timeout = MAXTIME; // No need to reschedule for dup SR.
            goto Return;

        }
        break;

    default:
        {
            VrrKdPrint("MsgQMsg: unexpected message type",NULL,Dest);
            VRRASSERT(FALSE);
            ExFreePool(Opt);
            Timeout = MAXTIME; // No need to reschedule for dup SR.
            goto Return;
        }

    } // switch()

    KeAcquireSpinLock(&PCache->Lock, &OldIrql);

    //
    // Filter and discard duplicate SR messages.
    //
    // Note: together with SR tx delay this throttles rate at which
    // we can generate duplicate SR for a given destination.
    //
    // Note: if we decide to filter other message types we must worry
    // about whether to keep the earlier or later duplicate, and whether
    // any messages between them in the queue order affect the semantics.
    // With SR the source will regen automatically if needed.
    //
    for (PO = PCache->List; PO != NULL; PO = PO->Next) {
        switch (Opt->Opt.optionType) {
        case VRR_OPTION_TYPE_SETUPREQ:
            if (PO->Opt->Opt.optionType == Opt->Opt.optionType)
            if (PO->Opt->Opt.optDataLen == Opt->Opt.optDataLen)
            if (RtlEqualMemory(PO->Opt->Opt.payload, Opt->Opt.payload, Opt->Opt.optDataLen)) {
                VrrSetupReq *SR = (VrrSetupReq *)&Opt->Opt;
                VrrTrace(VA,2,"MQ:SR=Drop(DupGen)",SR->Source,Token->NextVAddress,SR->Dest,NULL,0,"FrameSeqNo",RtlUlongByteSwap(SR->FrameSeqNo));
                ExFreePool(Opt);
                Timeout = MAXTIME; // No need to reschedule for dup SR.
                goto UnlockAndReturn;
            }
            break;
        default:
            break;
        }
    }

    NewPO = ExAllocatePool(NonPagedPool, sizeof *NewPO);
    if (NewPO == NULL) {
        //
        // We can't send the message but we do need to free it.
        //
        if (Opt->Opt.optionType == VRR_OPTION_TYPE_ACK ||
            Opt->Opt.optionType == VRR_OPTION_TYPE_SETUP ||
            Opt->Opt.optionType == VRR_OPTION_TYPE_TEARDOWN) {
            InterlockedIncrement((PLONG)&VA->CountMsQDropCritical);
        }
        ExFreePool(Opt);
        Timeout = MAXTIME; // No need to reschedule.
        goto UnlockAndReturn;
    }

    //
    // Initialize the piggyback option.
    //
    RtlCopyMemory(NewPO->Dest, Dest, SR_ADDR_LEN);
    NewPO->Opt = Opt;
    RtlCopyMemory(&NewPO->Token,Token,sizeof(TxToken));

    //
    // Convert the relative timeout to absolute.
    //
    Timeout = Now + Timeout;
    NewPO->Timeout = Timeout;

    //
    // Add the message to the message queue.
    // The queue is sorted by timeout, from soonest to latest.
    //
    PrevPO = &PCache->List;
    while ((PO = *PrevPO) != NULL) {
        if (Timeout < PO->Timeout)
            break;
        PrevPO = &PO->Next;
        Timeout = MAXTIME; // No need to reschedule.
    }
    NewPO->Next = PO;
    *PrevPO = NewPO;

    if (++PCache->Number > PCache->HighWater)
        PCache->HighWater = PCache->Number;

#if DBG
    if (Opt->Opt.optionType == VRR_OPTION_TYPE_SETUP) {
        VrrSetup *Setup = (VrrSetup *)&Opt->Opt;
        VrrTrace(VA,3,"MQ:SU=2MQ_",Setup->A,Token->NextVAddress,Setup->B,
               "Pid",RtlUlongByteSwap(Setup->PathId),"DelayMS",DelayMS);
    }
    else if (Opt->Opt.optionType == VRR_OPTION_TYPE_TEARDOWN) {
        VrrTearDown *TD = (VrrTearDown *)&Opt->Opt;
        int NumPId = RtlUlongByteSwap(TD->NumGlobalPathId);
        int i;

        for (i = 0; i < NumPId; i++)
            VrrTrace(VA,3,"MQ:TD=2MQ_",TD->Source,Token->NextVAddress,TD->PId[i].Address,"Pid",
                   RtlUlongByteSwap(TD->PId[i].PathId),"DelayMS",DelayMS);
    }
    else if (Opt->Opt.optionType == VRR_OPTION_TYPE_ACK) {
        Acknowledgement *Ack = (Acknowledgement *)&Opt->Opt;
        VrrTrace(VA,3,"MQ:AK=2MQ_",Ack->from,Token->NextVAddress,Ack->to,"SeqNo",Ack->identification,"DelayMS",DelayMS);
    }
    else if (Opt->Opt.optionType == VRR_OPTION_TYPE_SETUPREQ) {
        VrrSetupReq *SR = (VrrSetupReq *)&Opt->Opt;
        VrrTrace(VA,3,"MQ:SR=2MQ_",SR->Source,Token->NextVAddress,SR->Dest,
               "FrameSeqNo",RtlUlongByteSwap(SR->FrameSeqNo),"DelayMS",DelayMS);
    }

#endif

UnlockAndReturn:
    KeReleaseSpinLock(&PCache->Lock, OldIrql);
Return:

    //
    // If necessary, reschedule the next timeout.
    //
    if (Timeout != MAXTIME)
        MiniportRescheduleTimeout(VA, Now, Timeout);
}

//* MsgMoveMessageToSRP
//
//  Helper for MsgLoadSRPfromPCache and MessageTimeout.
//  Adds a VRR option to an SRPacket.
//
static void
MsgMoveMessageToSRP(
    MiniportAdapter *VA,
    PbackCache *PCache,
    SRPacket *SRP,
    InternalOption *Opt)
{
    InternalOption **Field;

    switch (Opt->Opt.optionType) {
    case VRR_OPTION_TYPE_ACK: {
        Acknowledgement *Ack = (Acknowledgement *)&Opt->Opt;
        Field = (InternalOption **) &SRP->ack;
        VrrTrace(VA,3,"MQ:AK=2SRP",Ack->from,SRP->Token.NextVAddress,Ack->to,
                 "id",Ack->identification,"FrameSeqNo",SRP->FrameSeqNo);
        break;
    }
    case VRR_OPTION_TYPE_SETUP: {
        VrrSetup *Setup = (VrrSetup *)&Opt->Opt;
        Field = (InternalOption **) &SRP->VrrSetup;
        VrrTrace(VA,3,"MQ:SU=2SRP",Setup->A,SRP->Token.NextVAddress,Setup->B,
                 "Pid",RtlUlongByteSwap(Setup->PathId),"FrameSeqNo",SRP->FrameSeqNo);
        UpdatePacketIndex(VA, Setup->A, RtlUlongByteSwap(Setup->FrameSeqNo), Setup->HopCount++,
                  SRP->Source, SRP->Dest, SRP->Token.LocIF, VRR_OPTION_TYPE_SETUP);
        break;
    }
    case VRR_OPTION_TYPE_TEARDOWN: {
        VrrTearDown *TD = (VrrTearDown *)&Opt->Opt;
        int NumPId = RtlUlongByteSwap(TD->NumGlobalPathId);
        int i;

        Field = (InternalOption **) &SRP->VrrTearDown;
        for (i = 0; i < NumPId; i++) {
            VrrTrace(VA,3,"MQ:TD=2SRP",TD->Source,SRP->Token.NextVAddress,TD->PId[i].Address,
                     "Pid",RtlUlongByteSwap(TD->PId[i].PathId),"FrameSeqNo",SRP->FrameSeqNo);
            UpdatePacketIndex(VA, TD->PId[i].Address, RtlUlongByteSwap(TD->FrameSeqNo), TD->HopCount++,
                  SRP->Source, SRP->Dest, SRP->Token.LocIF, VRR_OPTION_TYPE_TEARDOWN);
        }
        break;
    }
    case VRR_OPTION_TYPE_SETUPREQ: {
        VrrSetupReq *SR = (VrrSetupReq *)&Opt->Opt;

        Field = (InternalOption **) &SRP->VrrSetupReq;
        VrrTrace(VA,3,"MQ:SR=2SRP",SR->Source,SRP->Token.NextVAddress,SR->Dest,
                 NULL,0,"FrameSeqNo",SRP->FrameSeqNo);
        UpdatePacketIndex(VA, SR->Source, RtlUlongByteSwap(SR->FrameSeqNo), SR->HopCount++,
                  SRP->Source, SRP->Dest, SRP->Token.LocIF, 
                  (SR->Type & VRR_SR_TYPE_REQUEST) ? VRR_OPTION_TYPE_SETUPREQ : VRR_OPTION_TYPE_SR_NACK);

        break;
    }
        
    default:
        VRRASSERT(!"MsgToSRP: bad message type");
        ExFreePool(Opt);
        return;
    }

    Opt->Next = *Field;
    *Field = Opt;
}

//* MsgMoveMultiToSRP
//
//  Move messages from a list to an SRP bound for a known destination.
//
//  Returns a count of how many options were added
//  and updates the packet size.
//
//  Should be called with the piggy-back cache locked,
//  if PrevPO is &PCache->List.
//
static uint
MsgMoveMultiToSRP(
    PbackCache *PCache,
    PbackOption **PrevPO,       // Pointer to list of options.
    SRPacket *SRP,
    uint *Size,                 // Packet size.
    const VirtualAddress Dest)  // May be NULL, meaning all destinations.
{
    PbackOption *PO;
    uint Count = 0;
    MiniportAdapter *VA;
    

    //
    // Get address for the VA struct of which the PCache arg is a member.
    //
    VA = CONTAINING_RECORD(PCache,MiniportAdapter,PCache);
    
    //
    // Iterate over all waiting options looking
    // for options for this destination.
    //
    while ((PO = *PrevPO) != NULL) {

        //
        // Should this message be sent in this SRPacket?
        // Yes, if the SRPacket has same NextHop as PO->Dest and if size permits.
        //
        if (VirtualAddressEqual(SRP->Token.NextVAddress, PO->Token.NextVAddress) &&

⌨️ 快捷键说明

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