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

selftests/bpf: Add testcase for updating attached freplace prog to prog_array map

Add a selftest to confirm the issue, which gets -EINVAL when update
attached freplace prog to prog_array map, has been fixed.

cd tools/testing/selftests/bpf; ./test_progs -t tailcalls
328/25 tailcalls/tailcall_freplace:OK
328 tailcalls:OK
Summary: 1/25 PASSED, 0 SKIPPED, 0 FAILED

Acked-by: Yonghong Song <yonghong.song@linux.dev>
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
Link: https://lore.kernel.org/r/20240728114612.48486-3-leon.hwang@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Leon Hwang and committed by
Alexei Starovoitov
7559a7a8 50c374c6

+109 -1
+64 -1
tools/testing/selftests/bpf/prog_tests/tailcalls.c
··· 5 5 #include "tailcall_poke.skel.h" 6 6 #include "tailcall_bpf2bpf_hierarchy2.skel.h" 7 7 #include "tailcall_bpf2bpf_hierarchy3.skel.h" 8 - 8 + #include "tailcall_freplace.skel.h" 9 + #include "tc_bpf2bpf.skel.h" 9 10 10 11 /* test_tailcall_1 checks basic functionality by patching multiple locations 11 12 * in a single program for a single tail call slot with nop->jmp, jmp->nop ··· 1496 1495 RUN_TESTS(tailcall_bpf2bpf_hierarchy3); 1497 1496 } 1498 1497 1498 + /* test_tailcall_freplace checks that the attached freplace prog is OK to 1499 + * update the prog_array map. 1500 + */ 1501 + static void test_tailcall_freplace(void) 1502 + { 1503 + struct tailcall_freplace *freplace_skel = NULL; 1504 + struct bpf_link *freplace_link = NULL; 1505 + struct bpf_program *freplace_prog; 1506 + struct tc_bpf2bpf *tc_skel = NULL; 1507 + int prog_fd, map_fd; 1508 + char buff[128] = {}; 1509 + int err, key; 1510 + 1511 + LIBBPF_OPTS(bpf_test_run_opts, topts, 1512 + .data_in = buff, 1513 + .data_size_in = sizeof(buff), 1514 + .repeat = 1, 1515 + ); 1516 + 1517 + freplace_skel = tailcall_freplace__open(); 1518 + if (!ASSERT_OK_PTR(freplace_skel, "tailcall_freplace__open")) 1519 + return; 1520 + 1521 + tc_skel = tc_bpf2bpf__open_and_load(); 1522 + if (!ASSERT_OK_PTR(tc_skel, "tc_bpf2bpf__open_and_load")) 1523 + goto out; 1524 + 1525 + prog_fd = bpf_program__fd(tc_skel->progs.entry_tc); 1526 + freplace_prog = freplace_skel->progs.entry_freplace; 1527 + err = bpf_program__set_attach_target(freplace_prog, prog_fd, "subprog"); 1528 + if (!ASSERT_OK(err, "set_attach_target")) 1529 + goto out; 1530 + 1531 + err = tailcall_freplace__load(freplace_skel); 1532 + if (!ASSERT_OK(err, "tailcall_freplace__load")) 1533 + goto out; 1534 + 1535 + freplace_link = bpf_program__attach_freplace(freplace_prog, prog_fd, 1536 + "subprog"); 1537 + if (!ASSERT_OK_PTR(freplace_link, "attach_freplace")) 1538 + goto out; 1539 + 1540 + map_fd = bpf_map__fd(freplace_skel->maps.jmp_table); 1541 + prog_fd = bpf_program__fd(freplace_prog); 1542 + key = 0; 1543 + err = bpf_map_update_elem(map_fd, &key, &prog_fd, BPF_ANY); 1544 + if (!ASSERT_OK(err, "update jmp_table")) 1545 + goto out; 1546 + 1547 + prog_fd = bpf_program__fd(tc_skel->progs.entry_tc); 1548 + err = bpf_prog_test_run_opts(prog_fd, &topts); 1549 + ASSERT_OK(err, "test_run"); 1550 + ASSERT_EQ(topts.retval, 34, "test_run retval"); 1551 + 1552 + out: 1553 + bpf_link__destroy(freplace_link); 1554 + tc_bpf2bpf__destroy(tc_skel); 1555 + tailcall_freplace__destroy(freplace_skel); 1556 + } 1557 + 1499 1558 void test_tailcalls(void) 1500 1559 { 1501 1560 if (test__start_subtest("tailcall_1")) ··· 1604 1543 test_tailcall_bpf2bpf_hierarchy_fentry_entry(); 1605 1544 test_tailcall_bpf2bpf_hierarchy_2(); 1606 1545 test_tailcall_bpf2bpf_hierarchy_3(); 1546 + if (test__start_subtest("tailcall_freplace")) 1547 + test_tailcall_freplace(); 1607 1548 }
+23
tools/testing/selftests/bpf/progs/tailcall_freplace.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/bpf.h> 4 + #include <bpf/bpf_helpers.h> 5 + 6 + struct { 7 + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 8 + __uint(max_entries, 1); 9 + __uint(key_size, sizeof(__u32)); 10 + __uint(value_size, sizeof(__u32)); 11 + } jmp_table SEC(".maps"); 12 + 13 + int count = 0; 14 + 15 + SEC("freplace") 16 + int entry_freplace(struct __sk_buff *skb) 17 + { 18 + count++; 19 + bpf_tail_call_static(skb, &jmp_table, 0); 20 + return count; 21 + } 22 + 23 + char __license[] SEC("license") = "GPL";
+22
tools/testing/selftests/bpf/progs/tc_bpf2bpf.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/bpf.h> 4 + #include <bpf/bpf_helpers.h> 5 + #include "bpf_misc.h" 6 + 7 + __noinline 8 + int subprog(struct __sk_buff *skb) 9 + { 10 + int ret = 1; 11 + 12 + __sink(ret); 13 + return ret; 14 + } 15 + 16 + SEC("tc") 17 + int entry_tc(struct __sk_buff *skb) 18 + { 19 + return subprog(skb); 20 + } 21 + 22 + char __license[] SEC("license") = "GPL";