ITADN
unredacted/packetframe
unredacted/packetframe · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

PacketFrame

面向 Linux 边缘路由器的转发数据平面。 PacketFrame 将您允许列表中的流量从内核的 conntrack 和 netfilter 路径中剥离,直接在网卡之间转发,其余流量则交由常规的内核转发处理。它可以从 BGP 馈送中构建自己的路由表,而不是读取内核的路由表,因此不会与路由守护进程争夺该表。使用 Rust 编写,并按接口选择性启用:它仅处理您指定的接口。

已在配备全表 BGP 馈送的边缘路由器上投入生产运行。在那里,约 98% 的允许列表流量走快速路径;conntrack 条目和面向客户的延迟均大幅下降,具体数字见下文。

GPL-3.0-or-later。Linux ≥ 5.15。单一静态二进制文件;无需单独的 libbpf、bpftool 或运行时 nightly 工具链。

它做什么

一个守护进程,一个配置文件,以及一组模块。共有三个部分。

快速路径。 对于您挂载的每个接口,PacketFrame 在 XDP 入口运行一个 eBPF 程序,该程序:

  1. 过滤 基于您声明的 allow-prefix / allow-prefix6 列表。不匹配的包原样落入内核。
  2. 转发 匹配的包直接通过 bpf_redirect_map 发送到出口网卡:没有 nf_hook_slow,没有 conntrack,没有 iptables 遍历,在原生 XDP 模式下没有内核 skb 分配。
  3. 解析出口 通过内核 FIB(bpf_fib_lookup)或 PacketFrame 自己的路由表(通过 forwarding-mode 由您选择)。

路由侧。 在自定义 FIB 模式下,PacketFrame 自行读取 BGP —— 目前来自 bird,或 BMP (RFC 7854/9069) —— 并据此构建 LPM 树,通过 netlink 解析下一跳 MAC 地址。内核路由表不参与,因此读取该表的守护进程不受影响,且不存在针对 BGP 属性更新的竞态条件。

另一种转发方式。 vpp-offload 模块可以将白名单流量交给 SR-IOV 虚拟功能上的 VPP 进程,使用相同的路由。该模块已编写完成,但尚未在真实硬件上运行;参见 下文

快速路径可执行的其他操作:

  • 用于标记转发的 VLAN 推送/弹出/重写
  • 通过 local-prefix 指令 + ARP 扫描实现针对直连目的地的每主机快速路径
  • 用于在内核处理前丢弃发往不可路由目的地的流量的 XDP 阶段 bogon 拦截block-prefix
  • 自定义 FIB 模式下的默认路由合成fallback-default),用于捕获 BGP 馈送未覆盖的目的地
  • 针对快速路径 TCP 的 MSS 钳制,iptables 不再看到这些流量

变更内容

关注点标准内核转发PacketFrame 快速路径
每包 conntrack 查找是,每个数据包针对白名单流量被绕过
iptables FORWARD 链遍历是,每个数据包,每条规则被绕过
skb 分配开销(原生 XDP)被绕过
BGP 路由源来自路由守护进程的 netlink直接 iBGP/BMP;netlink 仅用于下一跳 MAC
内核功能仍有效是(慢速路径未改变)
回退路径不适用始终存在:不匹配的流量使用内核

在生产部署中启用自定义 FIB 后测得的相对改进:

