目录
将BPF 映射(maps)固定到指定的文件系统路径
函数原型与作用
/* bpf_object__pin_maps() pins each map contained within the BPF object at the passed directory. If path is NULL bpf_map__pin (which is being used on each map) will use the pin_path attribute of each map. In this case, maps that don’t have a pin_path set will be ignored. Parameters: obj – Pointer to a valid BPF object path – A directory where maps should be pinned. Returns: 0, on success; negative error code, otherwise */ LIBBPF_API int bpf_object__pin_maps (struct bpf_object *obj, const char *path)
bpf_object__pin_maps 函数的作用是将 BPF 对象中的所有 BPF 映射(maps)固定到指定的文件系统路径。固定(pinning)是一种将 BPF 映射的生命周期与创建它的进程解耦的方法。通过将映射固定到文件系统上的某个路径,其他进程可以在稍后访问和使用这些映射,即使创建它的原始进程已经退出。通常,BPF 映射会在创建它们的进程退出时自动关闭,但是固定映射允许它们在进程之间共享和持久化。
pf_object__unpin_maps 函数的作用是将 BPF 对象中的所有 BPF 映射(maps)从指定的文件系统路径解除固定。在之前使用 bpf_object__pin_maps 将映射固定到文件系统的路径后,你可以使用 bpf_object__unpin_maps 将它们解除固定。解除固定后,映射将不再在文件系统上可用。
代码demo
#include <stdio.h> #include <stdlib.h> #include <sys/resource.h> #include <bpf/libbpf.h> int main() { struct bpf_object *obj; const char *filename = "example.bpf.o"; const char *pin_path = "/sys/fs/bpf/example_maps"; int err; // 设置 RLIMIT_MEMLOCK 为无限制 struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY}; if (setrlimit(RLIMIT_MEMLOCK, &rlim)) { perror("Failed to set RLIMIT_MEMLOCK"); return 1; } // 使用 bpf_object__open_file 打开 BPF 对象文件 obj = bpf_object__open_file(filename, NULL); if (libbpf_get_error(obj)) { fprintf(stderr, "Error loading BPF object from file: %s\n", filename); return 1; } // 使用 bpf_object__load 加载 BPF 对象到内核中 err = bpf_object__load(obj); if (err) { fprintf(stderr, "Error loading BPF object: %d\n", err); bpf_object__close(obj); return 1; } printf("BPF object loaded successfully\n"); // 使用 bpf_object__pin_maps 将 BPF 对象中的所有地图固定到指定路径 err = bpf_object__pin_maps(obj, pin_path); if (err) { fprintf(stderr, "Error pinning BPF maps: %d\n", err); bpf_object__close(obj); return 1; } printf("BPF maps pinned at %s\n", pin_path); // 在此处,你可以执行其他操作,例如与固定的地图进行交互 // 然后,在完成操作后,使用 bpf_object__unpin_maps 解除固定: err = bpf_object__unpin_maps(obj, pin_path); if (err) { fprintf(stderr, "Error unpinning BPF maps: %d\n", err); bpf_object__close(obj); return 1; } printf("BPF maps unpinned from %s\n", pin_path); bpf_object__close(obj); return 0; }
makefile
CC = gcc CFLAGS = -Wall -Wextra -O2 TARGET = example SRCS = example.c OBJS = $(SRCS:.c=.o) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $@ $^ %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET) .PHONY: all clean
cmake
cmake_minimum_required(VERSION 3.10) project(example LANGUAGES C) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -O2") add_executable(example example.c)
将BPF 程序固定到指定的文件系统路径
函数原型与解释
LIBBPF_API int bpf_object__pin_programs (struct bpf_object *obj, const char *path) LIBBPF_API int bpf_object__unpin_programs (struct bpf_object *obj, const char *path)
将 BPF 对象中的所有 BPF 程序(programs)固定到指定的文件系统路径。固定后,其他进程可以通过路径找到这些 BPF 程序并将它们附加到相应的事件(event)上。这有助于实现进程之间的 BPF 程序共享,以及在进程终止后 BPF 程序仍然能被其他进程使用。
bpf_object__unpin_programs代表解除固定
代码demo
#include <bpf/bpf_helpers.h> #include <linux/bpf.h> SEC("kprobe/__x64_sys_getpid") int bpf_prog1(struct pt_regs *ctx) { char comm[16]; bpf_get_current_comm(&comm, sizeof(comm)); // 在此处,你可以使用获取到的 comm(进程名)执行其他操作 return 0; } char _license[] SEC("license") = "GPL";
#include <stdio.h> #include <stdlib.h> #include <sys/resource.h> #include <bpf/libbpf.h> int main() { struct bpf_object *obj; const char *filename = "example.bpf.o"; const char *pin_path = "/sys/fs/bpf/example_programs"; int err; // 设置 RLIMIT_MEMLOCK 为无限制 struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY}; if (setrlimit(RLIMIT_MEMLOCK, &rlim)) { perror("Failed to set RLIMIT_MEMLOCK"); return 1; } // 使用 bpf_object__open_file 打开 BPF 对象文件 obj = bpf_object__open_file(filename, NULL); if (libbpf_get_error(obj)) { fprintf(stderr, "Error loading BPF object from file: %s\n", filename); return 1; } // 使用 bpf_object__load 加载 BPF 对象到内核中 err = bpf_object__load(obj); if (err) { fprintf(stderr, "Error loading BPF object: %d\n", err); bpf_object__close(obj); return 1; } printf("BPF object loaded successfully\n"); // 使用 bpf_object__pin_programs 将 BPF 对象中的所有程序固定到指定路径 err = bpf_object__pin_programs(obj, pin_path); if (err) { fprintf(stderr, "Error pinning BPF programs: %d\n", err); bpf_object__close(obj); return 1; } printf("BPF programs pinned at %s\n", pin_path); // 在此处,你可以执行其他操作,例如将固定的程序附加到事件上 bpf_object__close(obj); return 0; }
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/resource.h> #include <sys/syscall.h> #include <linux/perf_event.h> #include <bpf/libbpf.h> static int perf_event_open_tracepoint(const char *name, const char *prog_path) { int err; struct bpf_program *prog; struct bpf_object *obj; // 打开固定的 BPF 程序 obj = bpf_object__open(prog_path); if (libbpf_get_error(obj)) { fprintf(stderr, "Error opening BPF object: %d\n", libbpf_get_error(obj)); return -1; } prog = bpf_program__next(NULL, obj); if (!prog) { fprintf(stderr, "Error finding BPF program\n"); bpf_object__close(obj); return -1; } // 使用 perf_event_open 系统调用创建 perf event struct perf_event_attr attr = { .type = PERF_TYPE_TRACEPOINT, .size = sizeof(attr), .config = bpf_program__kprobe_prog_type(prog), .sample_period = 1, .sample_type = PERF_SAMPLE_RAW, .wakeup_events = 1, }; err = syscall(__NR_perf_event_open, &attr, -1, 0, -1, 0); if (err < 0) { perror("Error creating perf event"); bpf_object__close(obj); return -1; } int perf_event_fd = err; // 将 BPF 程序附加到 perf event err = bpf_prog_attach(bpf_program__fd(prog), perf_event_fd, 0, 0); if (err) { fprintf(stderr, "Error attaching BPF program: %d\n", err); close(perf_event_fd); bpf_object__close(obj); return -1; } printf("Successfully attached BPF program to perf event\n"); return perf_event_fd; } int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "Usage: %s <tracepoint_name> <pinned_prog_path>\n", argv[0]); return 1; } const char *tracepoint_name = argv[1]; const char *pinned_prog_path = argv[2]; int perf_event_fd = perf_event_open_tracepoint(tracepoint_name, pinned_prog_path); if (perf_event_fd < 0) { return 1; } printf("Press Ctrl+C to exit\n"); pause(); // Wait for signals // Clean up close(perf_event_fd); return 0; }
makefile
CC = gcc CLANG = clang CFLAGS = -Wall -I/usr/include/bpf LDFLAGS = -lbpf BPF_TARGET = prog.o BPF_SRC = prog.c PIN_TARGET = pin_programs PIN_SRC = pin_programs.c ATTACH_TARGET = attach_pinned_program ATTACH_SRC = attach_pinned_program.c all: $(BPF_TARGET) $(PIN_TARGET) $(ATTACH_TARGET) $(BPF_TARGET): $(BPF_SRC) $(CLANG) -O2 -target bpf -c $(BPF_SRC) -o $(BPF_TARGET) $(PIN_TARGET): $(PIN_SRC) $(CC) $(CFLAGS) $(PIN_SRC) -o $(PIN_TARGET) $(LDFLAGS) $(ATTACH_TARGET): $(ATTACH_SRC) $(CC) $(CFLAGS) $(ATTACH_SRC) -o $(ATTACH_TARGET) $(LDFLAGS) clean: rm -f $(BPF_TARGET) $(PIN_TARGET) $(ATTACH_TARGET) .PHONY: all clean
cmake
cmake_minimum_required(VERSION 3.10) project(bpf_example) set(CMAKE_C_STANDARD 99) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") find_library(LIBBPF libbpf.so REQUIRED) add_executable(pin_programs pin_programs.c) target_link_libraries(pin_programs ${LIBBPF}) target_include_directories(pin_programs PUBLIC /usr/include/bpf) add_custom_command( OUTPUT prog.o COMMAND clang -O2 -target bpf -c ${CMAKE_CURRENT_SOURCE_DIR}/prog.c -o prog.o DEPENDS prog.c VERBATIM ) add_custom_target( prog_bpf DEPENDS prog.o ) add_executable(attach_pinned_program attach_pinned_program.c) target_link_libraries(attach_pinned_program ${LIBBPF}) target_include_directories(attach_pinned_program PUBLIC /usr/include/bpf)
将object固定到文件系统
函数原型与解析
LIBBPF_API int bpf_object__pin(struct bpf_object *object, const char *path);
参数解释:
- object:要固定的 bpf_object 实例。
- path:文件系统中的路径,用于保存固定的 BPF 对象。通常,这将是在 /sys/fs/bpf 目录下的一个路径。
返回值:
- 成功时返回 0。
- 失败时返回负数错误代码。
代码demo
#include <bpf/bpf_helpers.h> #include <linux/bpf.h> SEC("kprobe/__x64_sys_getpid") int bpf_prog1(struct pt_regs *ctx) { return 0; } char _license[] SEC("license") = "GPL";
#include <stdio.h> #include <stdlib.h> #include <bpf/libbpf.h> int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <path_to_pin>\n", argv[0]); return 1; } const char *path_to_pin = argv[1]; struct bpf_object *bpf_obj; struct bpf_program *prog; // 加载 BPF 程序 bpf_obj = bpf_object__open("prog.o"); if (libbpf_get_error(bpf_obj)) { fprintf(stderr, "Error opening BPF object: %d\n", libbpf_get_error(bpf_obj)); return 1; } // 设置 BPF 程序的类型 bpf_object__for_each_program(prog, bpf_obj) { bpf_program__set_type(prog, BPF_PROG_TYPE_KPROBE); } // 加载 BPF 对象 int err = bpf_object__load(bpf_obj); if (err) { fprintf(stderr, "Error loading BPF object: %d\n", err); bpf_object__close(bpf_obj); return 1; } // 固定 BPF 对象 err = bpf_object__pin(bpf_obj, path_to_pin); if (err) { fprintf(stderr, "Error pinning BPF object: %d\n", err); bpf_object__close(bpf_obj); return 1; } printf("Successfully pinned BPF object at: %s\n", path_to_pin); // 关闭 BPF 对象。请注意,在固定 BPF 对象后,它将继续存在,即使已关闭并释放相关资源。 bpf_object__close(bpf_obj); return 0; }
clang -O2 -target bpf -c prog.c -o prog.o gcc -I/usr/include/bpf -o pin_bpf_prog pin_bpf_prog.c -lbpf sudo mkdir -p /sys/fs/bpf/example_program sudo ./pin_bpf_prog /sys/fs/bpf/example_program/prog1
makefile
CC = gcc CLANG = clang CFLAGS = -Wall -I/usr/include/bpf LDFLAGS = -lbpf BPF_TARGET = prog.o BPF_SRC = prog.c PIN_TARGET = pin_bpf_prog PIN_SRC = pin_bpf_prog.c all: $(BPF_TARGET) $(PIN_TARGET) $(BPF_TARGET): $(BPF_SRC) $(CLANG) -O2 -target bpf -c $(BPF_SRC) -o $(BPF_TARGET) $(PIN_TARGET): $(PIN_SRC) $(CC) $(CFLAGS) $(PIN_SRC) -o $(PIN_TARGET) $(LDFLAGS) clean: rm -f $(BPF_TARGET) $(PIN_TARGET) .PHONY: all clean
cmake
cmake_minimum_required(VERSION 3.10) project(bpf_pin_example) set(CMAKE_C_STANDARD 99) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") find_library(LIBBPF libbpf.so REQUIRED) add_custom_command( OUTPUT prog.o COMMAND clang -O2 -target bpf -c ${CMAKE_CURRENT_SOURCE_DIR}/prog.c -o prog.o DEPENDS prog.c VERBATIM ) add_custom_target( prog_bpf DEPENDS prog.o ) add_executable(pin_bpf_prog pin_bpf_prog.c) target_link_libraries(pin_bpf_prog ${LIBBPF}) target_include_directories(pin_bpf_prog PUBLIC /usr/include/bpf)