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

selftests/bpf: Test bpf_link's get_next_id, get_fd_by_id, and get_obj_info

Extend bpf_obj_id selftest to verify bpf_link's observability APIs.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200429001614.1544-7-andriin@fb.com

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
2c2837b0 0dbc8668

+104 -20
+101 -9
tools/testing/selftests/bpf/prog_tests/bpf_obj_id.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 #include <test_progs.h> 3 3 4 + #define nr_iters 2 5 + 4 6 void test_bpf_obj_id(void) 5 7 { 6 8 const __u64 array_magic_value = 0xfaceb00c; 7 9 const __u32 array_key = 0; 8 - const int nr_iters = 2; 9 10 const char *file = "./test_obj_id.o"; 10 11 const char *expected_prog_name = "test_obj_id"; 11 12 const char *expected_map_name = "test_map_id"; 12 13 const __u64 nsec_per_sec = 1000000000; 13 14 14 - struct bpf_object *objs[nr_iters]; 15 + struct bpf_object *objs[nr_iters] = {}; 16 + struct bpf_link *links[nr_iters] = {}; 17 + struct bpf_program *prog; 15 18 int prog_fds[nr_iters], map_fds[nr_iters]; 16 19 /* +1 to test for the info_len returned by kernel */ 17 20 struct bpf_prog_info prog_infos[nr_iters + 1]; 18 21 struct bpf_map_info map_infos[nr_iters + 1]; 22 + struct bpf_link_info link_infos[nr_iters + 1]; 19 23 /* Each prog only uses one map. +1 to test nr_map_ids 20 24 * returned by kernel. 21 25 */ 22 26 __u32 map_ids[nr_iters + 1]; 23 - char jited_insns[128], xlated_insns[128], zeros[128]; 27 + char jited_insns[128], xlated_insns[128], zeros[128], tp_name[128]; 24 28 __u32 i, next_id, info_len, nr_id_found, duration = 0; 25 29 struct timespec real_time_ts, boot_time_ts; 26 30 int err = 0; ··· 40 36 CHECK(err >= 0 || errno != ENOENT, 41 37 "get-fd-by-notexist-map-id", "err %d errno %d\n", err, errno); 42 38 43 - for (i = 0; i < nr_iters; i++) 44 - objs[i] = NULL; 39 + err = bpf_link_get_fd_by_id(0); 40 + CHECK(err >= 0 || errno != ENOENT, 41 + "get-fd-by-notexist-link-id", "err %d errno %d\n", err, errno); 45 42 46 43 /* Check bpf_obj_get_info_by_fd() */ 47 44 bzero(zeros, sizeof(zeros)); 48 45 for (i = 0; i < nr_iters; i++) { 49 46 now = time(NULL); 50 - err = bpf_prog_load(file, BPF_PROG_TYPE_SOCKET_FILTER, 47 + err = bpf_prog_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, 51 48 &objs[i], &prog_fds[i]); 52 49 /* test_obj_id.o is a dumb prog. It should never fail 53 50 * to load. ··· 64 59 &array_magic_value, 0); 65 60 if (CHECK_FAIL(err)) 66 61 goto done; 62 + 63 + prog = bpf_object__find_program_by_title(objs[i], 64 + "raw_tp/sys_enter"); 65 + if (CHECK_FAIL(!prog)) 66 + goto done; 67 + links[i] = bpf_program__attach(prog); 68 + err = libbpf_get_error(links[i]); 69 + if (CHECK(err, "prog_attach", "prog #%d, err %d\n", i, err)) { 70 + links[i] = NULL; 71 + goto done; 72 + } 67 73 68 74 /* Check getting map info */ 69 75 info_len = sizeof(struct bpf_map_info) * 2; ··· 123 107 load_time = (real_time_ts.tv_sec - boot_time_ts.tv_sec) 124 108 + (prog_infos[i].load_time / nsec_per_sec); 125 109 if (CHECK(err || 126 - prog_infos[i].type != BPF_PROG_TYPE_SOCKET_FILTER || 110 + prog_infos[i].type != BPF_PROG_TYPE_RAW_TRACEPOINT || 127 111 info_len != sizeof(struct bpf_prog_info) || 128 112 (env.jit_enabled && !prog_infos[i].jited_prog_len) || 129 113 (env.jit_enabled && ··· 136 120 *(int *)(long)prog_infos[i].map_ids != map_infos[i].id || 137 121 strcmp((char *)prog_infos[i].name, expected_prog_name), 138 122 "get-prog-info(fd)", 139 - "err %d errno %d i %d type %d(%d) info_len %u(%zu) jit_enabled %d jited_prog_len %u xlated_prog_len %u jited_prog %d xlated_prog %d load_time %lu(%lu) uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) name %s(%s)\n", 123 + "err %d errno %d i %d type %d(%d) info_len %u(%zu) " 124 + "jit_enabled %d jited_prog_len %u xlated_prog_len %u " 125 + "jited_prog %d xlated_prog %d load_time %lu(%lu) " 126 + "uid %u(%u) nr_map_ids %u(%u) map_id %u(%u) " 127 + "name %s(%s)\n", 140 128 err, errno, i, 141 129 prog_infos[i].type, BPF_PROG_TYPE_SOCKET_FILTER, 142 130 info_len, sizeof(struct bpf_prog_info), ··· 155 135 *(int *)(long)prog_infos[i].map_ids, map_infos[i].id, 156 136 prog_infos[i].name, expected_prog_name)) 157 137 goto done; 138 + 139 + /* Check getting link info */ 140 + info_len = sizeof(struct bpf_link_info) * 2; 141 + bzero(&link_infos[i], info_len); 142 + link_infos[i].raw_tracepoint.tp_name = (__u64)&tp_name; 143 + link_infos[i].raw_tracepoint.tp_name_len = sizeof(tp_name); 144 + err = bpf_obj_get_info_by_fd(bpf_link__fd(links[i]), 145 + &link_infos[i], &info_len); 146 + if (CHECK(err || 147 + link_infos[i].type != BPF_LINK_TYPE_RAW_TRACEPOINT || 148 + link_infos[i].prog_id != prog_infos[i].id || 149 + link_infos[i].raw_tracepoint.tp_name != (__u64)&tp_name || 150 + strcmp((char *)link_infos[i].raw_tracepoint.tp_name, 151 + "sys_enter") || 152 + info_len != sizeof(struct bpf_link_info), 153 + "get-link-info(fd)", 154 + "err %d errno %d info_len %u(%zu) type %d(%d) id %d " 155 + "prog_id %d (%d) tp_name %s(%s)\n", 156 + err, errno, 157 + info_len, sizeof(struct bpf_link_info), 158 + link_infos[i].type, BPF_LINK_TYPE_RAW_TRACEPOINT, 159 + link_infos[i].id, 160 + link_infos[i].prog_id, prog_infos[i].id, 161 + (char *)link_infos[i].raw_tracepoint.tp_name, 162 + "sys_enter")) 163 + goto done; 164 + 158 165 } 159 166 160 167 /* Check bpf_prog_get_next_id() */ ··· 294 247 "nr_id_found %u(%u)\n", 295 248 nr_id_found, nr_iters); 296 249 250 + /* Check bpf_link_get_next_id() */ 251 + nr_id_found = 0; 252 + next_id = 0; 253 + while (!bpf_link_get_next_id(next_id, &next_id)) { 254 + struct bpf_link_info link_info; 255 + int link_fd, cmp_res; 256 + 257 + info_len = sizeof(link_info); 258 + memset(&link_info, 0, info_len); 259 + 260 + link_fd = bpf_link_get_fd_by_id(next_id); 261 + if (link_fd < 0 && errno == ENOENT) 262 + /* The bpf_link is in the dead row */ 263 + continue; 264 + if (CHECK(link_fd < 0, "get-link-fd(next_id)", 265 + "link_fd %d next_id %u errno %d\n", 266 + link_fd, next_id, errno)) 267 + break; 268 + 269 + for (i = 0; i < nr_iters; i++) 270 + if (link_infos[i].id == next_id) 271 + break; 272 + 273 + if (i == nr_iters) 274 + continue; 275 + 276 + nr_id_found++; 277 + 278 + err = bpf_obj_get_info_by_fd(link_fd, &link_info, &info_len); 279 + cmp_res = memcmp(&link_info, &link_infos[i], 280 + offsetof(struct bpf_link_info, raw_tracepoint)); 281 + CHECK(err || info_len != sizeof(link_info) || cmp_res, 282 + "check get-link-info(next_id->fd)", 283 + "err %d errno %d info_len %u(%zu) memcmp %d\n", 284 + err, errno, info_len, sizeof(struct bpf_link_info), 285 + cmp_res); 286 + 287 + close(link_fd); 288 + } 289 + CHECK(nr_id_found != nr_iters, 290 + "check total link id found by get_next_id", 291 + "nr_id_found %u(%u)\n", nr_id_found, nr_iters); 292 + 297 293 done: 298 - for (i = 0; i < nr_iters; i++) 294 + for (i = 0; i < nr_iters; i++) { 295 + bpf_link__destroy(links[i]); 299 296 bpf_object__close(objs[i]); 297 + } 300 298 }
+3 -11
tools/testing/selftests/bpf/progs/test_obj_id.c
··· 3 3 */ 4 4 #include <stddef.h> 5 5 #include <linux/bpf.h> 6 - #include <linux/pkt_cls.h> 7 6 #include <bpf/bpf_helpers.h> 8 - 9 - /* It is a dumb bpf program such that it must have no 10 - * issue to be loaded since testing the verifier is 11 - * not the focus here. 12 - */ 13 - 14 - int _version SEC("version") = 1; 15 7 16 8 struct { 17 9 __uint(type, BPF_MAP_TYPE_ARRAY); ··· 12 20 __type(value, __u64); 13 21 } test_map_id SEC(".maps"); 14 22 15 - SEC("test_obj_id_dummy") 16 - int test_obj_id(struct __sk_buff *skb) 23 + SEC("raw_tp/sys_enter") 24 + int test_obj_id(void *ctx) 17 25 { 18 26 __u32 key = 0; 19 27 __u64 *value; 20 28 21 29 value = bpf_map_lookup_elem(&test_map_id, &key); 22 30 23 - return TC_ACT_OK; 31 + return 0; 24 32 }