基于 XDP + AF_XDP 的 Linux 底层通讯库(ANSI C),同时提供内核 UDP socket 后端作为兼容/测试路径。向上提供消息导向、有序可靠、丢包侦测重发、支持点播/组播/广播的通讯能力。
- 目标平台:Linux x86_64 / aarch64,C99。
- 单包净荷上限固定(默认 1400),严格小于 MTU,禁止分片。
- 可靠性借鉴 KCP:滑动窗口、累积+选择性确认、快速重传、RTO 退避、RTT 估计、流控与拥塞控制。
- 组播/广播采用 高水位 + NACK 的尽力可靠(best-effort reliable)+ 按序投递。
应用
└─ 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);内核 UDP 后端无需特权。
# 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-commonmake # 构建 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}
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 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 的安装前缀与打包根 |
# 无 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=/usrMakefile 自动探测架构(uname -m,x86_64 / aarch64):用 $(CC) -print-multiarch
定位 multiarch 头文件,XDP 程序用 clang -target bpf 编译;无需手工指定目标。
cmake -S . -B build-cmake && cmake --build build-cmake -j
cd build-cmake && ctest # 运行单元/回环测试日志:库内不使用 stdout/stderr,统一通过
sx_config.on_log回调;测试/示例写入日志文件。
#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); /* len <= sx_max_payload(ep) */
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或子网广播)。
详见 使用手册 docs/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 后端端到端双向有序投递。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 计数)。
单进程(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 约 300400us,AF_XDP/veth 可到数百 us),
主因是进程迁移与中断/软中断争抢;绑到两个不同的性能核后 max 降到约 2030us:
| 路径 | 绑核 | 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)。
# 双进程 + 绑核
SX_CPU_SERVER=2 SX_CPU_CLIENT=3 sudo scripts/xdp_latency_2p.sh build/test_latency- attach 模式:native 优先,失败回退 generic;bind:zero-copy 优先,失败回退 copy(自动侦测)。
- AF_XDP 绑定单个 RX 队列;需将目标流量引导到该队列(RSS/ethtool 或单队列网卡)。
- ARP 由本库用户态处理(XDP 程序会重定向 ARP),因此仅在同一二层网段内可直接解析;跨网段需配置网关/静态映射。
- generic 模式强制 copy;zero-copy 需要网卡驱动支持。
- 组播在 XDP 后端需接口接受该组播(可能需要
ip maddr add或 allmulti)。
- 单播:严格可靠有序。累积确认
una+ 选择性确认ack_list+ 快速重传 + RTO 重传 + 拥塞/流控。 - 组播/广播:尽力可靠 + 有序。发送端保留历史窗口并周期性广播高水位;接收端侦测空洞后回送
NACK,发送端从历史重发到组地址。不保证送达(无多方 ACK 汇聚)。