~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php