09 XDP 与 AF_XDP
源码:
stmmac_xdp.c、stmmac_xdp.h
数据面:stmmac_main.c(stmmac_rx、stmmac_rx_zc、stmmac_xdp_xmit)
1. 模块划分
| 层 | 文件 | 职责 |
|---|---|---|
| 控制面 | stmmac_xdp.c |
挂载 BPF、绑定 XSK pool、队列模式切换 |
| 数据面 | stmmac_main.c |
RX 运行 BPF、XDP_TX、AF_XDP zero-copy |
2. XDP 挂载
2.1 ndo_bpf
1 | .ndo_bpf = stmmac_bpf, |
处理:
XDP_SETUP_PROG→stmmac_xdp_set_prog()XDP_SETUP_XSK_POOL→stmmac_xdp_setup_pool()
2.2 stmmac_xdp_set_prog()
- 替换
priv->xdp_prog(bpf_prog_put旧程序) - 若从无 XDP 到有 XDP:可能需调整 RX headroom(
stmmac_rx_offset()) - 与
rx_copybreak策略交互
3. AF_XDP Zero-Copy
3.1 启用 pool
stmmac_xdp_enable_pool():
- 校验 queue 同时具有 RX+TX 能力
- 校验 frame size 与 MTU/buffer 一致
- 绑定
rx_q->xsk_pool/tx_q->xsk_pool - 设置
af_xdp_zc_qpsbitmap - 重启队列:释放旧 page_pool ring,按 XSK umem 重建 descriptor
3.2 NAPI 模式切换
启用 XSK 后 channel 使用 rxtx_napi(合并 poll):
1 | rx_napi = rx_q->xsk_pool ? &ch->rxtx_napi : &ch->rx_napi; |
stmmac_napi_poll_rxtx() 同时处理 TX clean 与 stmmac_rx_zc()。
3.3 stmmac_rx_zc()
- DMA 直接写入 XSK buffer(用户态 umem)
- 通过
xsk_buff_alloc/xsk_buff_free管理 - 完成后
xsk_tx_completed()/xsk_wake_up()通知用户态
4. XDP 数据路径(非 zero-copy)
stmmac_rx() 中:
1 | if (stmmac_xdp_is_enabled(priv)) { |
5. XDP 发送
| 入口 | 说明 |
|---|---|
ndo_xdp_xmit |
stmmac_xdp_xmit() — bulk XDP 帧发送 |
| XDP_TX action | RX 中直接转发到 TX ring |
ndo_xsk_wakeup |
stmmac_xsk_wakeup() — 用户态 kick |
stmmac_tx_info.buf_type 区分:
STMMAC_TXBUF_T_SKBSTMMAC_TXBUF_T_XDP_TXSTMMAC_TXBUF_T_XDP_NDOSTMMAC_TXBUF_T_XSK_TX
6. 队列要求
AF_XDP zero-copy 要求:
- 同一 queue index 必须 RX 和 TX 均启用
- 通常 dedicated queue(如 queue 0 给 XDP,其它给内核栈)
7. 与 page_pool 关系
| 模式 | RX 缓冲来源 |
|---|---|
| 普通 | page_pool |
| XDP(无 ZC) | page_pool + XDP headroom |
| AF_XDP ZC | xsk_buff_pool(umem) |
模式切换需 down/up 接口 或驱动内部 queue reset。
8. 调试
1 | # 加载 XDP 程序 |
正在加载留言…