diff options
author | Daniel Borkmann <daniel@iogearbox.net> | 2017-04-26 19:39:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-28 15:48:15 -0400 |
commit | f3515b5d0b718cceae9e67802cfa20d5e6f9b567 (patch) | |
tree | f36c473e0e53ef2018334abd8cffcf42b4dd70b6 | |
parent | 43bcf707ccdc79ee63edb953fcf72e6dc244cfa1 (diff) |
bpf: provide a generic macro for percpu values for selftests
To overcome bugs as described and fixed in 89087c456fb5 ("bpf: Fix
values type used in test_maps"), provide a generic BPF_DECLARE_PERCPU()
and bpf_percpu() accessor macro for all percpu map values used in
tests.
Declaring variables works as follows (also works for structs):
BPF_DECLARE_PERCPU(uint32_t, my_value);
They can then be accessed normally as uint32_t type through:
bpf_percpu(my_value, <cpu_nr>)
For example:
bpf_percpu(my_value, 0)++;
Implicitly, we make sure that the passed type is allocated and aligned
by gcc at least on a 8-byte boundary, so that it works together with
the map lookup/update syscall for percpu maps. We use it as a usage
example in test_maps, so that others are free to adapt this into their
code when necessary.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | tools/testing/selftests/bpf/bpf_util.h | 7 | ||||
-rw-r--r-- | tools/testing/selftests/bpf/test_maps.c | 37 |
2 files changed, 27 insertions, 17 deletions
diff --git a/tools/testing/selftests/bpf/bpf_util.h b/tools/testing/selftests/bpf/bpf_util.h index 7de27966103d..369e7d7bba80 100644 --- a/tools/testing/selftests/bpf/bpf_util.h +++ b/tools/testing/selftests/bpf/bpf_util.h | |||
@@ -54,4 +54,11 @@ static inline unsigned int bpf_num_possible_cpus(void) | |||
54 | return possible_cpus; | 54 | return possible_cpus; |
55 | } | 55 | } |
56 | 56 | ||
57 | #define __bpf_percpu_val_align __attribute__((__aligned__(8))) | ||
58 | |||
59 | #define BPF_DECLARE_PERCPU(type, name) \ | ||
60 | struct { type v; /* padding */ } __bpf_percpu_val_align \ | ||
61 | name[bpf_num_possible_cpus()] | ||
62 | #define bpf_percpu(name, cpu) name[(cpu)].v | ||
63 | |||
57 | #endif /* __BPF_UTIL__ */ | 64 | #endif /* __BPF_UTIL__ */ |
diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index a977c4f7b0ce..93314524de0d 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c | |||
@@ -137,20 +137,20 @@ static void test_hashmap_sizes(int task, void *data) | |||
137 | static void test_hashmap_percpu(int task, void *data) | 137 | static void test_hashmap_percpu(int task, void *data) |
138 | { | 138 | { |
139 | unsigned int nr_cpus = bpf_num_possible_cpus(); | 139 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
140 | long long value[nr_cpus]; | 140 | BPF_DECLARE_PERCPU(long, value); |
141 | long long key, next_key, first_key; | 141 | long long key, next_key, first_key; |
142 | int expected_key_mask = 0; | 142 | int expected_key_mask = 0; |
143 | int fd, i; | 143 | int fd, i; |
144 | 144 | ||
145 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key), | 145 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_HASH, sizeof(key), |
146 | sizeof(value[0]), 2, map_flags); | 146 | sizeof(bpf_percpu(value, 0)), 2, map_flags); |
147 | if (fd < 0) { | 147 | if (fd < 0) { |
148 | printf("Failed to create hashmap '%s'!\n", strerror(errno)); | 148 | printf("Failed to create hashmap '%s'!\n", strerror(errno)); |
149 | exit(1); | 149 | exit(1); |
150 | } | 150 | } |
151 | 151 | ||
152 | for (i = 0; i < nr_cpus; i++) | 152 | for (i = 0; i < nr_cpus; i++) |
153 | value[i] = i + 100; | 153 | bpf_percpu(value, i) = i + 100; |
154 | 154 | ||
155 | key = 1; | 155 | key = 1; |
156 | /* Insert key=1 element. */ | 156 | /* Insert key=1 element. */ |
@@ -170,8 +170,9 @@ static void test_hashmap_percpu(int task, void *data) | |||
170 | /* Check that key=1 can be found. Value could be 0 if the lookup | 170 | /* Check that key=1 can be found. Value could be 0 if the lookup |
171 | * was run from a different CPU. | 171 | * was run from a different CPU. |
172 | */ | 172 | */ |
173 | value[0] = 1; | 173 | bpf_percpu(value, 0) = 1; |
174 | assert(bpf_map_lookup_elem(fd, &key, value) == 0 && value[0] == 100); | 174 | assert(bpf_map_lookup_elem(fd, &key, value) == 0 && |
175 | bpf_percpu(value, 0) == 100); | ||
175 | 176 | ||
176 | key = 2; | 177 | key = 2; |
177 | /* Check that key=2 is not found. */ | 178 | /* Check that key=2 is not found. */ |
@@ -211,7 +212,7 @@ static void test_hashmap_percpu(int task, void *data) | |||
211 | assert(bpf_map_lookup_elem(fd, &next_key, value) == 0); | 212 | assert(bpf_map_lookup_elem(fd, &next_key, value) == 0); |
212 | 213 | ||
213 | for (i = 0; i < nr_cpus; i++) | 214 | for (i = 0; i < nr_cpus; i++) |
214 | assert(value[i] == i + 100); | 215 | assert(bpf_percpu(value, i) == i + 100); |
215 | 216 | ||
216 | key = next_key; | 217 | key = next_key; |
217 | } | 218 | } |
@@ -296,34 +297,36 @@ static void test_arraymap(int task, void *data) | |||
296 | static void test_arraymap_percpu(int task, void *data) | 297 | static void test_arraymap_percpu(int task, void *data) |
297 | { | 298 | { |
298 | unsigned int nr_cpus = bpf_num_possible_cpus(); | 299 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
300 | BPF_DECLARE_PERCPU(long, values); | ||
299 | int key, next_key, fd, i; | 301 | int key, next_key, fd, i; |
300 | long long values[nr_cpus]; | ||
301 | 302 | ||
302 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), | 303 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), |
303 | sizeof(values[0]), 2, 0); | 304 | sizeof(bpf_percpu(values, 0)), 2, 0); |
304 | if (fd < 0) { | 305 | if (fd < 0) { |
305 | printf("Failed to create arraymap '%s'!\n", strerror(errno)); | 306 | printf("Failed to create arraymap '%s'!\n", strerror(errno)); |
306 | exit(1); | 307 | exit(1); |
307 | } | 308 | } |
308 | 309 | ||
309 | for (i = 0; i < nr_cpus; i++) | 310 | for (i = 0; i < nr_cpus; i++) |
310 | values[i] = i + 100; | 311 | bpf_percpu(values, i) = i + 100; |
311 | 312 | ||
312 | key = 1; | 313 | key = 1; |
313 | /* Insert key=1 element. */ | 314 | /* Insert key=1 element. */ |
314 | assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); | 315 | assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); |
315 | 316 | ||
316 | values[0] = 0; | 317 | bpf_percpu(values, 0) = 0; |
317 | assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) == -1 && | 318 | assert(bpf_map_update_elem(fd, &key, values, BPF_NOEXIST) == -1 && |
318 | errno == EEXIST); | 319 | errno == EEXIST); |
319 | 320 | ||
320 | /* Check that key=1 can be found. */ | 321 | /* Check that key=1 can be found. */ |
321 | assert(bpf_map_lookup_elem(fd, &key, values) == 0 && values[0] == 100); | 322 | assert(bpf_map_lookup_elem(fd, &key, values) == 0 && |
323 | bpf_percpu(values, 0) == 100); | ||
322 | 324 | ||
323 | key = 0; | 325 | key = 0; |
324 | /* Check that key=0 is also found and zero initialized. */ | 326 | /* Check that key=0 is also found and zero initialized. */ |
325 | assert(bpf_map_lookup_elem(fd, &key, values) == 0 && | 327 | assert(bpf_map_lookup_elem(fd, &key, values) == 0 && |
326 | values[0] == 0 && values[nr_cpus - 1] == 0); | 328 | bpf_percpu(values, 0) == 0 && |
329 | bpf_percpu(values, nr_cpus - 1) == 0); | ||
327 | 330 | ||
328 | /* Check that key=2 cannot be inserted due to max_entries limit. */ | 331 | /* Check that key=2 cannot be inserted due to max_entries limit. */ |
329 | key = 2; | 332 | key = 2; |
@@ -353,15 +356,15 @@ static void test_arraymap_percpu(int task, void *data) | |||
353 | static void test_arraymap_percpu_many_keys(void) | 356 | static void test_arraymap_percpu_many_keys(void) |
354 | { | 357 | { |
355 | unsigned int nr_cpus = bpf_num_possible_cpus(); | 358 | unsigned int nr_cpus = bpf_num_possible_cpus(); |
359 | BPF_DECLARE_PERCPU(long, values); | ||
356 | /* nr_keys is not too large otherwise the test stresses percpu | 360 | /* nr_keys is not too large otherwise the test stresses percpu |
357 | * allocator more than anything else | 361 | * allocator more than anything else |
358 | */ | 362 | */ |
359 | unsigned int nr_keys = 2000; | 363 | unsigned int nr_keys = 2000; |
360 | long long values[nr_cpus]; | ||
361 | int key, fd, i; | 364 | int key, fd, i; |
362 | 365 | ||
363 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), | 366 | fd = bpf_create_map(BPF_MAP_TYPE_PERCPU_ARRAY, sizeof(key), |
364 | sizeof(values[0]), nr_keys, 0); | 367 | sizeof(bpf_percpu(values, 0)), nr_keys, 0); |
365 | if (fd < 0) { | 368 | if (fd < 0) { |
366 | printf("Failed to create per-cpu arraymap '%s'!\n", | 369 | printf("Failed to create per-cpu arraymap '%s'!\n", |
367 | strerror(errno)); | 370 | strerror(errno)); |
@@ -369,19 +372,19 @@ static void test_arraymap_percpu_many_keys(void) | |||
369 | } | 372 | } |
370 | 373 | ||
371 | for (i = 0; i < nr_cpus; i++) | 374 | for (i = 0; i < nr_cpus; i++) |
372 | values[i] = i + 10; | 375 | bpf_percpu(values, i) = i + 10; |
373 | 376 | ||
374 | for (key = 0; key < nr_keys; key++) | 377 | for (key = 0; key < nr_keys; key++) |
375 | assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); | 378 | assert(bpf_map_update_elem(fd, &key, values, BPF_ANY) == 0); |
376 | 379 | ||
377 | for (key = 0; key < nr_keys; key++) { | 380 | for (key = 0; key < nr_keys; key++) { |
378 | for (i = 0; i < nr_cpus; i++) | 381 | for (i = 0; i < nr_cpus; i++) |
379 | values[i] = 0; | 382 | bpf_percpu(values, i) = 0; |
380 | 383 | ||
381 | assert(bpf_map_lookup_elem(fd, &key, values) == 0); | 384 | assert(bpf_map_lookup_elem(fd, &key, values) == 0); |
382 | 385 | ||
383 | for (i = 0; i < nr_cpus; i++) | 386 | for (i = 0; i < nr_cpus; i++) |
384 | assert(values[i] == i + 10); | 387 | assert(bpf_percpu(values, i) == i + 10); |
385 | } | 388 | } |
386 | 389 | ||
387 | close(fd); | 390 | close(fd); |