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

eBPF:TC egress侧如何识别并忽略TC ingress侧直接回复的报文

解决方案:TC egress侧过滤ingress直接回包的实现方法

核心识别原理

TC ingress hook 调用bpf_redirect/bpf_send类 helper 直接回送的报文,没有经过内核协议栈的上行处理,也没有和用户空间进程交互,和正常用户态程序生成的出站报文有两个可识别的核心特征:

  • 未关联sock结构体,或者sock的类型为特殊的内核临时sock
  • 可以通过自定义的eBPF标记逻辑完成精准识别

具体实现方案

方案1:基于skb的sock字段判定(无需修改ingress侧代码)

正常用户态程序生成的出站报文,skb->sk指针会指向对应进程的socket结构体,而TC ingress直接redirect回送的报文,skb->sk为空,或者指向内核内部的伪socket。
在eBPF代码中直接读取struct __sk_buff的sk字段即可判定:

// TC egress hook 代码
SEC("tc/egress")
int egress_filter(struct __sk_buff *skb) {
    // sk为0说明没有关联用户态socket,属于内核直接回送的报文
    if (skb->sk == 0) {
        return TC_ACT_OK; // 直接跳过你的业务逻辑即可
    }
    // 后续处理用户态生成的正常报文
    // ... 你的业务逻辑代码
    return TC_ACT_OK;
}

注意:部分内核版本中,内核协议栈自动生成的ICMP等控制报文也会存在skb->sk为空的情况,如果需要进一步区分,可以额外匹配报文的五元组特征做二次过滤。

方案2:自定义标记法(最精准,推荐)

在TC ingress侧的回包逻辑中,给直接回送的报文打上自定义标记,egress侧直接读取标记过滤即可,不会误判其他内核生成报文。
可以用两种方式打标记:

  1. 利用skb的mark字段(内核原生支持,无需额外map)
// TC ingress侧回包前打标记
SEC("tc/ingress")
int ingress_handle(struct __sk_buff *skb) {
    // 满足直接回包条件的业务逻辑
    if (need_direct_reply(skb)) {
        // 打自定义标记,比如用0x1234作为ingress直接回包的专属标识
        skb->mark = 0x1234;
        return bpf_redirect(skb->ifindex, 0);
    }
    // 正常上行报文处理逻辑
    return TC_ACT_OK;
}

// TC egress侧过滤逻辑
SEC("tc/egress")
int egress_filter(struct __sk_buff *skb) {
    if (skb->mark == 0x1234) {
        // 清除标记避免影响其他内核模块的正常逻辑
        skb->mark = 0;
        return TC_ACT_OK; // 跳过你的业务逻辑
    }
    // 处理正常出站报文
    return TC_ACT_OK;
}
  1. 用eBPF per-CPU hash map存储报文的哈希值作为标记,适合不能占用skb->mark字段的场景。

常见问题排查

  • 如果用skb->sk判定不准,可以先通过bpf_printk打印不同场景下的skb->sk、skb->mark值确认特征
  • 注意bpf_redirect的第二个参数如果传BPF_F_INGRESS的话,报文不会走到egress hook,不需要额外过滤

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 01:45:00