跳至正文
老丹的足迹 —— 代码写给机器,游记写给自己,感悟写给时间
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面
老丹的足迹 老丹的足迹
老丹的足迹 老丹的足迹
  • 首页
  • 示例页面
  • 首页
  • 示例页面

dropwatch:Linux内核网络丢包的”火眼金睛”——从原理到实战

在云原生和微服务架构日益普及的今天,网络问题变得越来越复杂和隐蔽。应用日志里可能只看到一句”connection reset”,但真正的原因——数据包在内核协议栈的哪个环节被丢弃了——却像一个黑盒,让人无从下手。dropwatch正是为了揭开这个黑盒而生的工具。

一、什么是dropwatch?

dropwatch是一个专为Linux系统设计的内核级网络丢包监控与诊断工具。它的核心使命是帮助开发者和系统管理员快速定位数据包在Linux网络协议栈中被丢弃的具体位置和原因。

与 tcpdump 这类网络抓包工具不同,dropwatch 不关注”网络上正在传输什么包”,而是直接”问内核”:“你刚刚把哪个包扔了?为什么扔?在哪里扔的?” 这种直达问题根源的能力,使其在处理复杂网络故障时成为一个”杀手锏”。

二、为什么要用dropwatch?

在 dropwatch 出现之前,排查网络丢包问题是一件相当痛苦的事情。该项目官方文档中明确指出了四大核心痛点:

  1. 信息来源分散:管理员需要分别检查 /proc/net/snmp 文件、netstat、tc 和 ethtool 等多个工具的输出,才能拼凑出丢包情况的完整图景。
  2. 信息模糊不清:即使是经验丰富的管理员,也未必能准确判断某个统计数据的增加是否意味着发生了丢包。
  3. 原因难以判定:即使确认发生了丢包,原因也常常是模糊的。例如,一个 UDPInError 的递增,可能是应用程序接收缓冲区满了,也可能是数据包校验和出错。
  4. 性能开销大:传统的方案需要定时轮询多个接口来获取统计数据,性能开销大,尤其当丢包事件并不频繁时,这种轮询方式很不划算。

dropwatch 的设计目标正是为了解决这四大痛点,它通过内核提供的一种异步通知机制,只在丢包事件发生时进行记录和报告,从而实现了高性能的监控。

三、工作原理:数据包的”终点站”报告员

dropwatch 的工作原理建立在对内核关键函数的监控之上。在Linux内核网络栈中,每一个数据包都被抽象为一个 sk_buff 结构体。无论数据包是因为何种原因被丢弃——可能是校验和错误、缓冲区满、路由失败、防火墙规则拒绝等——内核最终都会调用 kfree_skb() 函数来释放这个结构体所占用的内存。因此,kfree_skb 就像是数据包在内核中的”生命终点站”。

dropwatch 正是通过在 kfree_skb 这个内核跟踪点(Tracepoint)上”挂钩子”来实现监控的。当丢包事件发生时,它会:

  1. 捕获事件:记录下当前的内核函数调用栈,这能清晰地展示出数据包是在哪条代码路径上被丢弃的。
  2. 采集上下文:一并捕获丢包事件的”完整上下文”,包括IP五元组、进程名和PID、网络设备、MAC地址等关键信息。
  3. 地址符号化:将晦涩的内存地址翻译成人类可读的内核函数名(如 tcp_v4_rcv),让分析变得直观。

通过这一系列操作,dropwatch 将内核的”黑盒”行为透明化,为问题诊断提供了精确的线索。

四、三个版本全景对比

dropwatch 在发展过程中,衍生出了三个主要的版本分支。它们共享相同的内核监控原理,但在交互方式、功能特性和适用场景上各有侧重。

特性官方版 (nhorman/dropwatch)eBPF极简版 (feiskyer/dropwatch)HUATUO企业版 (didi/huatuo)
维护者Neil Horman(官方)feiskyer(第三方)滴滴开源(CCF孵化)
底层技术NetlinkeBPF + CO-REeBPF + CO-RE
构建方式Autotools(./autogen.sh && ./configure && make)Makefile(make)Makefile
交互方式交互式Shell(start/stop/help)启动即监控,Ctrl+C停止启动即监控,Ctrl+C停止
命令行参数支持 -l kas基本不支持支持 --filter、-j、--output 等
内核侧过滤❌ 不支持❌ 不支持✅ 支持 tcpdump 风格过滤
结构化输出❌ 不支持❌ 不支持✅ 支持 JSON 格式输出
内核版本要求较低,支持旧内核需要 5.8+ 且开启 BTF需要 5.8+ 且开启 BTF
文档来源man dropwatch项目 README.md项目 README.md

