Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf, selftests: Update array map tests for per-cpu batched ops

Follows the same logic as the hashtable tests.

Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20210424214510.806627-3-pctammela@mojatatu.com

authored by

Pedro Tammela and committed by
Daniel Borkmann
3733bfbb f008d732

+75 -29
+75 -29
tools/testing/selftests/bpf/map_tests/array_map_batch_ops.c
··· 9 9 10 10 #include <test_maps.h> 11 11 12 + static int nr_cpus; 13 + 12 14 static void map_batch_update(int map_fd, __u32 max_entries, int *keys, 13 - int *values) 15 + __s64 *values, bool is_pcpu) 14 16 { 15 - int i, err; 17 + int i, j, err; 18 + int cpu_offset = 0; 16 19 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 17 20 .elem_flags = 0, 18 21 .flags = 0, ··· 23 20 24 21 for (i = 0; i < max_entries; i++) { 25 22 keys[i] = i; 26 - values[i] = i + 1; 23 + if (is_pcpu) { 24 + cpu_offset = i * nr_cpus; 25 + for (j = 0; j < nr_cpus; j++) 26 + (values + cpu_offset)[j] = i + 1 + j; 27 + } else { 28 + values[i] = i + 1; 29 + } 27 30 } 28 31 29 32 err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts); 30 33 CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno)); 31 34 } 32 35 33 - static void map_batch_verify(int *visited, __u32 max_entries, 34 - int *keys, int *values) 36 + static void map_batch_verify(int *visited, __u32 max_entries, int *keys, 37 + __s64 *values, bool is_pcpu) 35 38 { 36 - int i; 39 + int i, j; 40 + int cpu_offset = 0; 37 41 38 42 memset(visited, 0, max_entries * sizeof(*visited)); 39 43 for (i = 0; i < max_entries; i++) { 40 - CHECK(keys[i] + 1 != values[i], "key/value checking", 41 - "error: i %d key %d value %d\n", i, keys[i], values[i]); 44 + if (is_pcpu) { 45 + cpu_offset = i * nr_cpus; 46 + for (j = 0; j < nr_cpus; j++) { 47 + __s64 value = (values + cpu_offset)[j]; 48 + CHECK(keys[i] + j + 1 != value, 49 + "key/value checking", 50 + "error: i %d j %d key %d value %lld\n", i, 51 + j, keys[i], value); 52 + } 53 + } else { 54 + CHECK(keys[i] + 1 != values[i], "key/value checking", 55 + "error: i %d key %d value %lld\n", i, keys[i], 56 + values[i]); 57 + } 42 58 visited[i] = 1; 43 59 } 44 60 for (i = 0; i < max_entries; i++) { ··· 66 44 } 67 45 } 68 46 69 - void test_array_map_batch_ops(void) 47 + static void __test_map_lookup_and_update_batch(bool is_pcpu) 70 48 { 71 49 struct bpf_create_map_attr xattr = { 72 50 .name = "array_map", 73 - .map_type = BPF_MAP_TYPE_ARRAY, 51 + .map_type = is_pcpu ? BPF_MAP_TYPE_PERCPU_ARRAY : 52 + BPF_MAP_TYPE_ARRAY, 74 53 .key_size = sizeof(int), 75 - .value_size = sizeof(int), 54 + .value_size = sizeof(__s64), 76 55 }; 77 - int map_fd, *keys, *values, *visited; 56 + int map_fd, *keys, *visited; 78 57 __u32 count, total, total_success; 79 58 const __u32 max_entries = 10; 80 59 __u64 batch = 0; 81 - int err, step; 60 + int err, step, value_size; 61 + void *values; 82 62 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 83 63 .elem_flags = 0, 84 64 .flags = 0, ··· 91 67 CHECK(map_fd == -1, 92 68 "bpf_create_map_xattr()", "error:%s\n", strerror(errno)); 93 69 94 - keys = malloc(max_entries * sizeof(int)); 95 - values = malloc(max_entries * sizeof(int)); 96 - visited = malloc(max_entries * sizeof(int)); 70 + value_size = sizeof(__s64); 71 + if (is_pcpu) 72 + value_size *= nr_cpus; 73 + 74 + keys = calloc(max_entries, sizeof(*keys)); 75 + values = calloc(max_entries, value_size); 76 + visited = calloc(max_entries, sizeof(*visited)); 97 77 CHECK(!keys || !values || !visited, "malloc()", "error:%s\n", 98 78 strerror(errno)); 99 - 100 - /* populate elements to the map */ 101 - map_batch_update(map_fd, max_entries, keys, values); 102 79 103 80 /* test 1: lookup in a loop with various steps. */ 104 81 total_success = 0; 105 82 for (step = 1; step < max_entries; step++) { 106 - map_batch_update(map_fd, max_entries, keys, values); 107 - map_batch_verify(visited, max_entries, keys, values); 83 + map_batch_update(map_fd, max_entries, keys, values, is_pcpu); 84 + map_batch_verify(visited, max_entries, keys, values, is_pcpu); 108 85 memset(keys, 0, max_entries * sizeof(*keys)); 109 - memset(values, 0, max_entries * sizeof(*values)); 86 + memset(values, 0, max_entries * value_size); 110 87 batch = 0; 111 88 total = 0; 112 89 /* iteratively lookup/delete elements with 'step' ··· 116 91 count = step; 117 92 while (true) { 118 93 err = bpf_map_lookup_batch(map_fd, 119 - total ? &batch : NULL, &batch, 120 - keys + total, 121 - values + total, 122 - &count, &opts); 94 + total ? &batch : NULL, 95 + &batch, keys + total, 96 + values + total * value_size, 97 + &count, &opts); 123 98 124 99 CHECK((err && errno != ENOENT), "lookup with steps", 125 100 "error: %s\n", strerror(errno)); ··· 133 108 CHECK(total != max_entries, "lookup with steps", 134 109 "total = %u, max_entries = %u\n", total, max_entries); 135 110 136 - map_batch_verify(visited, max_entries, keys, values); 111 + map_batch_verify(visited, max_entries, keys, values, is_pcpu); 137 112 138 113 total_success++; 139 114 } ··· 141 116 CHECK(total_success == 0, "check total_success", 142 117 "unexpected failure\n"); 143 118 144 - printf("%s:PASS\n", __func__); 145 - 146 119 free(keys); 147 120 free(values); 148 121 free(visited); 122 + } 123 + 124 + static void array_map_batch_ops(void) 125 + { 126 + __test_map_lookup_and_update_batch(false); 127 + printf("test_%s:PASS\n", __func__); 128 + } 129 + 130 + static void array_percpu_map_batch_ops(void) 131 + { 132 + __test_map_lookup_and_update_batch(true); 133 + printf("test_%s:PASS\n", __func__); 134 + } 135 + 136 + void test_array_map_batch_ops(void) 137 + { 138 + nr_cpus = libbpf_num_possible_cpus(); 139 + 140 + CHECK(nr_cpus < 0, "nr_cpus checking", 141 + "error: get possible cpus failed"); 142 + 143 + array_map_batch_ops(); 144 + array_percpu_map_batch_ops(); 149 145 }