]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/map_tests/htab_map_batch_ops.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / bpf / map_tests / htab_map_batch_ops.c
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, errno == 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 }
This page took 0.045007 seconds and 4 git commands to generate.