五、各版本详细介绍

5.1 官方版 (nhorman/dropwatch)

这是由 dropwatch 项目原作者 Neil Horman 维护的官方正统版本。它也是大多数Linux发行版软件源中提供的版本,以及 man dropwatch 手册所描述的版本。

核心特点:

  • 交互式Shell:运行 dropwatch -l kas 后进入 dropwatch> 提示符,通过输入 start、stop、help、set alertlimit 等命令来控制监控流程。
  • 地址符号化:-l kas 选项利用 /proc/kallsyms 将内核指令指针翻译为人类可读的函数名。
  • 基于Netlink:使用传统的内核Netlink接口与内核通信,兼容性较好,支持较旧版本的内核。

典型启动方式:

sudo dropwatch -l kas
> start          # 开始监控
> set alertmode packet   # 显示详细信息
> stop           # 停止监控
> exit           # 退出

适用场景:需要在较低版本内核上使用,或希望灵活控制监控时段的场景。

5.2 eBPF极简版 (feiskyer/dropwatch)

这是你此前实际编译和使用的版本。它基于 eBPF 技术重构,但设计上追求极致的简洁。

核心特点:

  • 启动即监控:运行后立即开始输出丢包事件,无交互式Shell,按 Ctrl+C 停止。
  • 利用 BTF + CO-RE:直接读取 /sys/kernel/btf/vmlinux 获取内核类型信息,无需安装 linux-headers 包,且支持跨内核版本运行。
  • 功能极简:不支持任何命令行参数(包括 -h),也不支持内置过滤。

编译与启动:

git clone https://github.com/feiskyer/dropwatch.git
cd dropwatch
git submodule update --init --recursive   # 拉取 libbpf 子模块
make
sudo ./out/dropwatch

适用场景:快速一次性观测,对性能开销要求极低的轻量级使用场景。

5.3 HUATUO企业版 (didi/huatuo)

这是功能最强大的版本,由滴滴出行开源,并孵化于 CCF(中国计算机学会)的 HUATUO(华佗)项目。它专门为大规模生产环境设计。

核心特点:

  • 内核侧过滤:支持 tcpdump 风格的过滤表达式(如 --filter "tcp and port 8080"),且过滤逻辑在内核态执行。只有匹配条件的丢包事件才会被上报,极大降低了性能开销,避免了海量无关信息的干扰。
  • 结构化输出:支持 --output json 参数,方便与 Elasticsearch 等可观测性平台集成,进行长期存储和多维分析。
  • 丰富元数据:能采集容器环境中的网络命名空间等上下文信息,对云原生排障尤为友好。

典型启动方式:

# 只监控特定端口的TCP丢包
sudo ./dropwatch --filter "tcp and port 8080"

# 输出JSON格式,便于日志采集
sudo ./dropwatch --output json

# 只监控特定网络接口
sudo ./dropwatch --iface eth0

适用场景:复杂的云原生生产环境、大规模分布式系统、需要精准过滤和日志集成的企业级场景。

六、编译安装指南

由于不同版本的构建方式不同,下面分别给出编译步骤。

6.1 环境准备:确认内核支持BTF(eBPF版必需)

eBPF版 dropwatch 依赖内核的BTF特性。主流发行版中,Ubuntu 20.10+、Fedora 31+、RHEL 8.2+、Debian 11+ 默认已开启。

# 检查BTF是否可用
ls /sys/kernel/btf/vmlinux

如果该文件存在,说明BTF已启用,编译时可直接从该文件读取内核类型信息。

6.2 安装通用编译依赖

不同版本所需的依赖有所不同,以下是各版本的依赖清单:

依赖包官方版eBPF极简版HUATUO版
make✅✅✅
gcc / build-essential✅❌✅
clang / llvm❌✅✅
libelf-dev❌✅✅
libnl-3-dev✅❌❌
libnl-genl-3-dev✅❌❌
autoconf / automake / libtool✅❌❌
git✅✅✅

各版本依赖安装命令:

# 官方版 (nhorman/dropwatch)
sudo apt update
sudo apt install -y git autoconf automake libtool make gcc libnl-3-dev libnl-genl-3-dev

# eBPF极简版 (feiskyer/dropwatch)
sudo apt update
sudo apt install -y git make clang llvm libelf-dev

# HUATUO版 (didi/huatuo)
sudo apt update
sudo apt install -y git make clang llvm libelf-dev

6.3 克隆并编译各版本

官方版:

