]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
selftests/bpf: Add kfunc_call test for simple dtor in bpf_testmod
authorAlan Maguire <alan.maguire@oracle.com>
Thu, 20 Jun 2024 09:17:33 +0000 (10:17 +0100)
committerAndrii Nakryiko <andrii@kernel.org>
Fri, 21 Jun 2024 21:46:29 +0000 (14:46 -0700)
add simple kfuncs to create/destroy a context type to bpf_testmod,
register them and add a kfunc_call test to use them.  This provides
test coverage for registration of dtor kfuncs from modules.

By transferring the context pointer to a map value as a __kptr
we also trigger the map-based dtor cleanup logic, improving test
coverage.

Suggested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20240620091733.1967885-7-alan.maguire@oracle.com
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c
tools/testing/selftests/bpf/bpf_testmod/bpf_testmod_kfunc.h
tools/testing/selftests/bpf/prog_tests/kfunc_call.c
tools/testing/selftests/bpf/progs/kfunc_call_test.c

index 49f9a311e49b3bb4905375adf0e6bf701b22020f..d8bd01d8560bbb667dba1794556d466790d26217 100644 (file)
@@ -159,6 +159,37 @@ __bpf_kfunc void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr,
 {
 }
 
+__bpf_kfunc struct bpf_testmod_ctx *
+bpf_testmod_ctx_create(int *err)
+{
+       struct bpf_testmod_ctx *ctx;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
+       if (!ctx) {
+               *err = -ENOMEM;
+               return NULL;
+       }
+       refcount_set(&ctx->usage, 1);
+
+       return ctx;
+}
+
+static void testmod_free_cb(struct rcu_head *head)
+{
+       struct bpf_testmod_ctx *ctx;
+
+       ctx = container_of(head, struct bpf_testmod_ctx, rcu);
+       kfree(ctx);
+}
+
+__bpf_kfunc void bpf_testmod_ctx_release(struct bpf_testmod_ctx *ctx)
+{
+       if (!ctx)
+               return;
+       if (refcount_dec_and_test(&ctx->usage))
+               call_rcu(&ctx->rcu, testmod_free_cb);
+}
+
 struct bpf_testmod_btf_type_tag_1 {
        int a;
 };
@@ -369,8 +400,14 @@ BTF_ID_FLAGS(func, bpf_iter_testmod_seq_next, KF_ITER_NEXT | KF_RET_NULL)
 BTF_ID_FLAGS(func, bpf_iter_testmod_seq_destroy, KF_ITER_DESTROY)
 BTF_ID_FLAGS(func, bpf_kfunc_common_test)
 BTF_ID_FLAGS(func, bpf_kfunc_dynptr_test)
+BTF_ID_FLAGS(func, bpf_testmod_ctx_create, KF_ACQUIRE | KF_RET_NULL)
+BTF_ID_FLAGS(func, bpf_testmod_ctx_release, KF_RELEASE)
 BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids)
 
+BTF_ID_LIST(bpf_testmod_dtor_ids)
+BTF_ID(struct, bpf_testmod_ctx)
+BTF_ID(func, bpf_testmod_ctx_release)
+
 static const struct btf_kfunc_id_set bpf_testmod_common_kfunc_set = {
        .owner = THIS_MODULE,
        .set   = &bpf_testmod_common_kfunc_ids,
@@ -904,6 +941,12 @@ extern int bpf_fentry_test1(int a);
 
 static int bpf_testmod_init(void)
 {
+       const struct btf_id_dtor_kfunc bpf_testmod_dtors[] = {
+               {
+                       .btf_id         = bpf_testmod_dtor_ids[0],
+                       .kfunc_btf_id   = bpf_testmod_dtor_ids[1]
+               },
+       };
        int ret;
 
        ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_UNSPEC, &bpf_testmod_common_kfunc_set);
@@ -912,6 +955,9 @@ static int bpf_testmod_init(void)
        ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_testmod_kfunc_set);
        ret = ret ?: register_bpf_struct_ops(&bpf_bpf_testmod_ops, bpf_testmod_ops);
        ret = ret ?: register_bpf_struct_ops(&bpf_testmod_ops2, bpf_testmod_ops2);
+       ret = ret ?: register_btf_id_dtor_kfuncs(bpf_testmod_dtors,
+                                                ARRAY_SIZE(bpf_testmod_dtors),
+                                                THIS_MODULE);
        if (ret < 0)
                return ret;
        if (bpf_fentry_test1(0) < 0)
index f9809517e7fa0e81795d0243d79f3f5ed7cc3426..e587a79f22395ceb109931c2da621b1795679208 100644 (file)
@@ -80,6 +80,11 @@ struct sendmsg_args {
        int msglen;
 };
 
+struct bpf_testmod_ctx {
+       struct callback_head    rcu;
+       refcount_t              usage;
+};
+
 struct prog_test_ref_kfunc *
 bpf_kfunc_call_test_acquire(unsigned long *scalar_ptr) __ksym;
 void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym;
@@ -135,4 +140,8 @@ int bpf_kfunc_call_kernel_getsockname(struct addr_args *args) __ksym;
 int bpf_kfunc_call_kernel_getpeername(struct addr_args *args) __ksym;
 
 void bpf_kfunc_dynptr_test(struct bpf_dynptr *ptr, struct bpf_dynptr *ptr__nullable) __ksym;
+
+struct bpf_testmod_ctx *bpf_testmod_ctx_create(int *err) __ksym;
+void bpf_testmod_ctx_release(struct bpf_testmod_ctx *ctx) __ksym;
+
 #endif /* _BPF_TESTMOD_KFUNC_H */
index 2eb71559713c95a133439d515239aaeff188698d..5b743212292f617d23b8540b3c8244014ec8c1e6 100644 (file)
@@ -78,6 +78,7 @@ static struct kfunc_test_params kfunc_tests[] = {
        SYSCALL_TEST(kfunc_syscall_test, 0),
        SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0),
        TC_TEST(kfunc_call_test_static_unused_arg, 0),
+       TC_TEST(kfunc_call_ctx, 0),
 };
 
 struct syscall_test_args {
index cf68d1e48a0f5967243cd3df46ebc1aeac8df5f8..f502f755f56793d7c0bfa241f0cb79539e1960c4 100644 (file)
@@ -177,4 +177,41 @@ int kfunc_call_test_static_unused_arg(struct __sk_buff *skb)
        return actual != expected ? -1 : 0;
 }
 
+struct ctx_val {
+       struct bpf_testmod_ctx __kptr *ctx;
+};
+
+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __uint(max_entries, 1);
+       __type(key, int);
+       __type(value, struct ctx_val);
+} ctx_map SEC(".maps");
+
+SEC("tc")
+int kfunc_call_ctx(struct __sk_buff *skb)
+{
+       struct bpf_testmod_ctx *ctx;
+       int err = 0;
+
+       ctx = bpf_testmod_ctx_create(&err);
+       if (!ctx && !err)
+               err = -1;
+       if (ctx) {
+               int key = 0;
+               struct ctx_val *ctx_val = bpf_map_lookup_elem(&ctx_map, &key);
+
+               /* Transfer ctx to map to be freed via implicit dtor call
+                * on cleanup.
+                */
+               if (ctx_val)
+                       ctx = bpf_kptr_xchg(&ctx_val->ctx, ctx);
+               if (ctx) {
+                       bpf_testmod_ctx_release(ctx);
+                       err = -1;
+               }
+       }
+       return err;
+}
+
 char _license[] SEC("license") = "GPL";