@@ -120,11 +120,12 @@ static void validate_fetch_results(int outer_map_fd,
120120
121121static void fetch_and_validate (int outer_map_fd ,
122122 struct bpf_map_batch_opts * opts ,
123- __u32 batch_size , bool delete_entries )
123+ __u32 batch_size , bool delete_entries ,
124+ bool has_holes )
124125{
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 ;
128129 __u32 value_size = sizeof (__u32 );
129130
130131 /* Total entries needs to be fetched */
@@ -134,9 +135,8 @@ static void fetch_and_validate(int outer_map_fd,
134135 "Memory allocation failed for fetched_keys or fetched_values" ,
135136 "error=%s\n" , strerror (errno ));
136137
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 ++ ) {
140140 fetch_count = step_size ;
141141 err = delete_entries
142142 ? bpf_map_lookup_and_delete_batch (outer_map_fd ,
@@ -155,6 +155,7 @@ static void fetch_and_validate(int outer_map_fd,
155155 if (err && errno == ENOSPC ) {
156156 /* Fetch again with higher batch size */
157157 total_fetched = 0 ;
158+ step_size += batch_size ;
158159 continue ;
159160 }
160161
@@ -184,18 +185,19 @@ static void fetch_and_validate(int outer_map_fd,
184185}
185186
186187static 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 )
188190{
191+ __u32 max_entries = OUTER_MAP_ENTRIES - !!has_holes ;
189192 __u32 * outer_map_keys , * inner_map_fds ;
190- __u32 max_entries = OUTER_MAP_ENTRIES ;
191193 LIBBPF_OPTS (bpf_map_batch_opts , opts );
192194 __u32 value_size = sizeof (__u32 );
193195 int batch_size [2 ] = {5 , 10 };
194196 __u32 map_index , op_index ;
195197 int outer_map_fd , ret ;
196198
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 );
199201 CHECK ((!outer_map_keys || !inner_map_fds ),
200202 "Memory allocation failed for outer_map_keys or inner_map_fds" ,
201203 "error=%s\n" , strerror (errno ));
@@ -209,6 +211,24 @@ static void _map_in_map_batch_ops(enum bpf_map_type outer_map_type,
209211 ((outer_map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS )
210212 ? 9 : 1000 ) - map_index ;
211213
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+
212232 /* batch operation - map_update */
213233 ret = bpf_map_update_batch (outer_map_fd , outer_map_keys ,
214234 inner_map_fds , & max_entries , & opts );
@@ -219,15 +239,17 @@ static void _map_in_map_batch_ops(enum bpf_map_type outer_map_type,
219239 /* batch operation - map_lookup */
220240 for (op_index = 0 ; op_index < 2 ; ++ op_index )
221241 fetch_and_validate (outer_map_fd , & opts ,
222- batch_size [op_index ], false);
242+ batch_size [op_index ], false,
243+ has_holes );
223244
224245 /* batch operation - map_lookup_delete */
225246 if (outer_map_type == BPF_MAP_TYPE_HASH_OF_MAPS )
226247 fetch_and_validate (outer_map_fd , & opts ,
227- max_entries , true /*delete*/ );
248+ max_entries , true /*delete*/ ,
249+ has_holes );
228250
229251 /* 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 ++ )
231253 close (inner_map_fds [map_index ]);
232254 close (outer_map_fd );
233255
@@ -237,16 +259,20 @@ static void _map_in_map_batch_ops(enum bpf_map_type outer_map_type,
237259
238260void test_map_in_map_batch_ops_array (void )
239261{
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 );
241263 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 );
243265 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__ );
244270}
245271
246272void test_map_in_map_batch_ops_hash (void )
247273{
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 );
249275 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 );
251277 printf ("%s:PASS with inner HASH map\n" , __func__ );
252278}
0 commit comments