git clone https://github.com/nhorman/dropwatch.git
cd dropwatch
./autogen.sh
./configure
make
sudo make install

eBPF极简版:

git clone https://github.com/feiskyer/dropwatch.git
cd dropwatch
git submodule update --init --recursive   # 关键:拉取libbpf子模块
make
sudo cp out/dropwatch /usr/local/bin/     # 可选安装到系统路径

HUATUO版:

git clone https://github.com/didi/huatuo.git
cd huatuo/dropwatch
make
sudo ./dropwatch --filter "tcp"           # 直接使用,支持过滤参数

6.4 常见编译报错与解决

报错信息原因解决方法
No such file or directory (libbpf/src)未拉取子模块(eBPF版)git submodule update --init --recursive
clang: No such file or directory未安装 clangsudo apt install clang llvm
libnl-3 not found缺少Netlink库(官方版)sudo apt install libnl-3-dev libnl-genl-3-dev
autogen.sh: command not found未安装autotools(官方版)sudo apt install autoconf automake libtool

七、实战使用:捕获真实的丢包事件

下面以你实际编译的 eBPF极简版 为例,演示使用流程和输出解读。其他版本的输出格式基本相同,差异在于交互方式和过滤能力。

7.1 启动 dropwatch

sudo ./out/dropwatch

启动后立即开始输出丢包事件。按 Ctrl+C 停止监控。

7.2 捕获到的输出示例

TIME             COMM             PID                SADDR:SPORT  ->           DADDR:DPORT  TCP_FLAGS    REASON
17:24:56         swapper/3        0          192.168.0.106:50075  ->   192.168.0.173:12678  .S......     NO_SOCKET
17:24:56         swapper/3        0          192.168.0.106:50075  ->   192.168.0.173:12678  .S......     NO_SOCKET
17:24:56         go2rtc           3500689    192.168.0.106:50083  ->   192.168.0.173:12678  .S......     NO_SOCKET
17:24:56         swapper/3        0          192.168.0.106:50083  ->   192.168.0.173:12678  .S......     NO_SOCKET
17:24:57         swapper/3        0          192.168.0.106:50083  ->   192.168.0.173:12678  .S......     NO_SOCKET
17:25:00         swapper/3        0          192.168.0.106:50084  ->   192.168.0.173:12678  .S......     NO_SOCKET
17:25:00         nginx            3500751        127.0.0.1:50608  ->       127.0.0.1:5001   F...A...
17:25:06         swapper/3        0          192.168.0.106:50087  ->   192.168.0.173:12678  .S......     NO_SOCKET

7.3 输出字段解读

字段含义
TIME丢包发生的时间
COMM触发丢包的进程名(swapper/3 表示内核线程)
PID进程ID(0表示内核态)
SADDR:SPORT源IP地址和源端口
DADDR:DPORT目标IP地址和目标端口
TCP_FLAGSTCP标志位(.S...... 表示SYN包,F...A... 表示FIN+ACK)
REASON丢包原因(最关键的信息)

7.4 案例分析:解读 NO_SOCKET 丢包

从上面的输出可以清晰看出:

  • 丢包原因:全部为 NO_SOCKET,表示目标端口上没有进程在监听
  • 目标地址:192.168.0.173:12678
  • 源进程:主要是 swapper/3,偶有 go2rtc
  • TCP标志:.S......(SYN包),说明这是TCP三次握手的第一个包被丢弃

结论:192.168.0.173 上的 12678 端口没有服务在监听,但 192.168.0.106 上的应用却在持续发起连接请求,导致内核不断拒绝这些 SYN 包。

7.5 常见丢包原因速查表

REASON含义常见场景
NO_SOCKET目标端口无监听进程服务未启动、端口配置错误
TIMEOUT连接超时网络延迟、对端无响应
SOCKET_OVERFLOW接收缓冲区满应用处理能力不足、突发流量
FILTER被防火墙规则拦截iptables/nftables 规则配置不当
ROUTE路由失败路由表缺失、网关不可达
NOT_SPECIFIED未明确指定原因需结合上下文进一步分析

7.6 输出过滤方法

对于不支持内置过滤的版本(官方版和eBPF极简版),可以通过 Linux 管道命令来实现输出筛选:

# 排除特定的噪音流量
sudo ./out/dropwatch | grep -v "192.168.0.173"

# 只关注本地回环的丢包
sudo ./out/dropwatch | grep "127.0.0.1"

# 同时排除多个条件
sudo ./out/dropwatch | grep -v -E "192.168.0.173|12678"

# 保存完整日志以便后续分析
sudo ./out/dropwatch | tee /tmp/drop.log

