1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2019 Facebook */ 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 <bpf_util.h> 11 #include <test_maps.h> 12 13 static void map_batch_update(int map_fd, __u32 max_entries, int *keys, 14 void *values, bool is_pcpu) 15 { 16 typedef BPF_DECLARE_PERCPU(int, value); 17 value *v = NULL; 18 int i, j, err; 19 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 20 .elem_flags = 0, 21 .flags = 0, 22 ); 23 24 if (is_pcpu) 25 v = (value *)values; 26 27 for (i = 0; i < max_entries; i++) { 28 keys[i] = i + 1; 29 if (is_pcpu) 30 for (j = 0; j < bpf_num_possible_cpus(); j++) 31 bpf_percpu(v[i], j) = i + 2 + j; 32 else 33 ((int *)values)[i] = i + 2; 34 } 35 36 err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts); 37 CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno)); 38 } 39 40 static void map_batch_verify(int *visited, __u32 max_entries, 41 int *keys, void *values, bool is_pcpu) 42 { 43 typedef BPF_DECLARE_PERCPU(int, value); 44 value *v = NULL; 45 int i, j; 46 47 if (is_pcpu) 48 v = (value *)values; 49 50 memset(visited, 0, max_entries * sizeof(*visited)); 51 for (i = 0; i < max_entries; i++) { 52 53 if (is_pcpu) { 54 for (j = 0; j < bpf_num_possible_cpus(); j++) { 55 CHECK(keys[i] + 1 + j != bpf_percpu(v[i], j), 56 "key/value checking", 57 "error: i %d j %d key %d value %d\n", 58 i, j, keys[i], bpf_percpu(v[i], j)); 59 } 60 } else { 61 CHECK(keys[i] + 1 != ((int *)values)[i], 62 "key/value checking", 63 "error: i %d key %d value %d\n", i, keys[i], 64 ((int *)values)[i]); 65 } 66 67 visited[i] = 1; 68 69 } 70 for (i = 0; i < max_entries; i++) { 71 CHECK(visited[i] != 1, "visited checking", 72 "error: keys array at index %d missing\n", i); 73 } 74 } 75 76 void __test_map_lookup_and_delete_batch(bool is_pcpu) 77 { 78 __u32 batch, count, total, total_success; 79 typedef BPF_DECLARE_PERCPU(int, value); 80 int map_fd, *keys, *visited, key; 81 const __u32 max_entries = 10; 82 value pcpu_values[max_entries]; 83 int err, step, value_size; 84 bool nospace_err; 85 void *values; 86 struct bpf_create_map_attr xattr = { 87 .name = "hash_map", 88 .map_type = is_pcpu ? BPF_MAP_TYPE_PERCPU_HASH : 89 BPF_MAP_TYPE_HASH, 90 .key_size = sizeof(int), 91 .value_size = sizeof(int), 92 }; 93 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 94 .elem_flags = 0, 95 .flags = 0, 96 ); 97 98 xattr.max_entries = max_entries; 99 map_fd = bpf_create_map_xattr(&xattr); 100 CHECK(map_fd == -1, 101 "bpf_create_map_xattr()", "error:%s\n", strerror(errno)); 102 103 value_size = is_pcpu ? sizeof(value) : sizeof(int); 104 keys = malloc(max_entries * sizeof(int)); 105 if (is_pcpu) 106 values = pcpu_values; 107 else 108 values = malloc(max_entries * sizeof(int)); 109 visited = malloc(max_entries * sizeof(int)); 110 CHECK(!keys || !values || !visited, "malloc()", 111 "error:%s\n", strerror(errno)); 112 113 /* test 1: lookup/delete an empty hash table, -ENOENT */ 114 count = max_entries; 115 err = bpf_map_lookup_and_delete_batch(map_fd, NULL, &batch, keys, 116 values, &count, &opts); 117 CHECK((err && errno != ENOENT), "empty map", 118 "error: %s\n", strerror(errno)); 119 120 /* populate elements to the map */ 121 map_batch_update(map_fd, max_entries, keys, values, is_pcpu); 122 123 /* test 2: lookup/delete with count = 0, success */ 124 count = 0; 125 err = bpf_map_lookup_and_delete_batch(map_fd, NULL, &batch, keys, 126 values, &count, &opts); 127 CHECK(err, "count = 0", "error: %s\n", strerror(errno)); 128 129 /* test 3: lookup/delete with count = max_entries, success */ 130 memset(keys, 0, max_entries * sizeof(*keys)); 131 memset(values, 0, max_entries * value_size); 132 count = max_entries; 133 err = bpf_map_lookup_and_delete_batch(map_fd, NULL, &batch, keys, 134 values, &count, &opts); 135 CHECK((err && errno != ENOENT), "count = max_entries", 136 "error: %s\n", strerror(errno)); 137 CHECK(count != max_entries, "count = max_entries", 138 "count = %u, max_entries = %u\n", count, max_entries); 139 map_batch_verify(visited, max_entries, keys, values, is_pcpu); 140 141 /* bpf_map_get_next_key() should return -ENOENT for an empty map. */ 142 err = bpf_map_get_next_key(map_fd, NULL, &key); 143 CHECK(!err, "bpf_map_get_next_key()", "error: %s\n", strerror(errno)); 144 145 /* test 4: lookup/delete in a loop with various steps. */ 146 total_success = 0; 147 for (step = 1; step < max_entries; step++) { 148 map_batch_update(map_fd, max_entries, keys, values, is_pcpu); 149 memset(keys, 0, max_entries * sizeof(*keys)); 150 memset(values, 0, max_entries * value_size); 151 total = 0; 152 /* iteratively lookup/delete elements with 'step' 153 * elements each 154 */ 155 count = step; 156 nospace_err = false; 157 while (true) { 158 err = bpf_map_lookup_batch(map_fd, 159 total ? &batch : NULL, 160 &batch, keys + total, 161 values + 162 total * value_size, 163 &count, &opts); 164 /* It is possible that we are failing due to buffer size 165 * not big enough. In such cases, let us just exit and 166 * go with large steps. Not that a buffer size with 167 * max_entries should always work. 168 */ 169 if (err && errno == ENOSPC) { 170 nospace_err = true; 171 break; 172 } 173 174 CHECK((err && errno != ENOENT), "lookup with steps", 175 "error: %s\n", strerror(errno)); 176 177 total += count; 178 if (err) 179 break; 180 181 } 182 if (nospace_err == true) 183 continue; 184 185 CHECK(total != max_entries, "lookup with steps", 186 "total = %u, max_entries = %u\n", total, max_entries); 187 map_batch_verify(visited, max_entries, keys, values, is_pcpu); 188 189 total = 0; 190 count = step; 191 while (total < max_entries) { 192 if (max_entries - total < step) 193 count = max_entries - total; 194 err = bpf_map_delete_batch(map_fd, 195 keys + total, 196 &count, &opts); 197 CHECK((err && errno != ENOENT), "delete batch", 198 "error: %s\n", strerror(errno)); 199 total += count; 200 if (err) 201 break; 202 } 203 CHECK(total != max_entries, "delete with steps", 204 "total = %u, max_entries = %u\n", total, max_entries); 205 206 /* check map is empty, errono == ENOENT */ 207 err = bpf_map_get_next_key(map_fd, NULL, &key); 208 CHECK(!err || errno != ENOENT, "bpf_map_get_next_key()", 209 "error: %s\n", strerror(errno)); 210 211 /* iteratively lookup/delete elements with 'step' 212 * elements each 213 */ 214 map_batch_update(map_fd, max_entries, keys, values, is_pcpu); 215 memset(keys, 0, max_entries * sizeof(*keys)); 216 memset(values, 0, max_entries * value_size); 217 total = 0; 218 count = step; 219 nospace_err = false; 220 while (true) { 221 err = bpf_map_lookup_and_delete_batch(map_fd, 222 total ? &batch : NULL, 223 &batch, keys + total, 224 values + 225 total * value_size, 226 &count, &opts); 227 /* It is possible that we are failing due to buffer size 228 * not big enough. In such cases, let us just exit and 229 * go with large steps. Not that a buffer size with 230 * max_entries should always work. 231 */ 232 if (err && errno == ENOSPC) { 233 nospace_err = true; 234 break; 235 } 236 237 CHECK((err && errno != ENOENT), "lookup with steps", 238 "error: %s\n", strerror(errno)); 239 240 total += count; 241 if (err) 242 break; 243 } 244 245 if (nospace_err == true) 246 continue; 247 248 CHECK(total != max_entries, "lookup/delete with steps", 249 "total = %u, max_entries = %u\n", total, max_entries); 250 251 map_batch_verify(visited, max_entries, keys, values, is_pcpu); 252 err = bpf_map_get_next_key(map_fd, NULL, &key); 253 CHECK(!err, "bpf_map_get_next_key()", "error: %s\n", 254 strerror(errno)); 255 256 total_success++; 257 } 258 259 CHECK(total_success == 0, "check total_success", 260 "unexpected failure\n"); 261 free(keys); 262 free(visited); 263 if (!is_pcpu) 264 free(values); 265 } 266 267 void htab_map_batch_ops(void) 268 { 269 __test_map_lookup_and_delete_batch(false); 270 printf("test_%s:PASS\n", __func__); 271 } 272 273 void htab_percpu_map_batch_ops(void) 274 { 275 __test_map_lookup_and_delete_batch(true); 276 printf("test_%s:PASS\n", __func__); 277 } 278 279 void test_htab_map_batch_ops(void) 280 { 281 htab_map_batch_ops(); 282 htab_percpu_map_batch_ops(); 283 } 284