QualNet收发包过程分析(二)

接上文:https://blog.csdn.net/zhang1806618/article/details/107268598

1.3 网络层(续)

1.3.4 底板(队列)处理 

在RoutePacketAndSendToMac函数对单播、广播、组播进行了分别处理。上文分析以单播为例,通过获取单播路由,然后调用NetworkIpSendPacketToMacLayer函数,再调用NetworkIpSendPacketOnInterface函数发送数据包。而广播、组播是直接调用NetworkIpSendPacketOnInterface函数发送数据包,跳过了路由阶段。上文已介绍了NetworkIpSendPacketOnInterface,主要调用NetworkIpSendOnBackplane函数发送数据。

NetworkIpSendOnBackplane函数主要代码如下,作用:一、判断队列是否无限制;二、队列有限时判断队列是否已满。已本地发送为例,无限制则直接调用QueueUpIpFragmentForMacLayer函数发送数据,有限制且队列未满时调用NetworkIpUseBackplaneIfPossible函数尝试发送数据。

void //inline//
NetworkIpSendOnBackplane(
     Node *node,
     Message *msg,
     int incomingInterface,
     int outgoingInterface,
     NodeAddress hopAddr)
{
    NetworkDataIp *ip = (NetworkDataIp *) node->networkData.networkVar;
    NetworkDataIcmp *icmp = (NetworkDataIcmp*) ip->icmpStruct;
    IpHeaderType *ipHeader = (IpHeaderType *) MESSAGE_ReturnPacket(msg);

    //判断吞吐量是否无限制
    //1.无限制情况
    if (ip->backplaneThroughputCapacity ==
        NETWORK_IP_UNLIMITED_BACKPLANE_THROUGHPUT)
    {
        //本地接收,将MAC层数据包上传至网络层、传输层
        if (outgoingInterface == CPU_INTERFACE)
        {
             DeliverPacket(node, msg, incomingInterface, hopAddr);
        }
        //为MAC层处理数据包
        else
        {
            QueueUpIpFragmentForMacLayer(node,
                                         msg,
                                         outgoingInterface,
                                         hopAddr,
                                         incomingInterface);
        }
    }
    //2.有限制情况
    else
    {
        BOOL queueIsFull = FALSE;
        //本地发送情况
        if (incomingInterface == CPU_INTERFACE ||
            ip->backplaneType == BACKPLANE_TYPE_CENTRAL)
        {
            //插入队列
            NetworkIpCpuQueueInsert(node,
                               msg,
                               hopAddr,
                               ipHeader->ip_dst,
                               outgoingInterface,
                               NETWORK_PROTOCOL_IP,
                               &queueIsFull,
                               incomingInterface);
        }
        //本地接收或转发情况
        else
        {
            //插入队列
            NetworkIpInputQueueInsert(node,
                               incomingInterface,
                               msg,
                               hopAddr,
                               ipHeader->ip_dst,
                               outgoingInterface,
                               NETWORK_PROTOCOL_IP,
                               &queueIsFull);
        }
        //队列已满,丢弃并发送ICMP消息
        if (queueIsFull)
        {           
            if (ip->isIcmpEnable && icmp->sourceQuenchEnable)
            {
                BOOL ICMPErrorMsgCreated = NetworkIcmpCreateErrorMessage(node,
                                            msg,
                                            ipHeader->ip_src,
                                            incomingInterface,
                                            ICMP_SOURCE_QUENCH,
                                            ICMP_SOURCE_QUENCH_CODE,
                                            0,
                                            0);               
            }
           MESSAGE_Free(node, msg);
        }
        //队列未满,发送消息
        else
        {
            NetworkIpUseBackplaneIfPossible(node,
                                            incomingInterface);
        }
    }
}

NetworkIpUseBackplaneIfPossible主要功能是判断接口是否繁忙,接口队列是否为空。只有在接口空闲,队列不为空时,才执行发送操作。通过调度网络层事件MSG_NETWORK_Backplane发送消息。

