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