# simplexudp **Repository Path**: itcraft-cn/simplexudp ## Basic Information - **Project Name**: simplexudp - **Description**: 基于 XDP + AF_XDP 的 Linux 底层通讯库(ANSI C),同时提供内核 UDP socket 后端作为兼容/测试路径。向上提供消息导向、有序可靠、丢包侦测重发、支持点播/组播/广播的通讯能力。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: https://itcraft.cn/simplexudp/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-02 - **Last Updated**: 2026-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: xdp, udp, AF-XDP, BPF ## README # simple-xudp (SX) [变更记录](CHANGELOG.md) | [使用手册](MANUAL.md) | [English](README_en.md) 基于 **XDP + AF_XDP** 的 Linux 底层通讯库(ANSI C),同时提供**内核 UDP socket** 后端作为兼容/测试路径。向上提供消息导向、**有序可靠**、**丢包侦测重发**、支持**点播/组播/广播**的通讯能力。 - 目标平台:Linux x86_64 / aarch64,C99。 - 单包净荷上限固定(默认 1400),严格小于 MTU,不做 IP 分片;超过上限的消息自动拆包/重组,单条消息上限 256KB;单播、组播、广播均支持。 - `send_window` 可配置,并会按 `max_message` 自动提升,硬下限 256、上限 65536,保证 256KB 消息一次入窗; `large_message_burst` 控制大消息是否临时拉满 `cwnd`(默认 1,设 0 走严格慢启动)。 - 可靠性借鉴 **KCP**:滑动窗口、累积+选择性确认、快速重传、RTO 退避、RTT 估计、流控与拥塞控制;专线可设 `SX_CC_OFF` 关闭窗口调节。 - 对端重启通过随机 `peer_id` 自动识别并重同步;组播晚加入/来源超时后按重排窗口快进。 - 组播/广播采用 **高水位 + NACK** 的尽力可靠(best-effort reliable)+ 按序投递。 - AF_XDP 支持静态 ARP(不可被应答覆盖)与跨网段网关配置。 - UDP 后端支持 `udp_rcvbuf`/`udp_sndbuf` 缓冲配置;专线可关闭 RTO 指数退避(`rto_backoff=0`)。 - 接收硬件时间戳默认关闭;`rx_ts_mode` 显式开启,`on_recv_ex`/`sx_recv_ex` 透出 PHC 时间。 ## 架构 ``` 应用 └─ sx_api (simplexudp.h) └─ sx_endpoint 端点/链路/报文集散、update 驱动 └─ sx_kcp 单播可靠引擎(ARQ/窗口/重排/流控/拥塞) │ sx_group 组播/广播引擎(高水位/NACK/重排) └─ sx_io 后端抽象 ├─ sx_io_udp 内核 UDP socket(无需 root) └─ sx_io_xdp AF_XDP + sx_frame(以太/IP/UDP) + sx_arp + XDP BPF ``` 线格式一致(SX 头位于 UDP 净荷内),因此 AF_XDP 与内核 UDP 后端可互操作。 ## 数据面帧格式 ``` Ethernet(14) | IPv4(20) | UDP(8) | SX header(32) | payload(<=1400) 总长 <= 1474 < 1500(MTU) ``` SX 头(网络序,32 字节):`magic/ver/cmd | conv | peer_id | seq | una | ts | wnd | ack_count | payload_len`,其后可选 `ack_list[]`。 命令:`PUSH / ACK / WASK / WINS / HELLO / BYE / PING / PONG / NACK`。 ## 构建 ### 依赖 - C 编译器:`gcc` 或 `clang`(C99)。 - 构建工具:`make`(或 CMake ≥ 3.16)。 - **AF_XDP 后端**额外需要:`libbpf`、`libxdp` 开发包,`clang`(支持 `-target bpf`,用于编译 XDP 程序), `xxd`(把 BPF 目标内嵌为字节数组),`pkg-config`(可选,用于探测 libbpf/libxdp)。 - 运行 AF_XDP 需要 root,或授予 `CAP_BPF`、`CAP_NET_ADMIN`、`CAP_NET_RAW`(内核 < 5.8 还需 `CAP_SYS_ADMIN`)并放开内存锁上限;**内核 UDP 后端无需特权**,只有绑定 1024 以下端口时才需要 `CAP_NET_BIND_SERVICE`。最小能力集、`setcap` 与 systemd 示例见 [MANUAL.md](MANUAL.md) 第 14 节。 ```sh # Debian / Ubuntu sudo apt-get install -y build-essential clang llvm libbpf-dev libxdp-dev pkg-config xxd # RHEL / CentOS / Fedora sudo dnf install -y gcc clang llvm libbpf-devel libxdp-devel pkgconf-pkg-config vim-common ``` ### 常用目标 ```sh make # 构建 build/libsimplexudp.a 与 .so(默认含 XDP BPF 目标) make bpf # 仅编译 XDP BPF 目标 make examples # 示例:build/sx_p2p、build/sx_group make tests # 单元/回环测试:build/test_{frame,proto,kcp,loopback,recv,arp,cc,frag} make tests-xdp # AF_XDP 端到端测试:build/test_xdp make tests-latency # 时延测试:build/test_latency make tests-throughput# 吞吐/长稳测试:build/test_throughput make group-tools # 组播/广播工具:build/test_gsend、build/test_grecv make relay-tool # 三跳接力:build/test_relay make xdp-echo # 纯 XDP_TX 反射程序与加载器(微基准) make test-xdp-echo # 纯 XDP_TX 反射的 RTT 发送端 make test-io-echo # 统一 IO 抽象:UDP/AF_XDP 发送端 RTT 对比 make test-hwts # UDP 硬件时间戳单向测量(需 PTP 同步) make unicast-big # 单播大消息跨机测试工具(server/client) make ts-status # 接收时间戳能力探测(UDP/AF_XDP) make check # 运行单元/回环测试(无需 root,UDP 后端) make check-xdp # 需要 root:创建 veth 跑 AF_XDP 端到端测试 make check-latency # 需要 root:AF_XDP 时延测试 + bpftool 佐证流量经过 XDP make check-latency-2p# 需要 root:双进程 AF_XDP 时延测试 make install # 安装头文件与库(默认 PREFIX=/usr/local) make uninstall make clean ``` ### 构建选项 | 变量 | 作用 | | --- | --- | | `SX_NO_XDP=1` | 仅内核 UDP 后端:不依赖 libbpf/libxdp/clang,用于无 XDP 环境或分发 | | `SX_LOSSY=1` | 编译进丢包/乱序注入(运行期环境变量 `SX_LOSSY_DROP_PPM`/`SX_LOSSY_DUP_PPM`/`SX_LOSSY_REORDER_PPM` 开启),用于无 root 的可靠性测试 | | `DEBUG=1` | `-O0 -g -DDEBUG` | | `CC=clang` | 指定编译器 | | `PREFIX` / `DESTDIR` | `install` 的安装前缀与打包根 | ```sh # 无 XDP 环境(例如仅需 UDP 后端/容器/CI) make SX_NO_XDP=1 make SX_NO_XDP=1 group-tools relay-tool # 带丢包注入的调试构建 make SX_LOSSY=1 DEBUG=1 # 安装 / 打包 sudo make install PREFIX=/usr/local make install DESTDIR=/tmp/pkg PREFIX=/usr ``` ### 架构 Makefile 自动探测架构(`uname -m`,x86_64 / aarch64):用 `$(CC) -print-multiarch` 定位 multiarch 头文件,XDP 程序用 `clang -target bpf` 编译;无需手工指定目标。 ### CMake 备选 ```sh cmake -S . -B build-cmake && cmake --build build-cmake -j cd build-cmake && ctest # 运行单元/回环测试 ``` > 日志:库内**不使用 stdout/stderr**,统一通过 `sx_config.on_log` 回调;测试/示例写入日志文件。 ## 快速使用 ```c #include "simplexudp.h" sx_config_t cfg; sx_config_init(&cfg); cfg.ifname = "eth0"; /* 置空则走内核 UDP */ cfg.backend = SX_BACKEND_AUTO; /* 优先 AF_XDP,失败回退 UDP */ cfg.local_port= 9000; cfg.conv = 0x1234; cfg.on_recv = my_recv; cfg.user = my_ctx; sx_endpoint_t *ep = sx_create(&cfg); sx_start(ep); sx_link_t *peer = sx_add_unicast(ep, ipv4("10.0.0.2"), 9000); sx_send(ep, peer, buf, len); /* 超过 max_payload 自动分片 */ for (;;) sx_update(ep, 0); /* 或 sx_run(ep, -1) */ sx_destroy(ep); ``` - 点播:`sx_add_unicast` / `sx_send_to`。 - 组播:`sx_add_multicast`(UDP 后端会 `IP_ADD_MEMBERSHIP`)。 - 广播:`sx_add_broadcast`(目的地址通常 `255.255.255.255` 或子网广播)。 详见 **[使用手册](MANUAL.md)**、设计文档 `docs/design.md`、示例 `examples/sx_p2p.c`、`examples/sx_group.c`。 多语言(Python/Java)绑定评估与计划见 `docs/ffi-evaluation.md`、`docs/ffi-todo.md`(当前聚焦 C 库,FFI 暂缓)。 ## 测试 - `tests/test_frame.c`:帧构造/解析与校验和防御。 - `tests/test_proto.c`:协议头编解码边界。 - `tests/test_kcp.c`:注入 **丢包 + 相邻乱序**,验证 100/100 按序到达且确有重传。 - `tests/test_loopback.c`:UDP 后端端到端双向有序投递,含 4KB 与 200KB 分片重组。 - `tests/test_arp.c`:静态 ARP 不被伪造应答覆盖、不老化。 - `tests/test_cc.c`:`SX_CC_OFF` 不降窗、`SX_CC_ON` 超时降窗。 - `tests/test_frag.c`:分片发送/重组与 256KB 大消息窗口。 - `tests/test_xdp.c` + `scripts/veth_test.sh`:veth 上 AF_XDP native/copy 端到端。 - `tests/test_latency.c` + `scripts/xdp_latency.sh`:停等往返时延统计(min/avg/p50/p99/max), 并在测试挂载期间用 `bpftool net show` / `bpftool prog show` / `bpftool map dump` 佐证 流量确实经 XDP 处理(`sx_stats_map` 的 redirect 计数)。 - `scripts/perf_skb_probe.sh`:用 bpftrace 统计 skb 构造与 `ip_rcv` 计数,判定 XDP/TC 是否真的省掉了包处理(不需要硬件 PMU);方法见 `docs/benchmark-methodology.md`。 CentOS 7 / 内核 5.18 实机记录见 `docs/centos7-test-20261102.md`;10.45/10.46 的 25G 跨机 AF_XDP 时延/吞吐与残留 XDP 问题见 `docs/cross-host-45-46-20261102.md`。 ### 性能结论的适用边界 下文的数字与拓扑、驱动、XDP 模式绑定,不可跨环境外推: - 本机小节与 `scripts/*.sh` 默认跑在 **veth** 上。veth 上的包在到达 XDP 处理点之前已经作为 `sk_buff` 存在(发送侧构造),接收侧最多做 `skb -> xdp_buff/xdp_frame` 的转换;因此 **这里的 XDP 不省 skb 分配**,只省后续协议栈。AF_XDP 的收益来自把包直接交给用户态、绕开内核 UDP socket 的排队/唤醒/系统调用,且必然是 copy 模式。 - 跨机小节的收益绑定 **mlx5 25G + native XDP**;e1000 等无 native XDP 的虚拟网卡只能 generic+copy(见 `docs/vm-udp-xdp-test.md`)。 - 引用任何数字时请同时给出:网卡/驱动、XDP 模式(driver/generic/skb)、是否 zero-copy、内核版本。 - 想验证“XDP 是否真的省掉了包处理”,用 `scripts/perf_skb_probe.sh` 看 skb 构造计数, 不要只看挂点早晚。方法、A/B 配方与三个常见测量陷阱见 `docs/benchmark-methodology.md`。 ### 实测参考(本机,停等 RTT,n=20000)单进程(A/B 两端点在同一进程): | 路径 | min | avg | p50 | p99 | max | | --- | --- | --- | --- | --- | --- | | AF_XDP(veth,native+copy) | 1us | 1~2us | 2us | 2us | 11~17us | | 内核 UDP(lo) | 4us | 4us | 4us | 6us | 55us | 双进程(server 与 client 各自独立进程,更接近真实): | 路径 | min | avg | p50 | p99 | max | | --- | --- | --- | --- | --- | --- | | AF_XDP(veth,native+copy) | 1us | 2us | 2us | 4us | ~425us | | 内核 UDP(lo) | 0us | 3us | 3us | 5us | ~173us | 均为**往返时延**(含两端用户态处理),单向约为一半量级。双进程 `bpftool map dump` 显示两个进程各自的 XDP 程序重定向计数均约 4 万(2 万请求 + 2 万回显 + 控制帧), 证明双向报文都确实经过 XDP 重定向到 AF_XDP。 ### 绑核(强烈建议) 不绑核时 max 抖动较大(UDP/lo 约 300~400us,AF_XDP/veth 可到数百 us), 主因是进程迁移与中断/软中断争抢;绑到两个不同的**性能核**后 max 降到约 20~30us: | 路径 | 绑核 | p50 | p99 | max | | --- | --- | --- | --- | --- | | UDP/lo | 不绑 | 3us | 4us | ~408us | | UDP/lo | s=4 c=5 | 2us | 3us | ~16us | | AF_XDP/veth | 不绑 | 2us | 4us | 66~845us | | AF_XDP/veth | s=1 c=2 | 2us | 4us | ~20us | | AF_XDP/veth | s=2 c=3 | 2us | 5us | ~22us | 建议:server 与 client 各绑一个不同的性能核(本机 c0–c5,6.8GHz),避开中断核 c0; iWLAN/WiFi 队列中断分布在 c0–c8,若追求极低抖动可把 IRQ 亲和性移出所用核 (`/proc/irq/*/smp_affinity_list`)。 ```sh # 双进程 + 绑核 SX_CPU_SERVER=2 SX_CPU_CLIENT=3 sudo scripts/xdp_latency_2p.sh build/test_latency ``` ### 跨机实测(10.45 / 10.46,25G 直连) 拓扑:mlx5_core 25G,10.45 `p3p2` 192.168.111.45 / 10.46 `ens3f1` 192.168.111.46; 测试期间数据口 `combined 1`,结束后恢复 `combined 40`。AF_XDP 为 native + copy,停等 RTT,n=20000: | 路径 | min | avg | p50 | p99 | max | | --- | --- | --- | --- | --- | --- | | AF_XDP 10.45 -> 10.46 | 10us | 16us | 16us | 31us | 94us | | AF_XDP 10.46 -> 10.45 | 7us | 23us | 21us | 38us | 91us | | 内核 UDP 10.45 -> 10.46 | 15us | 20us | 19us | 37us | 166us | 吞吐(500000 × 1024B): | 后端 | 客户端 MB/s | msg/s | 重传 | 超时 | 服务端 dup | 服务端 reorder | | --- | --- | --- | --- | --- | --- | --- | | 内核 UDP | 312.60 | 305276 | 3333 | 0 | 3167 | 1545 | | AF_XDP native+copy | 251.20 | 245308 | 16 | 13 | 0 | 5 | UDP 峰值吞吐更高但跨机丢包/重传明显;AF_XDP 吞吐略低,重传与乱序接近零,稳定性更好。 zero-copy 与绑核(`combined 2` + Flow Director steer 队列 2 + 静态 ARP): | 模式 | 运行 | p50 | p99 | max | | --- | --- | --- | --- | --- | | copy,未绑核 | 1 | 16us | 31us | 94us | | copy,绑核 | 1~2 | 15us | 30us | 43~106us | | zero-copy,未绑核 | 1 | 19us | 31us | 1065us | | zero-copy,绑核 | 1~2 | 16us | 23~24us | 71~358us | 剥离 KCP/用户态反射的纯 XDP_TX 基准 p50 10~11us、p99 13~15us;发送端改用 AF_XDP 后 p50 8~10us。`SX_BUSY_POLL=1` 跳过每包 `poll()` 后,KCP 路径 p50 15→11us、p99 31→26us。 硬件时间戳单向测量(PTP 同步后,n=10000): | 方向 | min | avg | p50 | p99 | max | | --- | --- | --- | --- | --- | --- | | 10.45 -> 10.46 | 0.363us | 0.384us | 0.384us | 0.405us | 2.524us | | 10.46 -> 10.45 | 0.385us | 0.405us | 0.405us | 0.425us | 0.436us | 网卡到网卡物理单向时延约 0.4us;RTT/2 得到的 4~5us 主要包含软件路径开销。 大消息验证:单播 256KB 在 45/46 完成自动分片、可靠传输、重组与内容校验;组播/广播 256KB 均为 got=1/1、bad=0(组播/广播依赖 NACK 恢复,发送端需 linger 以响应重传)。 完整拓扑、现场问题(残留 XDP、zero-copy 队列偏移)与逐项数据见 `docs/cross-host-45-46-20261102.md`。 ## AF_XDP 说明与限制 - attach 模式:native 优先,失败回退 generic;bind:zero-copy 优先,失败回退 copy(自动侦测)。 - AF_XDP 绑定单个 RX 队列;需将目标流量引导到该队列(RSS/ethtool 或单队列网卡)。 - **同一网卡同一时刻只支持一个 SX XDP 端点**:不替换已有 XDP 程序,第二个端点会 attach 失败; `SX_BACKEND_AUTO` 会回退 UDP 并置 `stats.backend_fallback=1`。多端点请用多网卡/多 netns。 - ARP 由本库用户态处理(XDP 程序会重定向 ARP)。生产建议用 `sx_add_static_arp` 固定对端/网关 MAC; 静态项不可被 ARP 应答覆盖、不老化。跨网段设置 `gateway_ip`/`netmask` 并为网关注册静态映射。 - generic 模式强制 copy;zero-copy 需要网卡驱动支持。 - 组播在 XDP 后端需接口接受该组播(可能需要 `ip maddr add` 或 allmulti)。 - 非 root 且未授予相应能力时:`SX_BACKEND_AUTO` 会回退内核 UDP 并置 `stats.backend_fallback=1`;强制 `SX_BACKEND_XDP` 不会回退,`sx_start` 返回 `SX_ERR_BACKEND`。 ## 可靠性语义 - **单播**:严格可靠有序。累积确认 `una` + 选择性确认 `ack_list` + 快速重传 + RTO 重传 + 拥塞/流控。 - **组播/广播**:尽力可靠 + 有序。发送端保留历史窗口并周期性广播高水位;接收端侦测空洞后回送 `NACK`,发送端从历史重发到组地址。不保证送达(无多方 ACK 汇聚)。 - **会话重同步**:对端重启后 `HELLO` 携带新的随机 `peer_id`,本端自动重置窗口并重新握手; 重同步会丢弃重启前未确认的发送数据。 - **重组失败**:分片重组失败时不推进接收序号、不发送 ACK,交由重传恢复。