Use the prog_test kfuncs to test the referenced PTR_TO_BTF_ID kfunc support, and PTR_TO_CTX, PTR_TO_MEM argument passing support. Also testing the various failure cases. The failure selftests will test the following cases for kfunc: kfunc_call_test_fail1 - Argument struct type has non-scalar member kfunc_call_test_fail2 - Nesting depth of type > 8 kfunc_call_test_fail3 - Struct type has trailing zero-sized FAM kfunc_call_test_fail4 - Trying to pass reg->type != PTR_TO_CTX when argument struct type is a ctx type kfunc_call_test_fail5 - void * not part of mem, len pair kfunc_call_test_fail6 - u64 * not part of mem, len pair kfunc_call_test_fail7 - mark_btf_ld_reg copies ref_obj_id kfunc_call_test_fail8 - Same type btf_struct_walk reference copy handled correctly during release (i.e. only parent object can be released) Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> --- .../selftests/bpf/prog_tests/kfunc_call.c | 28 ++++++++++ .../selftests/bpf/progs/kfunc_call_test.c | 52 ++++++++++++++++++- .../bpf/progs/kfunc_call_test_fail1.c | 16 ++++++ .../bpf/progs/kfunc_call_test_fail2.c | 16 ++++++ .../bpf/progs/kfunc_call_test_fail3.c | 16 ++++++ .../bpf/progs/kfunc_call_test_fail4.c | 16 ++++++ .../bpf/progs/kfunc_call_test_fail5.c | 16 ++++++ .../bpf/progs/kfunc_call_test_fail6.c | 16 ++++++ .../bpf/progs/kfunc_call_test_fail7.c | 24 +++++++++ .../bpf/progs/kfunc_call_test_fail8.c | 22 ++++++++ 10 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail1.c create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail2.c create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail3.c create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail4.c create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail5.c create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail6.c create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail7.c create mode 100644 tools/testing/selftests/bpf/progs/kfunc_call_test_fail8.c diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c index 7d7445ccc141..b6630b9427d0 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c +++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c @@ -5,11 +5,33 @@ #include "kfunc_call_test.lskel.h" #include "kfunc_call_test_subprog.skel.h" #include "kfunc_call_test_subprog.lskel.h" +#include "kfunc_call_test_fail1.skel.h" +#include "kfunc_call_test_fail2.skel.h" +#include "kfunc_call_test_fail3.skel.h" +#include "kfunc_call_test_fail4.skel.h" +#include "kfunc_call_test_fail5.skel.h" +#include "kfunc_call_test_fail6.skel.h" +#include "kfunc_call_test_fail7.skel.h" +#include "kfunc_call_test_fail8.skel.h" static void test_main(void) { struct kfunc_call_test_lskel *skel; int prog_fd, retval, err; + void *fskel; + +#define FAIL(nr) \ + ({ \ + fskel = kfunc_call_test_fail##nr##__open_and_load(); \ + if (!ASSERT_EQ(fskel, NULL, \ + "kfunc_call_test_fail" #nr \ + "__open_and_load")) { \ + kfunc_call_test_fail##nr##__destroy(fskel); \ + return; \ + } \ + }) + + FAIL(1); FAIL(2); FAIL(3); FAIL(4); FAIL(5); FAIL(6); FAIL(7); FAIL(8); skel = kfunc_call_test_lskel__open_and_load(); if (!ASSERT_OK_PTR(skel, "skel")) @@ -27,6 +49,12 @@ static void test_main(void) ASSERT_OK(err, "bpf_prog_test_run(test2)"); ASSERT_EQ(retval, 3, "test2-retval"); + prog_fd = skel->progs.kfunc_call_test_ref_btf_id.prog_fd; + err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4), + NULL, NULL, (__u32 *)&retval, NULL); + ASSERT_OK(err, "bpf_prog_test_run(test_ref_btf_id)"); + ASSERT_EQ(retval, 0, "test_ref_btf_id-retval"); + kfunc_call_test_lskel__destroy(skel); } diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test.c b/tools/testing/selftests/bpf/progs/kfunc_call_test.c index 8a8cf59017aa..5aecbb9fdc68 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test.c @@ -1,13 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2021 Facebook */ -#include <linux/bpf.h> +#include <vmlinux.h> #include <bpf/bpf_helpers.h> -#include "bpf_tcp_helpers.h" extern int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym; extern __u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b, __u32 c, __u64 d) __ksym; +extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; +extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; +extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; +extern void bpf_kfunc_call_test_pass1(struct prog_test_pass1 *p) __ksym; +extern void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym; +extern void bpf_kfunc_call_test_mem_len_pass1(void *mem, int len) __ksym; +extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; + SEC("tc") int kfunc_call_test2(struct __sk_buff *skb) { @@ -44,4 +51,45 @@ int kfunc_call_test1(struct __sk_buff *skb) return ret; } +SEC("tc") +int kfunc_call_test_ref_btf_id(struct __sk_buff *skb) +{ + struct prog_test_ref_kfunc *pt; + unsigned long s = 0; + int ret = 0; + + pt = bpf_kfunc_call_test_acquire(&s); + if (pt) { + if (pt->a != 42 || pt->b != 108) + ret = -1; + bpf_kfunc_call_test_release(pt); + } + return ret; +} + +SEC("tc") +int kfunc_call_test_pass(struct __sk_buff *skb) +{ + struct prog_test_pass1 p1 = {}; + struct prog_test_pass2 p2 = {}; + short a = 0; + __u64 b = 0; + long c = 0; + char d = 0; + int e = 0; + + bpf_kfunc_call_test_pass_ctx(skb); + bpf_kfunc_call_test_pass1(&p1); + bpf_kfunc_call_test_pass2(&p2); + + bpf_kfunc_call_test_mem_len_pass1(&a, sizeof(a)); + bpf_kfunc_call_test_mem_len_pass1(&b, sizeof(b)); + bpf_kfunc_call_test_mem_len_pass1(&c, sizeof(c)); + bpf_kfunc_call_test_mem_len_pass1(&d, sizeof(d)); + bpf_kfunc_call_test_mem_len_pass1(&e, sizeof(e)); + bpf_kfunc_call_test_mem_len_fail2(&b, -1); + + return 0; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail1.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail1.c new file mode 100644 index 000000000000..4088000dcfc0 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail1.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p) __ksym; + +SEC("tc") +int kfunc_call_test_fail1(struct __sk_buff *skb) +{ + struct prog_test_fail1 s = {}; + + bpf_kfunc_call_test_fail1(&s); + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail2.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail2.c new file mode 100644 index 000000000000..0c9779693576 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail2.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern void bpf_kfunc_call_test_fail2(struct prog_test_fail2 *p) __ksym; + +SEC("tc") +int kfunc_call_test_fail2(struct __sk_buff *skb) +{ + struct prog_test_fail2 s = {}; + + bpf_kfunc_call_test_fail2(&s); + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail3.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail3.c new file mode 100644 index 000000000000..4e5a7493cdf7 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail3.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern void bpf_kfunc_call_test_fail3(struct prog_test_fail3 *p) __ksym; + +SEC("tc") +int kfunc_call_test_fail3(struct __sk_buff *skb) +{ + struct prog_test_fail3 s = {}; + + bpf_kfunc_call_test_fail3(&s); + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail4.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail4.c new file mode 100644 index 000000000000..01c3523c7c50 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail4.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern void bpf_kfunc_call_test_pass_ctx(struct __sk_buff *skb) __ksym; + +SEC("tc") +int kfunc_call_test_fail4(struct __sk_buff *skb) +{ + struct __sk_buff local_skb = {}; + + bpf_kfunc_call_test_pass_ctx(&local_skb); + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail5.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail5.c new file mode 100644 index 000000000000..e32f13709357 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail5.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern void bpf_kfunc_call_test_mem_len_fail1(void *mem, int len) __ksym; + +SEC("tc") +int kfunc_call_test_fail5(struct __sk_buff *skb) +{ + int a = 0; + + bpf_kfunc_call_test_mem_len_fail1(&a, sizeof(a)); + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail6.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail6.c new file mode 100644 index 000000000000..998626aaca35 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail6.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym; + +SEC("tc") +int kfunc_call_test_fail6(struct __sk_buff *skb) +{ + int a = 0; + + bpf_kfunc_call_test_mem_len_fail2((void *)&a, sizeof(a)); + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail7.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail7.c new file mode 100644 index 000000000000..05d4914b0533 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail7.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; +extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; + +SEC("tc") +int kfunc_call_test_fail7(struct __sk_buff *skb) +{ + struct prog_test_ref_kfunc *p, *p2; + unsigned long sp = 0; + + p = bpf_kfunc_call_test_acquire(&sp); + if (p) { + p2 = p->next->next; + bpf_kfunc_call_test_release(p); + if (p2->a == 42) + return 1; + } + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test_fail8.c b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail8.c new file mode 100644 index 000000000000..eac8637ce841 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test_fail8.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <vmlinux.h> +#include <bpf/bpf_helpers.h> + +extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; +extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; + +SEC("tc") +int kfunc_call_test_fail8(struct __sk_buff *skb) +{ + struct prog_test_ref_kfunc *p, *p2; + unsigned long sp = 0; + + p = bpf_kfunc_call_test_acquire(&sp); + if (p) { + p2 = p->next->next; + bpf_kfunc_call_test_release(p2); + } + return 0; +} + +char _license[] SEC("license") = "GPL"; -- 2.34.1