-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Add local kptr stashing test
Add a new selftest, local_kptr_stash, which uses bpf_kptr_xchg to stash a bpf_obj_new-allocated object in a map. Test the following scenarios: * Stash two rb_nodes in an arraymap, don't unstash them, rely on map free to destruct them * Stash two rb_nodes in an arraymap, unstash the second one in a separate program, rely on map free to destruct first Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com> Link: https://lore.kernel.org/r/20230310230743.2320707-4-davemarchevsky@fb.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
- Loading branch information
Dave Marchevsky
authored and
Alexei Starovoitov
committed
Mar 11, 2023
1 parent
738c96d
commit 5d8d663
Showing
2 changed files
with
168 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ | ||
|
||
#include <test_progs.h> | ||
#include <network_helpers.h> | ||
|
||
#include "local_kptr_stash.skel.h" | ||
static void test_local_kptr_stash_simple(void) | ||
{ | ||
LIBBPF_OPTS(bpf_test_run_opts, opts, | ||
.data_in = &pkt_v4, | ||
.data_size_in = sizeof(pkt_v4), | ||
.repeat = 1, | ||
); | ||
struct local_kptr_stash *skel; | ||
int ret; | ||
|
||
skel = local_kptr_stash__open_and_load(); | ||
if (!ASSERT_OK_PTR(skel, "local_kptr_stash__open_and_load")) | ||
return; | ||
|
||
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.stash_rb_nodes), &opts); | ||
ASSERT_OK(ret, "local_kptr_stash_add_nodes run"); | ||
ASSERT_OK(opts.retval, "local_kptr_stash_add_nodes retval"); | ||
|
||
local_kptr_stash__destroy(skel); | ||
} | ||
|
||
static void test_local_kptr_stash_unstash(void) | ||
{ | ||
LIBBPF_OPTS(bpf_test_run_opts, opts, | ||
.data_in = &pkt_v4, | ||
.data_size_in = sizeof(pkt_v4), | ||
.repeat = 1, | ||
); | ||
struct local_kptr_stash *skel; | ||
int ret; | ||
|
||
skel = local_kptr_stash__open_and_load(); | ||
if (!ASSERT_OK_PTR(skel, "local_kptr_stash__open_and_load")) | ||
return; | ||
|
||
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.stash_rb_nodes), &opts); | ||
ASSERT_OK(ret, "local_kptr_stash_add_nodes run"); | ||
ASSERT_OK(opts.retval, "local_kptr_stash_add_nodes retval"); | ||
|
||
ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.unstash_rb_node), &opts); | ||
ASSERT_OK(ret, "local_kptr_stash_add_nodes run"); | ||
ASSERT_EQ(opts.retval, 42, "local_kptr_stash_add_nodes retval"); | ||
|
||
local_kptr_stash__destroy(skel); | ||
} | ||
|
||
void test_local_kptr_stash_success(void) | ||
{ | ||
if (test__start_subtest("local_kptr_stash_simple")) | ||
test_local_kptr_stash_simple(); | ||
if (test__start_subtest("local_kptr_stash_unstash")) | ||
test_local_kptr_stash_unstash(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ | ||
|
||
#include <vmlinux.h> | ||
#include <bpf/bpf_tracing.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_core_read.h> | ||
#include "bpf_experimental.h" | ||
|
||
struct node_data { | ||
long key; | ||
long data; | ||
struct bpf_rb_node node; | ||
}; | ||
|
||
struct map_value { | ||
struct prog_test_ref_kfunc *not_kptr; | ||
struct prog_test_ref_kfunc __kptr *val; | ||
struct node_data __kptr *node; | ||
}; | ||
|
||
/* This is necessary so that LLVM generates BTF for node_data struct | ||
* If it's not included, a fwd reference for node_data will be generated but | ||
* no struct. Example BTF of "node" field in map_value when not included: | ||
* | ||
* [10] PTR '(anon)' type_id=35 | ||
* [34] FWD 'node_data' fwd_kind=struct | ||
* [35] TYPE_TAG 'kptr_ref' type_id=34 | ||
* | ||
* (with no node_data struct defined) | ||
* Had to do the same w/ bpf_kfunc_call_test_release below | ||
*/ | ||
struct node_data *just_here_because_btf_bug; | ||
|
||
extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_ARRAY); | ||
__type(key, int); | ||
__type(value, struct map_value); | ||
__uint(max_entries, 2); | ||
} some_nodes SEC(".maps"); | ||
|
||
static int create_and_stash(int idx, int val) | ||
{ | ||
struct map_value *mapval; | ||
struct node_data *res; | ||
|
||
mapval = bpf_map_lookup_elem(&some_nodes, &idx); | ||
if (!mapval) | ||
return 1; | ||
|
||
res = bpf_obj_new(typeof(*res)); | ||
if (!res) | ||
return 1; | ||
res->key = val; | ||
|
||
res = bpf_kptr_xchg(&mapval->node, res); | ||
if (res) | ||
bpf_obj_drop(res); | ||
return 0; | ||
} | ||
|
||
SEC("tc") | ||
long stash_rb_nodes(void *ctx) | ||
{ | ||
return create_and_stash(0, 41) ?: create_and_stash(1, 42); | ||
} | ||
|
||
SEC("tc") | ||
long unstash_rb_node(void *ctx) | ||
{ | ||
struct map_value *mapval; | ||
struct node_data *res; | ||
long retval; | ||
int key = 1; | ||
|
||
mapval = bpf_map_lookup_elem(&some_nodes, &key); | ||
if (!mapval) | ||
return 1; | ||
|
||
res = bpf_kptr_xchg(&mapval->node, NULL); | ||
if (res) { | ||
retval = res->key; | ||
bpf_obj_drop(res); | ||
return retval; | ||
} | ||
return 1; | ||
} | ||
|
||
SEC("tc") | ||
long stash_test_ref_kfunc(void *ctx) | ||
{ | ||
struct prog_test_ref_kfunc *res; | ||
struct map_value *mapval; | ||
int key = 0; | ||
|
||
mapval = bpf_map_lookup_elem(&some_nodes, &key); | ||
if (!mapval) | ||
return 1; | ||
|
||
res = bpf_kptr_xchg(&mapval->val, NULL); | ||
if (res) | ||
bpf_kfunc_call_test_release(res); | ||
return 0; | ||
} | ||
|
||
char _license[] SEC("license") = "GPL"; |