nettools · 大规模物理网络丢包与 bitflip 检测工具
Usage Guide — 涵盖安装、配置、运行模式及典型使用场景。
bitflip 和 bitflip6 是百度系统部物理网络黑盒监控团队开发的高频 UDP 探测工具,用于检测大规模物理网络中的丢包和 bitflip(比特翻转)错误。支持单向(unidirectional)丢包和改包检测。
工作原理:Client 以高频率向 Server 发送 UDP 报文,Server 原样回复。双端独立检测:
-c。比特翻转(Bit Flip)是数字数据存储或传输中的一种常见错误,指单个二进制位从 0 变为 1,或从 1 变为 0 的现象。这通常由宇宙射线、电磁干扰、硬件老化或过热引起,可能导致静默数据损坏(Silent Data Corruption)或系统崩溃。
交换机和服务器的CPU 寄存器、缓存(Cache)、DRAM 内存或 Flash 闪存中的一个或多个位(bit)在没有软件参与的情况下,被硬件故障意外地由 0 反转为 1,或由 1 反转为 0。
如果一个代表重要数据的二进制位发生翻转,可能导致严重的错误。例如,计算机内部的一个指令可能因此从正确的代码 13 + 0 意外变成 13 ÷ 0,从而引发崩溃。在网络场景中,交换机端口的单个比特翻转可能导致报文 checksum 校验通过但数据错误,造成上层应用静默错误。
bitflip / bitflip6 正是为解决网络传输链路上比特翻转的检测和定位而设计的。传统网络监控工具只能检测丢包,无法发现"报文到达但内容被篡改"的情况。本工具通过高频发送已知模式的 UDP 报文,在收端逐字节校验,能够:
# 克隆仓库
git clone https://github.com/baidu/nettools.git
cd nettools
# 编译全部
make compile
# 或单独编译
make build # 仅 bitflip (IPv4)
make build6 # 仅 bitflip6 (IPv6)
# 本地测试构建 (snapshot)
make snapshot
# 正式发布 (需要 git tag + GITHUB_TOKEN)
git tag v1.0.0
make deploy
dist/ 目录。
| 操作系统 | 架构 | bitflip | bitflip6 |
|---|---|---|---|
| Linux | AMD64 | ✓ | ✓ |
| Linux | ARM64 | ✓ | ✓ |
| macOS | AMD64 | ✓ | ✓ |
| macOS | ARM64 | ✓ | ✓ |
# 最简启动 — 自动检测本机 IP,收到未知 Client 自动注册
./bitflip
# 指定服务端 IP
./bitflip -r server -s 10.0.0.1
# 指定目标 Server 地址
sudo ./bitflip -r client -s 10.0.0.1
# 指定双端地址
sudo ./bitflip -r client -c 10.0.0.2 -s 10.0.0.1
sudo 权限来设置 IP TOS/DSCP 值。
# Server
./bitflip6
# Client
sudo ./bitflip6 -r client -s fd00::1
bitflip 和 bitflip6 使用相同的参数格式,区别仅在于地址使用 IPv4 或 IPv6。
| 短标志 | 长标志 | 默认值 | 说明 |
|---|---|---|---|
-r | --role | server | 运行角色: client 或 server |
-c | --client-addr | "" | 客户端 IP 地址 (为空则自动检测) |
-s | --server-addr | "" | 服务端 IP 地址 (server 角色可自动检测) |
-t | --tos | 64 | IP TOS/DSCP 值 |
-n | --count | 0 | 最大发包数 (0 = 不限制) |
-d | --duration | 0 | 最大发送时长 (0 = 不限制) |
--client-ports | 43500,43599 | 客户端端口范围 [min,max] | |
--server-ports | 43500,43509 | 服务端端口范围 [min,max] | |
--rate | 5000 | 每个 span 发包速率 | |
--msglen | 1024 | 消息体大小 (不含 32 字节头部) | |
--delay | 3s | 统计处理延迟 (等待在途报文) | |
--verbose | false | 丢包时打印详细端口信息 (Client 和 Server 均支持) |
# Server 端 (目标机器) — 无需指定 -c,自动注册 Client
./bitflip -s 10.0.0.1
# Client 端 (发起探测)
sudo ./bitflip -r client -s 10.0.0.1
# 10000 pps, 发送 60 秒后自动停止
sudo ./bitflip -r client -s 10.0.0.1 --rate 10000 --duration 60s
# 发送 100000 个报文后停止
sudo ./bitflip -r client -s 10.0.0.1 -n 100000
# 客户端使用 50000-50099 端口, 服务端使用 50000-50009 端口
sudo ./bitflip -r client -s 10.0.0.1 \
--client-ports 50000,50099 \
--server-ports 50000,50009
# 设置 TOS 值为 128 (DSCP CS4)
sudo ./bitflip -r client -s 10.0.0.1 -t 128
# 使用 8KB payload 检测 MTU 相关问题
sudo ./bitflip -r client -s 10.0.0.1 --msglen 8192
# Client 端开启 --verbose,丢包时打印详细端口信息
sudo ./bitflip -r client -s 10.0.0.1 --verbose
# Server 端开启 --verbose,丢包时打印单向丢包五元组
./bitflip -s 10.0.0.1 --verbose
# 探测多个 Server (逗号分隔)
sudo ./bitflip6 -r client -s fd00::1,fd00::2,fd00::3
每个 UDP 报文的 payload 由 32 字节固定头部 + N 字节 Salt 填充组成:
| 字段 | 大小 | 说明 |
|---|---|---|
| Magic | 8 bytes | 魔术字标识,用于过滤非本工具的报文 |
| Seq | 8 bytes | 递增序列号,用于丢包检测和排序 |
| Timestamp | 8 bytes | 纳秒级时间戳,用于 RTT 计算 |
| LastSent | 4 bytes | 上一个 span 的发送计数(Server 端用于计算单向丢包率) |
| LastSrcPort | 2 bytes | 上一个 span 的起始源端口 |
| LastDstPort | 2 bytes | 上一个 span 的起始目的端口 |
| Salt | N bytes | 填充数据,用于 bitflip 校验 |
LastSrcPort + LastDstPort + LastSent 三个字段,通过 GetNextPorts 即可还原上一个 span 中每一个包的端口对——从而实现单向丢包的五元组级定位,仅增加 4 字节开销。
Client 使用 4 种 Salt 填充模式(由 seq % 4 决定),覆盖不同的位模式以最大化检测概率:
| Index | Pattern | 二进制 | 用途 |
|---|---|---|---|
| 0 | 0xFF | 11111111 | 全 1 — 检测 1→0 翻转 |
| 1 | 0x00 | 00000000 | 全 0 — 检测 0→1 翻转 |
| 2 | 0x5A | 01011010 | 交替位 — 检测相邻位翻转 |
| 3 | 0xAA/0x55 交替 | 10101010 / 01010101 | 互补 16-bit word 交替 — 专门检测 TCP/IP Checksum 无法发现的互补翻转 |
Server 端使用相同的 4 种模式验证返回报文。当检测到 bitflip 时,记录对应五元组 (srcIP:srcPort → dstIP:dstPort + protocol) 以便定位故障链路。
0xAAAA, 0x5555, 0xAAAA, 0x5555...)专门针对 TCP/IP Checksum 的盲区设计:相邻 16-bit word 在每个 bit 位都是互补的(一个 1 一个 0),完美模拟硬件互补翻转的前置条件。当硬件故障导致同一 bit 列的互补翻转(+2^k 与 -2^k 抵消,Checksum 无感知)时,逐字节 Salt 校验立即可见。
bitflip / bitflip6 支持单向(unidirectional)丢包和改包检测,这是其核心能力之一。通过 Client 端和 Server 端的双重统计,可以精确定位丢包发生在网络的哪个方向。
Client 发送报文并等待 Server 回包。如果报文在任一方向丢失,均计为丢包。Client 端统计反映的是全链路往返的丢包和 bitflip 情况。日志包含 RTT(往返时延)。
Server 端仅统计 Client→Server 方向的丢包和 bitflip。每个报文中的 LastSent、LastSrcPort、LastDstPort 字段携带 Client 上一时间窗口的实际发送计数和起始端口对,Server 据此计算丢包率并通过确定性的 GetNextPorts 算法还原上一个窗口中每一个包的端口对——实现单向丢包的五元组级定位,无需时钟同步或跟踪 Client 发送状态。Server 端日志不包含 RTT(因双端时钟不同步,RTT 无意义)。
--verbose 后,Server 端将对比预期端口对与实际收到的端口对,输出丢失的五元组信息。
-c 参数预配置客户端地址。
| Client 端丢包 | Server 端丢包 | 丢包方向 |
|---|---|---|
| 有 | 有 | 正向路径 (Client→Server) 存在丢包 |
| 有 | 无 | 回程路径 (Server→Client) 存在丢包 |
| 无 | 无 | 链路正常 |
Client 需要设置 socket 的 IP_TOS 选项来标记 DSCP 值,某些系统需要特权才能设置非默认 TOS。
Server 端口范围定义 Server 监听的端口集合(默认 10 个端口)。Client 端口范围定义 Client 发送报文时使用的源端口集合(默认 100 个端口)。多端口设计用于覆盖交换机 ECMP 哈希的不同路径。
--rate 表示每个 span(默认 1 秒)内的发包数量。默认 5000 即 5000 pps。所有端口对共享该速率。
发送 SIGINT (Ctrl+C) 或 SIGTERM 信号即可。程序会等待 1 秒让在途报文回来后退出。
可以。它们使用独立的端口空间,不会冲突。但注意确保端口范围不与其他服务重叠。
对比 Client 端(往返)和 Server 端(单向 Client→Server)的丢包率。若 Server 端有丢包,说明正向路径有问题;若仅 Client 端有丢包而 Server 端正常,说明回程路径有问题。详见"单向丢包检测"章节。
不需要。Server 收到未知 Client 的第一个报文时自动注册并开始统计。仍可通过 -c 参数预配置,但已非必需。