1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2019 Facebook */
8 #include <bpf/libbpf.h>
11 #include <test_maps.h>
13 static void map_batch_update(int map_fd
, __u32 max_entries
, int *keys
,
14 void *values
, bool is_pcpu
)
16 typedef BPF_DECLARE_PERCPU(int, value
);
19 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts
, opts
,
27 for (i
= 0; i
< max_entries
; i
++) {
30 for (j
= 0; j
< bpf_num_possible_cpus(); j
++)
31 bpf_percpu(v
[i
], j
) = i
+ 2 + j
;
33 ((int *)values
)[i
] = i
+ 2;
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
));
40 static void map_batch_verify(int *visited
, __u32 max_entries
,
41 int *keys
, void *values
, bool is_pcpu
)
43 typedef BPF_DECLARE_PERCPU(int, value
);
50 memset(visited
, 0, max_entries
* sizeof(*visited
));
51 for (i
= 0; i
< max_entries
; i
++) {
54 for (j
= 0; j
< bpf_num_possible_cpus(); j
++) {
55 CHECK(keys
[i
] + 1 + j
!= bpf_percpu(v
[i
], j
),
57 "error: i %d j %d key %d value %d\n",
58 i
, j
, keys
[i
], bpf_percpu(v
[i
], j
));
61 CHECK(keys
[i
] + 1 != ((int *)values
)[i
],
63 "error: i %d key %d value %d\n", i
, keys
[i
],
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
);
76 void __test_map_lookup_and_delete_batch(bool is_pcpu
)
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
;
86 struct bpf_create_map_attr xattr
= {
88 .map_type
= is_pcpu
? BPF_MAP_TYPE_PERCPU_HASH
:
90 .key_size
= sizeof(int),
91 .value_size
= sizeof(int),
93 DECLARE_LIBBPF_OPTS(bpf_map_batch_opts
, opts
,
98 xattr
.max_entries
= max_entries
;
99 map_fd
= bpf_create_map_xattr(&xattr
);
101 "bpf_create_map_xattr()", "error:%s\n", strerror(errno
));
103 value_size
= is_pcpu
? sizeof(value
) : sizeof(int);
104 keys
= malloc(max_entries
* sizeof(int));
106 values
= pcpu_values
;
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
));
113 /* test 1: lookup/delete an empty hash table, -ENOENT */
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
));
120 /* populate elements to the map */
121 map_batch_update(map_fd
, max_entries
, keys
, values
, is_pcpu
);
123 /* test 2: lookup/delete with count = 0, success */
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
));
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
);
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
);
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
));
145 /* test 4: lookup/delete in a loop with various steps. */
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
);
152 /* iteratively lookup/delete elements with 'step'
158 err
= bpf_map_lookup_batch(map_fd
,
159 total
? &batch
: NULL
,
160 &batch
, keys
+ total
,
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.
169 if (err
&& errno
== ENOSPC
) {
174 CHECK((err
&& errno
!= ENOENT
), "lookup with steps",
175 "error: %s\n", strerror(errno
));
182 if (nospace_err
== true)
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
);
191 while (total
< max_entries
) {
192 if (max_entries
- total
< step
)
193 count
= max_entries
- total
;
194 err
= bpf_map_delete_batch(map_fd
,
197 CHECK((err
&& errno
!= ENOENT
), "delete batch",
198 "error: %s\n", strerror(errno
));
203 CHECK(total
!= max_entries
, "delete with steps",
204 "total = %u, max_entries = %u\n", total
, max_entries
);
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
));
211 /* iteratively lookup/delete elements with 'step'
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
);
221 err
= bpf_map_lookup_and_delete_batch(map_fd
,
222 total
? &batch
: NULL
,
223 &batch
, keys
+ total
,
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.
232 if (err
&& errno
== ENOSPC
) {
237 CHECK((err
&& errno
!= ENOENT
), "lookup with steps",
238 "error: %s\n", strerror(errno
));
245 if (nospace_err
== true)
248 CHECK(total
!= max_entries
, "lookup/delete with steps",
249 "total = %u, max_entries = %u\n", total
, max_entries
);
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",
259 CHECK(total_success
== 0, "check total_success",
260 "unexpected failure\n");
267 void htab_map_batch_ops(void)
269 __test_map_lookup_and_delete_batch(false);
270 printf("test_%s:PASS\n", __func__
);
273 void htab_percpu_map_batch_ops(void)
275 __test_map_lookup_and_delete_batch(true);
276 printf("test_%s:PASS\n", __func__
);
279 void test_htab_map_batch_ops(void)
281 htab_map_batch_ops();
282 htab_percpu_map_batch_ops();