void NetworkIpUseBackplaneIfPossible(Node *node,
                                int incomingInterface)
{
    NetworkDataIp *ip = (NetworkDataIp *) node->networkData.networkVar;
    int outgoingInterface;
    int networkType = 0;
    NodeAddress hopAddr = 0;
    MacHWAddress hopMacAddr;
    TosType priority = 0;
    Message *newMsg = NULL;
    int packetSize;
    BOOL isEmpty = TRUE;
    NetworkIpBackplaneStatusType *backplaneStatus;
    //背板统计状态,根据本地发送还是转发确定
    if (incomingInterface == CPU_INTERFACE ||
        ip->backplaneType == BACKPLANE_TYPE_CENTRAL)
    {
        //本地发送
        backplaneStatus = &ip->backplaneStatus;
    }
    else
    {
        //转发或接收
        backplaneStatus = &ip->interfaceInfo[incomingInterface]->backplaneStatus;
    }

    //判断接口是否繁忙
    if (*backplaneStatus != NETWORK_IP_BACKPLANE_IDLE)
    {
       return;
    }
    
    //接口空闲,获取接口队列消息
    //本地发送时,获取本地发送队列顶端消息
    if (incomingInterface == CPU_INTERFACE ||
        ip->backplaneType == BACKPLANE_TYPE_CENTRAL)
    {
        if (!NetworkIpCpuQueueIsEmpty(node))
        {
            NetworkIpCpuQueueTopPacket(node,
                                 &newMsg,
                                 &hopAddr,
                                 &hopMacAddr,
                                 &outgoingInterface,
                                 &networkType,
                                 &priority);

            isEmpty = FALSE;
        }
    }
    //转发或接收时,获取本地接收队列顶端消息
    else
    {
        if (!NetworkIpInputQueueIsEmpty(node, incomingInterface))
        {
            NetworkIpInputQueueTopPacket(node,
                                 incomingInterface,
                                 &newMsg,
                                 &hopAddr,
                                 &hopMacAddr,
                                 &outgoingInterface,
                                 &networkType,
                                 &priority);

            isEmpty = FALSE;
        }
    }
    //只有在队列非空时才执行发送.
    if (!isEmpty)
    {
        Message *backplaneMsg;
        clocktype backplaneDelay;
        NetworkIpBackplaneInfo *backplaneInfo;
        packetSize = MESSAGE_ReturnPacketSize(newMsg);
        backplaneMsg = MESSAGE_Alloc(node,
                                     NETWORK_LAYER,
                                     NETWORK_PROTOCOL_IP,
                                     MSG_NETWORK_Backplane);
        MESSAGE_InfoAlloc(node,
                          backplaneMsg,
                          sizeof(NetworkIpBackplaneInfo));

        backplaneInfo = (NetworkIpBackplaneInfo *)
                         MESSAGE_ReturnInfo(backplaneMsg);

        backplaneInfo->incomingInterface = incomingInterface;
        backplaneInfo->hopAddr = hopAddr;
        MAC_CopyMacHWAddress(&backplaneInfo->hopMacAddr,&hopMacAddr);

        *backplaneStatus = NETWORK_IP_BACKPLANE_BUSY;

        MESSAGE_Send(node, backplaneMsg, backplaneDelay);
    }
}

对网络层事件处理,第一步:network.cpp中函数NETWORK_ProcessEvent,根据不同网络层协议调用不同协议处理;第二步:由IP协议的事件处理函数,network_ip.cpp中的NetworkIpLayer,根据不同事件进行处理;第三步:根据事件类型MSG_NETWORK_Backplane,调用函数NetworkIpReceiveFromBackplane处理。

void NetworkIpReceiveFromBackplane(Node *node, Message *msg)
{
    ......
    //本地发送,输出队列弹出最前数据包
    if (info->incomingInterface == CPU_INTERFACE
        || ip->backplaneType == BACKPLANE_TYPE_CENTRAL)
    {
        NetworkIpCpuQueueDequeuePacket(node,
                                 &queueMsg,
                                 &hopAddr,
                                 &nextHopMacAddr,
                                 &outgoingInterface,
                                 &networkType,
                                 &priority);
    }
    //转发或接收,输入队列弹出最前数据包
    else
    {  
        NetworkIpInputQueueDequeuePacket(node,
                                 info->incomingInterface,
                                 &queueMsg,
                                 &hopAddr,
                                 &nextHopMacAddr,
                                 &outgoingInterface,
                                 &networkType,
                                 &priority);
    }
    //本地转发或接收
    if (outgoingInterface == CPU_INTERFACE)
    {...      
    }
    else
    {
        QueueUpIpFragmentForMacLayer(node,
                                     queueMsg,
                                     outgoingInterface,
                                     info->hopAddr,
                                     info->incomingInterface);
    }
}

至此,与队列无限制时一样,调用QueueUpIpFragmentForMacLayer发送数据。

