nel*_*ela 3 linux linux-kernel bpf ebpf libbpf
我一直在阅读有关可休眠 eBPF 程序的内容,特别是这篇文章提供了很好的介绍。然而,我正在努力寻找任何有关如何在代码中实际实现这一目标的文档或示例。非常感谢任何提示或文档链接。
注意:此答案最后更新于 2023 年 3 月 29 日,可睡眠程序仍可能发生变化,在内核 v6.3 之后,此答案可能不准确。
截至撰写本答案时,尚无有关此功能的官方文档。此时您可以获得的最接近的是 LWN 文章和提交消息。
v5.10 中添加了可睡眠程序。
“可睡眠”的 eBPF 程序实际上无法像用户空间程序那样主动睡眠(例如“os.sleep(100ms)”)。它是一个属性,允许程序调用某些否则不可用的辅助函数。例如bpf_copy_from_user。
不可睡眠的 eBPF 程序保证不会在 CPU 之间切换,并且在非 RT(实时)内核上不会被调度程序中断。但是,某些操作(例如从用户空间内存读取)可能会受到 IO 限制(例如,如果该用户空间内存是文件支持的)。因此,这些函数可能会“休眠”或阻塞,直到 IO 完成。内核同时做其他事情是有意义的。这就是引入这一点的原因。
这有一些含义:
不可睡眠程序依靠隐式 rcu_read_lock() 和 migrate_disable() 来保护程序的生命周期、它们使用的映射以及用于在 bpf 程序和内核之间传递信息的每 CPU 内核结构。可休眠程序不能包含在 rcu_read_lock() 中。migrate_disable() 映射到非 RT 内核中的 preempt_disable(),因此 progs 也不应该包含在 migrate_disable() 中。因此 rcu_read_lock_trace 用于保护可休眠 prog 的生命周期。
要将程序加载为可睡眠状态,BPF_F_SLEEPABLE必须将该标志传递给BPF_PROG_LOAD系统调用命令。.s对于使用 libbpf 的作者来说,告诉加载器这样做的最简单方法是在程序部分的末尾添加。lsm.s/file_protect例如,对于 file_protect 上的 LSM 挂钩,节名称将变成uprobeuprobe.s//proc/self/exe:trigger_func3
在 v5.10 中,只有 fentry/fexit/fmod_ret 和 lsm 程序可以休眠。即便如此,并非所有 LSM 挂钩都允许处于睡眠状态。该补丁集添加了一个特殊的可休眠钩子列表:
/* non exhaustive list of sleepable bpf_lsm_*() functions */
BTF_SET_START(btf_sleepable_lsm_hooks)
#ifdef CONFIG_BPF_LSM
BTF_ID(func, bpf_lsm_file_mprotect)
BTF_ID(func, bpf_lsm_bprm_committed_creds)
#endif
BTF_SET_END(btf_sleepable_lsm_hooks)
static int check_sleepable_lsm_hook(u32 btf_id)
{
return btf_id_set_contains(&btf_sleepable_lsm_hooks, btf_id);
}
Run Code Online (Sandbox Code Playgroud)
在 v5.18 中,此补丁集中添加了对可休眠迭代器程序的支持。
在 v6.0 中,此补丁集中添加了对可睡眠 uprobes 和 uretprobes 的支持。
在 v6.3 中,此补丁集中添加了对可休眠 sockops 程序的支持。
最后,在 v5.10 中,可休眠程序只允许使用预分配的BPF_MAP_TYPE_HASH,BPF_MAP_TYPE_LRU_HASH和BPF_MAP_TYPE_ARRAY映射。
在 v5.12 中,此补丁允许可睡眠程序使用每 CPU 映射类型:BPF_MAP_TYPE_PERCPU_HASH、BPF_MAP_TYPE_PERCPU_ARRAY、BPF_MAP_TYPE_LRU_PERCPU_HASH、BPF_MAP_TYPE_ARRAY_OF_MAPS和BPF_MAP_TYPE_HASH_OF_MAPS
在 v5.12 中,此补丁集允许可睡眠程序使用环缓冲区:BPF_MAP_TYPE_RINGBUF
在 v5.17 中,此补丁集允许可休眠程序使用存储映射:BPF_MAP_TYPE_INODE_STORAGE、BPF_MAP_TYPE_SK_STORAGE和BPF_MAP_TYPE_TASK_STORAGE
当 v6.1 中引入用户环形缓冲区时,在此补丁集中BPF_MAP_TYPE_USER_RINGBUF,可睡眠程序也可以访问。
在 v6.2 中,该补丁集允许睡眠程序访问BPF_MAP_TYPE_CGRP_STORAGE.