前面的文章我们拆解了WQE/CQE的格式、MR注册时MTT/MPT的构建、RoCEv2数据包的逐层封装,也分析了PFC和ECN如何协同工作。这些模块各司其职,但它们是如何拼成一块完整的网卡硬件的?用户态下发的一个WQE,最终怎么变成线缆上的比特,反过来收到的包又怎么变成内存里的数据?
这篇从网卡硬件内部视角,把收发包的完整路径走一遍,串起我们之前聊过的所有概念------PCIe、DMA引擎、QP上下文缓存、MTT/MPT缓存、包处理流水线、拥塞控制模块,看它们如何协同工作。
一、整体架构:一张网卡内部有哪些核心模块
|--------------------|------|------------------------|
| 模块 | 所属路径 | 职责 |
| PCIe接口+DMA引擎 | 数据路径 | 与主机内存通信,搬移数据和描述符 |
| 描述符队列控制器 | 数据路径 | 管理SQ、RQ、CQ的环形缓冲区 |
| QP上下文缓存 | 数据路径 | 缓存活跃QP的控制信息 |
| 包处理流水线 | 数据路径 | 封装/解析IB/UDP/IP/以太网头,分段 |
| 地址翻译与保护单元(MTT/MPT) | 数据路径 | 虚拟地址到物理地址翻译+权限校验 |
| 拥塞控制单元(DCQCN) | 数据路径 | ECN标记生成/CNP处理 |
| Doorbell 处理模块 | 控制路径 | 处理CPU发出的"敲门"信号 |
| 中断控制器 | 控制路径 | 生成MSI-X中断 |
| 固件处理器 | 控制路径 | 建链、QP创建/销毁、MR注册 |
二、发送路径(SQ方向):从 WQE 到线缆上的比特
Step 1:Doorbell敲门
应用程序调用填充WQE到SQ后,驱动会向硬件写一个门铃寄存器(Doorbell),触发 RDMA 引擎的控制逻辑。
Step 2:获取QP上下文(QPC Cache)
收到Doorbell后,RDMA引擎第一步是获取该QP的上下文------包含 SQ 基址、当前SQ指针位置、操作类型、路径MTU等信息。
这些上下文存储在主机内存中,但如果每次处理Doorbell都去读主机内存,PCIe往返开销太大。因此网卡内部有一个QPC Cache(QP上下文缓存),用SRAM缓存最活跃的QP上下文。Cache miss时触发PCIe DMA从主机内存加载。
Step 3:读取 WQE
拿到QP上下文后,DMA引擎根据SQ基址和当前指针位置发起PCIe内存读,将WQE从主机内存的SQ区域拉入网卡内部。现代网卡的WQE大小通常为 64 字节的整数倍。
Step 4:地址翻译(MTT/MPT Cache)
WQE中的数据源地址是虚拟地址 ,但DMA引擎搬运数据需要物理地址。
网卡内部有一个 MTT/MPT Cache,用SRAM缓存近期访问过的地址翻译条目和权限信息。检查流程:
- 用L_Key的24位索引查MPT Cache → 拿到权限信息和MTT指针。
- 用虚拟地址的高位查MTT Cache → 拿到物理页地址(通常是 4KB)。
Step 5:DMA 取数据
地址翻译完成后,DMA引擎根据物理地址发起PCIe内存读,将用户数据从主机内存搬到网卡内部的包缓冲区。
若数据很小(比如几十字节的控制消息),WQE中直接把数据嵌在WQE里,不经过额外的DMA读。
Step 6:包处理流水线 - 封装
数据到达包缓冲区后,包处理流水线开始逐层添加头部。不同操作的封装路径不同。
Step 7:拥塞控制(ECN标记&速率限制)
在封装IP头时,DCQCN拥塞控制模块参与决策。如果本端已收到过CNP(拥塞通知包),DCQCN算法会降低发送速率。速率限制通过在发包流水线中插入延迟或限制令牌桶实现。
Step 8:发送到MAC/PHY
封装完成的以太帧送到MAC层,附加前导码和帧间隙,通过SerDes串行化为高速差分信号,经 PHY 驱动到线缆上。
Step 9:生成CQE
包发送出去后(不需要等待 ACK,立即通知),网卡在CQ中生成CQE,CQE写入主机内存,然后视配置决定是否产生MSI-X中断。
三、接收路径(RQ方向):从线缆上的比特到内存中的数据
Step 1:MAC/PHY 接收
线缆上的串行信号进入PHY,时钟数据恢复后解码,送到MAC层去除前导码和帧间隙,校验VCRC。
Step 2:包处理流水线 - 解析
数据包进入包处理流水线,逐层逆解封装。
Step 3:查找目标QP(QPC Cache)
用BTH中的dst QPN查QPC Cache。若Cache miss,触发PCIe DMA从主机内存加载该QP的上下文。上下文包含RQ基址、当前RQ指针、SRQ标志等。
Step 4:地址翻译与权限校验(MTT/MPT Cache)
对于需要写入内存的操作(SEND或RDMA WRITE with Immediate),取一个RQ WQE确定目标缓冲区后,用L_Key或R_Key查MPT/MTT Cache做权限校验和地址翻译。权限校验不通过:包被丢弃,计数器加1。
Cache miss:回退到主机内存查MTT/MPT表。
Step 5:DMA写内存
地址翻译通过后,DMA引擎将IB payload通过PCIe写入主机内存的指定缓冲区。整个过程CPU不感知。
Step 6:生成CQE
数据写入完成后,视OpCode决定是否产生 CQE。
Step 7:拥塞控制(CNP生成)
如果IP头中检测到CE标记,接收端网卡的拥塞控制模块立即生成CNP包,发回发送端,触发DCQCN降速。
Step 8:ACK/NAK处理(RC模式)
对于RC操作,根据RC专用的 AETH机制处理确认:
成功接收:生成ACK,携带被确认的PSN。
检测到丢包(PSN跳变):生成NAK,携带缺失的PSN。
ACK/NAK包走发送路径(复用发包流水线)发回,不需要用户态软件参与。
四、各模块协同关系
Doorbell处理模块→QPC Cache→DMA 引擎:Doorbell触发QPC加载;QPC提供 SQ/RQ地址;DMA引擎据此搬移WQE和用户数据。
地址翻译模块↔DMA引擎 ↔MTT/MPT Cache:DMA引擎请求地址翻译;翻译模块查缓存或回退到主机内存;翻译结果返回,DMA引擎执行。
包处理流水线↔DMA引擎 ↔拥塞控制模块:发包时流水线封装,DMA引擎搬运数据;拥塞控制模块决定ECN标记和速率;收包时流水线解析,拥塞控制模块识别CE并生成 CNP。
QPC Cache↔MTT/MPT Cache ↔包处理流水线:收包时流水线提取dst QPN,查QPC Cache得RQ地址;再从RQ WQE得L_Key,如果是远端来的数据包,则从数据包中提取R_Key,然后用L_Key/R_Key查MTT/MPT Cache翻译地址;三个模块串联完成一次收包。
五、总结
RNIC的内部设计,本质是把软件协议栈的每个功能点都映射到硬件流水线的一个级,并把频繁访问的元数据(QP上下文、MTT/MPT条目)缓存在片内SRAM中,用极小的片上资源换取接近线速的吞吐和微秒级的延迟。理解了这个从Doorbell到CQE的闭环,你就掌握了RDMA网卡的"硬件思维"。