xref: /linux/tools/testing/selftests/bpf/progs/rhash.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
1*24999636SMykyta Yatsenko // SPDX-License-Identifier: GPL-2.0
2*24999636SMykyta Yatsenko /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3*24999636SMykyta Yatsenko 
4*24999636SMykyta Yatsenko #include <vmlinux.h>
5*24999636SMykyta Yatsenko #include <stdbool.h>
6*24999636SMykyta Yatsenko #include <bpf/bpf_helpers.h>
7*24999636SMykyta Yatsenko #include <bpf/bpf_tracing.h>
8*24999636SMykyta Yatsenko #include "bpf_misc.h"
9*24999636SMykyta Yatsenko 
10*24999636SMykyta Yatsenko #define ENOENT 2
11*24999636SMykyta Yatsenko #define EEXIST 17
12*24999636SMykyta Yatsenko 
13*24999636SMykyta Yatsenko char _license[] SEC("license") = "GPL";
14*24999636SMykyta Yatsenko 
15*24999636SMykyta Yatsenko int err;
16*24999636SMykyta Yatsenko 
17*24999636SMykyta Yatsenko struct elem {
18*24999636SMykyta Yatsenko 	char arr[128];
19*24999636SMykyta Yatsenko 	int val;
20*24999636SMykyta Yatsenko };
21*24999636SMykyta Yatsenko 
22*24999636SMykyta Yatsenko struct {
23*24999636SMykyta Yatsenko 	__uint(type, BPF_MAP_TYPE_RHASH);
24*24999636SMykyta Yatsenko 	__uint(map_flags, BPF_F_NO_PREALLOC);
25*24999636SMykyta Yatsenko 	__uint(max_entries, 128);
26*24999636SMykyta Yatsenko 	__type(key, int);
27*24999636SMykyta Yatsenko 	__type(value, struct elem);
28*24999636SMykyta Yatsenko } rhmap SEC(".maps");
29*24999636SMykyta Yatsenko 
30*24999636SMykyta Yatsenko SEC("syscall")
31*24999636SMykyta Yatsenko int test_rhash_lookup_update(void *ctx)
32*24999636SMykyta Yatsenko {
33*24999636SMykyta Yatsenko 	int key = 5;
34*24999636SMykyta Yatsenko 	struct elem empty = {.val = 3, .arr = {0}};
35*24999636SMykyta Yatsenko 	struct elem *e;
36*24999636SMykyta Yatsenko 
37*24999636SMykyta Yatsenko 	err = 1;
38*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
39*24999636SMykyta Yatsenko 	if (e)
40*24999636SMykyta Yatsenko 		return 1;
41*24999636SMykyta Yatsenko 
42*24999636SMykyta Yatsenko 	err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST);
43*24999636SMykyta Yatsenko 	if (err)
44*24999636SMykyta Yatsenko 		return 1;
45*24999636SMykyta Yatsenko 
46*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
47*24999636SMykyta Yatsenko 	if (!e || e->val != empty.val) {
48*24999636SMykyta Yatsenko 		err = 2;
49*24999636SMykyta Yatsenko 		return 2;
50*24999636SMykyta Yatsenko 	}
51*24999636SMykyta Yatsenko 
52*24999636SMykyta Yatsenko 	err = 0;
53*24999636SMykyta Yatsenko 	return 0;
54*24999636SMykyta Yatsenko }
55*24999636SMykyta Yatsenko 
56*24999636SMykyta Yatsenko SEC("syscall")
57*24999636SMykyta Yatsenko int test_rhash_update_delete(void *ctx)
58*24999636SMykyta Yatsenko {
59*24999636SMykyta Yatsenko 	int key = 6;
60*24999636SMykyta Yatsenko 	struct elem empty = {.val = 4, .arr = {0}};
61*24999636SMykyta Yatsenko 	struct elem *e;
62*24999636SMykyta Yatsenko 
63*24999636SMykyta Yatsenko 	err = 1;
64*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
65*24999636SMykyta Yatsenko 	if (e)
66*24999636SMykyta Yatsenko 		return 1;
67*24999636SMykyta Yatsenko 
68*24999636SMykyta Yatsenko 	err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST);
69*24999636SMykyta Yatsenko 	if (err)
70*24999636SMykyta Yatsenko 		return 2;
71*24999636SMykyta Yatsenko 
72*24999636SMykyta Yatsenko 	err = bpf_map_delete_elem(&rhmap, &key);
73*24999636SMykyta Yatsenko 	if (err)
74*24999636SMykyta Yatsenko 		return 3;
75*24999636SMykyta Yatsenko 
76*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
77*24999636SMykyta Yatsenko 	if (e) {
78*24999636SMykyta Yatsenko 		err = 4;
79*24999636SMykyta Yatsenko 		return 4;
80*24999636SMykyta Yatsenko 	}
81*24999636SMykyta Yatsenko 
82*24999636SMykyta Yatsenko 	err = 0;
83*24999636SMykyta Yatsenko 	return 0;
84*24999636SMykyta Yatsenko }
85*24999636SMykyta Yatsenko 
86*24999636SMykyta Yatsenko SEC("syscall")
87*24999636SMykyta Yatsenko int test_rhash_update_elements(void *ctx)
88*24999636SMykyta Yatsenko {
89*24999636SMykyta Yatsenko 	int key = 0;
90*24999636SMykyta Yatsenko 	struct elem empty = {.val = 4, .arr = {0}};
91*24999636SMykyta Yatsenko 	struct elem *e;
92*24999636SMykyta Yatsenko 	int i;
93*24999636SMykyta Yatsenko 
94*24999636SMykyta Yatsenko 	err = 1;
95*24999636SMykyta Yatsenko 
96*24999636SMykyta Yatsenko 	for (i = 0; i < 128; ++i) {
97*24999636SMykyta Yatsenko 		key = i;
98*24999636SMykyta Yatsenko 		e = bpf_map_lookup_elem(&rhmap, &key);
99*24999636SMykyta Yatsenko 		if (e)
100*24999636SMykyta Yatsenko 			return 1;
101*24999636SMykyta Yatsenko 
102*24999636SMykyta Yatsenko 		empty.val = key;
103*24999636SMykyta Yatsenko 		err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST);
104*24999636SMykyta Yatsenko 		if (err)
105*24999636SMykyta Yatsenko 			return 2;
106*24999636SMykyta Yatsenko 
107*24999636SMykyta Yatsenko 		e = bpf_map_lookup_elem(&rhmap, &key);
108*24999636SMykyta Yatsenko 		if (!e || e->val != key) {
109*24999636SMykyta Yatsenko 			err = 4;
110*24999636SMykyta Yatsenko 			return 4;
111*24999636SMykyta Yatsenko 		}
112*24999636SMykyta Yatsenko 	}
113*24999636SMykyta Yatsenko 
114*24999636SMykyta Yatsenko 	for (i = 0; i < 128; ++i) {
115*24999636SMykyta Yatsenko 		key = i;
116*24999636SMykyta Yatsenko 		err = bpf_map_delete_elem(&rhmap, &key);
117*24999636SMykyta Yatsenko 		if (err)
118*24999636SMykyta Yatsenko 			return 3;
119*24999636SMykyta Yatsenko 
120*24999636SMykyta Yatsenko 		e = bpf_map_lookup_elem(&rhmap, &key);
121*24999636SMykyta Yatsenko 		if (e) {
122*24999636SMykyta Yatsenko 			err = 5;
123*24999636SMykyta Yatsenko 			return 5;
124*24999636SMykyta Yatsenko 		}
125*24999636SMykyta Yatsenko 	}
126*24999636SMykyta Yatsenko 
127*24999636SMykyta Yatsenko 	err = 0;
128*24999636SMykyta Yatsenko 	return 0;
129*24999636SMykyta Yatsenko }
130*24999636SMykyta Yatsenko 
131*24999636SMykyta Yatsenko SEC("syscall")
132*24999636SMykyta Yatsenko int test_rhash_update_exist(void *ctx)
133*24999636SMykyta Yatsenko {
134*24999636SMykyta Yatsenko 	int key = 10;
135*24999636SMykyta Yatsenko 	struct elem val1 = {.val = 100, .arr = {0}};
136*24999636SMykyta Yatsenko 	struct elem val2 = {.val = 200, .arr = {0}};
137*24999636SMykyta Yatsenko 	struct elem *e;
138*24999636SMykyta Yatsenko 	int ret;
139*24999636SMykyta Yatsenko 
140*24999636SMykyta Yatsenko 	err = 1;
141*24999636SMykyta Yatsenko 
142*24999636SMykyta Yatsenko 	/* BPF_EXIST on non-existent key should fail with -ENOENT */
143*24999636SMykyta Yatsenko 	ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_EXIST);
144*24999636SMykyta Yatsenko 	if (ret != -ENOENT)
145*24999636SMykyta Yatsenko 		return 1;
146*24999636SMykyta Yatsenko 
147*24999636SMykyta Yatsenko 	/* Insert element first */
148*24999636SMykyta Yatsenko 	ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_NOEXIST);
149*24999636SMykyta Yatsenko 	if (ret)
150*24999636SMykyta Yatsenko 		return 2;
151*24999636SMykyta Yatsenko 
152*24999636SMykyta Yatsenko 	/* Verify initial value */
153*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
154*24999636SMykyta Yatsenko 	if (!e || e->val != 100)
155*24999636SMykyta Yatsenko 		return 3;
156*24999636SMykyta Yatsenko 
157*24999636SMykyta Yatsenko 	/* BPF_EXIST on existing key should succeed and update value */
158*24999636SMykyta Yatsenko 	ret = bpf_map_update_elem(&rhmap, &key, &val2, BPF_EXIST);
159*24999636SMykyta Yatsenko 	if (ret)
160*24999636SMykyta Yatsenko 		return 4;
161*24999636SMykyta Yatsenko 
162*24999636SMykyta Yatsenko 	/* Verify value was updated */
163*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
164*24999636SMykyta Yatsenko 	if (!e || e->val != 200)
165*24999636SMykyta Yatsenko 		return 5;
166*24999636SMykyta Yatsenko 
167*24999636SMykyta Yatsenko 	/* Cleanup */
168*24999636SMykyta Yatsenko 	bpf_map_delete_elem(&rhmap, &key);
169*24999636SMykyta Yatsenko 	err = 0;
170*24999636SMykyta Yatsenko 	return 0;
171*24999636SMykyta Yatsenko }
172*24999636SMykyta Yatsenko 
173*24999636SMykyta Yatsenko SEC("syscall")
174*24999636SMykyta Yatsenko int test_rhash_update_any(void *ctx)
175*24999636SMykyta Yatsenko {
176*24999636SMykyta Yatsenko 	int key = 11;
177*24999636SMykyta Yatsenko 	struct elem val1 = {.val = 111, .arr = {0}};
178*24999636SMykyta Yatsenko 	struct elem val2 = {.val = 222, .arr = {0}};
179*24999636SMykyta Yatsenko 	struct elem *e;
180*24999636SMykyta Yatsenko 	int ret;
181*24999636SMykyta Yatsenko 
182*24999636SMykyta Yatsenko 	err = 1;
183*24999636SMykyta Yatsenko 
184*24999636SMykyta Yatsenko 	/* BPF_ANY on non-existent key should insert */
185*24999636SMykyta Yatsenko 	ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_ANY);
186*24999636SMykyta Yatsenko 	if (ret)
187*24999636SMykyta Yatsenko 		return 1;
188*24999636SMykyta Yatsenko 
189*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
190*24999636SMykyta Yatsenko 	if (!e || e->val != 111)
191*24999636SMykyta Yatsenko 		return 2;
192*24999636SMykyta Yatsenko 
193*24999636SMykyta Yatsenko 	/* BPF_ANY on existing key should update */
194*24999636SMykyta Yatsenko 	ret = bpf_map_update_elem(&rhmap, &key, &val2, BPF_ANY);
195*24999636SMykyta Yatsenko 	if (ret)
196*24999636SMykyta Yatsenko 		return 3;
197*24999636SMykyta Yatsenko 
198*24999636SMykyta Yatsenko 	e = bpf_map_lookup_elem(&rhmap, &key);
199*24999636SMykyta Yatsenko 	if (!e || e->val != 222)
200*24999636SMykyta Yatsenko 		return 4;
201*24999636SMykyta Yatsenko 
202*24999636SMykyta Yatsenko 	/* Cleanup */
203*24999636SMykyta Yatsenko 	bpf_map_delete_elem(&rhmap, &key);
204*24999636SMykyta Yatsenko 	err = 0;
205*24999636SMykyta Yatsenko 	return 0;
206*24999636SMykyta Yatsenko }
207*24999636SMykyta Yatsenko 
208*24999636SMykyta Yatsenko SEC("syscall")
209*24999636SMykyta Yatsenko int test_rhash_noexist_duplicate(void *ctx)
210*24999636SMykyta Yatsenko {
211*24999636SMykyta Yatsenko 	int key = 12;
212*24999636SMykyta Yatsenko 	struct elem val = {.val = 600, .arr = {0}};
213*24999636SMykyta Yatsenko 	int ret;
214*24999636SMykyta Yatsenko 
215*24999636SMykyta Yatsenko 	err = 1;
216*24999636SMykyta Yatsenko 
217*24999636SMykyta Yatsenko 	/* Insert element */
218*24999636SMykyta Yatsenko 	ret = bpf_map_update_elem(&rhmap, &key, &val, BPF_NOEXIST);
219*24999636SMykyta Yatsenko 	if (ret)
220*24999636SMykyta Yatsenko 		return 1;
221*24999636SMykyta Yatsenko 
222*24999636SMykyta Yatsenko 	/* Try to insert again with BPF_NOEXIST - should fail with -EEXIST */
223*24999636SMykyta Yatsenko 	ret = bpf_map_update_elem(&rhmap, &key, &val, BPF_NOEXIST);
224*24999636SMykyta Yatsenko 	if (ret != -EEXIST)
225*24999636SMykyta Yatsenko 		return 2;
226*24999636SMykyta Yatsenko 
227*24999636SMykyta Yatsenko 	/* Cleanup */
228*24999636SMykyta Yatsenko 	bpf_map_delete_elem(&rhmap, &key);
229*24999636SMykyta Yatsenko 	err = 0;
230*24999636SMykyta Yatsenko 	return 0;
231*24999636SMykyta Yatsenko }
232*24999636SMykyta Yatsenko 
233*24999636SMykyta Yatsenko SEC("syscall")
234*24999636SMykyta Yatsenko int test_rhash_delete_nonexistent(void *ctx)
235*24999636SMykyta Yatsenko {
236*24999636SMykyta Yatsenko 	int key = 99999;
237*24999636SMykyta Yatsenko 	int ret;
238*24999636SMykyta Yatsenko 
239*24999636SMykyta Yatsenko 	err = 1;
240*24999636SMykyta Yatsenko 
241*24999636SMykyta Yatsenko 	/* Delete non-existent key should return -ENOENT */
242*24999636SMykyta Yatsenko 	ret = bpf_map_delete_elem(&rhmap, &key);
243*24999636SMykyta Yatsenko 	if (ret != -ENOENT)
244*24999636SMykyta Yatsenko 		return 1;
245*24999636SMykyta Yatsenko 
246*24999636SMykyta Yatsenko 	err = 0;
247*24999636SMykyta Yatsenko 	return 0;
248*24999636SMykyta Yatsenko }
249