ns-3 源码学习笔记(2):RDMA 报文发送和接收过程

写在前面

主要针对数据包发送和接收的过程进行具体分析。

一、报文发送过程

1.1 概述

sequenceDiagram
    participant App as 应用层(RdmaClient)
    participant HW as RDMA硬件(RdmaHw)
    participant NIC as 网卡(QbbNetDevice)
    participant Channel as 链路(QbbChannel)
    participant Switch as 交换机(SwitchNode)
    participant MMU as 内存管理(SwitchMmu)
    participant DestNIC as 目标网卡(QbbNetDevice)
    participant DestHW as 目标RDMA硬件(RdmaHw)
    
    App->>HW: 创建队列对(QP)
    HW->>NIC: 请求发送数据包
    HW->>HW: GetNxtPacket()生成数据包
    HW->>NIC: 返回数据包
    NIC->>NIC: DequeueAndTransmit()
    NIC->>Channel: TransmitStart()
    Channel->>DestNIC: 调度接收事件
    
    alt 目标是交换机
        DestNIC->>Switch: SwitchReceiveFromDevice()
        Switch->>Switch: GetOutDev()查找路由
        Switch->>MMU: CheckIngressAdmission()
        MMU-->>Switch: 准入控制结果
        
        alt 准入成功
            Switch->>MMU: UpdateIngressAdmission()
            Switch->>MMU: UpdateEgressAdmission()
            Switch->>MMU: CheckShouldPause()
            
            alt 需要PFC
                MMU-->>Switch: 返回需要PFC
                Switch->>DestNIC: SendPfc(pause)
                DestNIC->>Channel: 发送PFC帧
            end
            
            Switch->>DestNIC: SwitchSend()
            DestNIC->>Channel: 转发数据包
            
            Switch->>MMU: RemoveFromIngressAdmission()
            Switch->>MMU: RemoveFromEgressAdmission()
            Switch->>MMU: CheckShouldResume()
            
            alt 需要恢复
                MMU-->>Switch: 返回需要恢复
                Switch->>DestNIC: SendPfc(resume)
                DestNIC->>Channel: 发送PFC恢复帧
            end
            
            alt ECN标记
                Switch->>Switch: 设置ECN位
            end
            
            alt INT处理
                Switch->>Switch: 添加/更新INT信息
            end
        else 准入失败
            Switch->>Switch: 丢弃数据包
        end
    else 目标是终端
        DestNIC->>DestHW: Receive()
        DestHW->>DestHW: ReceiveUdp()
        DestHW->>DestNIC: 生成ACK/NACK
        DestNIC->>Channel: 发送ACK/NACK
        Channel->>NIC: 接收ACK/NACK
        NIC->>HW: 处理ACK/NACK
        HW->>HW: 更新拥塞控制状态
    end

RDMA 在 NS3 中的报文发送过程遵循从上至下的协议栈流程,即 RdmaClient \rightarrow RdmaDriver \rightarrow RdmaHw \rightarrow QbbNetDevice \rightarrow 网络。关于应用层通过 RdmaClient 发起 RDMA 传输请求,驱动层 RdmaDriver 作为中间层,将请求传递给 RdmaHw ,再由硬件层 RdmaHw 创建队列对并负责数据包的生成,已经在前一篇文章《ns-3 源码学习笔记(1):RDMA 的实现》的分析。本文重点关注数据包的实际传输过程,即网络通道 \leftrightarrow 网络设备

1.2 网络设备层 QbbNetDevice

网络设备层 QbbNetDevice 负责实际的数据包发送操作,它通过 DequeueAndTransmit 方法从队列中取出数据包并发送。

注意,这里的网络设备层 \ne 网卡,RDMA 的基础模型中,确实认为端到端的通信中两者直接通过控制 RDMA NIC 传输数据,实际过程中,中间可能还需要经过交换机(DC Switch)。网卡和交换机都能收到数据并进行发送,在下面的方法实现中也可以看出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void QbbNetDevice::DequeueAndTransmit(void)
{
if (!m_linkUp) return; // 链路检查
if (m_txMachineState == BUSY) return; // 通道忙检查

Ptr<Packet> p;
if (m_node->GetNodeType() == 0){ // 终端节点
int qIndex = m_rdmaEQ->GetNextQindex(m_paused);
if (qIndex != -1024){
if (qIndex == -1){ // 高优先级队列
p = m_rdmaEQ->DequeueQindex(qIndex);
m_traceDequeue(p, 0);
TransmitStart(p);
return;
}
// RDMA队列对出队
Ptr<RdmaQueuePair> lastQp = m_rdmaEQ->GetQp(qIndex);
p = m_rdmaEQ->DequeueQindex(qIndex);

// 发送数据包
m_traceQpDequeue(p, lastQp);
TransmitStart(p);

// 更新下一次可发送时间
m_rdmaPktSent(lastQp, p, m_tInterframeGap);
}
} else { // 交换机
// 交换机的发送逻辑
p = m_queue->DequeueRR(m_paused); // 轮询调度
if (p != 0){
// 处理数据包
TransmitStart(p);
return;
}
}
}

两者在发送逻辑和状态管理上略有不同,但是都通过 TransmitStart 方法将数据包发送到网络通道:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool QbbNetDevice::TransmitStart(Ptr<Packet> p)
{
m_txMachineState = BUSY;
m_currentPkt = p;
m_phyTxBeginTrace(m_currentPkt);
Time txTime = Seconds(m_bps.CalculateTxTime(p->GetSize()));
Time txCompleteTime = txTime + m_tInterframeGap;
Simulator::Schedule(txCompleteTime, &QbbNetDevice::TransmitComplete, this);

// 调用通道的 TransmitStart 方法发送数据包
bool result = m_channel->TransmitStart(p, this, txTime);
if (result == false)
{
m_phyTxDropTrace(p);
}
return result;
}

1.3 网络通道 QbbChannel

QbbChannel 接收来自 QbbNetDevice 的数据包,并在链路延迟后将数据包传递给目标设备:

1
2
3
4
5
6
7
8
9
10
11
12
13
bool QbbChannel::TransmitStart(Ptr<Packet> p, Ptr<PointToPointNetDevice> src, Time txTime)
{
// 找到目标设备
Ptr<PointToPointNetDevice> dst = GetDevice(src == m_link.first ? 1 : 0);

// 计算传输延迟
Time delay = txTime + m_delay;

// 调度接收事件
Simulator::Schedule(delay, &PointToPointNetDevice::Receive, dst, p->Copy());

return true;
}

二、报文接收过程

报文接收过程是发送过程的逆向,从网络通道到应用层:网络 \rightarrow QbbNetDevice \rightarrow RdmaHw \rightarrow RdmaDriver \rightarrow RdmaClient

2.1 网络通道 \rightarrow 网络设备

当数据包通过网络传输到达目标节点时,首先由 QbbChannel 将数据包传递给 QbbNetDevice。这是通过 NS3 的事件调度机制实现的:

1

参考资料


ns-3 源码学习笔记(2):RDMA 报文发送和接收过程
https://blog.yokumi.cn/2025/07/15/ns-3 源码学习笔记(2):RDMA 报文发送和接收过程/
作者
Yokumi
发布于
2025年7月15日
更新于
2025年7月16日
许可协议