Analysis of QualNet receiving and sending packets (two)

Continue from above: https://blog.csdn.net/zhang1806618/article/details/107268598

1.3 Network layer (continued)

1.3.4 Backplane (queue) processing 

In the RoutePacketAndSendToMac function, unicast, broadcast, and multicast are processed separately. The above analysis takes unicast as an example, by obtaining the unicast route, then calling the NetworkIpSendPacketToMacLayer function, and then calling the NetworkIpSendPacketOnInterface function to send the data packet. Broadcast and multicast directly call the NetworkIpSendPacketOnInterface function to send data packets, skipping the routing stage. The NetworkIpSendPacketOnInterface has been introduced above, which mainly calls the NetworkIpSendOnBackplane function to send data.

The main code of the NetworkIpSendOnBackplane function is as follows: 1. Determine whether the queue is unlimited; 2. When the queue is limited, judge whether the queue is full. For example, if it has been sent locally, if there is no limit, call the QueueUpIpFragmentForMacLayer function to send the data. If there is a limit and the queue is not full, call the NetworkIpUseBackplaneIfPossible function to try to send the data.

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);
        }
    }
}

The main function of NetworkIpUseBackplaneIfPossible is to determine whether the interface is busy and whether the interface queue is empty. The sending operation is performed only when the interface is idle and the queue is not empty. Send messages by scheduling the network layer event 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);
    }
}

For network layer event processing, the first step: the function NETWORK_ProcessEvent in network.cpp calls different protocol processing according to different network layer protocols; the second step: the event processing function of the IP protocol, NetworkIpLayer in network_ip.cpp, is performed according to different events Processing; Step 3: According to the event type MSG_NETWORK_Backplane, call the function NetworkIpReceiveFromBackplane to process.

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);
    }
}

So far, just like when the queue is unlimited, call QueueUpIpFragmentForMacLayer to send data.

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 layer

The function MAC_NetworkLayerHasPacketToSend in mac.cpp mainly distinguishes the MAC layer protocol types and calls them separately.

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();        
}

Take the mac802.11 protocol as an example, call the MacDot11NetworkLayerHasPacketToSend() function in mac_dot11.cpp. The main function of this function is to move the data packet from the network layer to the link layer and add the frame header. See the function MacDot11StationMoveAPacketFromTheNetworkLayerToTheLocalBuffer(); the second is When the link is idle, try to send data, see the function MacDot11StationAttemptToGoIntoWaitForDifsOrEifsState(). Two functions are defined in mac_dot11_sta.h

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

The MacDot11StationAttemptToGoIntoWaitForDifsOrEifsState() function mainly judges whether to enable the RTS\CTS mechanism, and judges whether the physical layer state is idle, and only starts the timer to send messages when it is idle, and cancels the timer when it is not idle.

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));
        }
    }

}

 In the timer, the MAC layer 802.11 protocol event MSG_MAC_TimerExpired is scheduled.

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);
}

 The mac.cpp function MAC_ProcessEvent() dispatches the MacDot11Layer() dispatches the MSG_MAC_TimerExpired event, and calls the MacDot11HandleTimeout() function to send data. MacDot11HandleTimeout() decides whether to transmit the frame, modify the link state, or resend according to the link state. The transmission frame function is 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;
        }
    }
}

Continue below.

Guess you like

Origin blog.csdn.net/zhang1806618/article/details/107753611