前言:
这篇非常非常干,很有可能读不懂。
这里非常非常推荐,建议使用Cilium官网的lab来辅助学习!!!
Resources Library - IsovalentExplore Isovalent's Resource Library, your one-stop destination for insightful videos, case studies, blogs, books, labs, analyst reports, and more.https://isovalent.com/resource-library/?solution=networking
一、为什么需要新的ebpf技术?
我们是应用工程师,使用技术的的。
那么已知ebpf可以实现网络过滤、可观测性以及安全!
那么我们来探讨它是怎么实现的?
1、网络过滤
网络的ebpf程序运行在网络数据包到达内核网络协议栈之前,数据包到达物理网卡后就会触发ebpf程序。此时ebpf程序可以在in/out不同方向执行简单到复杂的规则来实现网络过滤。
2、可观测性。
其实就回答一个问题:内核层面是否可以看到整个机器的设备状态、进程树?答案是肯定的,
那么ebpf程序同样运行在内核,说直接点ebpf程序知道现在机器上所有进程的性能状态和进程正在使用的系统调用。
3、安全规则
你现在拥有内核层面的对于进程可观测性和网络控制能力,那么实际上你就可以通过写安全规则,来实现安全访问控制器。
二、什么是ebpf?
ebpf(扩展的伯克利数据包过滤器)
这是在运行Linux 5.x+内核的顶级子程序。
他运行用户在 Linux用户空间对在运行在内核空间对ebpf程序进行编程.
实现网络数据包处理、性能监控、故障排除和安全策略等多种任务。
ebpf之所以可以实现上述的能力,是因为ebpf支持多种类型挂载点(即将你编写的ebpf程序挂载到相应类型的能力的挂载点上)。
比如网络(XDP),系统调用(内核函数)(Kprobe 和 Kretprobe),系统调用(用户空间程序)Uprobe 和 Uretprobe等等。
核心重点:
1、官方叫(扩展的伯克利数据包过滤器),其实你这么理解为更方便:“extend use space tools”,扩展用户空间工具。
2、因为ebpf运行我们编程在内核层面,ebpf程序并且拥有很符合我们网络、可观测性、安全需求的ebpf挂载点,那么几乎可以做到监控物理服务器上我们想知道的所有事情。特别是针对于微服务场景!
三、ebpf的工作原理
编写 eBPF 程序 编译 eBPF 程序 加载 eBPF 程序 运行eBPF 程序 收集和分析eBPF 程序
别慌,完事都可以用Python.
BCC库,提供了一个Python接口。意思就是虽然ebpf是C语言写的,但是你可以用Python的代码机构来实现。接下来是代码了:
这里为了方便你能继续读懂,必须要补充和复习一下系统调用的碎片知识。
1、用户空间是无能直接操作、编程内核函数的!
2、用户空间的所有操作都是由很多很多系统调用来具体实现的。比如:你cat 、ls 一个文件,那么背后就是open,
write,read,close
等系统调用来实现!简单的说系统调用是用户空间于内核空间访问的通道,他是一个标准的接口,一个抽象层。
3、当你执行l s操作时,会调用open的系统调用,然后open的系统调用具体是使用do_sys_open这个内核函数来具体执行!
4、接下来代码中你看不到系统调用open,但你能看到do_sys_open这个内核函数.因为ebpf是运行在内核层!
下面为例子,来方便理解:
这个 Python 脚本使用 BCC (BPF Compiler Collection) 来编写和加载一个简单的 eBPF 程序,该程序在来追踪每次文件打开操作,并记录文件名。
open
系统调用用于打开文件。Linux命令: ls cat touch vim 都会调用open系统调用。
do_sys_open:这个内核函数对应系统调用的open
#!/usr/bin/python3
from bcc import BPF
program = r"""
#include <uapi/linux/ptrace.h>
#include <linux/fs.h>
BPF_HASH(counter, u64);
int trace_open(struct pt_regs *ctx, const char __user *filename, int flags) {
u64 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
u64 *count = counter.lookup(&uid);
u64 zero = 0;
if (count) {
(*count)++;
} else {
counter.update(&uid, &zero);
}
bpf_trace_printk("File opened: %s\\n", filename);
return 0;
}
"""
b = BPF(text=program)
b.attach_kprobe(event="do_sys_open", fn_name="trace_open")
print("Tracing file open... Ctrl-C to end.")
b.trace_print()
**上面的代码的简单解释:
##编写ebpf程序:这一块语言是C语言,但是不用你自己写,你可以用ai帮助你完成,你只需要告诉他你想做什么。
BPF_HASH(counter, u64);
int trace_open(struct pt_regs *ctx, const char __user *filename, int flags) {
u64 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
u64 *count = counter.lookup(&uid);
u64 zero = 0;
if (count) {
(*count)++;
} else {
counter.update(&uid, &zero);
}
bpf_trace_printk("File opened: %s\\n", filename);
return 0;
}
"""
##加载 eBPF 程序并附加到 open 系统调用:这一段代码是Python。
b = BPF(text=program)
b.attach_kprobe(event="do_sys_open", fn_name="trace_open")
将上面的代码放置在一个脚hello.py的文件中,执行 eBPF 程序(请提前安装BCC工具集)
./hello.py
收集和分析数据
在另一个终端中执行一些命令(如 ls touch vim等等都可以
),触发 open系统调用.
下面为演示效果:
验证成功加载:
bpftool prog show
##上面的实验是为了证明你在用户空间编写的ebpf程序可以在内核中运行,并且监控系统调用和内核函数。