wirefisher:介绍
skaiuijing
引言
eBPF 是 Linux 内核中近年来最受关注的技术之一,它允许我们在不修改内核源码的前提下,实现高性能、低开销的内核扩展。
笔者最近遇到一个需求:需要对某个端口的网络流量进行监控和限速。
传统工具无法关联网络行为,tc
配置复杂且粒度粗,iptables
虽然能过滤流量,但缺乏实时速率统计和动态调度能力。
花了点时间,笔者写了 一个基于 eBPF 的流量控制工具,目的是实现精确、高效的流量监控与限速。
四个控制维度
Wirefisher 支持从以下四个维度进行流量识别与限速:
- 进程维度(PID):可精确控制某个进程的入站或出站带宽
- cgroup 维度:适用于容器或服务组的统一流量管理
- 网卡维度(Interface):对指定网卡进行 ingress/egress 流量调度
- IP/端口/协议维度:支持对特定 IP、端口或协议(TCP/UDP)进行限速与过滤
每个维度都可以独立启用,互不干扰,也可以组合使用,实现更复杂的流量策略。
程序框架
Wirefisher 的整体框架很简单分为两层:
1. BPF 层(C语言编写)
- 使用原生 C 编写 eBPF 程序,挂载在 Netfilter 或 tc 等钩子点上
- 实现流量统计、速率计算、令牌桶限速逻辑
- 所有逻辑运行在内核态,性能极高,延迟极低
2. 控制层(C++ + YAML)
- 使用 C++ 编写用户态控制程序
- 集成 YAML 解析库,支持模块化配置文件
- 根据配置动态加载对应的 BPF 程序,并传入参数(如 PID、网卡名、速率等)
如果读者有分布式监控需求,可以尝试使用python等编写http接口,使用Prometheus等作为分布式监控平台。
限速机制
Wirefisher 的限速逻辑参考了 Cilium 的令牌桶算法实现,并结合 Linux 内核的 BBR 拥塞控制算法,具备以下特点:
- 令牌桶算法:每个流量实体维护一个独立的令牌桶,根据速率定期补充令牌,发送数据时消耗令牌,超限则丢包或延迟处理
- BBR 宽容机制:对偶发丢包具有一定容忍度,避免误判突发流量为拥塞
- 平滑速率计算:支持瞬时速率、平均速率、峰值速率和指数加权平滑速率,便于动态调度和策略调整
这种机制既保证了限速的精度,又避免了对突发流量的过度惩罚,所以如果使用限速机制,最好启用BBR算法。
使用方式
Wirefisher 的使用非常简单,只需编写YAML 配置文件,指定你要控制的对象和速率即可:
功能特点
- 按进程限速(PID)
- 按 IP、端口、协议过滤与限速
- 按网卡进行速率控制
- 按 cgroup 统一调度
- 支持 ingress / egress 双向控制
- 实时速率统计:平均速率、峰值速率、平滑速率
配置文件示例
进入配置目录:
先git:
1 | git@github.com:skaiui2/wirefisher.git |
然后进入配置目录:
1 | cd config |
可以这样配置:
1 | process_module: |
编译与运行
编译 BPF 程序:
1 | cd bpf |
构建用户态控制程序:
1 | mkdir build |
启动 Wirefisher:
1 | sudo ./ebpf_system |
程序将根据 config.yaml
中的配置自动加载限速规则并开始运行。
环境要求
- Linux 内核版本 ≥ 5.4,需支持 eBPF 和 CO-RE
- 需要 root 权限运行
- 安装 libbpf 和 clang 工具链
输出
1 | === process_traffic === |
字段解释
instant_rate_bps
当前包的瞬时速率(单位:MB/s),根据最近一次数据包的大小与时间间隔计算,反映突发流量情况。rate_bps
平均速率(单位:MB/s),从窗口起始时间到当前时间的总流量除以时间差,反映整体带宽使用情况。peak_rate_bps
峰值速率(单位:MB/s),记录历史上出现过的最大瞬时速率,用于识别突发流量峰值。smoothed_rate_bps
平滑速率(单位:MB/s),采用指数加权移动平均(EWMA)算法计算,用于消除瞬时波动,更适合用于限速判断。timestamp
当前输出时间戳,格式为HH:MM:SS.mmm
,便于对比不同时间点的流量变化。
如需启用其他维度(如 IP、端口、网卡、cgroup)或调整输出频率,可在配置文件中进行设置。