1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 4 #include <vmlinux.h> 5 #include <bpf/bpf_tracing.h> 6 #include <bpf/bpf_helpers.h> 7 #include <bpf/bpf_core_read.h> 8 #include "../bpf_experimental.h" 9 #include "../bpf_testmod/bpf_testmod_kfunc.h" 10 11 struct node_data { 12 long key; 13 long data; 14 struct bpf_rb_node node; 15 }; 16 17 struct map_value { 18 struct prog_test_ref_kfunc *not_kptr; 19 struct prog_test_ref_kfunc __kptr *val; 20 struct node_data __kptr *node; 21 }; 22 23 /* This is necessary so that LLVM generates BTF for node_data struct 24 * If it's not included, a fwd reference for node_data will be generated but 25 * no struct. Example BTF of "node" field in map_value when not included: 26 * 27 * [10] PTR '(anon)' type_id=35 28 * [34] FWD 'node_data' fwd_kind=struct 29 * [35] TYPE_TAG 'kptr_ref' type_id=34 30 * 31 * (with no node_data struct defined) 32 * Had to do the same w/ bpf_kfunc_call_test_release below 33 */ 34 struct node_data *just_here_because_btf_bug; 35 36 struct { 37 __uint(type, BPF_MAP_TYPE_ARRAY); 38 __type(key, int); 39 __type(value, struct map_value); 40 __uint(max_entries, 2); 41 } some_nodes SEC(".maps"); 42 43 static int create_and_stash(int idx, int val) 44 { 45 struct map_value *mapval; 46 struct node_data *res; 47 48 mapval = bpf_map_lookup_elem(&some_nodes, &idx); 49 if (!mapval) 50 return 1; 51 52 res = bpf_obj_new(typeof(*res)); 53 if (!res) 54 return 1; 55 res->key = val; 56 57 res = bpf_kptr_xchg(&mapval->node, res); 58 if (res) 59 bpf_obj_drop(res); 60 return 0; 61 } 62 63 SEC("tc") 64 long stash_rb_nodes(void *ctx) 65 { 66 return create_and_stash(0, 41) ?: create_and_stash(1, 42); 67 } 68 69 SEC("tc") 70 long unstash_rb_node(void *ctx) 71 { 72 struct map_value *mapval; 73 struct node_data *res; 74 long retval; 75 int key = 1; 76 77 mapval = bpf_map_lookup_elem(&some_nodes, &key); 78 if (!mapval) 79 return 1; 80 81 res = bpf_kptr_xchg(&mapval->node, NULL); 82 if (res) { 83 retval = res->key; 84 bpf_obj_drop(res); 85 return retval; 86 } 87 return 1; 88 } 89 90 SEC("tc") 91 long stash_test_ref_kfunc(void *ctx) 92 { 93 struct prog_test_ref_kfunc *res; 94 struct map_value *mapval; 95 int key = 0; 96 97 mapval = bpf_map_lookup_elem(&some_nodes, &key); 98 if (!mapval) 99 return 1; 100 101 res = bpf_kptr_xchg(&mapval->val, NULL); 102 if (res) 103 bpf_kfunc_call_test_release(res); 104 return 0; 105 } 106 107 char _license[] SEC("license") = "GPL"; 108