3、网卡基础回顾:网卡架构、MAC层、PHY层、PCIe接口、DMA引擎、中断机制

各位同学,咱们今天聊聊网卡。别觉得基础,我做了这么多年低延迟交易系统,发现很多问题都出在对网卡的理解不够深。说白了,网卡就是FPGA和外部网络之间的桥梁,这座桥要是搭不好,你FPGA处理得再快也没用。

3.1 网卡整体架构

先看一张整体图,我习惯把网卡分成三个层次来看:

网卡架构分层图 应用层(FPGA/CPU) PCIe接口 + DMA引擎 MAC层(Media Access Control) 帧封装/解封装、CRC校验、流量控制 PHY层(Physical Layer) 编码/解码、串并转换、信号调制 物理介质(网线/光纤)

这张图我画了很多次了。从上往下看,数据从FPGA或CPU出发,经过PCIe和DMA,到达MAC层做帧处理,再到PHY层做信号转换,最后通过网线发出去。反过来就是接收路径。

核心要点:在低延迟交易中,我们最关心的是数据从网线到FPGA逻辑的路径有多短。每一层都会引入延迟,所以很多高端网卡允许FPGA直接接管MAC和PHY的控制权。

3.2 MAC层

MAC层,全称是Media Access Control。它干的事说白了就是三件:

  • 帧封装与解封装:给数据包加上MAC头尾,或者反过来拆掉
  • CRC校验:检查数据在传输过程中有没有出错
  • 流量控制:防止发送方太快,接收方来不及处理

我记得有一次做项目,发现收到的数据包偶尔会丢几个字节。查了半天,最后发现是MAC层的CRC校验没通过,网卡直接把包扔了。嗯,这里要注意,很多低延迟场景下我们会关闭MAC层的某些功能,比如流量控制,因为那会增加不确定的等待时间。

实战技巧:在FPGA中实现MAC层时,我个人习惯把CRC校验放在最后一级流水线。这样即使校验失败,前面的处理也不会被阻塞,适合流水线式的数据处理。

3.3 PHY层

PHY层是物理层,它负责把数字信号变成模拟信号,或者反过来。你想想看,网线里传的是电信号或者光信号,不是0和1。PHY层做的就是这件事。

PHY层的关键参数有:

参数 说明 低延迟关注点
速率 10M/100M/1G/10G/25G/100G 越高越好,但功耗也高
编码方式 8B/10B, 64B/66B, 128B/130B 编码效率影响有效带宽
串并转换 SERDES 延迟通常在几纳秒到几十纳秒
自动协商 Auto-negotiation 建议关闭,固定速率减少延迟

我曾经踩过一个坑:某款网卡的PHY层默认开启了自动协商,结果每次链路重连都要花2-3秒。在交易系统里,2秒意味着什么?可能几十万笔订单就错过了。所以我的建议是:固定速率,关闭自动协商。

3.4 PCIe接口

PCIe是网卡和主机通信的高速通道。在低延迟交易中,PCIe的延迟直接影响数据从网卡到CPU或FPGA的速度。

PCIe的几个关键概念:

  • Lane(通道):每个Lane是一对差分信号,x1、x4、x8、x16表示通道数
  • Gen(代):Gen1=2.5GT/s, Gen2=5GT/s, Gen3=8GT/s, Gen4=16GT/s, Gen5=32GT/s
  • TLP(事务层包):PCIe通信的基本单位

注意:PCIe的延迟不仅仅是物理传输延迟,还包括协议开销。比如一次DMA读操作,需要先发送读请求,等待返回数据。这个往返时间在几百纳秒到几微秒之间。在FPGA设计中,我通常会用写操作代替读操作来减少延迟。

3.5 DMA引擎

DMA,Direct Memory Access。它的作用是不经过CPU,直接把网卡的数据搬到内存里。你想想看,如果没有DMA,每个数据包都要CPU去读,那CPU就别干别的了。

DMA的工作流程大致是这样的:

  1. 网卡收到数据包,存入内部缓冲区
  2. DMA引擎发起PCIe写操作,把数据写入主机内存
  3. 写入完成后,通知CPU或FPGA数据已就绪

在低延迟场景下,DMA的设计有几个关键点:

  • 描述符环(Descriptor Ring):预分配的内存区域,避免动态分配
  • 零拷贝(Zero Copy):数据直接从网卡到应用缓冲区,不经过内核
  • 多队列(Multi-Queue):每个CPU核心一个队列,避免锁竞争

我的经验:在FPGA中实现DMA时,我习惯用寄存器映射的方式代替传统的描述符环。虽然灵活性差一些,但延迟可以降低30%以上。说白了,就是用空间换时间。

3.6 中断机制

中断是网卡通知主机数据到了的方式。传统的中断方式是:网卡发一个中断信号,CPU停下当前工作,去处理网卡数据。

但这种方式在高速网络下有问题——中断太多了,CPU光处理中断就忙不过来。所以有了这些优化:

  • 中断合并(Interrupt Coalescing):攒几个包再发一次中断
  • NAPI:Linux内核的轮询+中断混合机制
  • 忙轮询(Busy Polling):CPU不断检查网卡状态,不用中断

在低延迟交易中,我们通常选择忙轮询。为什么?因为中断有不确定性。中断来了,CPU要保存上下文、跳转到中断处理函数、处理完再恢复。这个过程少说也要几微秒。而忙轮询虽然占用CPU,但延迟是确定的。

避坑指南:我曾经在一个项目里用了中断合并,结果发现延迟的抖动特别大。后来改成忙轮询,延迟从平均5微秒降到了1.2微秒,而且几乎没有抖动。所以,如果你的CPU核心够用,别犹豫,用轮询。

3.7 小结

好了,网卡的基础知识就回顾到这里。总结一下:

  • 网卡架构分三层:应用层(PCIe+DMA)、MAC层、PHY层
  • MAC层负责帧处理和CRC校验,低延迟场景可以精简
  • PHY层负责信号转换,建议关闭自动协商
  • PCIe接口是高速通道,用写操作代替读操作减少延迟
  • DMA引擎实现数据直传,零拷贝和多队列是标配
  • 中断机制在低延迟场景下建议用忙轮询

这些内容看起来基础,但每一个点在实际项目中都可能成为瓶颈。下一章我们会深入FPGA和网卡的协同设计,到时候这些基础知识都会用上。


专注资料整理