如何不使用bpftool分离残留的eBPF cgroup程序?
先排查根源:阻止程序自动重现
重启虚拟机后程序再次出现,大概率是Cilium服务开机自启并自动重新挂载了eBPF程序,先停止并禁用Cilium的自动挂载:
- 停止Cilium服务:
systemctl stop cilium.service(如果是容器运行的Cilium,直接停止对应容器) - 禁用开机自启:
systemctl disable cilium.service
方法1:通过Systemd重启服务清理cgroup绑定
对于system.slice下的系统服务(如systemd-udevd、systemd-journald等),重启服务会让systemd销毁旧cgroup并创建新实例,绑定在旧cgroup上的eBPF程序会因挂载点消失被内核自动卸载:
- 单个服务重启示例:
systemctl restart systemd-udevd.service - 批量重启残留程序对应的服务:
for svc in systemd-udevd.service systemd-journald.service systemd-logind.service; do systemctl restart $svc done
操作后用bpftool cgroup tree验证,对应cgroup下的程序应已消失。
方法2:编写C工具调用内核bpf()系统调用手动Detach
bpftool本质是封装内核bpf系统调用,我们可以自己实现轻量工具完成detach,不依赖bpftool:
示例代码(编译需链接libbpf):
#include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #include <bpf/libbpf.h> #include <linux/bpf.h> int detach_cgroup_prog(const char *cgroup_path, enum bpf_attach_type attach_type, __u32 prog_id) { int cgroup_fd = open(cgroup_path, O_RDONLY); if (cgroup_fd < 0) { perror("open cgroup"); return -1; } struct bpf_prog_detach_attr attr = { .target_fd = cgroup_fd, .attach_type = attach_type, .prog_id = prog_id, }; int ret = bpf(BPF_PROG_DETACH, &attr, sizeof(attr)); if (ret < 0) { perror("bpf prog detach"); close(cgroup_fd); return -1; } close(cgroup_fd); return 0; } int main(int argc, char **argv) { if (argc != 4) { fprintf(stderr, "Usage: %s <cgroup-path> <attach-type> <prog-id>\n", argv[0]); fprintf(stderr, "Attach types: 6(ingress), 7(egress), 14(device)\n"); return 1; } const char *cgroup_path = argv[1]; enum bpf_attach_type attach_type = atoi(argv[2]); __u32 prog_id = atoi(argv[3]); return detach_cgroup_prog(cgroup_path, attach_type, prog_id) ? 1 : 0; }
编译命令:gcc -o cgroup_detach cgroup_detach.c -lbpf
使用示例:要移除/sys/fs/cgroup/system.slice/systemd-udevd.service下ID为1844的ingress程序,执行:./cgroup_detach /sys/fs/cgroup/system.slice/systemd-udevd.service 6 1844
(attach_type对应值:ingress=6,egress=7,device=14)
方法3:手动销毁自定义cgroup(谨慎操作)
对于非systemd管理的自定义cgroup,可直接删除cgroup目录(需先迁移目录下所有进程):
- 查看并迁移cgroup内的进程到根cgroup:
# 列出目标cgroup下的进程 cat /sys/fs/cgroup/your-custom-cgroup/cgroup.procs # 迁移每个进程 for pid in $(cat /sys/fs/cgroup/your-custom-cgroup/cgroup.procs); do echo $pid > /sys/fs/cgroup/cgroup.procs done - 删除cgroup目录:
rmdir /sys/fs/cgroup/your-custom-cgroup
注意:systemd管理的cgroup不建议手动删除,优先用方法1重启服务。
额外验证
清理后执行bpftool prog show,若目标cgroup程序仍存在,说明还有其他引用(如挂载到其他cgroup),需继续排查对应挂载点重复清理。
内容的提问来源于stack exchange,提问作者Angela

