You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SO_ATTACH_REUSEPORT_CBPF分配UDP报文失败,求排查错误

问题描述

未添加SO_REUSEPORT相关BPF代码时,程序运行正常,但UDP报文会被静态分配到单个监听套接字,导致核心负载不均。添加SO_ATTACH_REUSEPORT_CBPF随机分配UDP报文的代码后,程序运行失败,相关代码如下:

int optval = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));

struct sock_filter code[3] = {
    /* Load random to A */
    { BPF_LD  | BPF_W | BPF_ABS,  0,  0, 0xfffff038 },
    
    /* A = A % mod */
    { BPF_ALU | BPF_MOD, 0, 0, 8 /* threads */ },
    
    /* return A */
    { BPF_RET | BPF_A, 0, 0, 0 },
};
struct sock_fprog bpf = {
    .len = 3,
    .filter = code,
};

setsockopt(sock, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &bpf, sizeof(bpf));
问题分析与修复

你的代码存在两个核心错误,导致BPF过滤器加载失败:

  • 非法访问内核地址:你使用BPF_LD | BPF_W | BPF_ABS指令加载0xfffff038这个内核虚拟地址,用户态CBPF过滤器不允许直接访问内核内存,BPF验证器会直接拒绝该指令。正确做法是使用BPF_LD | BPF_W | BPF_RANDOM指令,它专门用于生成32位随机值并存入A寄存器,无需访问内核地址。

  • BPF_MOD指令的兼容性问题:CBPF的BPF_MOD指令仅支持除数为2的幂的场景(非2幂值会触发验证失败或兼容性问题)。由于你的除数是8(2的3次方),可以用位与运算BPF_ALU | BPF_AND替代取模,既符合BPF规范,又更高效。

修复后的BPF代码如下:

struct sock_filter code[3] = {
    /* 加载32位随机值到A寄存器 */
    { BPF_LD  | BPF_W | BPF_RANDOM,  0,  0, 0 },
    
    /* A = A & 7 等价于 A % 8,生成0-7的套接字索引 */
    { BPF_ALU | BPF_AND, 0, 0, 7 },
    
    /* 返回A作为套接字选择索引 */
    { BPF_RET | BPF_A, 0, 0, 0 },
};

另外建议添加setsockopt的返回值检查,便于快速定位错误:

if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &bpf, sizeof(bpf)) == -1) {
    perror("SO_ATTACH_REUSEPORT_CBPF failed");
    exit(EXIT_FAILURE);
}

内容的提问来源于stack exchange,提问作者fadedbee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 10:05:33