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.controllersnet字段,需要调整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
相关产品推荐
相关产品推荐

