Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

samples, bpf: Refactor kprobe tracing user progs with libbpf

Currently, the kprobe BPF program attachment method for bpf_load is
quite old. The implementation of bpf_load "directly" controls and
manages(create, delete) the kprobe events of DEBUGFS. On the other hand,
using using the libbpf automatically manages the kprobe event.
(under bpf_link interface)

By calling bpf_program__attach(_kprobe) in libbpf, the corresponding
kprobe is created and the BPF program will be attached to this kprobe.
To remove this, by simply invoking bpf_link__destroy will clean up the
event.

This commit refactors kprobe tracing programs (tracex{1~7}_user.c) with
libbpf using bpf_link interface and bpf_program__attach.

tracex2_kern.c, which tracks system calls (sys_*), has been modified to
append prefix depending on architecture.

Signed-off-by: Daniel T. Lee <danieltimlee@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20200516040608.1377876-3-danieltimlee@gmail.com

authored by

Daniel T. Lee and committed by
Daniel Borkmann
63841bc0 0efdcefb

+253 -65
+6 -6
samples/bpf/Makefile
··· 64 64 sockex1-objs := sockex1_user.o 65 65 sockex2-objs := sockex2_user.o 66 66 sockex3-objs := bpf_load.o sockex3_user.o 67 - tracex1-objs := bpf_load.o tracex1_user.o $(TRACE_HELPERS) 68 - tracex2-objs := bpf_load.o tracex2_user.o 69 - tracex3-objs := bpf_load.o tracex3_user.o 70 - tracex4-objs := bpf_load.o tracex4_user.o 67 + tracex1-objs := tracex1_user.o $(TRACE_HELPERS) 68 + tracex2-objs := tracex2_user.o 69 + tracex3-objs := tracex3_user.o 70 + tracex4-objs := tracex4_user.o 71 71 tracex5-objs := bpf_load.o tracex5_user.o $(TRACE_HELPERS) 72 - tracex6-objs := bpf_load.o tracex6_user.o 73 - tracex7-objs := bpf_load.o tracex7_user.o 72 + tracex6-objs := tracex6_user.o 73 + tracex7-objs := tracex7_user.o 74 74 test_probe_write_user-objs := bpf_load.o test_probe_write_user_user.o 75 75 trace_output-objs := bpf_load.o trace_output_user.o $(TRACE_HELPERS) 76 76 lathist-objs := bpf_load.o lathist_user.o
+13
samples/bpf/trace_common.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #ifndef __TRACE_COMMON_H 3 + #define __TRACE_COMMON_H 4 + 5 + #ifdef __x86_64__ 6 + #define SYSCALL(SYS) "__x64_" __stringify(SYS) 7 + #elif defined(__s390x__) 8 + #define SYSCALL(SYS) "__s390x_" __stringify(SYS) 9 + #else 10 + #define SYSCALL(SYS) __stringify(SYS) 11 + #endif 12 + 13 + #endif
+30 -7
samples/bpf/tracex1_user.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #include <stdio.h> 3 - #include <linux/bpf.h> 4 3 #include <unistd.h> 5 - #include <bpf/bpf.h> 6 - #include "bpf_load.h" 4 + #include <bpf/libbpf.h> 7 5 #include "trace_helpers.h" 8 6 9 7 int main(int ac, char **argv) 10 8 { 11 - FILE *f; 9 + struct bpf_link *link = NULL; 10 + struct bpf_program *prog; 11 + struct bpf_object *obj; 12 12 char filename[256]; 13 + FILE *f; 13 14 14 15 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 16 + obj = bpf_object__open_file(filename, NULL); 17 + if (libbpf_get_error(obj)) { 18 + fprintf(stderr, "ERROR: opening BPF object file failed\n"); 19 + return 0; 20 + } 15 21 16 - if (load_bpf_file(filename)) { 17 - printf("%s", bpf_log_buf); 18 - return 1; 22 + prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); 23 + if (!prog) { 24 + fprintf(stderr, "ERROR: finding a prog in obj file failed\n"); 25 + goto cleanup; 26 + } 27 + 28 + /* load BPF program */ 29 + if (bpf_object__load(obj)) { 30 + fprintf(stderr, "ERROR: loading BPF object file failed\n"); 31 + goto cleanup; 32 + } 33 + 34 + link = bpf_program__attach(prog); 35 + if (libbpf_get_error(link)) { 36 + fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 37 + link = NULL; 38 + goto cleanup; 19 39 } 20 40 21 41 f = popen("taskset 1 ping -c5 localhost", "r"); ··· 43 23 44 24 read_trace_pipe(); 45 25 26 + cleanup: 27 + bpf_link__destroy(link); 28 + bpf_object__close(obj); 46 29 return 0; 47 30 }
+2 -1
samples/bpf/tracex2_kern.c
··· 10 10 #include <uapi/linux/bpf.h> 11 11 #include <bpf/bpf_helpers.h> 12 12 #include <bpf/bpf_tracing.h> 13 + #include "trace_common.h" 13 14 14 15 struct bpf_map_def SEC("maps") my_map = { 15 16 .type = BPF_MAP_TYPE_HASH, ··· 78 77 .max_entries = 1024, 79 78 }; 80 79 81 - SEC("kprobe/sys_write") 80 + SEC("kprobe/" SYSCALL(sys_write)) 82 81 int bpf_prog3(struct pt_regs *ctx) 83 82 { 84 83 long write_size = PT_REGS_PARM3(ctx);
+42 -9
samples/bpf/tracex2_user.c
··· 3 3 #include <unistd.h> 4 4 #include <stdlib.h> 5 5 #include <signal.h> 6 - #include <linux/bpf.h> 7 6 #include <string.h> 8 7 #include <sys/resource.h> 9 8 10 9 #include <bpf/bpf.h> 11 - #include "bpf_load.h" 10 + #include <bpf/libbpf.h> 12 11 #include "bpf_util.h" 13 12 14 13 #define MAX_INDEX 64 15 14 #define MAX_STARS 38 15 + 16 + /* my_map, my_hist_map */ 17 + static int map_fd[2]; 16 18 17 19 static void stars(char *str, long val, long max, int width) 18 20 { ··· 117 115 int main(int ac, char **argv) 118 116 { 119 117 struct rlimit r = {1024*1024, RLIM_INFINITY}; 120 - char filename[256]; 121 118 long key, next_key, value; 119 + struct bpf_link *links[2]; 120 + struct bpf_program *prog; 121 + struct bpf_object *obj; 122 + char filename[256]; 123 + int i, j = 0; 122 124 FILE *f; 123 - int i; 124 - 125 - snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 126 125 127 126 if (setrlimit(RLIMIT_MEMLOCK, &r)) { 128 127 perror("setrlimit(RLIMIT_MEMLOCK)"); 129 128 return 1; 129 + } 130 + 131 + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 132 + obj = bpf_object__open_file(filename, NULL); 133 + if (libbpf_get_error(obj)) { 134 + fprintf(stderr, "ERROR: opening BPF object file failed\n"); 135 + return 0; 136 + } 137 + 138 + /* load BPF program */ 139 + if (bpf_object__load(obj)) { 140 + fprintf(stderr, "ERROR: loading BPF object file failed\n"); 141 + goto cleanup; 142 + } 143 + 144 + map_fd[0] = bpf_object__find_map_fd_by_name(obj, "my_map"); 145 + map_fd[1] = bpf_object__find_map_fd_by_name(obj, "my_hist_map"); 146 + if (map_fd[0] < 0 || map_fd[1] < 0) { 147 + fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 148 + goto cleanup; 130 149 } 131 150 132 151 signal(SIGINT, int_exit); ··· 161 138 f = popen("dd if=/dev/zero of=/dev/null count=5000000", "r"); 162 139 (void) f; 163 140 164 - if (load_bpf_file(filename)) { 165 - printf("%s", bpf_log_buf); 166 - return 1; 141 + bpf_object__for_each_program(prog, obj) { 142 + links[j] = bpf_program__attach(prog); 143 + if (libbpf_get_error(links[j])) { 144 + fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 145 + links[j] = NULL; 146 + goto cleanup; 147 + } 148 + j++; 167 149 } 168 150 169 151 for (i = 0; i < 5; i++) { ··· 184 156 } 185 157 print_hist(map_fd[1]); 186 158 159 + cleanup: 160 + for (j--; j >= 0; j--) 161 + bpf_link__destroy(links[j]); 162 + 163 + bpf_object__close(obj); 187 164 return 0; 188 165 }
+45 -16
samples/bpf/tracex3_user.c
··· 7 7 #include <unistd.h> 8 8 #include <stdbool.h> 9 9 #include <string.h> 10 - #include <linux/bpf.h> 11 10 #include <sys/resource.h> 12 11 13 12 #include <bpf/bpf.h> 14 - #include "bpf_load.h" 13 + #include <bpf/libbpf.h> 15 14 #include "bpf_util.h" 16 15 17 16 #define SLOTS 100 ··· 108 109 int main(int ac, char **argv) 109 110 { 110 111 struct rlimit r = {1024*1024, RLIM_INFINITY}; 112 + struct bpf_link *links[2]; 113 + struct bpf_program *prog; 114 + struct bpf_object *obj; 111 115 char filename[256]; 112 - int i; 113 - 114 - snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 115 - 116 - if (setrlimit(RLIMIT_MEMLOCK, &r)) { 117 - perror("setrlimit(RLIMIT_MEMLOCK)"); 118 - return 1; 119 - } 120 - 121 - if (load_bpf_file(filename)) { 122 - printf("%s", bpf_log_buf); 123 - return 1; 124 - } 116 + int map_fd, i, j = 0; 125 117 126 118 for (i = 1; i < ac; i++) { 127 119 if (strcmp(argv[i], "-a") == 0) { ··· 125 135 " -t text only\n"); 126 136 return 1; 127 137 } 138 + } 139 + 140 + if (setrlimit(RLIMIT_MEMLOCK, &r)) { 141 + perror("setrlimit(RLIMIT_MEMLOCK)"); 142 + return 1; 143 + } 144 + 145 + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 146 + obj = bpf_object__open_file(filename, NULL); 147 + if (libbpf_get_error(obj)) { 148 + fprintf(stderr, "ERROR: opening BPF object file failed\n"); 149 + return 0; 150 + } 151 + 152 + /* load BPF program */ 153 + if (bpf_object__load(obj)) { 154 + fprintf(stderr, "ERROR: loading BPF object file failed\n"); 155 + goto cleanup; 156 + } 157 + 158 + map_fd = bpf_object__find_map_fd_by_name(obj, "lat_map"); 159 + if (map_fd < 0) { 160 + fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 161 + goto cleanup; 162 + } 163 + 164 + bpf_object__for_each_program(prog, obj) { 165 + links[j] = bpf_program__attach(prog); 166 + if (libbpf_get_error(links[j])) { 167 + fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 168 + links[j] = NULL; 169 + goto cleanup; 170 + } 171 + j++; 128 172 } 129 173 130 174 printf(" heatmap of IO latency\n"); ··· 177 153 for (i = 0; ; i++) { 178 154 if (i % 20 == 0) 179 155 print_banner(); 180 - print_hist(map_fd[1]); 156 + print_hist(map_fd); 181 157 sleep(2); 182 158 } 183 159 160 + cleanup: 161 + for (j--; j >= 0; j--) 162 + bpf_link__destroy(links[j]); 163 + 164 + bpf_object__close(obj); 184 165 return 0; 185 166 }
+40 -11
samples/bpf/tracex4_user.c
··· 8 8 #include <stdbool.h> 9 9 #include <string.h> 10 10 #include <time.h> 11 - #include <linux/bpf.h> 12 11 #include <sys/resource.h> 13 12 14 13 #include <bpf/bpf.h> 15 - #include "bpf_load.h" 14 + #include <bpf/libbpf.h> 16 15 17 16 struct pair { 18 17 long long val; ··· 35 36 key = write(1, "\e[1;1H\e[2J", 12); /* clear screen */ 36 37 37 38 key = -1; 38 - while (bpf_map_get_next_key(map_fd[0], &key, &next_key) == 0) { 39 - bpf_map_lookup_elem(map_fd[0], &next_key, &v); 39 + while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { 40 + bpf_map_lookup_elem(fd, &next_key, &v); 40 41 key = next_key; 41 42 if (val - v.val < 1000000000ll) 42 43 /* object was allocated more then 1 sec ago */ ··· 49 50 int main(int ac, char **argv) 50 51 { 51 52 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 53 + struct bpf_link *links[2]; 54 + struct bpf_program *prog; 55 + struct bpf_object *obj; 52 56 char filename[256]; 53 - int i; 54 - 55 - snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 57 + int map_fd, i, j = 0; 56 58 57 59 if (setrlimit(RLIMIT_MEMLOCK, &r)) { 58 60 perror("setrlimit(RLIMIT_MEMLOCK, RLIM_INFINITY)"); 59 61 return 1; 60 62 } 61 63 62 - if (load_bpf_file(filename)) { 63 - printf("%s", bpf_log_buf); 64 - return 1; 64 + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 65 + obj = bpf_object__open_file(filename, NULL); 66 + if (libbpf_get_error(obj)) { 67 + fprintf(stderr, "ERROR: opening BPF object file failed\n"); 68 + return 0; 69 + } 70 + 71 + /* load BPF program */ 72 + if (bpf_object__load(obj)) { 73 + fprintf(stderr, "ERROR: loading BPF object file failed\n"); 74 + goto cleanup; 75 + } 76 + 77 + map_fd = bpf_object__find_map_fd_by_name(obj, "my_map"); 78 + if (map_fd < 0) { 79 + fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 80 + goto cleanup; 81 + } 82 + 83 + bpf_object__for_each_program(prog, obj) { 84 + links[j] = bpf_program__attach(prog); 85 + if (libbpf_get_error(links[j])) { 86 + fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 87 + links[j] = NULL; 88 + goto cleanup; 89 + } 90 + j++; 65 91 } 66 92 67 93 for (i = 0; ; i++) { 68 - print_old_objects(map_fd[1]); 94 + print_old_objects(map_fd); 69 95 sleep(1); 70 96 } 71 97 98 + cleanup: 99 + for (j--; j >= 0; j--) 100 + bpf_link__destroy(links[j]); 101 + 102 + bpf_object__close(obj); 72 103 return 0; 73 104 }
+44 -7
samples/bpf/tracex6_user.c
··· 4 4 #include <assert.h> 5 5 #include <fcntl.h> 6 6 #include <linux/perf_event.h> 7 - #include <linux/bpf.h> 8 7 #include <sched.h> 9 8 #include <stdio.h> 10 9 #include <stdlib.h> ··· 14 15 #include <sys/wait.h> 15 16 #include <unistd.h> 16 17 17 - #include "bpf_load.h" 18 18 #include <bpf/bpf.h> 19 + #include <bpf/libbpf.h> 19 20 #include "perf-sys.h" 20 21 21 22 #define SAMPLE_PERIOD 0x7fffffffffffffffULL 23 + 24 + /* counters, values, values2 */ 25 + static int map_fd[3]; 22 26 23 27 static void check_on_cpu(int cpu, struct perf_event_attr *attr) 24 28 { ··· 176 174 int main(int argc, char **argv) 177 175 { 178 176 struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; 177 + struct bpf_link *links[2]; 178 + struct bpf_program *prog; 179 + struct bpf_object *obj; 179 180 char filename[256]; 180 - 181 - snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 181 + int i = 0; 182 182 183 183 setrlimit(RLIMIT_MEMLOCK, &r); 184 - if (load_bpf_file(filename)) { 185 - printf("%s", bpf_log_buf); 186 - return 1; 184 + 185 + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 186 + obj = bpf_object__open_file(filename, NULL); 187 + if (libbpf_get_error(obj)) { 188 + fprintf(stderr, "ERROR: opening BPF object file failed\n"); 189 + return 0; 190 + } 191 + 192 + /* load BPF program */ 193 + if (bpf_object__load(obj)) { 194 + fprintf(stderr, "ERROR: loading BPF object file failed\n"); 195 + goto cleanup; 196 + } 197 + 198 + map_fd[0] = bpf_object__find_map_fd_by_name(obj, "counters"); 199 + map_fd[1] = bpf_object__find_map_fd_by_name(obj, "values"); 200 + map_fd[2] = bpf_object__find_map_fd_by_name(obj, "values2"); 201 + if (map_fd[0] < 0 || map_fd[1] < 0 || map_fd[2] < 0) { 202 + fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 203 + goto cleanup; 204 + } 205 + 206 + bpf_object__for_each_program(prog, obj) { 207 + links[i] = bpf_program__attach(prog); 208 + if (libbpf_get_error(links[i])) { 209 + fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 210 + links[i] = NULL; 211 + goto cleanup; 212 + } 213 + i++; 187 214 } 188 215 189 216 test_bpf_perf_event(); 217 + 218 + cleanup: 219 + for (i--; i >= 0; i--) 220 + bpf_link__destroy(links[i]); 221 + 222 + bpf_object__close(obj); 190 223 return 0; 191 224 }
+31 -8
samples/bpf/tracex7_user.c
··· 1 1 #define _GNU_SOURCE 2 2 3 3 #include <stdio.h> 4 - #include <linux/bpf.h> 5 4 #include <unistd.h> 6 - #include <bpf/bpf.h> 7 - #include "bpf_load.h" 5 + #include <bpf/libbpf.h> 8 6 9 7 int main(int argc, char **argv) 10 8 { 11 - FILE *f; 9 + struct bpf_link *link = NULL; 10 + struct bpf_program *prog; 11 + struct bpf_object *obj; 12 12 char filename[256]; 13 13 char command[256]; 14 - int ret; 14 + int ret = 0; 15 + FILE *f; 15 16 16 17 snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); 18 + obj = bpf_object__open_file(filename, NULL); 19 + if (libbpf_get_error(obj)) { 20 + fprintf(stderr, "ERROR: opening BPF object file failed\n"); 21 + return 0; 22 + } 17 23 18 - if (load_bpf_file(filename)) { 19 - printf("%s", bpf_log_buf); 20 - return 1; 24 + prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); 25 + if (!prog) { 26 + fprintf(stderr, "ERROR: finding a prog in obj file failed\n"); 27 + goto cleanup; 28 + } 29 + 30 + /* load BPF program */ 31 + if (bpf_object__load(obj)) { 32 + fprintf(stderr, "ERROR: loading BPF object file failed\n"); 33 + goto cleanup; 34 + } 35 + 36 + link = bpf_program__attach(prog); 37 + if (libbpf_get_error(link)) { 38 + fprintf(stderr, "ERROR: bpf_program__attach failed\n"); 39 + link = NULL; 40 + goto cleanup; 21 41 } 22 42 23 43 snprintf(command, 256, "mount %s tmpmnt/", argv[1]); 24 44 f = popen(command, "r"); 25 45 ret = pclose(f); 26 46 47 + cleanup: 48 + bpf_link__destroy(link); 49 + bpf_object__close(obj); 27 50 return ret ? 0 : 1; 28 51 }