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

eBPF sockops程序附加Kubernetes Pod cgroup无输出问题排查

问题

尝试将eBPF sockops程序附加到特定Kubernetes Pod,使用的bpf_prog_attach()调用如下:

err = bpf_prog_attach(sockops_prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);

对应的eBPF程序代码:

#include <linux/in.h>
#include <linux/tcp.h>

#include <linux/bpf.h>
#include <sys/socket.h>

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

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

// sock_ops_map maps the sock_ops key to a socket descriptor
struct {
  __uint(type, BPF_MAP_TYPE_SOCKHASH);
  __uint(max_entries, 65535);
  __type(key, struct sock_key);
  __type(value, __u64);
} sock_ops_map SEC(".maps");

// `sock_key' is a key for the sockmap
struct sock_key {
  __u32 sip4;
  __u32 dip4;
  __u32 sport;
  __u32 dport;
} __attribute__((packed));

// `sk_extract_key' extracts the key from the `bpf_sock_ops' struct
static inline void sk_extract_key(struct bpf_sock_ops *ops,
                                  struct sock_key *key) {
  key->dip4 = ops->remote_ip4;
  key->sip4 = ops->local_ip4;
  key->sport = (bpf_htonl(ops->local_port) >> 16);
  key->dport = ops->remote_port >> 16;
}

SEC("sockops")
int bpf_add_to_sockhash(struct bpf_sock_ops *skops) {
  __u32 family, op;

  family = skops->family;
  op = skops->op;
  bpf_printk("Got new operation %d for socket.\n", op);

  switch (op) {
    case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
    case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
      if (family == AF_INET) {
        struct sock_key key = {};
        sk_extract_key(skops, &key);
        int ret = bpf_sock_hash_update(skops, &sock_ops_map, &key, BPF_NOEXIST);
        if (ret != 0) {
          bpf_printk("Failed to update sockmap: %d\n", ret);
        } else {
          bpf_printk("Added new socket to sockmap\n");
        }
      }
      break;
    default:
      break;
  }
  return 0;
}

出现的现象:

  • 当cgroup_fd指向/sys/fs/cgroup/unified根目录时,程序正常加载,bpf_printk的日志能正常输出;
  • 当cgroup_fd指向Kubernetes Pod对应的cgroup路径(/sys/fs/cgroup/unified/kubepods-burstable-podad4348c2_ac53_4c09_a9dc_c207a6c68dec.slice:cri-containerd:30a47e8e847277317a29ff7bdcf5bf03391ff79b847be647120d285f62a0f7e6)时,程序附加成功,但没有任何日志输出。

疑问:附加到子cgroup的SOCKOPS钩子是否存在问题?Kubernetes Pod的cgroup和unified根cgroup有什么差异?

分析与解决

以下是可能的原因及对应的排查/解决方法:

  • cgroup v2控制器权限未开启:cgroup v2中,sock_ops钩子依赖net控制器。Kubernetes创建的子cgroup可能默认没有继承或启用该控制器,导致事件无法传递到子cgroup的eBPF程序。可以通过以下命令检查:
    cat /sys/fs/cgroup/unified/kubepods-burstable-podad4348c2_ac53_4c09_a9dc_c207a6c68dec.slice:cri-containerd:30a47e8e847277317a29ff7bdcf5bf03391ff79b847be647120d285f62a0f7e6/cgroup.controllers
    
    如果输出中没有net字段,需要调整Kubernetes的cgroup配置,确保子cgroup启用net控制器。
  • 进程归属cgroup不匹配:确认Pod内的进程确实属于你指定的cgroup。进入Pod后执行cat /proc/self/cgroup,查看输出路径是否和你附加的cgroup完全一致。容器运行时可能存在嵌套cgroup或路径命名差异,导致程序附加到错误的cgroup,无法接收事件。
  • eBPF程序附加参数缺失:当根cgroup已附加sock_ops程序时,子cgroup的程序可能需要设置BPF_F_ALLOW_MULTI标志来允许多个程序叠加。修改bpf_prog_attach调用:
    err = bpf_prog_attach(sockops_prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, BPF_F_ALLOW_MULTI);
    
    重新尝试附加并观察日志。
  • 日志查看方式验证:确保你是通过cat /sys/kernel/debug/tracing/trace_pipe查看bpf_printk日志,该文件会输出所有eBPF程序的打印内容,不存在cgroup过滤的情况。如果用其他方式查看,可能会遗漏日志。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:03:09