Files
dpdk-blog/notes/phase0/day02-kernel-rx-path.md
T
newbieandClaude 6d8c994dde init: DPDK → DPU learning blog (VitePress)
- 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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-09 15:42:47 +00:00

105 lines
4.1 KiB
Markdown
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 找到你的网卡