1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Facebook */
3 #include <test_progs.h>
4 #include <network_helpers.h>
5 #include <bpf/btf.h>
6 #include "bind4_prog.skel.h"
7 #include "freplace_progmap.skel.h"
8 #include "fentry_sleepable.skel.h"
9 #include "xdp_dummy.skel.h"
10
11 typedef int (*test_cb)(struct bpf_object *obj);
12
check_data_map(struct bpf_object * obj,int prog_cnt,bool reset)13 static int check_data_map(struct bpf_object *obj, int prog_cnt, bool reset)
14 {
15 struct bpf_map *data_map = NULL, *map;
16 __u64 *result = NULL;
17 const int zero = 0;
18 __u32 duration = 0;
19 int ret = -1, i;
20
21 result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));
22 if (CHECK(!result, "alloc_memory", "failed to alloc memory"))
23 return -ENOMEM;
24
25 bpf_object__for_each_map(map, obj)
26 if (bpf_map__is_internal(map)) {
27 data_map = map;
28 break;
29 }
30 if (CHECK(!data_map, "find_data_map", "data map not found\n"))
31 goto out;
32
33 ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
34 if (CHECK(ret, "get_result",
35 "failed to get output data: %d\n", ret))
36 goto out;
37
38 for (i = 0; i < prog_cnt; i++) {
39 if (CHECK(result[i] != 1, "result",
40 "fexit_bpf2bpf result[%d] failed err %llu\n",
41 i, result[i]))
42 goto out;
43 result[i] = 0;
44 }
45 if (reset) {
46 ret = bpf_map_update_elem(bpf_map__fd(data_map), &zero, result, 0);
47 if (CHECK(ret, "reset_result", "failed to reset result\n"))
48 goto out;
49 }
50
51 ret = 0;
52 out:
53 free(result);
54 return ret;
55 }
56
test_fexit_bpf2bpf_common(const char * obj_file,const char * target_obj_file,int prog_cnt,const char ** prog_name,bool run_prog,test_cb cb)57 static void test_fexit_bpf2bpf_common(const char *obj_file,
58 const char *target_obj_file,
59 int prog_cnt,
60 const char **prog_name,
61 bool run_prog,
62 test_cb cb)
63 {
64 struct bpf_object *obj = NULL, *tgt_obj;
65 __u32 tgt_prog_id, info_len;
66 struct bpf_prog_info prog_info = {};
67 struct bpf_program **prog = NULL, *p;
68 struct bpf_link **link = NULL;
69 int err, tgt_fd, i;
70 struct btf *btf;
71 LIBBPF_OPTS(bpf_test_run_opts, topts,
72 .data_in = &pkt_v6,
73 .data_size_in = sizeof(pkt_v6),
74 .repeat = 1,
75 );
76
77 err = bpf_prog_test_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
78 &tgt_obj, &tgt_fd);
79 if (!ASSERT_OK(err, "tgt_prog_load"))
80 return;
81
82 info_len = sizeof(prog_info);
83 err = bpf_prog_get_info_by_fd(tgt_fd, &prog_info, &info_len);
84 if (!ASSERT_OK(err, "tgt_fd_get_info"))
85 goto close_prog;
86
87 tgt_prog_id = prog_info.id;
88 btf = bpf_object__btf(tgt_obj);
89
90 link = calloc(sizeof(struct bpf_link *), prog_cnt);
91 if (!ASSERT_OK_PTR(link, "link_ptr"))
92 goto close_prog;
93
94 prog = calloc(sizeof(struct bpf_program *), prog_cnt);
95 if (!ASSERT_OK_PTR(prog, "prog_ptr"))
96 goto close_prog;
97
98 obj = bpf_object__open_file(obj_file, NULL);
99 if (!ASSERT_OK_PTR(obj, "obj_open"))
100 goto close_prog;
101
102 bpf_object__for_each_program(p, obj) {
103 err = bpf_program__set_attach_target(p, tgt_fd, NULL);
104 ASSERT_OK(err, "set_attach_target");
105 }
106
107 err = bpf_object__load(obj);
108 if (!ASSERT_OK(err, "obj_load"))
109 goto close_prog;
110
111 for (i = 0; i < prog_cnt; i++) {
112 struct bpf_link_info link_info;
113 struct bpf_program *pos;
114 const char *pos_sec_name;
115 const char *tgt_name;
116 __s32 btf_id;
117
118 tgt_name = strstr(prog_name[i], "/");
119 if (!ASSERT_OK_PTR(tgt_name, "tgt_name"))
120 goto close_prog;
121 btf_id = btf__find_by_name_kind(btf, tgt_name + 1, BTF_KIND_FUNC);
122
123 prog[i] = NULL;
124 bpf_object__for_each_program(pos, obj) {
125 pos_sec_name = bpf_program__section_name(pos);
126 if (pos_sec_name && !strcmp(pos_sec_name, prog_name[i])) {
127 prog[i] = pos;
128 break;
129 }
130 }
131 if (!ASSERT_OK_PTR(prog[i], prog_name[i]))
132 goto close_prog;
133
134 link[i] = bpf_program__attach_trace(prog[i]);
135 if (!ASSERT_OK_PTR(link[i], "attach_trace"))
136 goto close_prog;
137
138 info_len = sizeof(link_info);
139 memset(&link_info, 0, sizeof(link_info));
140 err = bpf_link_get_info_by_fd(bpf_link__fd(link[i]),
141 &link_info, &info_len);
142 ASSERT_OK(err, "link_fd_get_info");
143 ASSERT_EQ(link_info.tracing.attach_type,
144 bpf_program__expected_attach_type(prog[i]),
145 "link_attach_type");
146 ASSERT_EQ(link_info.tracing.target_obj_id, tgt_prog_id, "link_tgt_obj_id");
147 ASSERT_EQ(link_info.tracing.target_btf_id, btf_id, "link_tgt_btf_id");
148 }
149
150 if (cb) {
151 err = cb(obj);
152 if (err)
153 goto close_prog;
154 }
155
156 if (!run_prog)
157 goto close_prog;
158
159 err = bpf_prog_test_run_opts(tgt_fd, &topts);
160 ASSERT_OK(err, "prog_run");
161 ASSERT_EQ(topts.retval, 0, "prog_run_ret");
162
163 if (check_data_map(obj, prog_cnt, false))
164 goto close_prog;
165
166 close_prog:
167 for (i = 0; i < prog_cnt; i++)
168 bpf_link__destroy(link[i]);
169 bpf_object__close(obj);
170 bpf_object__close(tgt_obj);
171 free(link);
172 free(prog);
173 }
174
test_target_no_callees(void)175 static void test_target_no_callees(void)
176 {
177 const char *prog_name[] = {
178 "fexit/test_pkt_md_access",
179 };
180 test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.bpf.o",
181 "./test_pkt_md_access.bpf.o",
182 ARRAY_SIZE(prog_name),
183 prog_name, true, NULL);
184 }
185
test_target_yes_callees(void)186 static void test_target_yes_callees(void)
187 {
188 const char *prog_name[] = {
189 "fexit/test_pkt_access",
190 "fexit/test_pkt_access_subprog1",
191 "fexit/test_pkt_access_subprog2",
192 "fexit/test_pkt_access_subprog3",
193 };
194 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.bpf.o",
195 "./test_pkt_access.bpf.o",
196 ARRAY_SIZE(prog_name),
197 prog_name, true, NULL);
198 }
199
test_func_replace(void)200 static void test_func_replace(void)
201 {
202 const char *prog_name[] = {
203 "fexit/test_pkt_access",
204 "fexit/test_pkt_access_subprog1",
205 "fexit/test_pkt_access_subprog2",
206 "fexit/test_pkt_access_subprog3",
207 "freplace/get_skb_len",
208 "freplace/get_skb_ifindex",
209 "freplace/get_constant",
210 "freplace/test_pkt_write_access_subprog",
211 };
212 test_fexit_bpf2bpf_common("./fexit_bpf2bpf.bpf.o",
213 "./test_pkt_access.bpf.o",
214 ARRAY_SIZE(prog_name),
215 prog_name, true, NULL);
216 }
217
test_func_replace_verify(void)218 static void test_func_replace_verify(void)
219 {
220 const char *prog_name[] = {
221 "freplace/do_bind",
222 };
223 test_fexit_bpf2bpf_common("./freplace_connect4.bpf.o",
224 "./connect4_prog.bpf.o",
225 ARRAY_SIZE(prog_name),
226 prog_name, false, NULL);
227 }
228
test_second_attach(struct bpf_object * obj)229 static int test_second_attach(struct bpf_object *obj)
230 {
231 const char *prog_name = "security_new_get_constant";
232 const char *tgt_name = "get_constant";
233 const char *tgt_obj_file = "./test_pkt_access.bpf.o";
234 struct bpf_program *prog = NULL;
235 struct bpf_object *tgt_obj;
236 struct bpf_link *link;
237 int err = 0, tgt_fd;
238 LIBBPF_OPTS(bpf_test_run_opts, topts,
239 .data_in = &pkt_v6,
240 .data_size_in = sizeof(pkt_v6),
241 .repeat = 1,
242 );
243
244 prog = bpf_object__find_program_by_name(obj, prog_name);
245 if (!ASSERT_OK_PTR(prog, "find_prog"))
246 return -ENOENT;
247
248 err = bpf_prog_test_load(tgt_obj_file, BPF_PROG_TYPE_UNSPEC,
249 &tgt_obj, &tgt_fd);
250 if (!ASSERT_OK(err, "second_prog_load"))
251 return err;
252
253 link = bpf_program__attach_freplace(prog, tgt_fd, tgt_name);
254 if (!ASSERT_OK_PTR(link, "second_link"))
255 goto out;
256
257 err = bpf_prog_test_run_opts(tgt_fd, &topts);
258 if (!ASSERT_OK(err, "ipv6 test_run"))
259 goto out;
260 if (!ASSERT_OK(topts.retval, "ipv6 retval"))
261 goto out;
262
263 err = check_data_map(obj, 1, true);
264 if (err)
265 goto out;
266
267 out:
268 bpf_link__destroy(link);
269 bpf_object__close(tgt_obj);
270 return err;
271 }
272
test_func_replace_multi(void)273 static void test_func_replace_multi(void)
274 {
275 const char *prog_name[] = {
276 "freplace/get_constant",
277 };
278 test_fexit_bpf2bpf_common("./freplace_get_constant.bpf.o",
279 "./test_pkt_access.bpf.o",
280 ARRAY_SIZE(prog_name),
281 prog_name, true, test_second_attach);
282 }
283
test_fmod_ret_freplace(void)284 static void test_fmod_ret_freplace(void)
285 {
286 struct bpf_object *freplace_obj = NULL, *pkt_obj, *fmod_obj = NULL;
287 const char *freplace_name = "./freplace_get_constant.bpf.o";
288 const char *fmod_ret_name = "./fmod_ret_freplace.bpf.o";
289 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
290 const char *tgt_name = "./test_pkt_access.bpf.o";
291 struct bpf_link *freplace_link = NULL;
292 struct bpf_program *prog;
293 __u32 duration = 0;
294 int err, pkt_fd, attach_prog_fd;
295
296 err = bpf_prog_test_load(tgt_name, BPF_PROG_TYPE_UNSPEC,
297 &pkt_obj, &pkt_fd);
298 /* the target prog should load fine */
299 if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
300 tgt_name, err, errno))
301 return;
302
303 freplace_obj = bpf_object__open_file(freplace_name, NULL);
304 if (!ASSERT_OK_PTR(freplace_obj, "freplace_obj_open"))
305 goto out;
306
307 prog = bpf_object__next_program(freplace_obj, NULL);
308 err = bpf_program__set_attach_target(prog, pkt_fd, NULL);
309 ASSERT_OK(err, "freplace__set_attach_target");
310
311 err = bpf_object__load(freplace_obj);
312 if (CHECK(err, "freplace_obj_load", "err %d\n", err))
313 goto out;
314
315 freplace_link = bpf_program__attach_trace(prog);
316 if (!ASSERT_OK_PTR(freplace_link, "freplace_attach_trace"))
317 goto out;
318
319 fmod_obj = bpf_object__open_file(fmod_ret_name, NULL);
320 if (!ASSERT_OK_PTR(fmod_obj, "fmod_obj_open"))
321 goto out;
322
323 attach_prog_fd = bpf_program__fd(prog);
324 prog = bpf_object__next_program(fmod_obj, NULL);
325 err = bpf_program__set_attach_target(prog, attach_prog_fd, NULL);
326 ASSERT_OK(err, "fmod_ret_set_attach_target");
327
328 err = bpf_object__load(fmod_obj);
329 if (CHECK(!err, "fmod_obj_load", "loading fmod_ret should fail\n"))
330 goto out;
331
332 out:
333 bpf_link__destroy(freplace_link);
334 bpf_object__close(freplace_obj);
335 bpf_object__close(fmod_obj);
336 bpf_object__close(pkt_obj);
337 }
338
test_func_replace_void(void)339 static void test_func_replace_void(void)
340 {
341 const char *prog_name[] = {
342 "freplace/foo",
343 };
344 test_fexit_bpf2bpf_common("./freplace_void.bpf.o",
345 "./test_global_func7.bpf.o",
346 ARRAY_SIZE(prog_name),
347 prog_name, false, NULL);
348 }
349
test_obj_load_failure_common(const char * obj_file,const char * target_obj_file,const char * exp_msg)350 static void test_obj_load_failure_common(const char *obj_file,
351 const char *target_obj_file,
352 const char *exp_msg)
353 {
354 /*
355 * standalone test that asserts failure to load freplace prog
356 * because of invalid return code.
357 */
358 struct bpf_object *obj = NULL, *pkt_obj;
359 struct bpf_program *prog;
360 char log_buf[64 * 1024];
361 int err, pkt_fd;
362 __u32 duration = 0;
363
364 err = bpf_prog_test_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
365 &pkt_obj, &pkt_fd);
366 /* the target prog should load fine */
367 if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
368 target_obj_file, err, errno))
369 return;
370
371 obj = bpf_object__open_file(obj_file, NULL);
372 if (!ASSERT_OK_PTR(obj, "obj_open"))
373 goto close_prog;
374
375 prog = bpf_object__next_program(obj, NULL);
376 err = bpf_program__set_attach_target(prog, pkt_fd, NULL);
377 ASSERT_OK(err, "set_attach_target");
378
379 log_buf[0] = '\0';
380 if (exp_msg)
381 bpf_program__set_log_buf(prog, log_buf, sizeof(log_buf));
382 if (env.verbosity > VERBOSE_NONE)
383 bpf_program__set_log_level(prog, 2);
384
385 /* It should fail to load the program */
386 err = bpf_object__load(obj);
387 if (env.verbosity > VERBOSE_NONE && exp_msg) /* we overtook log */
388 printf("VERIFIER LOG:\n================\n%s\n================\n", log_buf);
389 if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err))
390 goto close_prog;
391
392 if (exp_msg)
393 ASSERT_HAS_SUBSTR(log_buf, exp_msg, "fail_msg");
394 close_prog:
395 bpf_object__close(obj);
396 bpf_object__close(pkt_obj);
397 }
398
test_func_replace_return_code(void)399 static void test_func_replace_return_code(void)
400 {
401 /* test invalid return code in the replaced program */
402 test_obj_load_failure_common("./freplace_connect_v4_prog.bpf.o",
403 "./connect4_prog.bpf.o", NULL);
404 }
405
test_func_map_prog_compatibility(void)406 static void test_func_map_prog_compatibility(void)
407 {
408 /* test with spin lock map value in the replaced program */
409 test_obj_load_failure_common("./freplace_attach_probe.bpf.o",
410 "./test_attach_probe.bpf.o", NULL);
411 }
412
test_func_replace_unreliable(void)413 static void test_func_replace_unreliable(void)
414 {
415 /* freplace'ing unreliable main prog should fail with error
416 * "Cannot replace static functions"
417 */
418 test_obj_load_failure_common("freplace_unreliable_prog.bpf.o",
419 "./verifier_btf_unreliable_prog.bpf.o",
420 "Cannot replace static functions");
421 }
422
test_func_replace_global_func(void)423 static void test_func_replace_global_func(void)
424 {
425 const char *prog_name[] = {
426 "freplace/test_pkt_access",
427 };
428
429 test_fexit_bpf2bpf_common("./freplace_global_func.bpf.o",
430 "./test_pkt_access.bpf.o",
431 ARRAY_SIZE(prog_name),
432 prog_name, false, NULL);
433 }
434
test_func_replace_int_with_void(void)435 static void test_func_replace_int_with_void(void)
436 {
437 /* Make sure we can't freplace with the wrong type */
438 test_obj_load_failure_common("freplace_int_with_void.bpf.o",
439 "./test_global_func2.bpf.o",
440 "Return type UNKNOWN of test_freplace_int_with_void()"
441 " doesn't match type INT of global_func2()");
442 }
443
find_prog_btf_id(const char * name,__u32 attach_prog_fd)444 static int find_prog_btf_id(const char *name, __u32 attach_prog_fd)
445 {
446 struct bpf_prog_info info = {};
447 __u32 info_len = sizeof(info);
448 struct btf *btf;
449 int ret;
450
451 ret = bpf_prog_get_info_by_fd(attach_prog_fd, &info, &info_len);
452 if (ret)
453 return ret;
454
455 if (!info.btf_id)
456 return -EINVAL;
457
458 btf = btf__load_from_kernel_by_id(info.btf_id);
459 ret = libbpf_get_error(btf);
460 if (ret)
461 return ret;
462
463 ret = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);
464 btf__free(btf);
465 return ret;
466 }
467
load_fentry(int attach_prog_fd,int attach_btf_id)468 static int load_fentry(int attach_prog_fd, int attach_btf_id)
469 {
470 LIBBPF_OPTS(bpf_prog_load_opts, opts,
471 .expected_attach_type = BPF_TRACE_FENTRY,
472 .attach_prog_fd = attach_prog_fd,
473 .attach_btf_id = attach_btf_id,
474 );
475 struct bpf_insn insns[] = {
476 BPF_MOV64_IMM(BPF_REG_0, 0),
477 BPF_EXIT_INSN(),
478 };
479
480 return bpf_prog_load(BPF_PROG_TYPE_TRACING,
481 "bind4_fentry",
482 "GPL",
483 insns,
484 ARRAY_SIZE(insns),
485 &opts);
486 }
487
test_fentry_to_cgroup_bpf(void)488 static void test_fentry_to_cgroup_bpf(void)
489 {
490 struct bind4_prog *skel = NULL;
491 struct bpf_prog_info info = {};
492 __u32 info_len = sizeof(info);
493 int cgroup_fd = -1;
494 int fentry_fd = -1;
495 int btf_id;
496
497 cgroup_fd = test__join_cgroup("/fentry_to_cgroup_bpf");
498 if (!ASSERT_GE(cgroup_fd, 0, "cgroup_fd"))
499 return;
500
501 skel = bind4_prog__open_and_load();
502 if (!ASSERT_OK_PTR(skel, "skel"))
503 goto cleanup;
504
505 skel->links.bind_v4_prog = bpf_program__attach_cgroup(skel->progs.bind_v4_prog, cgroup_fd);
506 if (!ASSERT_OK_PTR(skel->links.bind_v4_prog, "bpf_program__attach_cgroup"))
507 goto cleanup;
508
509 btf_id = find_prog_btf_id("bind_v4_prog", bpf_program__fd(skel->progs.bind_v4_prog));
510 if (!ASSERT_GE(btf_id, 0, "find_prog_btf_id"))
511 goto cleanup;
512
513 fentry_fd = load_fentry(bpf_program__fd(skel->progs.bind_v4_prog), btf_id);
514 if (!ASSERT_GE(fentry_fd, 0, "load_fentry"))
515 goto cleanup;
516
517 /* Make sure bpf_prog_get_info_by_fd works correctly when attaching
518 * to another BPF program.
519 */
520
521 ASSERT_OK(bpf_prog_get_info_by_fd(fentry_fd, &info, &info_len),
522 "bpf_prog_get_info_by_fd");
523
524 ASSERT_EQ(info.btf_id, 0, "info.btf_id");
525 ASSERT_EQ(info.attach_btf_id, btf_id, "info.attach_btf_id");
526 ASSERT_GT(info.attach_btf_obj_id, 0, "info.attach_btf_obj_id");
527
528 cleanup:
529 if (cgroup_fd >= 0)
530 close(cgroup_fd);
531 if (fentry_fd >= 0)
532 close(fentry_fd);
533 bind4_prog__destroy(skel);
534 }
535
test_func_replace_progmap(void)536 static void test_func_replace_progmap(void)
537 {
538 struct bpf_cpumap_val value = { .qsize = 1 };
539 struct freplace_progmap *skel = NULL;
540 struct xdp_dummy *tgt_skel = NULL;
541 __u32 key = 0;
542 int err;
543
544 skel = freplace_progmap__open();
545 if (!ASSERT_OK_PTR(skel, "prog_open"))
546 return;
547
548 tgt_skel = xdp_dummy__open_and_load();
549 if (!ASSERT_OK_PTR(tgt_skel, "tgt_prog_load"))
550 goto out;
551
552 err = bpf_program__set_attach_target(skel->progs.xdp_cpumap_prog,
553 bpf_program__fd(tgt_skel->progs.xdp_dummy_prog),
554 "xdp_dummy_prog");
555 if (!ASSERT_OK(err, "set_attach_target"))
556 goto out;
557
558 err = freplace_progmap__load(skel);
559 if (!ASSERT_OK(err, "obj_load"))
560 goto out;
561
562 /* Prior to fixing the kernel, loading the PROG_TYPE_EXT 'redirect'
563 * program above will cause the map owner type of 'cpumap' to be set to
564 * PROG_TYPE_EXT. This in turn will cause the bpf_map_update_elem()
565 * below to fail, because the program we are inserting into the map is
566 * of PROG_TYPE_XDP. After fixing the kernel, the initial ownership will
567 * be correctly resolved to the *target* of the PROG_TYPE_EXT program
568 * (i.e., PROG_TYPE_XDP) and the map update will succeed.
569 */
570 value.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_drop_prog);
571 err = bpf_map_update_elem(bpf_map__fd(skel->maps.cpu_map),
572 &key, &value, 0);
573 ASSERT_OK(err, "map_update");
574
575 out:
576 xdp_dummy__destroy(tgt_skel);
577 freplace_progmap__destroy(skel);
578 }
579
test_sleepable_fentry_to_xdp(void)580 static void test_sleepable_fentry_to_xdp(void)
581 {
582 struct fentry_sleepable *skel = NULL;
583 struct xdp_dummy *skel_xdp = NULL;
584 int ifindex, prog_fd, err;
585 char buff[64] = {};
586
587 #ifndef __x86_64__
588 test__skip();
589 return;
590 #endif
591
592 ifindex = if_nametoindex("lo");
593 if (!ASSERT_GT(ifindex, 0, "if_nametoindex"))
594 return;
595
596 skel_xdp = xdp_dummy__open_and_load();
597 if (!ASSERT_OK_PTR(skel_xdp, "xdp_dummy__open_and_load"))
598 return;
599
600 skel = fentry_sleepable__open();
601 if (!ASSERT_OK_PTR(skel, "fentry_sleepable__open"))
602 goto out;
603
604 skel->bss->user_ptr = buff;
605
606 prog_fd = bpf_program__fd(skel_xdp->progs.__x64_sys_nop);
607 err = bpf_program__set_attach_target(skel->progs.fentry_xdp, prog_fd, "__x64_sys_nop");
608 if (!ASSERT_OK(err, "bpf_program__set_attach_target"))
609 goto out;
610
611 err = fentry_sleepable__load(skel);
612 ASSERT_ERR(err, "fentry_sleepable__load");
613 if (err)
614 goto out;
615
616 skel->links.fentry_xdp = bpf_program__attach_trace(skel->progs.fentry_xdp);
617 if (!ASSERT_OK_PTR(skel->links.fentry_xdp, "bpf_program__attach_trace"))
618 goto out;
619
620 skel_xdp->links.__x64_sys_nop = bpf_program__attach_xdp(skel_xdp->progs.__x64_sys_nop,
621 ifindex);
622 if (!ASSERT_OK_PTR(skel_xdp->links.__x64_sys_nop, "bpf_program__attach_xdp"))
623 goto out;
624
625 err = system("ping -q -c 1 -W 1 127.0.0.1 > /dev/null");
626 ASSERT_OK(err, "ping");
627 ASSERT_ERR(skel->bss->retval, "retval");
628
629 out:
630 fentry_sleepable__destroy(skel);
631 xdp_dummy__destroy(skel_xdp);
632 }
633
634 /* NOTE: affect other tests, must run in serial mode */
serial_test_fexit_bpf2bpf(void)635 void serial_test_fexit_bpf2bpf(void)
636 {
637 if (test__start_subtest("target_no_callees"))
638 test_target_no_callees();
639 if (test__start_subtest("target_yes_callees"))
640 test_target_yes_callees();
641 if (test__start_subtest("func_replace"))
642 test_func_replace();
643 if (test__start_subtest("func_replace_verify"))
644 test_func_replace_verify();
645 if (test__start_subtest("func_replace_return_code"))
646 test_func_replace_return_code();
647 if (test__start_subtest("func_map_prog_compatibility"))
648 test_func_map_prog_compatibility();
649 if (test__start_subtest("func_replace_unreliable"))
650 test_func_replace_unreliable();
651 if (test__start_subtest("func_replace_multi"))
652 test_func_replace_multi();
653 if (test__start_subtest("fmod_ret_freplace"))
654 test_fmod_ret_freplace();
655 if (test__start_subtest("func_replace_global_func"))
656 test_func_replace_global_func();
657 if (test__start_subtest("fentry_to_cgroup_bpf"))
658 test_fentry_to_cgroup_bpf();
659 if (test__start_subtest("func_replace_progmap"))
660 test_func_replace_progmap();
661 if (test__start_subtest("freplace_int_with_void"))
662 test_func_replace_int_with_void();
663 if (test__start_subtest("freplace_void"))
664 test_func_replace_void();
665 if (test__start_subtest("sleepable_fentry_to_xdp"))
666 test_sleepable_fentry_to_xdp();
667 }
668