- VitePress static site for rendering all markdown documents - Auto-discovers .md files from dpdk-roadmap-v3 and dpdk-study-kb - Features: full-text search, dark mode, responsive design - Pages: roadmap, notes (Phase 0-3), product docs, knowledge base
4.1 KiB
Executable File
4.1 KiB
Executable File
Phase 0 · Day 2: 内核中断 + 网络收包路径
一、你的系统数据
IRQ 56 (ens160-rxtx-0): CPU0:1329万 CPU1:191万 CPU2:112万 CPU3:676万
IRQ 57 (ens160-rxtx-1): CPU0:11万 CPU1:33万 CPU2:36万 CPU3:38万
IRQ 58 (ens160-rxtx-2): CPU0:19万 CPU1:37万 CPU2:43万 CPU3:42万
IRQ 59 (ens160-rxtx-3): CPU0:30万 CPU1:39万 CPU2:52万 CPU3:52万
IRQ 60 (ens160-event): 全 0 (事件队列, 未使用)
NET_RX 软中断: CPU0:1339万 CPU1:436万 CPU2:381万 CPU3:791万
ksoftirqd: 每个 CPU 一个 (PID 16/24/30/36)
- 4 个 MSI-X 向量 → 4 个 RX 队列 → 4 个 CPU 并行收包
- IRQ 56 在 CPU0 上触发了 1329 万次(主流量),CPU1-3 只触发了少量——IRQ affinity 配置不均
二、收包 6 道关卡
关卡1: 硬件中断
网卡 DMA 写 RX ring → MSI-X 中断 → APIC → CPU → IDT → irq_handler
此时在硬中断上下文,所有中断被屏蔽
关卡2: NAPI 调度
irq_handler → napi_schedule → 关网卡中断 + 触发 NET_RX_SOFTIRQ → 返回
源码: net/core/dev.c ____napi_schedule (line 4551)
关卡3: ksoftirqd
ksoftirqd 被唤醒 → __do_softirq → net_rx_action → 遍历 poll_list
源码: kernel/softirq.c + net/core/dev.c
关卡4: 驱动 poll → netif_receive_skb
从 RX descriptor ring 取包 → alloc_skb → memcpy → netif_receive_skb(skb)
源码: net/core/dev.c netif_receive_skb (line 5899)
关卡5: 协议分发 (L2→L3)
__netif_receive_skb_core → skb->protocol → 查 ptype_base 哈希表 → ip_rcv()
源码: net/core/dev.c __netif_receive_skb_core (line 5434)
net/ipv4/ip_input.c ip_rcv (line 560)
协议注册: net/ipv4/af_inet.c dev_add_pack (line 2065)
关卡6: TCP 收包 (L3→L4→socket)
ip_rcv → NF_HOOK → ip_local_deliver → tcp_v4_rcv
→ __inet_lookup_established → tcp_rcv_established (fast path!)
→ tcp_queue_rcv → sk_data_ready → wake_up → epoll 返回
源码: net/ipv4/tcp_ipv4.c (line 1999)
net/ipv4/tcp_input.c tcp_rcv_established
三、DPDK 为什么快
| 内核步骤 | 耗时 | DPDK |
|---|---|---|
| MSI-X → IDT → handler | ~3us | PMD 轮询, 无中断 |
| napi_schedule + ksoftirqd 调度 | ~5us | PMD 线程永不睡眠 |
| alloc_skb (slab 锁) | ~1us | mbuf 从 per-lcore cache 弹出 |
| memcpy DMA→skb | ~2us | DMA 直接写 mbuf, 零拷贝 |
| ptype_base 查找 | ~0.3us | 应用自己解析协议 |
| Netfilter HOOK | ~5us | 不需要 |
| ehash 查 socket | ~1us | rte_hash_lookup |
| copy_to_user | ~3us | 零拷贝 |
| 总计 | ~20us | ~1us |
四、实战踩坑
坑 1: 中断全绑 CPU0
- 现象: top 看 CPU0 si=99%, 其他 CPU 空闲
- 根因: smp_affinity 默认只开 CPU0
- 定位:
cat /proc/irq/56/smp_affinity - 修复:
echo ff > /proc/irq/56/smp_affinity
坑 2: NAPI budget 耗尽
- 现象: 100G 线速达不到,
ethtool -S看 rx_missed 增长 - 根因: net_rx_action 默认一次最多 300 包,收不够就返回
- 定位:
cat /proc/net/softnet_stat, 第三列 = "times queue full" - 修复: 增大 net.core.netdev_budget,或换 DPDK
坑 3: ksoftirqd 被抢占
- 现象: 收包延迟 P99 抖动严重
- 根因: ksoftirqd 不是实时线程,被磁盘 I/O 抢占
- 定位:
perf sched latency - 修复:
chrt -f 1 $(pidof ksoftirqd/0)或换 DPDK PMD
坑 4: Netfilter 静默丢包
- 现象: tcpdump 能看到包,应用收不到
- 根因: Docker/k8s 自动注入 iptables drop 规则
- 定位:
iptables -L -v -n, 看每条规则的计数器
坑 5: TCP backlog 满
- 现象: 客户端 connect 超时
- 根因: accept queue=128, 第 129 个 SYN 被内核静默丢弃
- 定位:
netstat -s | grep overflow - 修复:
echo 4096 > /proc/sys/net/core/somaxconn
五、检验标准
- 能画中断→NAPI→ksoftirqd→poll→netif_receive_skb→ip_rcv→tcp_v4_rcv 完整调用链
- 能解释 NAPI 为什么要关中断、用软中断
- 能说 ptype_base 的作用
- 能列 DPDK 比内核快 ≥5 个原因
- 能在 /proc/interrupts 和 /proc/softirqs 找到你的网卡