static void //inline//
QueueUpIpFragmentForMacLayer(
    Node *node,
    Message *msg,
    int interfaceIndex,
    NodeAddress nextHop,
    int incomingInterface)
{
    NetworkDataIp *ip = (NetworkDataIp *) node->networkData.networkVar;
    Scheduler *scheduler = ip->interfaceInfo[interfaceIndex]->scheduler;
    IpHeaderType* ipHeader = (IpHeaderType *) MESSAGE_ReturnPacket(msg);
    NetworkDataIcmp *icmp = (NetworkDataIcmp*) ip->icmpStruct;
    BOOL queueIsFull;
    BOOL queueWasEmpty;
    ActionData acnData;
    NetworkType netType = NETWORK_IPV4;

    //在接口输出队列中插入数据包
    NetworkIpOutputQueueInsert(node,
                               interfaceIndex,
                               msg,
                               nextHop,
                               ipHeader->ip_dst,
                               NETWORK_PROTOCOL_IP,
                               &queueIsFull);
    //队列已满,输出ICMP错误消息
    if (queueIsFull)
    {
        if (ip->isIcmpEnable && icmp->sourceQuenchEnable)
             BOOL ICMPErrorMsgCreated = NetworkIcmpCreateErrorMessage(node,
                                        msg,
                                        ipHeader->ip_src,
                                        incomingInterface,
                                        ICMP_SOURCE_QUENCH,
                                        ICMP_SOURCE_QUENCH_CODE,
                                        0,
                                        0);          
        MESSAGE_Free(node, msg);
        return;
    }
    //发送数据
    if (queueWasEmpty)
    {
        if (!NetworkIpOutputQueueIsEmpty(node, interfaceIndex))
        {
            MAC_NetworkLayerHasPacketToSend(node, interfaceIndex);
        }
    }
}

1.4 MAC层

mac.cpp中函数MAC_NetworkLayerHasPacketToSend,主要区分MAC层协议类型进行分别调用。

void MAC_NetworkLayerHasPacketToSend(Node *node, int interfaceIndex)
{    
    //进入接口
    node->enterInterface(interfaceIndex);
    switch (node->macData[interfaceIndex]->macProtocol)
    {    
        ...    
        case MAC_PROTOCOL_DOT11:
        {
            MacDot11NetworkLayerHasPacketToSend(
                node, (MacDataDot11 *) node->macData[interfaceIndex]->macVar);
            break;
        }
        case MAC_PROTOCOL_CSMA:
        {......}
        case MAC_PROTOCOL_MACA:
        {...... }
        case MAC_PROTOCOL_TDMA:
        {......}
        ...
    }
    //退出接口
    node->exitInterface();        
}

以mac802.11协议为例,调用mac_dot11.cpp中MacDot11NetworkLayerHasPacketToSend()函数,此函数主要作用:一是将数据包从网络层移至链路层,并添加帧首部,见函数MacDot11StationMoveAPacketFromTheNetworkLayerToTheLocalBuffer();二是在链路空闲时,尝试发送数据,见函数MacDot11StationAttemptToGoIntoWaitForDifsOrEifsState()。两个函数在mac_dot11_sta.h中定义

void MacDot11NetworkLayerHasPacketToSend(
    Node* node,
    MacDataDot11* dot11)
{    
    //将数据包由网络层移至缓存
    MacDot11StationMoveAPacketFromTheNetworkLayerToTheLocalBuffer(
        node,
        dot11);
    //链路状态为空闲
    if (dot11->state == DOT11_S_IDLE) 
    {
        MacDot11StationAttemptToGoIntoWaitForDifsOrEifsState(node, dot11);
    }
}

MacDot11StationAttemptToGoIntoWaitForDifsOrEifsState()函数主要判断是否启用RTS\CTS机制,判断物理层状态是否为空闲,只有在空闲时才启动定时器发送消息,非空闲时取消定时器。

