├── .clang-format ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .vscode ├── c_cpp_properties.json └── settings.json ├── Makefile ├── README.md ├── bpf-core-availability.sh ├── tracepoint.bpf.c └── tracepoint.c /.clang-format: -------------------------------------------------------------------------------- 1 | # requires clang-format >= 3.6 2 | BasedOnStyle: "LLVM" 3 | IndentWidth: 4 4 | ColumnLimit: 132 5 | BreakBeforeBraces: Linux 6 | AllowShortFunctionsOnASingleLine: None 7 | SortIncludes: false 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | timeout-minutes: 5 12 | strategy: 13 | matrix: 14 | runner: 15 | - ubuntu-20.04 16 | runs-on: ${{ matrix.runner }} 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Set Swap Space 20 | uses: pierotofy/set-swap-space@master 21 | with: 22 | swap-size-gb: 8 23 | - name: check availability 24 | run: | 25 | ./bpf-core-availability.sh 26 | - name: build deps 27 | run: | 28 | make deps 29 | - name: build 30 | run: | 31 | make build 32 | - name: test 33 | run: | 34 | make test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | deps/ 3 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${workspaceFolder}/build" 8 | ], 9 | "defines": [], 10 | "compilerPath": "/usr/bin/clang", 11 | "cStandard": "c17", 12 | "cppStandard": "c++14", 13 | "intelliSenseMode": "linux-clang-x64", 14 | "configurationProvider": "ms-vscode.cmake-tools" 15 | } 16 | ], 17 | "version": 4 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "Dockerfile.*": "dockerfile", 4 | "*.mt": "html", 5 | "hello.skel.h": "c", 6 | "bpf_helpers.h": "c", 7 | "vmlinux.h": "c" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MAKEFILE_DIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 2 | CLANG=clang 3 | 4 | all: deps build 5 | .PHONY: all 6 | 7 | deps: apt-packages libbpf bpftool 8 | .PHONY: deps 9 | 10 | apt-packages: 11 | sudo apt-get -q update && sudo apt-get install --no-install-recommends -q -y \ 12 | libelf-dev \ 13 | llvm \ 14 | clang 15 | .PHONY: install-deps 16 | 17 | # If there's libbpf-dev in the apt repository, use it. Otherwise, you can build your own. 18 | libbpf: 19 | if [ ! -e deps/libbpf ] ; then git clone --recursive --depth 1 https://github.com/libbpf/libbpf ./deps/libbpf ; fi 20 | $(MAKE) -j -C deps/libbpf/src/ BUILD_STATIC_ONLY=1 DESTDIR="$(MAKEFILE_DIR)/build" INCLUDEDIR= LIBDIR= UAPIDIR= install 21 | .PHONY: libbpf 22 | 23 | bpftool: 24 | if [ ! -e deps/bpftool ] ; then git clone --branch v6.7.0 --recursive --depth 1 https://github.com/libbpf/bpftool ./deps/bpftool ; fi 25 | $(MAKE) -j -C deps/bpftool/src/ 26 | .PHONY: bpftool 27 | 28 | build: 29 | uname -a 30 | mkdir -p $@ 31 | deps/bpftool/src/bpftool btf dump file /sys/kernel/btf/vmlinux format c > $@/vmlinux.h 32 | $(CLANG) -g -O2 -Wall -Wextra -target bpf -D__TARGET_ARCH_x86_64 -I $@ -c tracepoint.bpf.c -o $@/tracepoint.bpf.o 33 | deps/bpftool/src/bpftool gen skeleton $@/tracepoint.bpf.o > $@/tracepoint.skel.h 34 | $(CLANG) -g -O2 -Wall -Wextra -I $@ -c tracepoint.c -o build/tracepoint.o 35 | $(CLANG) -g -O2 -Wall -Wextra $@/tracepoint.o -L$@ -lbpf -lelf -lz -o $@/tracepoint 36 | .PHONY: build 37 | 38 | test: 39 | sudo ./build/tracepoint -t 40 | 41 | clean: 42 | rm -rf build deps 43 | 44 | .PHONY: clean 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hello, BPF CO-RE! 2 | 3 | ## Trouble Shooting 4 | 5 | ### `clang` cannot compile BPF source files 6 | 7 | If you cannot build a BPF source file with the following messages: 8 | 9 | ``` 10 | build/vmlinux.h:4629:20: error: expected member name or ';' after declaration specifiers 11 | struct cgroup_bpf bpf; 12 | ^ 13 | :284:13: note: expanded from here 14 | #define bpf 1 15 | ``` 16 | 17 | Then, your `clang` could be too old. I've confirmed clang-8 cannot build BPF source files but clang-10 can do. 18 | 19 | ## References 20 | 21 | * https://www.sartura.hr/blog/simple-ebpf-core-application/ 22 | * repo: https://github.com/sartura/ebpf-hello-world 23 | * [BPF Documentation - kernel.org](https://www.kernel.org/doc/html/latest/bpf/) 24 | * [BPF CO-RE Reference Guide - nakryiko.com](https://nakryiko.com/posts/bpf-core-reference-guide/) 25 | -------------------------------------------------------------------------------- /bpf-core-availability.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eux -o pipefail 3 | 4 | KERNEL_RELEASE="$(uname -r)" 5 | 6 | grep 'CONFIG_DEBUG_INFO_BTF=' "/boot/config-$KERNEL_RELEASE" 7 | -------------------------------------------------------------------------------- /tracepoint.bpf.c: -------------------------------------------------------------------------------- 1 | #include "vmlinux.h" 2 | #include 3 | 4 | SEC("tracepoint/syscalls/sys_enter_execve") 5 | int tracepoint__syscalls__sys_enter_execve(struct trace_event_raw_sys_enter *ctx) 6 | { 7 | bpf_printk("execve %s", ctx->args[0]); 8 | return 0; 9 | } 10 | 11 | char LICENSE[] SEC("license") = "GPL"; 12 | -------------------------------------------------------------------------------- /tracepoint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "tracepoint.skel.h" 15 | 16 | void read_trace_pipe(void) 17 | { 18 | int trace_fd = open("/sys/kernel/debug/tracing/trace_pipe", O_RDONLY, 0); 19 | if (trace_fd < 0) 20 | return; 21 | 22 | while (1) { 23 | static char buf[4096]; 24 | ssize_t sz; 25 | 26 | sz = read(trace_fd, buf, sizeof(buf) - 1); 27 | if (sz > 0) { 28 | printf("%.*s", (int)sz, buf); 29 | } 30 | } 31 | } 32 | 33 | int main(int argc, char *argv[]) 34 | { 35 | bool test_mode = argc >= 2 && strcmp(argv[1], "-t") == 0; 36 | 37 | int err; 38 | 39 | struct rlimit rlim = { 40 | .rlim_cur = 512UL << 20, 41 | .rlim_max = 512UL << 20, 42 | }; 43 | err = setrlimit(RLIMIT_MEMLOCK, &rlim); 44 | if (err) { 45 | fprintf(stderr, "failed to change rlimit\n"); 46 | return 1; 47 | } 48 | 49 | struct tracepoint_bpf *obj = tracepoint_bpf__open(); 50 | if (!obj) { 51 | fprintf(stderr, "failed to open and/or load BPF object\n"); 52 | return 1; 53 | } 54 | fprintf(stderr, "BPF object opened\n"); 55 | 56 | err = tracepoint_bpf__load(obj); 57 | if (err) { 58 | fprintf(stderr, "failed to load BPF object %d\n", err); 59 | goto cleanup; 60 | } 61 | fprintf(stderr, "BPF object loaded\n"); 62 | 63 | err = tracepoint_bpf__attach(obj); 64 | if (err) { 65 | fprintf(stderr, "failed to attach BPF programs\n"); 66 | goto cleanup; 67 | } 68 | fprintf(stderr, "BPF programs attached\n"); 69 | 70 | if (!test_mode) { 71 | read_trace_pipe(); 72 | } 73 | 74 | cleanup: 75 | tracepoint_bpf__destroy(obj); 76 | fprintf(stderr, "BPF object destroyed\n"); 77 | return err != 0; 78 | } 79 | --------------------------------------------------------------------------------