xref: /linux/tools/testing/selftests/bpf/prog_tests/fexit_bpf2bpf.c (revision 9d19ca5d0e8b4a3f4b2eaa14e86a25f1c93ff35b)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 */
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