分阶段明确两端角色:
1、收包 burst 阶段(硬件 DMA 环)
生产者 NIC 网卡 DMA 硬件
消费者:rx_thread(CPU)
2、rte_ring 传递阶段(软件无锁环)
生产者:rx_thread(CPU)
消费者:worker 线程(CPU)
以下代码是第 1 阶段。
/* 轮询网卡接收报文,mbuf 送入无锁 rx_ring 完全不解析控制命令,只处理业务数据帧 1、网口收到报文 -> NIC DMA 硬件把报文写入 mbuf 物理内存,更新硬件 RX 描述符 2、rte_eth_rx_burst() CPU 线程去 poll 硬件desc ring,拿到已填好的 mbuf 3、软件做 vlan 过滤,丢弃不匹配的报文 4、把合法的 mbuf 指针 push进 rte_ring(软件无锁队列,只存指针) 5、worker 线程从 rte_ring 取出 mbuf 指针,处理报文 6、worker 线程处理完调用 rte_pkt_mbuf_free 归还 mbuf 到 mempool */staticintdata_plane_rx_thread(void*arg){RTE_SET_USED(arg);printf("[DataPlane] RX thread start\n");structrte_mbuf*bufs[32];while(1){// 从网卡硬件Rx队列批量收包uint16_tnb_rx=rte_eth_rx_burst(g_port_id,0,bufs,32);if(nb_rx>0){for(inti=0;i<nb_rx;i++){structrte_mbuf*m=bufs[i];uint16_tvlan=rte_vlan_get_vlan(m);if(vlan!=g_dev_cfg.target_vlan){rte_pktmbuf_free(m);continue;}// 推入无锁ring,交给worker处理rte_ring_enqueue(rx_ring,m);}}rte_pause();}return0;}DPDK 大页内存
/* 1、struct rte_mbuf 报文描述头对象,这个结构体本身的地址,是用户态虚拟地址 2、mbuf 结构体 + 报文 buffer(payload) 是连续存在一个 mempool 对象里面,都在大页内存 3、mempool 大页内存:同时可供 DMA 硬件 + 用户进程 CPU 访问 */structrte_mbuf{void*buf_addr;// 虚拟地址VA:CPU访问报文数据用rte_iova_tbuf_iova;// IOVA物理地址:DMA硬件使用// ...}/* 1、m 这个指针的值,就是 struct rte_mbuf 实例的用户态虚拟地址 2、CPU通过这个虚拟地址访问 mbuf 里各个成员:buf_addr、buf_iova、data_off 3、struct rte_mbuf(元数据头):只有 CPU 访问,硬件不碰;地址是用户虚拟地址。 4、payload 报文缓冲区:CPU (VA)、网卡 DMA (IOVA) 两边都访问,这块才是 DMA‑coherent 内存。 5、默认情况下,mbuf 结构体和 payload 缓冲区在 mempool 里面物理连续的一大块大页: 6、硬件只往 payload 部分 DMA 写数据; 7、mbuf 结构体那一段,硬件根本不去碰。 */structrte_mbuf*m=rte_pkt_mbuf_alloc(pool)【rte_mempool】 ├─大页整块内存 │ ├─mbuf#0:structrte_mbuf{buf_addr,buf_iova,...}+紧随其后的报文buffer │ ├─mbuf#1:structrte_mbuf{buf_addr,buf_iova,...}+紧随其后的报文buffer │ └─mbuf#2:structrte_mbuf{buf_addr,buf_iova,...}+紧随其后的报文bufferRX 描述符环,是网卡硬件自己维护的一块内存
// 网卡硬件RX Descriptorstructrx_desc_hw{rte_iova_tbuf_iova;// DMA写入的IO物理地址,CPU填入uint64_tstatus;// 硬件写:收包完成、包长度、错误标记};整个 RX ring 就是一个数组,头尾循环,形成环
rx_desc_hw desc_ring[DESC_NUM];// 环形数组,比如512个描述符head(硬件指针)↓ ┌─────┬─────┬─────┬─────┬─────┬─────┐ │desc0│desc1│desc2│desc3│desc4│desc5│ └─────┴─────┴─────┴─────┴─────┴─────┘ ↑tail(CPU软件指针)head:网卡硬件维护指针:硬件下一个要用的描述符位置;硬件顺着 head 填报文、更新 status。 tail:CPU 软件维护指针:CPU 下一个要填充新 buffer 的位置。1 个硬件 RX 描述符,对应 1 个 struct rte_mbuf*,对应 bufs[] 里面的一个元素 bufs[i]。