指标改进
白名单流量走快速路径(绕过率)~98%
活跃 conntrack 条目↓ ~85%
每 CPU softirq 利用率(%soft降低约 18 个百分点
每 CPU 空闲余量(%idle提高约 20 个百分点
面向客户的 ping(平均值)降低约 57%
面向客户的 ping(p99 尾部)降低约 55%

实际结果取决于工作负载组合、网卡、内核版本和部署拓扑。

对比

PacketFrameDPDK / VPPFRR / 纯路由守护进程纯内核 + iptables
绕过内核部分 (XDP)完全 (用户空间)
需要专用核心
内核功能仍可用否,替换协议栈
拥有自己的 BGP 守护进程否,与 bird 配对通常没有不适用
内存模型内核管理的 BPF 映射大页内存内核内核
部署干扰按接口附加,可选替换网络协议栈并行运行默认

PacketFrame 列描述的是快速路径,即在生产环境中运行的部分。vpp-offload 位于前两列之间:它在 PacketFrame 的监督下将 VPP 置于虚拟功能之上,因此对于被引导的流量,它确实完全绕过内核,并且确实需要专用核心。快速路径作为回退机制保留在下方。

PacketFrame 并不替换路由守护进程。预期的配对方式是 bird (BGP) + pathvector (配置生成器) + PacketFrame。FRR 也可以通过其 BMP 支持正常工作。

状态

组件状态
fast-path 模块(XDP 入站、允许列表、重定向)生产环境
kernel-fib 转发模式(默认)生产环境
custom-fib 转发模式(BGP 驱动的 LPM)生产环境(v0.2.0+)
iBGP 路由源(route-source bgp生产环境(v0.2.0+)
BMP 站点路由源(route-source bmp就绪,未在生产环境测试(当前无发射器)
直连目的地快速路径(local-prefix生产环境(v0.2.1+)
fallback-default 综合生产环境(v0.2.1+)
block-prefix XDP 时间丢弃生产环境(v0.2.1+)
mss-clamp 指令(快速路径)生产环境(v0.2.4+;在更严格的内核上,v0.2.5+ 支持按前缀加载)
packetframe reconfigure / systemctl reload packetframe生产环境(v0.2.4+)
两阶段 BPF 数据路径(fast_path + finalize 通过 bpf_tail_call生产环境(v0.2.5+);参见 docs/runbooks/tail-call-architecture.md
probe 模块(诊断 XDP)生产环境
tc-ingress 数据路径(attach <iface> tc,仅限自定义 FIB)已构建并测量出更慢:在参考硬件上每包 CPU 增加 70%。保留供参考,不推荐;参见 docs/runbooks/tc-datapath.md
每模块健康状态 + 指标,由 packetframe status 和 Prometheus 文本文件读取生产环境(v0.2.7+)
vpp-offload 模块(VPP-on-VF 转发向量)代码完整,硬件未验证 — 从未针对真实 VPP 运行;参见 docs/runbooks/vpp-offload.md
ddos 模块(XDP 时间 SYN 泛洪 + 放大攻击过滤器)未来;在 SPEC §5.2 中草图(优先级 0–999,安全/准入)
sampler 模块(每流 ringbuf 可观测性)未来;已在 SPEC §5.3 中概述(优先级 2000–2999,观测)
randomizer 模块(NoiseNet 反相关的 TC 出口抖动)未来;已在 SPEC §5.1 中概述(优先级 ~3000,出口)
多模块分发器(同一 hook 上任何第二个模块的先决条件)未来;模块 trait 已为其塑形(SPEC §3.2 / §3.4)

安装

发布版本已发布在 GitHub 发布页面,同时提供 .deb 软件包(Debian / Ubuntu,amd64arm64)以及 .tar.gz 归档文件(任意 Linux,四个目标三元组)。

Debian / Ubuntu (.deb)

VERSION=v0.2.7
ARCH=$(dpkg --print-architecture)   # amd64 or arm64

curl -LO "https://github.com/unredacted/packetframe/releases/download/${VERSION}/packetframe_${VERSION#v}_${ARCH}.deb"
curl -LO "https://github.com/unredacted/packetframe/releases/download/${VERSION}/SHA256SUMS"
sha256sum -c SHA256SUMS --ignore-missing

sudo apt-get install ./packetframe_${VERSION#v}_${ARCH}.deb

安装 /usr/bin/packetframe,位于 /lib/systemd/system/packetframe.service 的 systemd 单元,以及位于 /etc/packetframe/example.conf 的示例配置。该服务不会自动启动。将示例复制到 /etc/packetframe/packetframe.conf,按照 Quickstart 进行编辑,然后执行 sudo systemctl enable --now packetframe。需要 glibc ≥ 2.31(Debian 11+ / Ubuntu 20.04+)。

Tarball (any Linux)

适用于 musl-static 部署、非 Debian 发行版或其他情况:

VERSION=v0.2.7
TARGET=aarch64-unknown-linux-gnu     # or: x86_64-unknown-linux-{gnu,musl}, aarch64-unknown-linux-musl

curl -LO "https://github.com/unredacted/packetframe/releases/download/${VERSION}/packetframe-${VERSION}-${TARGET}.tar.gz"
curl -LO "https://github.com/unredacted/packetframe/releases/download/${VERSION}/SHA256SUMS"
sha256sum -c SHA256SUMS --ignore-missing
tar xzf "packetframe-${VERSION}-${TARGET}.tar.gz"

sudo install -m 0755 "packetframe-${VERSION}-${TARGET}/packetframe" /usr/local/bin/
sudo install -m 0644 -D "packetframe-${VERSION}-${TARGET}/conf/example.conf" /etc/packetframe/example.conf

可选的 GPG 验证:下载 SHA256SUMS.ascgpg --verify SHA256SUMS.asc SHA256SUMS(密钥 ID 见发布说明)。

快速入门

参考工作流为 probe → dry-run → live。它刻意要求你在切换任何影响生产流量的设置之前,先观察计数器。

1. 验证主机

sudo packetframe feasibility --human

报告内核能力(BPF 系统调用、LPM trie、devmap-hash、ringbuf 等)以及 bpffs 是否已挂载。任何 FAIL 都是继续之前需要修复的内核/主机先决条件。

2. 编写一个最小配置

/etc/packetframe/packetframe.conf:

global
  bpffs-root /sys/fs/bpf/packetframe
  state-dir /var/lib/packetframe/state
  metrics-textfile /var/lib/node_exporter/textfile/packetframe.prom

module fast-path
  attach eth0 auto
  allow-prefix 192.0.2.0/24       # your customer / forwarding scope
  allow-prefix6 2001:db8::/48
  dry-run on                       # observe-only, no redirects yet
  circuit-breaker drop-ratio 0.01 of matched window 5s threshold 5
  # mss-clamp via eth0 1360       # optional, clamp TCP MSS for fast-pathed
                                   # traffic egressing eth0 (closes the
                                   # iptables-bypass MSS gap; v0.2.4+)

dry-run on 使程序统计匹配的报文,但始终返回 XDP_PASS。内核处理转发时,就好像 PacketFrame 不存在一样。计数器能让你在切换开关之前,确认你的允许列表是否匹配了正确的流量。

3. 针对主机进行验证

sudo packetframe feasibility --config /etc/packetframe/packetframe.conf --human

现在还会执行针对每个接口的试验性 XDP 挂载,以便在正式部署前捕获驱动程序兼容性问题。

4. 运行

sudo packetframe run                 # foreground; --config defaults to /etc/...
sudo packetframe status              # in another shell, live counters

5. 当匹配比率看起来正确时,关闭 dry-run

编辑配置文件,将 dry-run on 更改为 dry-run off,然后触发重新加载(v0.2.4+):

sudo packetframe reconfigure                # synchronous; exits non-zero on parse error
sudo systemctl reload packetframe           # equivalent under systemd; both end up sending SIGHUP

可热重载的内容:allow-prefix*block-prefixdry-runforwarding-modemss-clamp、VLAN 子接口解析以及重定向 devmap。Attach 集变更(接口添加/移除)、route-source 配置、circuit-breaker 阈值以及 local-prefix/local-prefix6 仍需要完全重启。参见 docs/runbooks/reconfigure.md

6. 拆除

sudo packetframe detach --all        # removes pins, detaches XDP

转发模式

forwarding-mode 选择 PacketFrame 如何为匹配的报文解析出口:

  • kernel-fib(默认):使用 bpf_fib_lookup() 针对内核路由表。与纯 Linux 相同的路由决策。永久回滚路径。
  • custom-fib:使用 PacketFrame 自身的 LPM 树,由 BGP 馈送填充。允许消费内核路由表的守护进程并行工作,而不会与路由守护进程的 BGP 属性更新发生竞争。
  • compare:执行两种查找,通过内核结果转发,增加不一致计数器。仅用于切换前验证。

Custom-fib 模式需要一个 route-source 指令:

route-source bgp 127.0.0.1:1179 local-as 65000 peer-as 65000

Bird 通过该地址作为 iBGP 对等体连接到 PacketFrame。Bird 的 protocol bgp 导出过滤器在最优路径选择之后运行,因此 PacketFrame 每个前缀仅接收一条 UPDATE。

对于发送 RFC 9069 Loc-RIB 的 BMP 发射器(FRR;未来的 bird):

route-source bmp 127.0.0.1:6543 require-loc-rib

require-loc-rib 在会话初始化时拒绝 pre/post-policy 帧,因此配置错误的发送器会显式失败,而不是静默地基于错误的 RIB 视图进行转发。

请参阅 docs/runbooks/custom-fib.md 获取完整的操作指南:切换序列、回滚、完整性检查、故障排除。

第二条转发路径 (vpp-offload)

XDP 快速路径是 PacketFrame 当前转发数据包的方式。 vpp-offload 模块为同一流量增加了第二个选项:NIC 的 硬件分类器将白名单中的数据包直接发送到 SR-IOV 虚拟功能,由 PacketFrame 启动并监督的 VPP 进程进行转发。VPP 从快速路径使用的同一 BGP 源获取路由,因此两条路径做出相同的转发决策。

未被引导的流量仍保留在 XDP 路径上,如果 VPP 停止运行,所有流量也是如此。

引导是按接口进行的,默认关闭。您可以一次在一个接口上开启,并通过配置重新加载将其关闭,而无需重启 VPP。此仓库中不包含 VPP 源代码:PacketFrame 构建未修改的上游 VPP 并在其自己的发布标签下发布。

代码已完成,但从未针对真实的 VPP 进程或真实的 NIC 运行过。在 docs/runbooks/vpp-offload.md 之前 在任何承载流量的地方开启它。

附加模式

每个 attach <iface> <mode> 指令选择 XDP 如何绑定到接口:

模式成本适用场景
native最低;在 NIC 驱动中于 skb 分配前运行驱动支持原生 XDP 并交付以太网形状的帧
generic较高;在 skb 分配后运行驱动不支持原生 XDP,或存在已知的原生模式 bug
auto尝试原生,回退到通用大多数情况;在存在已知 bug 的驱动上自动降级

驱动注意事项

PacketFrame 拒绝有实证证据表明不安全的配置:

Marvell rvu-nicpf 在内核 < v6.8 上: 原生 XDP 附加在每次分离时泄漏一个内核资源计数器(non_qos_queues)。经过几次附加/分离循环后,内核页分配器可能会损坏。PacketFrame 在此处硬性拒绝显式的 attach <iface> native 并将 auto 降级为 generic。已在上游提交 04f647c8e456 中修复;拥有该回移补丁的运维人员可通过 driver-workaround rvu-nicpf-head-shift off 选择退出。

Marvell rvu-nicpf 在多成员网桥上: XDP 附加和分离都会短暂地使链路抖动,网桥堆栈将其视为端口状态变化。在一个 STP/RSTP 窗口内两个端口抖动曾导致 L2 环路和内核恐慌。当 ≥ 2 个已附加接口共享一个 /sys/class/net/<iface>/master 时,PacketFrame 通过 attach-settle-time 对附加和分离进行节奏控制(默认 2 秒,在慢收敛网桥上提高)。

诊断特定驱动问题

如果 packetframe status 显示 rx_totalpass_not_ip 同步攀升,而 matched_* 保持为零,则程序正在运行但未解析其接收到的帧。这通常指向驱动特定的原生模式交付怪癖。使用 packetframe probe 检查驱动实际传递给 XDP 的内容:

sudo packetframe probe --iface eth0 --mode native --duration 2s
sudo packetframe probe --iface eth0 --mode native --duration 2s --offset 128
sudo packetframe probe --iface eth0 --mode generic --duration 2s   # what kernel sees

输出数据包样本的前 16 个字节以及一行判定结果。

配置参考

conf/example.conf 随二进制文件附带作为标准参考,其中每条指令均附有注释和行内说明。请阅读该文件以获取完整语法。

快速指令索引:

全局

  • bpffs-root, state-dir, metrics-textfile, log-level, attach-settle-time

模块快速路径:附加 + 允许列表

  • attach <iface> {native|generic|auto}
  • allow-prefix <ipv4-cidr>, allow-prefix6 <ipv6-cidr>: 源或目的匹配
  • dry-run {on|off}
  • circuit-breaker drop-ratio X of matched window Ys threshold N

模块快速路径:转发模式

  • forwarding-mode {kernel-fib|custom-fib|compare}
  • route-source bgp <addr>:<port> local-as <asn> peer-as <asn> [router-id <ipv4>]
  • route-source bmp <addr>:<port> [require-loc-rib]
  • local-prefix <cidr> via <iface> [arp-scavenge]: 针对已连接 IPv4 目的地的每主机 /32 快速路径
  • local-prefix6 <cidr> via <iface>: 每主机 /128 等效项,通过 NDP 解析(无 arp-scavenge;/64 不可枚举)
  • fallback-default via <iface> nexthop <ipv4>: 合成的 0.0.0.0/0 全匹配
  • block-prefix <cidr>: 针对不可路由目的地的 XDP 时丢弃
  • ecmp-default-hash-mode {3|4|5}: 用于 ECMP 哈希的元组宽度

模块快速路径:TCP 转换 (v0.2.4+)

  • mss-clamp <mtu>: 匹配 TCP SYN/SYN-ACK 的全局钳制上限
  • mss-clamp via <iface> <mtu>: 每出口接口
  • mss-clamp <cidr> <mtu>: 每源或目的前缀(任意出口)
  • mss-clamp <cidr> via <iface> <mtu>: 最具体(优先级:前缀+接口 > 前缀 > 接口 > 全局)

模块快速路径:驱动程序选项

  • driver-workaround rvu-nicpf-head-shift {auto|on|off}

模块 vpp-offload(使用前请参阅 runbook

  • port <iface> cores <n> steer {on|off}: VPP 参与的每个接口一行;steer 是每接口开关
  • expected-routes <n>: 设定 VPP 的内存大小,启动时固定
  • hugepages <n>, vpp-binary <path>
  • require-table-complete {on|off}: 在引导前等待路由表加载完成(默认开启)

SIGHUP(或 packetframe reconfigure / systemctl reload packetframe)应用仅增量变更,涉及允许列表、块前缀、VLAN 解析、devmap、mss-clamp、dry-run、转发模式位以及 vpp-offload 的 steer 开关。添加或移除 attach、更改 route-source、修改 circuit-breaker 阈值、编辑 local-prefix/local-prefix6,或更改除 steer 以外的任何 vpp-offload 指令,都需要重启。

运维工具

sudo packetframe status                # live counters, plus each module's health
sudo packetframe fib stats             # custom-FIB occupancy / hash mode
sudo packetframe fib lookup <ip>       # "what would XDP do for this dst?"
sudo packetframe fib dump-v4           # walk FIB_V4 LPM trie
sudo packetframe detach --all          # remove all pins, detach XDP

当设置 metrics-textfile 时,计数器每 15 秒导出为 Prometheus textfile:包括每个计数器的 gauge、按下一跳状态划分的自定义 FIB 占用率、当前活动转发模式,以及每个已加载模块发布的内容。

文档

Runbooks,位于 docs/runbooks/

文件涵盖内容
custom-fib.md自定义 FIB 模式:切换、回滚、完整性检查、按症状分类的故障排查
reconfigure.mdSIGHUP 应用的内容以及需要重启的内容
mss-clamp.mdMSS 钳制及其解决的 iptables 绕过漏洞
tail-call-architecture.md两阶段 BPF 数据路径及其拆分原因
generic-mode-performance.md通用 XDP 与原生 XDP 的实测成本,以及主机调优
tc-datapath.mdtc-ingress 变体,以及其实测较慢的原因
vpp-offload.md运行 vpp-offload:部署、回滚、故障排查,哪些数值是实测的
vpp-offload-spike.mdvpp-offload 在测试硬件上的启动过程,以及失败之处

从源码构建

make build        # debug, host target
make release      # release, host target
make release-all  # all four published targets (requires `cross`)

make test         # workspace tests
make lint         # cargo fmt --check + cargo clippy -D warnings

工具链:在 rust-toolchain.toml 中固定的 stable Rust。BPF 相关 crate(crates/modules/*/bpf/)各自拥有固定的 nightly 工具链 + bpf-linker,由 CI 自动安装;对于本地 BPF 重新构建,请安装 rustup 并让其遵循工具链文件。

交叉编译到 release 目标使用 crosscargo install --locked cross

项目布局

packetframe/
├── crates/
│   ├── common/                       # config parser, Module trait, capability probes
│   ├── cli/                          # the `packetframe` binary
│   ├── modules/
│   │   ├── fast-path/                # main forwarding module
│   │   │   └── bpf/                  # XDP program (nightly toolchain)
│   │   ├── probe/                    # diagnostic XDP probe
│   │   │   └── bpf/                  # probe BPF program
│   │   └── vpp-offload/              # second forwarding path (supervises VPP)
│   └── tools/vpp-api-codegen/        # generates VPP binary-API structs from its .api.json
├── conf/example.conf                 # annotated reference config
├── docs/runbooks/                    # operational runbooks
├── vpp/pin.toml                      # which upstream VPP we build and ship
└── .github/workflows/                # CI (fmt/clippy/test, cross-build, qemu-verifier, release)

许可证

GPL-3.0-or-later。参见 LICENSE