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

使用eBPF sk_skb_stream_verdict时数据包永久排队问题求助

eBPF sk_skb_stream_verdict 实现TCP重定向时的数据包排队问题

架构与环境

拓扑结构:

client <--[key=0]--> proxy <--[key=1]--> server
  • 服务器:Go编写的TCP回显服务器,收到数据包原样返回
  • 代理:Go协程实现的TCP代理,负责客户端与服务器间的数据包转发
  • 环境:Linux archlinux 6.1.52,客户端与服务器通过Docker host网络启动

BPF程序代码

//go:build ignore

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>

#define SERVER_PORT 8080
#define PROXY_PORT 8081

// client <--[key=0]--> proxy <--[key=1]--> server

struct {
    __uint(type, BPF_MAP_TYPE_SOCKMAP);
    __uint(max_entries, 32);
    __type(key, __u32);
    __type(value, __u32); // socket FD
} sockmap SEC(".maps");

SEC("sockops/prog")
int sockops_prog(struct bpf_sock_ops *skops) {
    switch (skops->op) {
    case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: // SYN-ACK
        if (skops->local_port == PROXY_PORT) {
            __u32 key = 0;
            bpf_sock_map_update(skops, &sockmap, &key, BPF_ANY);
        }
        break;
    case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: // SYN
        if (bpf_ntohl(skops->remote_port) == SERVER_PORT) {
            __u32 key = 1;
            bpf_sock_map_update(skops, &sockmap, &key, BPF_ANY);
        }
        break;
    }

    return 0;
}

SEC("sk_skb/stream_verdict/prog")
int sk_skb_stream_verdict_prog(struct __sk_buff *skb) {
    int res;

    if (skb->local_port == PROXY_PORT) {
        // 不工作
        // res = bpf_sk_redirect_map(skb, &sockmap, 0, BPF_F_INGRESS);

        // 正常工作
        res = bpf_sk_redirect_map(skb, &sockmap, 1, 0);
        return res;
    }

    if (bpf_ntohl(skb->remote_port) == SERVER_PORT) {
        // 不工作
        // res = bpf_sk_redirect_map(skb, &sockmap, 1, BPF_F_INGRESS);

        // 正常工作
        res = bpf_sk_redirect_map(skb, &sockmap, 0, 0);
        return res;
    }

    return SK_DROP;
}

char _license[] SEC("license") = "GPL";

问题现象

当调用bpf_sk_redirect_map时使用BPF_F_INGRESS标志,让代理应用处理数据包时出现异常;而使用flag=0直接转发时一切正常。

用nc作为客户端连接代理时:

  • 发送第一个数据包"aaaaa",客户端立即收到回显;
  • 发送第二个数据包"bbbbb",数据包永久排队;
  • 发送第三个数据包"ccccc",客户端立即收到"bbbbb"和"ccccc"的回显。

追踪结果

使用cilium/pwru追踪数据包发现:

  • 第一个数据包发送时会调用sk_psock_verdict_recv函数;
  • 第二个数据包发送时该函数未被调用,直到第三个数据包发送才触发。

请求帮助

需要排查上述异常的原因,并给出修复建议。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:08:19