spi: meson: Add GXBB compatible
[cascardo/linux.git] / samples / bpf / test_maps.c
1 /*
2  * Testsuite for eBPF maps
3  *
4  * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
5  * Copyright (c) 2016 Facebook
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of version 2 of the GNU General Public
9  * License as published by the Free Software Foundation.
10  */
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <linux/bpf.h>
14 #include <errno.h>
15 #include <string.h>
16 #include <assert.h>
17 #include <sys/wait.h>
18 #include <stdlib.h>
19 #include "libbpf.h"
20
21 static int map_flags;
22
23 /* sanity tests for map API */
24 static void test_hashmap_sanity(int i, void *data)
25 {
26         long long key, next_key, value;
27         int map_fd;
28
29         map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
30                                 2, map_flags);
31         if (map_fd < 0) {
32                 printf("failed to create hashmap '%s'\n", strerror(errno));
33                 exit(1);
34         }
35
36         key = 1;
37         value = 1234;
38         /* insert key=1 element */
39         assert(bpf_update_elem(map_fd, &key, &value, BPF_ANY) == 0);
40
41         value = 0;
42         /* BPF_NOEXIST means: add new element if it doesn't exist */
43         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
44                /* key=1 already exists */
45                errno == EEXIST);
46
47         assert(bpf_update_elem(map_fd, &key, &value, -1) == -1 && errno == EINVAL);
48
49         /* check that key=1 can be found */
50         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 1234);
51
52         key = 2;
53         /* check that key=2 is not found */
54         assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT);
55
56         /* BPF_EXIST means: update existing element */
57         assert(bpf_update_elem(map_fd, &key, &value, BPF_EXIST) == -1 &&
58                /* key=2 is not there */
59                errno == ENOENT);
60
61         /* insert key=2 element */
62         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);
63
64         /* key=1 and key=2 were inserted, check that key=0 cannot be inserted
65          * due to max_entries limit
66          */
67         key = 0;
68         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
69                errno == E2BIG);
70
71         /* check that key = 0 doesn't exist */
72         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT);
73
74         /* iterate over two elements */
75         assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&
76                (next_key == 1 || next_key == 2));
77         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&
78                (next_key == 1 || next_key == 2));
79         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&
80                errno == ENOENT);
81
82         /* delete both elements */
83         key = 1;
84         assert(bpf_delete_elem(map_fd, &key) == 0);
85         key = 2;
86         assert(bpf_delete_elem(map_fd, &key) == 0);
87         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT);
88
89         key = 0;
90         /* check that map is empty */
91         assert(bpf_get_next_key(map_fd, &key, &next_key) == -1 &&
92                errno == ENOENT);
93         close(map_fd);
94 }
95
96 /* sanity tests for percpu map API */
97 static void test_percpu_hashmap_sanity(int task, void *data)
98 {
99         long long key, next_key;
100         int expected_key_mask = 0;
101         unsigned int nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
102         long long value[nr_cpus];
103         int map_fd, i;
104
105         map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
106                                 sizeof(value[0]), 2, map_flags);
107         if (map_fd < 0) {
108                 printf("failed to create hashmap '%s'\n", strerror(errno));
109                 exit(1);
110         }
111
112         for (i = 0; i < nr_cpus; i++)
113                 value[i] = i + 100;
114         key = 1;
115         /* insert key=1 element */
116         assert(!(expected_key_mask & key));
117         assert(bpf_update_elem(map_fd, &key, value, BPF_ANY) == 0);
118         expected_key_mask |= key;
119
120         /* BPF_NOEXIST means: add new element if it doesn't exist */
121         assert(bpf_update_elem(map_fd, &key, value, BPF_NOEXIST) == -1 &&
122                /* key=1 already exists */
123                errno == EEXIST);
124
125         /* -1 is an invalid flag */
126         assert(bpf_update_elem(map_fd, &key, value, -1) == -1 &&
127                errno == EINVAL);
128
129         /* check that key=1 can be found. value could be 0 if the lookup
130          * was run from a different cpu.
131          */
132         value[0] = 1;
133         assert(bpf_lookup_elem(map_fd, &key, value) == 0 && value[0] == 100);
134
135         key = 2;
136         /* check that key=2 is not found */
137         assert(bpf_lookup_elem(map_fd, &key, value) == -1 && errno == ENOENT);
138
139         /* BPF_EXIST means: update existing element */
140         assert(bpf_update_elem(map_fd, &key, value, BPF_EXIST) == -1 &&
141                /* key=2 is not there */
142                errno == ENOENT);
143
144         /* insert key=2 element */
145         assert(!(expected_key_mask & key));
146         assert(bpf_update_elem(map_fd, &key, value, BPF_NOEXIST) == 0);
147         expected_key_mask |= key;
148
149         /* key=1 and key=2 were inserted, check that key=0 cannot be inserted
150          * due to max_entries limit
151          */
152         key = 0;
153         assert(bpf_update_elem(map_fd, &key, value, BPF_NOEXIST) == -1 &&
154                errno == E2BIG);
155
156         /* check that key = 0 doesn't exist */
157         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT);
158
159         /* iterate over two elements */
160         while (!bpf_get_next_key(map_fd, &key, &next_key)) {
161                 assert((expected_key_mask & next_key) == next_key);
162                 expected_key_mask &= ~next_key;
163
164                 assert(bpf_lookup_elem(map_fd, &next_key, value) == 0);
165                 for (i = 0; i < nr_cpus; i++)
166                         assert(value[i] == i + 100);
167
168                 key = next_key;
169         }
170         assert(errno == ENOENT);
171
172         /* Update with BPF_EXIST */
173         key = 1;
174         assert(bpf_update_elem(map_fd, &key, value, BPF_EXIST) == 0);
175
176         /* delete both elements */
177         key = 1;
178         assert(bpf_delete_elem(map_fd, &key) == 0);
179         key = 2;
180         assert(bpf_delete_elem(map_fd, &key) == 0);
181         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == ENOENT);
182
183         key = 0;
184         /* check that map is empty */
185         assert(bpf_get_next_key(map_fd, &key, &next_key) == -1 &&
186                errno == ENOENT);
187         close(map_fd);
188 }
189
190 static void test_arraymap_sanity(int i, void *data)
191 {
192         int key, next_key, map_fd;
193         long long value;
194
195         map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
196                                 2, 0);
197         if (map_fd < 0) {
198                 printf("failed to create arraymap '%s'\n", strerror(errno));
199                 exit(1);
200         }
201
202         key = 1;
203         value = 1234;
204         /* insert key=1 element */
205         assert(bpf_update_elem(map_fd, &key, &value, BPF_ANY) == 0);
206
207         value = 0;
208         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
209                errno == EEXIST);
210
211         /* check that key=1 can be found */
212         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 1234);
213
214         key = 0;
215         /* check that key=0 is also found and zero initialized */
216         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 0);
217
218
219         /* key=0 and key=1 were inserted, check that key=2 cannot be inserted
220          * due to max_entries limit
221          */
222         key = 2;
223         assert(bpf_update_elem(map_fd, &key, &value, BPF_EXIST) == -1 &&
224                errno == E2BIG);
225
226         /* check that key = 2 doesn't exist */
227         assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT);
228
229         /* iterate over two elements */
230         assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&
231                next_key == 0);
232         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&
233                next_key == 1);
234         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&
235                errno == ENOENT);
236
237         /* delete shouldn't succeed */
238         key = 1;
239         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == EINVAL);
240
241         close(map_fd);
242 }
243
244 static void test_percpu_arraymap_many_keys(void)
245 {
246         unsigned nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
247         unsigned nr_keys = 20000;
248         long values[nr_cpus];
249         int key, map_fd, i;
250
251         map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
252                                 sizeof(values[0]), nr_keys, 0);
253         if (map_fd < 0) {
254                 printf("failed to create per-cpu arraymap '%s'\n",
255                        strerror(errno));
256                 exit(1);
257         }
258
259         for (i = 0; i < nr_cpus; i++)
260                 values[i] = i + 10;
261
262         for (key = 0; key < nr_keys; key++)
263                 assert(bpf_update_elem(map_fd, &key, values, BPF_ANY) == 0);
264
265         for (key = 0; key < nr_keys; key++) {
266                 for (i = 0; i < nr_cpus; i++)
267                         values[i] = 0;
268                 assert(bpf_lookup_elem(map_fd, &key, values) == 0);
269                 for (i = 0; i < nr_cpus; i++)
270                         assert(values[i] == i + 10);
271         }
272
273         close(map_fd);
274 }
275
276 static void test_percpu_arraymap_sanity(int i, void *data)
277 {
278         unsigned nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
279         long values[nr_cpus];
280         int key, next_key, map_fd;
281
282         map_fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
283                                 sizeof(values[0]), 2, 0);
284         if (map_fd < 0) {
285                 printf("failed to create arraymap '%s'\n", strerror(errno));
286                 exit(1);
287         }
288
289         for (i = 0; i < nr_cpus; i++)
290                 values[i] = i + 100;
291
292         key = 1;
293         /* insert key=1 element */
294         assert(bpf_update_elem(map_fd, &key, values, BPF_ANY) == 0);
295
296         values[0] = 0;
297         assert(bpf_update_elem(map_fd, &key, values, BPF_NOEXIST) == -1 &&
298                errno == EEXIST);
299
300         /* check that key=1 can be found */
301         assert(bpf_lookup_elem(map_fd, &key, values) == 0 && values[0] == 100);
302
303         key = 0;
304         /* check that key=0 is also found and zero initialized */
305         assert(bpf_lookup_elem(map_fd, &key, values) == 0 &&
306                values[0] == 0 && values[nr_cpus - 1] == 0);
307
308
309         /* check that key=2 cannot be inserted due to max_entries limit */
310         key = 2;
311         assert(bpf_update_elem(map_fd, &key, values, BPF_EXIST) == -1 &&
312                errno == E2BIG);
313
314         /* check that key = 2 doesn't exist */
315         assert(bpf_lookup_elem(map_fd, &key, values) == -1 && errno == ENOENT);
316
317         /* iterate over two elements */
318         assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&
319                next_key == 0);
320         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&
321                next_key == 1);
322         assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&
323                errno == ENOENT);
324
325         /* delete shouldn't succeed */
326         key = 1;
327         assert(bpf_delete_elem(map_fd, &key) == -1 && errno == EINVAL);
328
329         close(map_fd);
330 }
331
332 #define MAP_SIZE (32 * 1024)
333 static void test_map_large(void)
334 {
335         struct bigkey {
336                 int a;
337                 char b[116];
338                 long long c;
339         } key;
340         int map_fd, i, value;
341
342         /* allocate 4Mbyte of memory */
343         map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
344                                 MAP_SIZE, map_flags);
345         if (map_fd < 0) {
346                 printf("failed to create large map '%s'\n", strerror(errno));
347                 exit(1);
348         }
349
350         for (i = 0; i < MAP_SIZE; i++) {
351                 key = (struct bigkey) {.c = i};
352                 value = i;
353                 assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);
354         }
355         key.c = -1;
356         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
357                errno == E2BIG);
358
359         /* iterate through all elements */
360         for (i = 0; i < MAP_SIZE; i++)
361                 assert(bpf_get_next_key(map_fd, &key, &key) == 0);
362         assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);
363
364         key.c = 0;
365         assert(bpf_lookup_elem(map_fd, &key, &value) == 0 && value == 0);
366         key.a = 1;
367         assert(bpf_lookup_elem(map_fd, &key, &value) == -1 && errno == ENOENT);
368
369         close(map_fd);
370 }
371
372 /* fork N children and wait for them to complete */
373 static void run_parallel(int tasks, void (*fn)(int i, void *data), void *data)
374 {
375         pid_t pid[tasks];
376         int i;
377
378         for (i = 0; i < tasks; i++) {
379                 pid[i] = fork();
380                 if (pid[i] == 0) {
381                         fn(i, data);
382                         exit(0);
383                 } else if (pid[i] == -1) {
384                         printf("couldn't spawn #%d process\n", i);
385                         exit(1);
386                 }
387         }
388         for (i = 0; i < tasks; i++) {
389                 int status;
390
391                 assert(waitpid(pid[i], &status, 0) == pid[i]);
392                 assert(status == 0);
393         }
394 }
395
396 static void test_map_stress(void)
397 {
398         run_parallel(100, test_hashmap_sanity, NULL);
399         run_parallel(100, test_percpu_hashmap_sanity, NULL);
400         run_parallel(100, test_arraymap_sanity, NULL);
401         run_parallel(100, test_percpu_arraymap_sanity, NULL);
402 }
403
404 #define TASKS 1024
405 #define DO_UPDATE 1
406 #define DO_DELETE 0
407 static void do_work(int fn, void *data)
408 {
409         int map_fd = ((int *)data)[0];
410         int do_update = ((int *)data)[1];
411         int i;
412         int key, value;
413
414         for (i = fn; i < MAP_SIZE; i += TASKS) {
415                 key = value = i;
416                 if (do_update)
417                         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == 0);
418                 else
419                         assert(bpf_delete_elem(map_fd, &key) == 0);
420         }
421 }
422
423 static void test_map_parallel(void)
424 {
425         int i, map_fd, key = 0, value = 0;
426         int data[2];
427
428         map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
429                                 MAP_SIZE, map_flags);
430         if (map_fd < 0) {
431                 printf("failed to create map for parallel test '%s'\n",
432                        strerror(errno));
433                 exit(1);
434         }
435
436         data[0] = map_fd;
437         data[1] = DO_UPDATE;
438         /* use the same map_fd in children to add elements to this map
439          * child_0 adds key=0, key=1024, key=2048, ...
440          * child_1 adds key=1, key=1025, key=2049, ...
441          * child_1023 adds key=1023, ...
442          */
443         run_parallel(TASKS, do_work, data);
444
445         /* check that key=0 is already there */
446         assert(bpf_update_elem(map_fd, &key, &value, BPF_NOEXIST) == -1 &&
447                errno == EEXIST);
448
449         /* check that all elements were inserted */
450         key = -1;
451         for (i = 0; i < MAP_SIZE; i++)
452                 assert(bpf_get_next_key(map_fd, &key, &key) == 0);
453         assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);
454
455         /* another check for all elements */
456         for (i = 0; i < MAP_SIZE; i++) {
457                 key = MAP_SIZE - i - 1;
458                 assert(bpf_lookup_elem(map_fd, &key, &value) == 0 &&
459                        value == key);
460         }
461
462         /* now let's delete all elemenets in parallel */
463         data[1] = DO_DELETE;
464         run_parallel(TASKS, do_work, data);
465
466         /* nothing should be left */
467         key = -1;
468         assert(bpf_get_next_key(map_fd, &key, &key) == -1 && errno == ENOENT);
469 }
470
471 static void run_all_tests(void)
472 {
473         test_hashmap_sanity(0, NULL);
474         test_percpu_hashmap_sanity(0, NULL);
475         test_arraymap_sanity(0, NULL);
476         test_percpu_arraymap_sanity(0, NULL);
477         test_percpu_arraymap_many_keys();
478
479         test_map_large();
480         test_map_parallel();
481         test_map_stress();
482 }
483
484 int main(void)
485 {
486         map_flags = 0;
487         run_all_tests();
488         map_flags = BPF_F_NO_PREALLOC;
489         run_all_tests();
490         printf("test_maps: OK\n");
491         return 0;
492 }