@@ -120,11 +120,12 @@ static void validate_fetch_results(int outer_map_fd,
120
120
121
121
static void fetch_and_validate (int outer_map_fd ,
122
122
struct bpf_map_batch_opts * opts ,
123
- __u32 batch_size , bool delete_entries )
123
+ __u32 batch_size , bool delete_entries ,
124
+ bool has_holes )
124
125
{
125
- __u32 * fetched_keys , * fetched_values , total_fetched = 0 ;
126
- __u32 batch_key = 0 , fetch_count , step_size ;
127
- int err , max_entries = OUTER_MAP_ENTRIES ;
126
+ int err , max_entries = OUTER_MAP_ENTRIES - !! has_holes ;
127
+ __u32 * fetched_keys , * fetched_values , total_fetched = 0 , i ;
128
+ __u32 batch_key = 0 , fetch_count , step_size = batch_size ;
128
129
__u32 value_size = sizeof (__u32 );
129
130
130
131
/* Total entries needs to be fetched */
@@ -134,9 +135,8 @@ static void fetch_and_validate(int outer_map_fd,
134
135
"Memory allocation failed for fetched_keys or fetched_values" ,
135
136
"error=%s\n" , strerror (errno ));
136
137
137
- for (step_size = batch_size ;
138
- step_size <= max_entries ;
139
- step_size += batch_size ) {
138
+ /* hash map may not always return full batch */
139
+ for (i = 0 ; i < OUTER_MAP_ENTRIES ; i ++ ) {
140
140
fetch_count = step_size ;
141
141
err = delete_entries
142
142
? bpf_map_lookup_and_delete_batch (outer_map_fd ,
@@ -155,6 +155,7 @@ static void fetch_and_validate(int outer_map_fd,
155
155
if (err && errno == ENOSPC ) {
156
156
/* Fetch again with higher batch size */
157
157
total_fetched = 0 ;
158
+ step_size += batch_size ;
158
159
continue ;
159
160
}
160
161
@@ -184,18 +185,19 @@ static void fetch_and_validate(int outer_map_fd,
184
185
}
185
186
186
187
static void _map_in_map_batch_ops (enum bpf_map_type outer_map_type ,
187
- enum bpf_map_type inner_map_type )
188
+ enum bpf_map_type inner_map_type ,
189
+ bool has_holes )
188
190
{
191
+ __u32 max_entries = OUTER_MAP_ENTRIES - !!has_holes ;
189
192
__u32 * outer_map_keys , * inner_map_fds ;
190
- __u32 max_entries = OUTER_MAP_ENTRIES ;
191
193
LIBBPF_OPTS (bpf_map_batch_opts , opts );
192
194
__u32 value_size = sizeof (__u32 );
193
195
int batch_size [2 ] = {5 , 10 };
194
196
__u32 map_index , op_index ;
195
197
int outer_map_fd , ret ;
196
198
197
- outer_map_keys = calloc (max_entries , value_size );
198
- inner_map_fds = calloc (max_entries , value_size );
199
+ outer_map_keys = calloc (OUTER_MAP_ENTRIES , value_size );
200
+ inner_map_fds = calloc (OUTER_MAP_ENTRIES , value_size );
199
201
CHECK ((!outer_map_keys || !inner_map_fds ),
200
202
"Memory allocation failed for outer_map_keys or inner_map_fds" ,
201
203
"error=%s\n" , strerror (errno ));
@@ -209,6 +211,24 @@ static void _map_in_map_batch_ops(enum bpf_map_type outer_map_type,
209
211
((outer_map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS )
210
212
? 9 : 1000 ) - map_index ;
211
213
214
+ /* This condition is only meaningful for array of maps.
215
+ *
216
+ * max_entries == OUTER_MAP_ENTRIES - 1 if it is true. Say
217
+ * max_entries is short for n, then outer_map_keys looks like:
218
+ *
219
+ * [n, n-1, ... 2, 1]
220
+ *
221
+ * We change it to
222
+ *
223
+ * [n, n-1, ... 2, 0]
224
+ *
225
+ * So it will leave key 1 as a hole. It will serve to test the
226
+ * correctness when batch on an array: a "non-exist" key might be
227
+ * actually allocated and returned from key iteration.
228
+ */
229
+ if (has_holes )
230
+ outer_map_keys [max_entries - 1 ]-- ;
231
+
212
232
/* batch operation - map_update */
213
233
ret = bpf_map_update_batch (outer_map_fd , outer_map_keys ,
214
234
inner_map_fds , & max_entries , & opts );
@@ -219,15 +239,17 @@ static void _map_in_map_batch_ops(enum bpf_map_type outer_map_type,
219
239
/* batch operation - map_lookup */
220
240
for (op_index = 0 ; op_index < 2 ; ++ op_index )
221
241
fetch_and_validate (outer_map_fd , & opts ,
222
- batch_size [op_index ], false);
242
+ batch_size [op_index ], false,
243
+ has_holes );
223
244
224
245
/* batch operation - map_lookup_delete */
225
246
if (outer_map_type == BPF_MAP_TYPE_HASH_OF_MAPS )
226
247
fetch_and_validate (outer_map_fd , & opts ,
227
- max_entries , true /*delete*/ );
248
+ max_entries , true /*delete*/ ,
249
+ has_holes );
228
250
229
251
/* close all map fds */
230
- for (map_index = 0 ; map_index < max_entries ; map_index ++ )
252
+ for (map_index = 0 ; map_index < OUTER_MAP_ENTRIES ; map_index ++ )
231
253
close (inner_map_fds [map_index ]);
232
254
close (outer_map_fd );
233
255
@@ -237,16 +259,20 @@ static void _map_in_map_batch_ops(enum bpf_map_type outer_map_type,
237
259
238
260
void test_map_in_map_batch_ops_array (void )
239
261
{
240
- _map_in_map_batch_ops (BPF_MAP_TYPE_ARRAY_OF_MAPS , BPF_MAP_TYPE_ARRAY );
262
+ _map_in_map_batch_ops (BPF_MAP_TYPE_ARRAY_OF_MAPS , BPF_MAP_TYPE_ARRAY , false );
241
263
printf ("%s:PASS with inner ARRAY map\n" , __func__ );
242
- _map_in_map_batch_ops (BPF_MAP_TYPE_ARRAY_OF_MAPS , BPF_MAP_TYPE_HASH );
264
+ _map_in_map_batch_ops (BPF_MAP_TYPE_ARRAY_OF_MAPS , BPF_MAP_TYPE_HASH , false );
243
265
printf ("%s:PASS with inner HASH map\n" , __func__ );
266
+ _map_in_map_batch_ops (BPF_MAP_TYPE_ARRAY_OF_MAPS , BPF_MAP_TYPE_ARRAY , true);
267
+ printf ("%s:PASS with inner ARRAY map with holes\n" , __func__ );
268
+ _map_in_map_batch_ops (BPF_MAP_TYPE_ARRAY_OF_MAPS , BPF_MAP_TYPE_HASH , true);
269
+ printf ("%s:PASS with inner HASH map with holes\n" , __func__ );
244
270
}
245
271
246
272
void test_map_in_map_batch_ops_hash (void )
247
273
{
248
- _map_in_map_batch_ops (BPF_MAP_TYPE_HASH_OF_MAPS , BPF_MAP_TYPE_ARRAY );
274
+ _map_in_map_batch_ops (BPF_MAP_TYPE_HASH_OF_MAPS , BPF_MAP_TYPE_ARRAY , false );
249
275
printf ("%s:PASS with inner ARRAY map\n" , __func__ );
250
- _map_in_map_batch_ops (BPF_MAP_TYPE_HASH_OF_MAPS , BPF_MAP_TYPE_HASH );
276
+ _map_in_map_batch_ops (BPF_MAP_TYPE_HASH_OF_MAPS , BPF_MAP_TYPE_HASH , false );
251
277
printf ("%s:PASS with inner HASH map\n" , __func__ );
252
278
}
0 commit comments