DevilKing's blog

冷灯看剑,剑上几分功名?炉香无需计苍生,纵一穿烟逝,万丈云埋,孤阳还照古陵

0%

BPF Intro

原文链接

网络监控器,都是作为用户级进程运行的。为了分析只在内核空间运行的数据,它们必须将这些数据从内核空间复制到用户空间的内存中去,并进行上下文切换。这与直接在内核空间分析这些数据相比,导致了巨大的性能开销

img

BPF 在数据包过滤上引入了两大革新:

  • 一个新的虚拟机 (VM) 设计,可以有效地工作在基于寄存器结构的 CPU 之上;
  • 应用程序使用缓存只复制与过滤数据包相关的数据,不会复制数据包的所有信息,最大程度地减少BPF 处理的数据,提高处理效率;

在目前的Linux内核中已经有了近10种的钩子,如下所示:

  • kernel functions (kprobes)
  • userspace functions (uprobes)
  • system calls
  • fentry/fexit
  • Tracepoints
  • network devices (tc/xdp)
  • network routes
  • TCP congestion algorithms
  • sockets (data level)

从文件打开、创建TCP链接、Socket链接到发送系统消息等几乎所有的系统调用,加上用户空间的各种动态信息,都能加载BPF程序,可以说是无所不能。它们在内核中形成不同的BPF程序类型,在加载时会有类型判断。

BPF Map

1
2
3
4
5
6
7
struct bpf_map_def SEC("maps") my_bpf_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(int),
.value_size = sizeof(int),
.max_entries = 100,
.map_flags = BPF_F_NO_PREALLOC,
};

BPF Helper

通过定义和维护BPF辅助函数,由BPF辅助函数来去面对后端的内核函数的变化,对开发者透明,形成稳定API接口。

  • eBPF 程序中循环次数限制且必须在有限时间内结束
  • eBPF 堆栈大小被限制在 MAXBPFSTACK,截止到内核 Linux 5.8 版本,被设置为 512。目前没有计划增加这个限制,解决方法是改用 BPF Map,它的大小是无限的。
  • eBPF 字节码大小最初被限制为 4096 条指令,截止到内核 Linux 5.8 版本, 当前已将放宽至 100 万指令( BPF_COMPLEXITY_LIMIT_INSNS),对于无权限的BPF程序,仍然保留4096条限制 ( BPF_MAXINSNS )

Cilium

通过使用基于Linux内核特性的新技术——BPF,提供了基于service/pod/container作为标识,而非传统的IP地址,来定义和加强容器和Pod之间网络层、应用层的安全策略

Falco主要使用了raw_tracepoint的系统调用hook,检测应用进程的启动和退出,然后通过Perf类型的BPF Map将检测到的数据发送回用户空间,实现监控的pipeline。