2 * Testsuite for eBPF maps
4 * Copyright (c) 2014 PLUMgrid, http://plumgrid.com
5 * Copyright (c) 2016 Facebook
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.
13 #include <linux/bpf.h>
23 /* sanity tests for map API */
24 static void test_hashmap_sanity(int i
, void *data
)
26 long long key
, next_key
, value
;
29 map_fd
= bpf_create_map(BPF_MAP_TYPE_HASH
, sizeof(key
), sizeof(value
),
32 printf("failed to create hashmap '%s'\n", strerror(errno
));
38 /* insert key=1 element */
39 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_ANY
) == 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 */
47 assert(bpf_update_elem(map_fd
, &key
, &value
, -1) == -1 && errno
== EINVAL
);
49 /* check that key=1 can be found */
50 assert(bpf_lookup_elem(map_fd
, &key
, &value
) == 0 && value
== 1234);
53 /* check that key=2 is not found */
54 assert(bpf_lookup_elem(map_fd
, &key
, &value
) == -1 && errno
== ENOENT
);
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 */
61 /* insert key=2 element */
62 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_NOEXIST
) == 0);
64 /* key=1 and key=2 were inserted, check that key=0 cannot be inserted
65 * due to max_entries limit
68 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_NOEXIST
) == -1 &&
71 /* check that key = 0 doesn't exist */
72 assert(bpf_delete_elem(map_fd
, &key
) == -1 && errno
== ENOENT
);
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 &&
82 /* delete both elements */
84 assert(bpf_delete_elem(map_fd
, &key
) == 0);
86 assert(bpf_delete_elem(map_fd
, &key
) == 0);
87 assert(bpf_delete_elem(map_fd
, &key
) == -1 && errno
== ENOENT
);
90 /* check that map is empty */
91 assert(bpf_get_next_key(map_fd
, &key
, &next_key
) == -1 &&
96 /* sanity tests for percpu map API */
97 static void test_percpu_hashmap_sanity(int task
, void *data
)
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
];
105 map_fd
= bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH
, sizeof(key
),
106 sizeof(value
[0]), 2, map_flags
);
108 printf("failed to create hashmap '%s'\n", strerror(errno
));
112 for (i
= 0; i
< nr_cpus
; i
++)
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
;
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 */
125 /* -1 is an invalid flag */
126 assert(bpf_update_elem(map_fd
, &key
, value
, -1) == -1 &&
129 /* check that key=1 can be found. value could be 0 if the lookup
130 * was run from a different cpu.
133 assert(bpf_lookup_elem(map_fd
, &key
, value
) == 0 && value
[0] == 100);
136 /* check that key=2 is not found */
137 assert(bpf_lookup_elem(map_fd
, &key
, value
) == -1 && errno
== ENOENT
);
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 */
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
;
149 /* key=1 and key=2 were inserted, check that key=0 cannot be inserted
150 * due to max_entries limit
153 assert(bpf_update_elem(map_fd
, &key
, value
, BPF_NOEXIST
) == -1 &&
156 /* check that key = 0 doesn't exist */
157 assert(bpf_delete_elem(map_fd
, &key
) == -1 && errno
== ENOENT
);
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
;
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);
170 assert(errno
== ENOENT
);
172 /* Update with BPF_EXIST */
174 assert(bpf_update_elem(map_fd
, &key
, value
, BPF_EXIST
) == 0);
176 /* delete both elements */
178 assert(bpf_delete_elem(map_fd
, &key
) == 0);
180 assert(bpf_delete_elem(map_fd
, &key
) == 0);
181 assert(bpf_delete_elem(map_fd
, &key
) == -1 && errno
== ENOENT
);
184 /* check that map is empty */
185 assert(bpf_get_next_key(map_fd
, &key
, &next_key
) == -1 &&
190 static void test_arraymap_sanity(int i
, void *data
)
192 int key
, next_key
, map_fd
;
195 map_fd
= bpf_create_map(BPF_MAP_TYPE_ARRAY
, sizeof(key
), sizeof(value
),
198 printf("failed to create arraymap '%s'\n", strerror(errno
));
204 /* insert key=1 element */
205 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_ANY
) == 0);
208 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_NOEXIST
) == -1 &&
211 /* check that key=1 can be found */
212 assert(bpf_lookup_elem(map_fd
, &key
, &value
) == 0 && value
== 1234);
215 /* check that key=0 is also found and zero initialized */
216 assert(bpf_lookup_elem(map_fd
, &key
, &value
) == 0 && value
== 0);
219 /* key=0 and key=1 were inserted, check that key=2 cannot be inserted
220 * due to max_entries limit
223 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_EXIST
) == -1 &&
226 /* check that key = 2 doesn't exist */
227 assert(bpf_lookup_elem(map_fd
, &key
, &value
) == -1 && errno
== ENOENT
);
229 /* iterate over two elements */
230 assert(bpf_get_next_key(map_fd
, &key
, &next_key
) == 0 &&
232 assert(bpf_get_next_key(map_fd
, &next_key
, &next_key
) == 0 &&
234 assert(bpf_get_next_key(map_fd
, &next_key
, &next_key
) == -1 &&
237 /* delete shouldn't succeed */
239 assert(bpf_delete_elem(map_fd
, &key
) == -1 && errno
== EINVAL
);
244 static void test_percpu_arraymap_many_keys(void)
246 unsigned nr_cpus
= sysconf(_SC_NPROCESSORS_CONF
);
247 unsigned nr_keys
= 20000;
248 long values
[nr_cpus
];
251 map_fd
= bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY
, sizeof(key
),
252 sizeof(values
[0]), nr_keys
, 0);
254 printf("failed to create per-cpu arraymap '%s'\n",
259 for (i
= 0; i
< nr_cpus
; i
++)
262 for (key
= 0; key
< nr_keys
; key
++)
263 assert(bpf_update_elem(map_fd
, &key
, values
, BPF_ANY
) == 0);
265 for (key
= 0; key
< nr_keys
; key
++) {
266 for (i
= 0; i
< nr_cpus
; i
++)
268 assert(bpf_lookup_elem(map_fd
, &key
, values
) == 0);
269 for (i
= 0; i
< nr_cpus
; i
++)
270 assert(values
[i
] == i
+ 10);
276 static void test_percpu_arraymap_sanity(int i
, void *data
)
278 unsigned nr_cpus
= sysconf(_SC_NPROCESSORS_CONF
);
279 long values
[nr_cpus
];
280 int key
, next_key
, map_fd
;
282 map_fd
= bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY
, sizeof(key
),
283 sizeof(values
[0]), 2, 0);
285 printf("failed to create arraymap '%s'\n", strerror(errno
));
289 for (i
= 0; i
< nr_cpus
; i
++)
293 /* insert key=1 element */
294 assert(bpf_update_elem(map_fd
, &key
, values
, BPF_ANY
) == 0);
297 assert(bpf_update_elem(map_fd
, &key
, values
, BPF_NOEXIST
) == -1 &&
300 /* check that key=1 can be found */
301 assert(bpf_lookup_elem(map_fd
, &key
, values
) == 0 && values
[0] == 100);
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);
309 /* check that key=2 cannot be inserted due to max_entries limit */
311 assert(bpf_update_elem(map_fd
, &key
, values
, BPF_EXIST
) == -1 &&
314 /* check that key = 2 doesn't exist */
315 assert(bpf_lookup_elem(map_fd
, &key
, values
) == -1 && errno
== ENOENT
);
317 /* iterate over two elements */
318 assert(bpf_get_next_key(map_fd
, &key
, &next_key
) == 0 &&
320 assert(bpf_get_next_key(map_fd
, &next_key
, &next_key
) == 0 &&
322 assert(bpf_get_next_key(map_fd
, &next_key
, &next_key
) == -1 &&
325 /* delete shouldn't succeed */
327 assert(bpf_delete_elem(map_fd
, &key
) == -1 && errno
== EINVAL
);
332 #define MAP_SIZE (32 * 1024)
333 static void test_map_large(void)
340 int map_fd
, i
, value
;
342 /* allocate 4Mbyte of memory */
343 map_fd
= bpf_create_map(BPF_MAP_TYPE_HASH
, sizeof(key
), sizeof(value
),
344 MAP_SIZE
, map_flags
);
346 printf("failed to create large map '%s'\n", strerror(errno
));
350 for (i
= 0; i
< MAP_SIZE
; i
++) {
351 key
= (struct bigkey
) {.c
= i
};
353 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_NOEXIST
) == 0);
356 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_NOEXIST
) == -1 &&
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
);
365 assert(bpf_lookup_elem(map_fd
, &key
, &value
) == 0 && value
== 0);
367 assert(bpf_lookup_elem(map_fd
, &key
, &value
) == -1 && errno
== ENOENT
);
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
)
378 for (i
= 0; i
< tasks
; i
++) {
383 } else if (pid
[i
] == -1) {
384 printf("couldn't spawn #%d process\n", i
);
388 for (i
= 0; i
< tasks
; i
++) {
391 assert(waitpid(pid
[i
], &status
, 0) == pid
[i
]);
396 static void test_map_stress(void)
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
);
407 static void do_work(int fn
, void *data
)
409 int map_fd
= ((int *)data
)[0];
410 int do_update
= ((int *)data
)[1];
414 for (i
= fn
; i
< MAP_SIZE
; i
+= TASKS
) {
417 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_NOEXIST
) == 0);
419 assert(bpf_delete_elem(map_fd
, &key
) == 0);
423 static void test_map_parallel(void)
425 int i
, map_fd
, key
= 0, value
= 0;
428 map_fd
= bpf_create_map(BPF_MAP_TYPE_HASH
, sizeof(key
), sizeof(value
),
429 MAP_SIZE
, map_flags
);
431 printf("failed to create map for parallel test '%s'\n",
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, ...
443 run_parallel(TASKS
, do_work
, data
);
445 /* check that key=0 is already there */
446 assert(bpf_update_elem(map_fd
, &key
, &value
, BPF_NOEXIST
) == -1 &&
449 /* check that all elements were inserted */
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
);
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 &&
462 /* now let's delete all elemenets in parallel */
464 run_parallel(TASKS
, do_work
, data
);
466 /* nothing should be left */
468 assert(bpf_get_next_key(map_fd
, &key
, &key
) == -1 && errno
== ENOENT
);
471 static void run_all_tests(void)
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();
488 map_flags
= BPF_F_NO_PREALLOC
;
490 printf("test_maps: OK\n");