0001
0002 #include <vmlinux.h>
0003 #include <bpf/bpf_tracing.h>
0004 #include <bpf/bpf_helpers.h>
0005
0006 struct map_value {
0007 struct prog_test_ref_kfunc __kptr *unref_ptr;
0008 struct prog_test_ref_kfunc __kptr_ref *ref_ptr;
0009 };
0010
0011 struct array_map {
0012 __uint(type, BPF_MAP_TYPE_ARRAY);
0013 __type(key, int);
0014 __type(value, struct map_value);
0015 __uint(max_entries, 1);
0016 } array_map SEC(".maps");
0017
0018 struct hash_map {
0019 __uint(type, BPF_MAP_TYPE_HASH);
0020 __type(key, int);
0021 __type(value, struct map_value);
0022 __uint(max_entries, 1);
0023 } hash_map SEC(".maps");
0024
0025 struct hash_malloc_map {
0026 __uint(type, BPF_MAP_TYPE_HASH);
0027 __type(key, int);
0028 __type(value, struct map_value);
0029 __uint(max_entries, 1);
0030 __uint(map_flags, BPF_F_NO_PREALLOC);
0031 } hash_malloc_map SEC(".maps");
0032
0033 struct lru_hash_map {
0034 __uint(type, BPF_MAP_TYPE_LRU_HASH);
0035 __type(key, int);
0036 __type(value, struct map_value);
0037 __uint(max_entries, 1);
0038 } lru_hash_map SEC(".maps");
0039
0040 #define DEFINE_MAP_OF_MAP(map_type, inner_map_type, name) \
0041 struct { \
0042 __uint(type, map_type); \
0043 __uint(max_entries, 1); \
0044 __uint(key_size, sizeof(int)); \
0045 __uint(value_size, sizeof(int)); \
0046 __array(values, struct inner_map_type); \
0047 } name SEC(".maps") = { \
0048 .values = { [0] = &inner_map_type }, \
0049 }
0050
0051 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, array_map, array_of_array_maps);
0052 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, hash_map, array_of_hash_maps);
0053 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, hash_malloc_map, array_of_hash_malloc_maps);
0054 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_ARRAY_OF_MAPS, lru_hash_map, array_of_lru_hash_maps);
0055 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, array_map, hash_of_array_maps);
0056 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_map, hash_of_hash_maps);
0057 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, hash_malloc_map, hash_of_hash_malloc_maps);
0058 DEFINE_MAP_OF_MAP(BPF_MAP_TYPE_HASH_OF_MAPS, lru_hash_map, hash_of_lru_hash_maps);
0059
0060 extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym;
0061 extern struct prog_test_ref_kfunc *
0062 bpf_kfunc_call_test_kptr_get(struct prog_test_ref_kfunc **p, int a, int b) __ksym;
0063 extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym;
0064
0065 static void test_kptr_unref(struct map_value *v)
0066 {
0067 struct prog_test_ref_kfunc *p;
0068
0069 p = v->unref_ptr;
0070
0071 v->unref_ptr = p;
0072 if (!p)
0073 return;
0074 if (p->a + p->b > 100)
0075 return;
0076
0077 v->unref_ptr = p;
0078
0079 v->unref_ptr = NULL;
0080 }
0081
0082 static void test_kptr_ref(struct map_value *v)
0083 {
0084 struct prog_test_ref_kfunc *p;
0085
0086 p = v->ref_ptr;
0087
0088 v->unref_ptr = p;
0089 if (!p)
0090 return;
0091 if (p->a + p->b > 100)
0092 return;
0093
0094 p = bpf_kptr_xchg(&v->ref_ptr, NULL);
0095 if (!p)
0096 return;
0097 if (p->a + p->b > 100) {
0098 bpf_kfunc_call_test_release(p);
0099 return;
0100 }
0101
0102 v->unref_ptr = p;
0103 bpf_kfunc_call_test_release(p);
0104
0105 p = bpf_kfunc_call_test_acquire(&(unsigned long){0});
0106 if (!p)
0107 return;
0108
0109 p = bpf_kptr_xchg(&v->ref_ptr, p);
0110 if (!p)
0111 return;
0112 if (p->a + p->b > 100) {
0113 bpf_kfunc_call_test_release(p);
0114 return;
0115 }
0116 bpf_kfunc_call_test_release(p);
0117 }
0118
0119 static void test_kptr_get(struct map_value *v)
0120 {
0121 struct prog_test_ref_kfunc *p;
0122
0123 p = bpf_kfunc_call_test_kptr_get(&v->ref_ptr, 0, 0);
0124 if (!p)
0125 return;
0126 if (p->a + p->b > 100) {
0127 bpf_kfunc_call_test_release(p);
0128 return;
0129 }
0130 bpf_kfunc_call_test_release(p);
0131 }
0132
0133 static void test_kptr(struct map_value *v)
0134 {
0135 test_kptr_unref(v);
0136 test_kptr_ref(v);
0137 test_kptr_get(v);
0138 }
0139
0140 SEC("tc")
0141 int test_map_kptr(struct __sk_buff *ctx)
0142 {
0143 struct map_value *v;
0144 int key = 0;
0145
0146 #define TEST(map) \
0147 v = bpf_map_lookup_elem(&map, &key); \
0148 if (!v) \
0149 return 0; \
0150 test_kptr(v)
0151
0152 TEST(array_map);
0153 TEST(hash_map);
0154 TEST(hash_malloc_map);
0155 TEST(lru_hash_map);
0156
0157 #undef TEST
0158 return 0;
0159 }
0160
0161 SEC("tc")
0162 int test_map_in_map_kptr(struct __sk_buff *ctx)
0163 {
0164 struct map_value *v;
0165 int key = 0;
0166 void *map;
0167
0168 #define TEST(map_in_map) \
0169 map = bpf_map_lookup_elem(&map_in_map, &key); \
0170 if (!map) \
0171 return 0; \
0172 v = bpf_map_lookup_elem(map, &key); \
0173 if (!v) \
0174 return 0; \
0175 test_kptr(v)
0176
0177 TEST(array_of_array_maps);
0178 TEST(array_of_hash_maps);
0179 TEST(array_of_hash_malloc_maps);
0180 TEST(array_of_lru_hash_maps);
0181 TEST(hash_of_array_maps);
0182 TEST(hash_of_hash_maps);
0183 TEST(hash_of_hash_malloc_maps);
0184 TEST(hash_of_lru_hash_maps);
0185
0186 #undef TEST
0187 return 0;
0188 }
0189
0190 SEC("tc")
0191 int test_map_kptr_ref(struct __sk_buff *ctx)
0192 {
0193 struct prog_test_ref_kfunc *p, *p_st;
0194 unsigned long arg = 0;
0195 struct map_value *v;
0196 int key = 0, ret;
0197
0198 p = bpf_kfunc_call_test_acquire(&arg);
0199 if (!p)
0200 return 1;
0201
0202 p_st = p->next;
0203 if (p_st->cnt.refs.counter != 2) {
0204 ret = 2;
0205 goto end;
0206 }
0207
0208 v = bpf_map_lookup_elem(&array_map, &key);
0209 if (!v) {
0210 ret = 3;
0211 goto end;
0212 }
0213
0214 p = bpf_kptr_xchg(&v->ref_ptr, p);
0215 if (p) {
0216 ret = 4;
0217 goto end;
0218 }
0219 if (p_st->cnt.refs.counter != 2)
0220 return 5;
0221
0222 p = bpf_kfunc_call_test_kptr_get(&v->ref_ptr, 0, 0);
0223 if (!p)
0224 return 6;
0225 if (p_st->cnt.refs.counter != 3) {
0226 ret = 7;
0227 goto end;
0228 }
0229 bpf_kfunc_call_test_release(p);
0230 if (p_st->cnt.refs.counter != 2)
0231 return 8;
0232
0233 p = bpf_kptr_xchg(&v->ref_ptr, NULL);
0234 if (!p)
0235 return 9;
0236 bpf_kfunc_call_test_release(p);
0237 if (p_st->cnt.refs.counter != 1)
0238 return 10;
0239
0240 p = bpf_kfunc_call_test_acquire(&arg);
0241 if (!p)
0242 return 11;
0243 p = bpf_kptr_xchg(&v->ref_ptr, p);
0244 if (p) {
0245 ret = 12;
0246 goto end;
0247 }
0248 if (p_st->cnt.refs.counter != 2)
0249 return 13;
0250
0251
0252 return 0;
0253 end:
0254 bpf_kfunc_call_test_release(p);
0255 return ret;
0256 }
0257
0258 SEC("tc")
0259 int test_map_kptr_ref2(struct __sk_buff *ctx)
0260 {
0261 struct prog_test_ref_kfunc *p, *p_st;
0262 struct map_value *v;
0263 int key = 0;
0264
0265 v = bpf_map_lookup_elem(&array_map, &key);
0266 if (!v)
0267 return 1;
0268
0269 p_st = v->ref_ptr;
0270 if (!p_st || p_st->cnt.refs.counter != 2)
0271 return 2;
0272
0273 p = bpf_kptr_xchg(&v->ref_ptr, NULL);
0274 if (!p)
0275 return 3;
0276 if (p_st->cnt.refs.counter != 2) {
0277 bpf_kfunc_call_test_release(p);
0278 return 4;
0279 }
0280
0281 p = bpf_kptr_xchg(&v->ref_ptr, p);
0282 if (p) {
0283 bpf_kfunc_call_test_release(p);
0284 return 5;
0285 }
0286 if (p_st->cnt.refs.counter != 2)
0287 return 6;
0288
0289 return 0;
0290 }
0291
0292 char _license[] SEC("license") = "GPL";