我正在 Ubuntu 机器上开发 eBPF 程序:
$ uname -a
Linux ubuntu-bionic 4.18.0-16-generic #17~18.04.1-Ubuntu SMP Tue Feb 12 13:35:51 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)
为此,我需要bpf.h许多定义以及bpf_helpers.h辅助函数定义。我安装了一个带有标题的新内核:
apt-get update -y
apt-get install -y linux-image-4.18.0-16-generic linux-headers-4.18.0-16-generic
Run Code Online (Sandbox Code Playgroud)
标头包括bpf.h:
$ find /usr/src/linux-headers-4.18.0-16 -name bpf.h
/usr/src/linux-headers-4.18.0-16/include/uapi/linux/bpf.h
/usr/src/linux-headers-4.18.0-16/include/linux/bpf.h
Run Code Online (Sandbox Code Playgroud)
但不是bpf_helpers.h:
$ find /usr/src/linux-headers-4.18.0-16 -name bpf_helpers.h
Run Code Online (Sandbox Code Playgroud)
如何为我的内核获取此文件?为什么它不包含在分发标头中?
我可以签出特定版本的 Linux 内核或从master获取文件,但发行版可能会对上游进行更改,这让我这样做感到不舒服。
我确实有一些 DPDK 经验,但目前我正在阅读许多有关 XDP 的博客。我正在尝试比较这两种技术并了解 DPDK 和 XDP 之间的差异。这引发了一些问题。我希望有人能帮助我解决以下问题:
预先感谢您的帮助!
是否可以编写一个通用的 EBPF 程序来读取所有用户空间程序的未加密 HTTPS 请求和响应主体?
据我了解,EBPF 处理网络第 2、3 和 4 层的数据包。HTTPS 有效负载在这些数据包中加密,因此 EBPF 可以读取数据包元数据,但不能读取构成 HTTPS 请求/响应的有效负载?
这样做是将日志记录添加到用户空间程序的唯一方法吗?
在内核中,eBPF 映射可以定义为:
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(uint32_t),
.value_size = sizeof(struct task_prov_struct),
.max_entries = 4096,
};
Run Code Online (Sandbox Code Playgroud)
如果我提前不知道最大可能大小my_map(我也不想浪费内存),有没有办法预先分配一个小大小并根据需要动态增加大小?我知道bpf_map__resize函数,但它似乎是一个用户空间函数,只能在加载地图之前调用。我将不胜感激任何示例代码片段或参考。
eBPF 已成为轻松快速地监控流程的重要工具。然而,我无法找到如何计算探针本身对性能的影响。我确信如果我挂钩每个系统调用并在地图中推送一些信息,一定会产生一些影响,没有什么是免费的,但是我将如何正确计算这种增加的延迟?
我想到的唯一解决方案是在探测器处于活动状态和不活动状态的情况下多次运行相同的程序,并检查系统执行时间差异,但在我看来,这会受到各种因素的影响,这些因素可能会增加很多差异因此不会给出非常可靠的结果。
我找到了一个 eBPF 示例,它代理请求,根据目标端口过滤哪些请求。
我试图按客户端的 process_id 而不是目标端口进行过滤,并尝试添加bpf_get_current_pid_tgid() here。然而,该方法似乎在该上下文中未找到/可用。
在这种情况下,如何找到正确的方法来获取连接所有者 process_id ?
由于现在 ebpf 程序中允许有界循环https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=2589726d12a1b12eaaa93c7f1ea64287e383c7a5 验证程序是否仍然检查如果程序控制流是有向无环图,则第一遍?
目前,我正在跟踪 bpf 程序并发现一些我无法理解的内容。
有几个声明,例如:
struct bpf_map_def SEC("maps") map_parsing_context = {
...
};
struct {
...
} map_keys SEC(".maps");
Run Code Online (Sandbox Code Playgroud)
我的问题是:
__attribute__((section("name")))?map和之间有什么不同.map?它们只是用户定义的部分吗?我正在进入 eBPF 编程并想要使用原始跟踪点,但我不太明白如何使用它们以及如何正确访问参数。我将不胜感激任何对文档的帮助和提示。
我的问题:
uint16_t common_type;顺便说一句:原始跟踪点是什么?系统:Ubuntu 2004,内核 5.4 通用,x86_64
解释/示例:
我从“正常跟踪点”开始sys_enter_kill,我可以在其中使用以下参数创建结构sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format:
// sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format
// name: sys_enter_kill
// ID: 184
// format:
// field:unsigned short common_type; offset:0; size:2; signed:0;
// field:unsigned char common_flags; offset:2; size:1; signed:0;
// field:unsigned char common_preempt_count; offset:3; size:1;signed:0;
// field:int common_pid; offset:4; size:4; signed:1;
// field:int __syscall_nr; offset:8; size:4; signed:1;
// field:pid_t pid; offset:16; size:8; signed:0;
// field:int sig; offset:24; size:8; signed:0;
struct syscalls_enter_kill_args …Run Code Online (Sandbox Code Playgroud) 我正在编写一个检查任务 UID 的 eBPF kprobe,即在 execve 调用之间唯一允许的 UID 更改是 setuid()、seteuid() 和 setreuid() 调用所允许的 UID 更改。
由于探测器检查所有任务,因此它使用从 init_task 开始迭代的展开循环,并且最多必须使用 1024 或 8192 个分支,具体取决于内核版本。
我的问题是,如果存在非法更改,如何实现返回非零的检查,定义为:
(new_ruid != old_euid && new_ruid != old_ruid) ||
(new_euid != old_euid && new_euid != old_ruid && new_euid != old_suid)
Run Code Online (Sandbox Code Playgroud)
但不使用分支(clang 使用跳转来短路检查之间的任何表达式是否&&计算为 true)。
ebpf ×10
bpf ×7
c ×3
linux ×3
linux-kernel ×3
xdp-bpf ×2
assembly ×1
c++ ×1
clang ×1
cpu ×1
dpdk ×1
header-files ×1
https ×1
kernel ×1
monitoring ×1
performance ×1