ping延迟正常但业务连接频繁超时或重传,因ping走独立ICMP路径,而TCP业务丢包可能发生在网卡驱动、软中断队列、GRO合并失败、XDP/tc策略等底层环节,需用eBPF和内核统计综合定位。

为什么 ping 延迟正常但业务连接频繁超时或重传
因为 ping 只发 ICMP Echo Request,走的是内核独立的 ICMP 处理路径,不经过 TCP/IP 栈的连接管理、队列调度、拥塞控制等环节。真实业务(如 HTTP、gRPC)用的是 TCP,丢包可能发生在:网卡驱动收包中断丢失、软中断队列溢出、sk_buff 分配失败、socket 接收缓冲区满、甚至 eBPF 程序中误 drop。此时 ping 依然能通,但 tcpdump 在应用侧抓不到包,说明丢包发生在更底层。
perf record -e 'net:netif_receive_skb' 抓不到丢包点怎么办
这个 tracepoint 只在数据帧成功进入协议栈第一入口时触发,如果丢包发生在网卡 DMA 后但尚未调用 netif_receive_skb()(比如 NAPI poll 被延迟、RX ring 溢出、驱动丢包),它就完全沉默。必须上到更底层:
- 用
perf record -e 'skb:kfree_skb'观察是否大量 skb 在极短时间内被释放,且comm字段为ksoftirqd或网卡驱动名(如ixgbe),说明软中断处理不过来 - 检查
/proc/net/snmp中Udp:行的noport和inerrors,或Tcp:行的EstabResets、AttemptFails—— 这些是内核统计的真实丢包信号 - 确认网卡是否启用了 LRO/GRO:
ethtool -k eth0 | grep gro;GRO 合并失败时可能静默丢弃分片,且不记入常规计数器
bpftrace 跟踪 sk_buff 生命周期的关键位置
不能只盯 netif_receive_skb,要串联从 DMA 到 socket 的完整链路。以下 bpftrace one-liner 可快速定位异常释放点:
bpftrace -e '
kprobe:__kfree_skb {
@kfree_reason[ksym(func)] = count();
}
kretprobe:dev_gro_receive /retval == NULL/ {
@gro_fail[ustack] = count();
}
tracepoint:skb:kfree_skb /args->reason == 12/ {
printf("DROPPED in %s (reason=12=SKB_DROP_REASON_PKT_TOO_SMALL)\n", ksym(args->func));
}'
注意:reason == 12 对应 SKB_DROP_REASON_PKT_TOO_SMALL,常见于 GRO 合并后校验失败;dev_gro_receive 返回 NULL 表示 GRO 流水线拒绝该包,往往因 IP ID 不连续或 TCP 选项不一致 —— 这类丢包不会进 tcpdump,但会显著影响长连接吞吐。
确认是否是 XDP 层或 tc ingress 丢包
如果服务器部署了 Cilium、Calico 或自定义 tc eBPF 策略,丢包可能发生在比 netif_receive_skb 更早的位置。检查:
-
tc filter show dev eth0 ingress—— 是否有bpf类型 filter 且 action 是drop -
ip link show eth0查看是否有xdp标记;再运行bpftool net show确认 XDP 程序挂载状态 - 用
bpftrace -e 'kprobe:generic_xdp_tx { @xdp_drop = count(); }'配合xdp:xdp_exceptiontracepoint,判断是否触发了 XDP 异常路径
这类丢包完全绕过内核协议栈,netstat -s 和 /proc/net/snmp 都不会体现,只能靠 eBPF 实时观测或驱动日志(dmesg | grep -i xdp)。










