ebpf tracing 源码阅读
2 min read

ebpf tracing 源码阅读

ebpf tracing kernel 源码阅读理解
ebpf tracing 源码阅读
Photo by Gabriel Heinzer / Unsplash
/*
 * 通过linux-krsi的样例进行学习ebpf trace:
 * user_space:   samples/bpf/tracex1_user.c
 * samples/bpf/tracex1_kern.c:bpf程序,需要编译成bpf byte code加载到kernel的ebpf vm进行执行
 * samples/bpf/tracex1_user.c:bpf的用户态工具
 * trace helper程序:tools/testing/selftests/bpf/trace_helpers.c
 */
 
// ebpf程序执行的过程分为step1到step5
// step1: 通过tracex1_kern.c编译成的object文件创建bpf object
bpf_object__open_file(filename, NULL)
|-- __bpf_object__open(path, NULL, 0, opts)
|-- |-- bpf_object__new(path, obj_buf, obj_buf_sz, obj_name)
|-- |-- bpf_object__elf_init(obj) // 读取bpf object并且映射到elf符号描述
|-- |-- |-- elf_begin(obj->efile.fd, ELF_C_READ_MMAP, NULL)
|-- |-- |-- gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)
|-- |-- |-- elf_getshdrstrndx(obj->efile.elf, &obj->efile.shstrndx)
|-- |-- |-- elf_rawdata(elf_getscn(obj->efile.elf, obj->efile.shstrndx), NULL)
|-- |-- bpf_object__check_endianness(obj) // bpf对象的大小端检查
|-- |-- bpf_object__elf_collect(obj)      // 将读取的elf解析成bpf对象
|-- |-- |-- bpf_object__init_btf(obj, btf_data, btf_ext_data) // 根据elf的BTF和BTF.ext字段新建bpf对象的btf(TODO: 不知道btf跟vmlinux kernel的关系是什么,找@云伯请教一下)
|-- |-- bpf_object__collect_externs(obj) // 从读取的elf中解析.ksyms和.kconf字段到bpf对象中
|-- |-- bpf_object__finalize_btf(obj)
|-- |-- bpf_object__init_maps(obj, opts)
|-- |-- |-- bpf_object__init_user_maps(obj, strict) // 用户态maps初始化
|-- |-- |-- bpf_object__init_user_btf_maps(obj, strict, pin_root_path) // btf maps初始化
|-- |-- |-- bpf_object__init_global_data_maps(obj) // 全局数据maps初始化
|-- |-- |-- bpf_object__init_kconfig_map(obj) // kcofigmaps初始化
|-- |-- |-- bpf_object__init_struct_ops_maps(obj) // bpf_struct_ops maps初始化
|-- |-- bpf_object__collect_relos(obj) // 解析elf中的reloc字段到bpf对象中
|-- |-- bpf_object__elf_finish(obj) // bpf程序elf解析结束
|-- |-- |-- elf_end(obj->efile.elf)


// step2: 通过bpf object找到需要使用的bpf程序
bpf_object__find_program_by_name(obj, "bpf_prog1") // 从bpf对象中查找名为“bpf_prog1”的bpf程序
|-- |-- bpf_object__for_each_program(prog, obj)


// step3: 加载bpf object
bpf_object__load(obj) // 加载bpf对象
|-- |-- bpf_object__load_xattr(&attr)
|-- |-- |-- bpf_object__probe_loading(obj)
|-- |-- |-- |-- bpf_load_program_xattr(&attr, NULL, 0)
|-- |-- |-- |-- |-- sys_bpf_prog_load(&attr, sizeof(attr))
|-- |-- |-- |-- |-- |-- sys_bpf(BPF_PROG_LOAD, attr, size) //系统调用sys_bpf加载bpf程序
|-- |-- |-- bpf_object__resolve_externs(obj, obj->kconfig)
|-- |-- |-- bpf_object__sanitize_and_load_btf(obj) // 加载面向bpf的btf
|-- |-- |-- bpf_object__sanitize_maps(obj) // bpf对象的map属性检查
|-- |-- |-- bpf_object__load_vmlinux_btf(obj) // 加载vmlinux的btf
|-- |-- |-- bpf_object__init_kern_struct_ops_maps(obj) // 初始化bpf_struct_ops的map
|-- |-- |-- bpf_object__create_maps(obj)
|-- |-- |-- bpf_object__relocate(obj, attr->target_btf_path) // bpf程序中relocate处理
|-- |-- |-- bpf_object__load_progs(obj, attr->log_level) // 加载bpf对象


// step4: attach需要生效的bpf程序
bpf_program__attach(prog) // bpf_link于“bpf_prog1”的bpf_program建立联系
|-- ?? // TODO: 尚有疑问,等有空再研究一下


// step5: helper程序消费bpf程序的tracing信息
read_trace_pipe(void) // bpf程序的helper程序
|-- open(DEBUGFS "trace_pipe", O_RDONLY, 0)
|-- read(trace_fd, buf, sizeof(buf) - 1) // 从“/sys/kernel/debug/tracing/trace_pipe”中读取bpf的tracing信息
/******************************************************************************/

References

  1. sinkap/linux-krsi

Public discussion