基本原理
如图(盗图)
- 内存(RAM)和网卡(NIC)之间通过Descriptor ring 交互网络报文数据
- 内存中需要申请内存 packet buffer 的内存池,内存池中的每个实例,地址是物理连续的或者IOVA连续的
- 一个数据报文通过一个descriptor描述(大报文需要分段的就需要多个描述符),(descriptor还可以描述其他东西,如各种offload的上下文等,详见手册)
- 内存中需要申请一段内存存放 descriptor rings, (这些内存需要物理连续,或者IOVA连续)
- descriptor中有指向它要写入/读取数据的packet buffer的地址
- 对于发送ring NIC从(Head,Tail-1)中读取数据,CPU往其他descriptor描述的内存中写入数据
- NIC有对应的寄存器可以感知head,tail的变化
- 需要物理连续或IOVA连续的内存,需要有两个地址,虚拟地址/物理地址(IOVA)地址,他们是不通的视角表示同一块内存;CPU使用虚拟地址,NIC使用物理(IOVA)地址
dpdk e1000
发包过程中典型ring状态流量如上图所示。
开发测试过程中,无意间将rte_mbuf的nb_segs字段重置成了0。数据包发送过程中nb_used字段的更新是根据nb_segs做计算的,如果rte_mbuf是小包没有分段nb_segs就应该是1,如果是打包,有分段就是分段的个数,有几个nb_segs就会使用几个descriptor,并更新nb_used.
错误的nb_segs设置,导致上述流程中空闲描述符不足做清理时,取到的descrptor状态不是DD,导致一直清理失败,使队列阻塞无法发包。