blob: be52c808d6cf3b6ab22d9b8fdfc1bd7bdf988366 [file] [log] [blame]
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +02001/*
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
12#include <stdio.h>
13#include <unistd.h>
14#include <errno.h>
15#include <string.h>
16#include <assert.h>
17#include <stdlib.h>
18
19#include <sys/wait.h>
20#include <sys/resource.h>
21
22#include <linux/bpf.h>
23
Mickaël Salaün10ecc722017-02-10 00:21:39 +010024#include <bpf/bpf.h>
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020025#include "bpf_sys.h"
Daniel Borkmanne00c7b22016-11-26 01:28:09 +010026#include "bpf_util.h"
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020027
28static int map_flags;
29
30static void test_hashmap(int task, void *data)
31{
32 long long key, next_key, value;
33 int fd;
34
35 fd = bpf_map_create(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
36 2, map_flags);
37 if (fd < 0) {
38 printf("Failed to create hashmap '%s'!\n", strerror(errno));
39 exit(1);
40 }
41
42 key = 1;
43 value = 1234;
44 /* Insert key=1 element. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +010045 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020046
47 value = 0;
48 /* BPF_NOEXIST means add new element if it doesn't exist. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +010049 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020050 /* key=1 already exists. */
51 errno == EEXIST);
52
53 /* -1 is an invalid flag. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +010054 assert(bpf_map_update_elem(fd, &key, &value, -1) == -1 &&
55 errno == EINVAL);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020056
57 /* Check that key=1 can be found. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +010058 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020059
60 key = 2;
61 /* Check that key=2 is not found. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +010062 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020063
64 /* BPF_EXIST means update existing element. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +010065 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020066 /* key=2 is not there. */
67 errno == ENOENT);
68
69 /* Insert key=2 element. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +010070 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020071
72 /* key=1 and key=2 were inserted, check that key=0 cannot be
73 * inserted due to max_entries limit.
74 */
75 key = 0;
Mickaël Salaün10ecc722017-02-10 00:21:39 +010076 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020077 errno == E2BIG);
78
79 /* Update existing element, though the map is full. */
80 key = 1;
Mickaël Salaün10ecc722017-02-10 00:21:39 +010081 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020082 key = 2;
Mickaël Salaün10ecc722017-02-10 00:21:39 +010083 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020084 key = 1;
Mickaël Salaün10ecc722017-02-10 00:21:39 +010085 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020086
87 /* Check that key = 0 doesn't exist. */
88 key = 0;
Mickaël Salaüne58383b2017-02-10 00:21:41 +010089 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020090
91 /* Iterate over two elements. */
Mickaël Salaün5f155c22017-02-10 00:21:42 +010092 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020093 (next_key == 1 || next_key == 2));
Mickaël Salaün5f155c22017-02-10 00:21:42 +010094 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020095 (next_key == 1 || next_key == 2));
Mickaël Salaün5f155c22017-02-10 00:21:42 +010096 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +020097 errno == ENOENT);
98
99 /* Delete both elements. */
100 key = 1;
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100101 assert(bpf_map_delete_elem(fd, &key) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200102 key = 2;
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100103 assert(bpf_map_delete_elem(fd, &key) == 0);
104 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200105
106 key = 0;
107 /* Check that map is empty. */
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100108 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200109 errno == ENOENT);
110
111 close(fd);
112}
113
114static void test_hashmap_percpu(int task, void *data)
115{
Daniel Borkmanne00c7b22016-11-26 01:28:09 +0100116 unsigned int nr_cpus = bpf_num_possible_cpus();
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200117 long long value[nr_cpus];
118 long long key, next_key;
119 int expected_key_mask = 0;
120 int fd, i;
121
122 fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key),
123 sizeof(value[0]), 2, map_flags);
124 if (fd < 0) {
125 printf("Failed to create hashmap '%s'!\n", strerror(errno));
126 exit(1);
127 }
128
129 for (i = 0; i < nr_cpus; i++)
130 value[i] = i + 100;
131
132 key = 1;
133 /* Insert key=1 element. */
134 assert(!(expected_key_mask & key));
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100135 assert(bpf_map_update_elem(fd, &key, value, BPF_ANY) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200136 expected_key_mask |= key;
137
138 /* BPF_NOEXIST means add new element if it doesn't exist. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100139 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200140 /* key=1 already exists. */
141 errno == EEXIST);
142
143 /* -1 is an invalid flag. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100144 assert(bpf_map_update_elem(fd, &key, value, -1) == -1 &&
145 errno == EINVAL);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200146
147 /* Check that key=1 can be found. Value could be 0 if the lookup
148 * was run from a different CPU.
149 */
150 value[0] = 1;
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100151 assert(bpf_map_lookup_elem(fd, &key, value) == 0 && value[0] == 100);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200152
153 key = 2;
154 /* Check that key=2 is not found. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100155 assert(bpf_map_lookup_elem(fd, &key, value) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200156
157 /* BPF_EXIST means update existing element. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100158 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200159 /* key=2 is not there. */
160 errno == ENOENT);
161
162 /* Insert key=2 element. */
163 assert(!(expected_key_mask & key));
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100164 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200165 expected_key_mask |= key;
166
167 /* key=1 and key=2 were inserted, check that key=0 cannot be
168 * inserted due to max_entries limit.
169 */
170 key = 0;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100171 assert(bpf_map_update_elem(fd, &key, value, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200172 errno == E2BIG);
173
174 /* Check that key = 0 doesn't exist. */
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100175 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200176
177 /* Iterate over two elements. */
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100178 while (!bpf_map_get_next_key(fd, &key, &next_key)) {
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200179 assert((expected_key_mask & next_key) == next_key);
180 expected_key_mask &= ~next_key;
181
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100182 assert(bpf_map_lookup_elem(fd, &next_key, value) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200183
184 for (i = 0; i < nr_cpus; i++)
185 assert(value[i] == i + 100);
186
187 key = next_key;
188 }
189 assert(errno == ENOENT);
190
191 /* Update with BPF_EXIST. */
192 key = 1;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100193 assert(bpf_map_update_elem(fd, &key, value, BPF_EXIST) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200194
195 /* Delete both elements. */
196 key = 1;
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100197 assert(bpf_map_delete_elem(fd, &key) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200198 key = 2;
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100199 assert(bpf_map_delete_elem(fd, &key) == 0);
200 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200201
202 key = 0;
203 /* Check that map is empty. */
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100204 assert(bpf_map_get_next_key(fd, &key, &next_key) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200205 errno == ENOENT);
206
207 close(fd);
208}
209
210static void test_arraymap(int task, void *data)
211{
212 int key, next_key, fd;
213 long long value;
214
215 fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value),
216 2, 0);
217 if (fd < 0) {
218 printf("Failed to create arraymap '%s'!\n", strerror(errno));
219 exit(1);
220 }
221
222 key = 1;
223 value = 1234;
224 /* Insert key=1 element. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100225 assert(bpf_map_update_elem(fd, &key, &value, BPF_ANY) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200226
227 value = 0;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100228 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200229 errno == EEXIST);
230
231 /* Check that key=1 can be found. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100232 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 1234);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200233
234 key = 0;
235 /* Check that key=0 is also found and zero initialized. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100236 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200237
238 /* key=0 and key=1 were inserted, check that key=2 cannot be inserted
239 * due to max_entries limit.
240 */
241 key = 2;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100242 assert(bpf_map_update_elem(fd, &key, &value, BPF_EXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200243 errno == E2BIG);
244
245 /* Check that key = 2 doesn't exist. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100246 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200247
248 /* Iterate over two elements. */
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100249 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200250 next_key == 0);
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100251 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200252 next_key == 1);
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100253 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200254 errno == ENOENT);
255
256 /* Delete shouldn't succeed. */
257 key = 1;
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100258 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == EINVAL);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200259
260 close(fd);
261}
262
263static void test_arraymap_percpu(int task, void *data)
264{
Daniel Borkmanne00c7b22016-11-26 01:28:09 +0100265 unsigned int nr_cpus = bpf_num_possible_cpus();
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200266 int key, next_key, fd, i;
267 long values[nr_cpus];
268
269 fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
270 sizeof(values[0]), 2, 0);
271 if (fd < 0) {
272 printf("Failed to create arraymap '%s'!\n", strerror(errno));
273 exit(1);
274 }
275
276 for (i = 0; i < nr_cpus; i++)
277 values[i] = i + 100;
278
279 key = 1;
280 /* Insert key=1 element. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100281 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200282
283 values[0] = 0;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100284 assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200285 errno == EEXIST);
286
287 /* Check that key=1 can be found. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100288 assert(bpf_map_lookup_elem(fd, &key, values) == 0 && values[0] == 100);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200289
290 key = 0;
291 /* Check that key=0 is also found and zero initialized. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100292 assert(bpf_map_lookup_elem(fd, &key, values) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200293 values[0] == 0 && values[nr_cpus - 1] == 0);
294
295 /* Check that key=2 cannot be inserted due to max_entries limit. */
296 key = 2;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100297 assert(bpf_map_update_elem(fd, &key, values, BPF_EXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200298 errno == E2BIG);
299
300 /* Check that key = 2 doesn't exist. */
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100301 assert(bpf_map_lookup_elem(fd, &key, values) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200302
303 /* Iterate over two elements. */
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100304 assert(bpf_map_get_next_key(fd, &key, &next_key) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200305 next_key == 0);
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100306 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200307 next_key == 1);
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100308 assert(bpf_map_get_next_key(fd, &next_key, &next_key) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200309 errno == ENOENT);
310
311 /* Delete shouldn't succeed. */
312 key = 1;
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100313 assert(bpf_map_delete_elem(fd, &key) == -1 && errno == EINVAL);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200314
315 close(fd);
316}
317
318static void test_arraymap_percpu_many_keys(void)
319{
Daniel Borkmanne00c7b22016-11-26 01:28:09 +0100320 unsigned int nr_cpus = bpf_num_possible_cpus();
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200321 unsigned int nr_keys = 20000;
322 long values[nr_cpus];
323 int key, fd, i;
324
325 fd = bpf_map_create(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key),
326 sizeof(values[0]), nr_keys, 0);
327 if (fd < 0) {
328 printf("Failed to create per-cpu arraymap '%s'!\n",
329 strerror(errno));
330 exit(1);
331 }
332
333 for (i = 0; i < nr_cpus; i++)
334 values[i] = i + 10;
335
336 for (key = 0; key < nr_keys; key++)
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100337 assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200338
339 for (key = 0; key < nr_keys; key++) {
340 for (i = 0; i < nr_cpus; i++)
341 values[i] = 0;
342
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100343 assert(bpf_map_lookup_elem(fd, &key, values) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200344
345 for (i = 0; i < nr_cpus; i++)
346 assert(values[i] == i + 10);
347 }
348
349 close(fd);
350}
351
352#define MAP_SIZE (32 * 1024)
353
354static void test_map_large(void)
355{
356 struct bigkey {
357 int a;
358 char b[116];
359 long long c;
360 } key;
361 int fd, i, value;
362
363 fd = bpf_map_create(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
364 MAP_SIZE, map_flags);
365 if (fd < 0) {
366 printf("Failed to create large map '%s'!\n", strerror(errno));
367 exit(1);
368 }
369
370 for (i = 0; i < MAP_SIZE; i++) {
371 key = (struct bigkey) { .c = i };
372 value = i;
373
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100374 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200375 }
376
377 key.c = -1;
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100378 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200379 errno == E2BIG);
380
381 /* Iterate through all elements. */
382 for (i = 0; i < MAP_SIZE; i++)
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100383 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
384 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200385
386 key.c = 0;
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100387 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 && value == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200388 key.a = 1;
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100389 assert(bpf_map_lookup_elem(fd, &key, &value) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200390
391 close(fd);
392}
393
394static void run_parallel(int tasks, void (*fn)(int task, void *data),
395 void *data)
396{
397 pid_t pid[tasks];
398 int i;
399
400 for (i = 0; i < tasks; i++) {
401 pid[i] = fork();
402 if (pid[i] == 0) {
403 fn(i, data);
404 exit(0);
405 } else if (pid[i] == -1) {
406 printf("Couldn't spawn #%d process!\n", i);
407 exit(1);
408 }
409 }
410
411 for (i = 0; i < tasks; i++) {
412 int status;
413
414 assert(waitpid(pid[i], &status, 0) == pid[i]);
415 assert(status == 0);
416 }
417}
418
419static void test_map_stress(void)
420{
421 run_parallel(100, test_hashmap, NULL);
422 run_parallel(100, test_hashmap_percpu, NULL);
423
424 run_parallel(100, test_arraymap, NULL);
425 run_parallel(100, test_arraymap_percpu, NULL);
426}
427
428#define TASKS 1024
429
430#define DO_UPDATE 1
431#define DO_DELETE 0
432
433static void do_work(int fn, void *data)
434{
435 int do_update = ((int *)data)[1];
436 int fd = ((int *)data)[0];
437 int i, key, value;
438
439 for (i = fn; i < MAP_SIZE; i += TASKS) {
440 key = value = i;
441
442 if (do_update) {
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100443 assert(bpf_map_update_elem(fd, &key, &value,
444 BPF_NOEXIST) == 0);
445 assert(bpf_map_update_elem(fd, &key, &value,
446 BPF_EXIST) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200447 } else {
Mickaël Salaüne58383b2017-02-10 00:21:41 +0100448 assert(bpf_map_delete_elem(fd, &key) == 0);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200449 }
450 }
451}
452
453static void test_map_parallel(void)
454{
455 int i, fd, key = 0, value = 0;
456 int data[2];
457
458 fd = bpf_map_create(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value),
459 MAP_SIZE, map_flags);
460 if (fd < 0) {
461 printf("Failed to create map for parallel test '%s'!\n",
462 strerror(errno));
463 exit(1);
464 }
465
466 /* Use the same fd in children to add elements to this map:
467 * child_0 adds key=0, key=1024, key=2048, ...
468 * child_1 adds key=1, key=1025, key=2049, ...
469 * child_1023 adds key=1023, ...
470 */
471 data[0] = fd;
472 data[1] = DO_UPDATE;
473 run_parallel(TASKS, do_work, data);
474
475 /* Check that key=0 is already there. */
Mickaël Salaün10ecc722017-02-10 00:21:39 +0100476 assert(bpf_map_update_elem(fd, &key, &value, BPF_NOEXIST) == -1 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200477 errno == EEXIST);
478
479 /* Check that all elements were inserted. */
480 key = -1;
481 for (i = 0; i < MAP_SIZE; i++)
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100482 assert(bpf_map_get_next_key(fd, &key, &key) == 0);
483 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200484
485 /* Another check for all elements */
486 for (i = 0; i < MAP_SIZE; i++) {
487 key = MAP_SIZE - i - 1;
488
Mickaël Salaüne5ff7c42017-02-10 00:21:40 +0100489 assert(bpf_map_lookup_elem(fd, &key, &value) == 0 &&
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200490 value == key);
491 }
492
493 /* Now let's delete all elemenets in parallel. */
494 data[1] = DO_DELETE;
495 run_parallel(TASKS, do_work, data);
496
497 /* Nothing should be left. */
498 key = -1;
Mickaël Salaün5f155c22017-02-10 00:21:42 +0100499 assert(bpf_map_get_next_key(fd, &key, &key) == -1 && errno == ENOENT);
Daniel Borkmann5aa5bd12016-10-17 14:28:36 +0200500}
501
502static void run_all_tests(void)
503{
504 test_hashmap(0, NULL);
505 test_hashmap_percpu(0, NULL);
506
507 test_arraymap(0, NULL);
508 test_arraymap_percpu(0, NULL);
509
510 test_arraymap_percpu_many_keys();
511
512 test_map_large();
513 test_map_parallel();
514 test_map_stress();
515}
516
517int main(void)
518{
519 struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
520
521 setrlimit(RLIMIT_MEMLOCK, &rinf);
522
523 map_flags = 0;
524 run_all_tests();
525
526 map_flags = BPF_F_NO_PREALLOC;
527 run_all_tests();
528
529 printf("test_maps: OK\n");
530 return 0;
531}