# 统计各类丢包原因的数量
sudo ./out/dropwatch | awk '{print $NF}' | sort | uniq -c

而对于 HUATUO版,可以直接使用内置的 --filter 参数在内核侧完成过滤,更加高效。

八、获取帮助:各版本的文档来源

由于三个版本的行为差异较大,获取帮助的途径也有所不同:

信息来源官方版eBPF极简版HUATUO版
man dropwatch✅ 适用❌ 不适用❌ 不适用
项目 README.md✅ 适用✅ 唯一权威✅ 唯一权威
-h / --help✅ 适用❌ 不支持✅ 适用
交互式 help 命令✅ 适用❌ 不支持❌ 不支持

九、典型应用场景

  1. Kubernetes 云原生网络排障:在容器漂移、Pod频繁重启、Service端口冲突等场景下,精确捕获特定Pod或Service的丢包事件,快速定位根因。此场景推荐使用 HUATUO版,其容器网络命名空间信息采集能力尤为适用。
  2. 性能毛刺分析:当业务出现周期性延迟增加时,通过分析丢包事件的内核调用栈,区分问题究竟是防火墙规则导致、路由失败,还是接收缓冲区溢出。
  3. 多租户环境隔离问题排查:在共享网络命名空间的环境中,通过指定网络设备进行过滤,精准采集目标租户的丢包事件,避免其他租户的流量干扰诊断。
  4. 服务未启动导致的连接失败:如本文案例所示,NO_SOCKET 丢包能快速揭示目标端口无服务监听的问题,避免在错误的方向上耗费时间。

十、总结

dropwatch 不仅是一个工具,更是一种将内核的”不确定”变为”可观测” 的方法论。它通过监控 kfree_skb 这个内核”终点站”,将数据包在内核中被丢弃的瞬间完整记录下来,让网络问题排查从”猜谜游戏”变成”精准定位”。

在版本选择上,建议根据实际场景灵活决策:

  • 官方版:适合需要在较低版本内核上使用,或偏好交互式控制的场景。
  • eBPF极简版:适合快速一次性观测,对性能开销要求极低的轻量级使用。
  • HUATUO企业版:适合复杂的云原生生产环境,其内核侧过滤和结构化输出能力能显著提升排障效率。

对于系统工程师、SRE 和内核开发者而言,熟练掌握 dropwatch 的编译和使用,意味着在面对棘手的网络疑难杂症时,手中多了一把直达内核的”手术刀”。而随着 eBPF 技术的不断成熟,dropwatch 这类工具的演进也将持续降低网络问题诊断的门槛,让每一个被丢弃的数据包都有迹可循。

作者

老丹

关注我
其他文章
上一个

从 ip maddr show 命令输出看 ens38 接口的多播组加入情况

下一个

eBPF深度解析:重塑Linux内核可编程性的革命性技术

关于博主

    老丹是一名C/C++后台开发工程师,信奉“无抽象不设计,无性能不生产”。

  • 技术栈:Modern C++、Linux环境编程、多线程/并发、网络编程等。
  • 信条:能用constexpr解决的问题绝不拖到运行时,能靠RAII避免的泄漏绝不写析构。
  • 正在填坑:从解封装到渲染的C++全链路实现,正在驯服FFmpeg与H.264/H.265。
  • 输出原则:这里的每一段代码都经过-Wall -Wextra -Werror -O2的洗礼。

近期文章

  • Ubuntu 防火墙迁移指南:从 UFW 到 firewalld 的完整实践 2026年9月12日
  • Nano 编辑器完全操作指南:从入门到熟练 2026年9月12日
  • SSCG:让自签名证书不再“危险”的生成工具 2026年9月12日
  • Ubuntu Samba 服务安装与配置完全指南 2026年9月12日
  • 从零开始:用 Docker 部署 Jellyfin 并启用英特尔核显硬件加速 2026年9月11日

文章分类

  • C/C++开发 (22)
  • Docker容器 (5)
  • Linux工具包 (17)
  • Linux服务配置 (50)
  • Linux系统 (16)
  • OpenWrt路由 (3)
  • Shell脚本 (3)
  • 代码管理 (1)
  • 安防技术 (4)
  • 数据安全 (36)
  • 未分类 (1)
  • 网络协议 (25)
  • 计算机理论 (23)
  • 音视频技术 (5)
联系我们:📍 地址:中国·广东省深圳市   |   ✉️ 邮箱:support@tanglinux.com   |   💬 QQ:870866607
版权所有:老丹的足迹粤ICP备2026061170号-1       公安备案图标 粤公网安备44030002013274号