static //inline//
void MacDot11StationAttemptToGoIntoWaitForDifsOrEifsState(
    Node* node,
    MacDataDot11* dot11)
{
    BOOL mustWaitForNAV = FALSE;
    clocktype navTimeoutTime  = 0;

    if (!dot11->useDvcs) 
    {
        if (MacDot11StationPhyStatus(node, dot11) != PHY_IDLE) 
        {
            MacDot11StationSetState(node, dot11, DOT11_S_IDLE);
            MacDot11StationCancelTimer(node, dot11);

            return;
        }
        if (!dot11->IsInExtendedIfsMode)
        {
            if (MacDot11StationWaitForNAV(node, dot11)) 
            {
                // Set timer to wait for NAV to finish.
                mustWaitForNAV = TRUE;
                navTimeoutTime = dot11->NAV;
            }
        }
        else 
        {
            dot11->NAV = 0;
        }
    }
    else 
    {        
        if (MacDot11StationPhyStatus(node, dot11) == PHY_RECEIVING) 
        {
            MacDot11StationSetState(node, dot11, DOT11_S_IDLE);
            MacDot11StationCancelTimer(node, dot11);
            return;
        }              
        if (MacDot11StationPhyStatus(node, dot11) == PHY_SENSING) 
        {
            MacDot11StationSetState(node, dot11, DOT11_S_IDLE);
            MacDot11StationCancelTimer(node, dot11);
            return;
        }
        ERROR_Assert(MacDot11StationPhyStatus(node, dot11) == PHY_IDLE,
                     "Current state should be IDLE");
    }

    if (mustWaitForNAV) 
    {       
        MacDot11StationSetState(node, dot11, DOT11_S_WFNAV);
        MacDot11StationStartTimer(node, dot11, (navTimeoutTime - getSimTime(node)));
    }
    else 
    {
        clocktype extraWait = 0;
        MacDot11StationSetState(node, dot11, DOT11_S_WF_DIFS_OR_EIFS);
        if (getSimTime(node) < dot11->noOutgoingPacketsUntilTime) 
        {
            extraWait = dot11->noOutgoingPacketsUntilTime - getSimTime(node);
        }

        if (dot11->IsInExtendedIfsMode) 
        {
            MacDot11StationStartTimer(
                       node,dot11, (extraWait + dot11->extendedIfsDelay));
        }
        else 
        {
            MacDot11StationStartTimer(
                node, dot11, (extraWait + dot11->txDifs));
        }
    }

}

 在定时器中,调度MAC层802.11协议事件MSG_MAC_TimerExpired。

static 
void MacDot11StationStartTimer(
    Node* node,
    MacDataDot11* dot11,
    clocktype timerDelay)
{
    Message *newMsg;
    dot11->timerSequenceNumber++;
    newMsg = MESSAGE_Alloc(node, MAC_LAYER, MAC_PROTOCOL_DOT11,
                           MSG_MAC_TimerExpired);
    MESSAGE_SetInstanceId(newMsg, (short) dot11->myMacData->interfaceIndex);
    MESSAGE_InfoAlloc(node, newMsg, sizeof(dot11->timerSequenceNumber));
    *((int*)(MESSAGE_ReturnInfo(newMsg))) = dot11->timerSequenceNumber;
    newMsg->originatingNodeId = node->nodeId;
    MESSAGE_Send(node, newMsg, timerDelay);
}

 由mac.cpp函数MAC_ProcessEvent()调度MacDot11Layer()调度MSG_MAC_TimerExpired事件,调用MacDot11HandleTimeout()函数发送数据。MacDot11HandleTimeout()根据链路状态决定是传输帧还是修改链路状态,或重新发送。传输帧函数为MacDot11StationTransmitFrame()。

static //inline//
void MacDot11HandleTimeout(
    Node* node,
    MacDataDot11* dot11,
    Message* msg)
{
    ...
    switch (dot11->state) 
    {
        //等待DIFS或EIFS状态
        case DOT11_S_WF_DIFS_OR_EIFS: 
        {
            if (dot11->BO == 0) 
            {
                if (MacDot11StationHasFrameToSend(dot11)) 
                {       
                    //传输帧         
                    MacDot11StationTransmitFrame(node, dot11);
                }
                else 
                {
                    MacDot11StationSetState(node, dot11, DOT11_S_IDLE);
                }
            }
            else 
            {
                MacDot11StationContinueBackoff(node, dot11);
                MacDot11StationSetState(node, dot11, DOT11_S_BO);
                MacDot11StationStartTimer(node, dot11, dot11->BO);
            }

            break;
        }        
        //等待CTS
        case DOT11_S_WFCTS: 
        {
            //重新发送
            MacDot11StationRetransmit(node, dot11);
            break;
        }
        //等待数据
        case DOT11_S_WFDATA: 
        {
            MacDot11StationSetState(node, dot11, DOT11_S_IDLE);
            MacDot11StationCheckForOutgoingPacket(node, dot11, FALSE);
            break;
        }
    }
}

接下文。

猜你喜欢

转载自blog.csdn.net/zhang1806618/article/details/107753611
今日推荐