Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 #include <stdio.h>
0004 #include <errno.h>
0005 #include <string.h>
0006 #include <unistd.h>
0007 
0008 #include <bpf/bpf.h>
0009 #include <bpf/libbpf.h>
0010 
0011 #include <test_maps.h>
0012 
0013 #define OUTER_MAP_ENTRIES 10
0014 
0015 static __u32 get_map_id_from_fd(int map_fd)
0016 {
0017     struct bpf_map_info map_info = {};
0018     uint32_t info_len = sizeof(map_info);
0019     int ret;
0020 
0021     ret = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len);
0022     CHECK(ret < 0, "Finding map info failed", "error:%s\n",
0023           strerror(errno));
0024 
0025     return map_info.id;
0026 }
0027 
0028 /* This creates number of OUTER_MAP_ENTRIES maps that will be stored
0029  * in outer map and return the created map_fds
0030  */
0031 static void create_inner_maps(enum bpf_map_type map_type,
0032                   __u32 *inner_map_fds)
0033 {
0034     int map_fd, map_index, ret;
0035     __u32 map_key = 0, map_id;
0036     char map_name[15];
0037 
0038     for (map_index = 0; map_index < OUTER_MAP_ENTRIES; map_index++) {
0039         memset(map_name, 0, sizeof(map_name));
0040         sprintf(map_name, "inner_map_fd_%d", map_index);
0041         map_fd = bpf_map_create(map_type, map_name, sizeof(__u32),
0042                     sizeof(__u32), 1, NULL);
0043         CHECK(map_fd < 0,
0044               "inner bpf_map_create() failed",
0045               "map_type=(%d) map_name(%s), error:%s\n",
0046               map_type, map_name, strerror(errno));
0047 
0048         /* keep track of the inner map fd as it is required
0049          * to add records in outer map
0050          */
0051         inner_map_fds[map_index] = map_fd;
0052 
0053         /* Add entry into this created map
0054          * eg: map1 key = 0, value = map1's map id
0055          *     map2 key = 0, value = map2's map id
0056          */
0057         map_id = get_map_id_from_fd(map_fd);
0058         ret = bpf_map_update_elem(map_fd, &map_key, &map_id, 0);
0059         CHECK(ret != 0,
0060               "bpf_map_update_elem failed",
0061               "map_type=(%d) map_name(%s), error:%s\n",
0062               map_type, map_name, strerror(errno));
0063     }
0064 }
0065 
0066 static int create_outer_map(enum bpf_map_type map_type, __u32 inner_map_fd)
0067 {
0068     int outer_map_fd;
0069     LIBBPF_OPTS(bpf_map_create_opts, attr);
0070 
0071     attr.inner_map_fd = inner_map_fd;
0072     outer_map_fd = bpf_map_create(map_type, "outer_map", sizeof(__u32),
0073                       sizeof(__u32), OUTER_MAP_ENTRIES,
0074                       &attr);
0075     CHECK(outer_map_fd < 0,
0076           "outer bpf_map_create()",
0077           "map_type=(%d), error:%s\n",
0078           map_type, strerror(errno));
0079 
0080     return outer_map_fd;
0081 }
0082 
0083 static void validate_fetch_results(int outer_map_fd,
0084                    __u32 *fetched_keys, __u32 *fetched_values,
0085                    __u32 max_entries_fetched)
0086 {
0087     __u32 inner_map_key, inner_map_value;
0088     int inner_map_fd, entry, err;
0089     __u32 outer_map_value;
0090 
0091     for (entry = 0; entry < max_entries_fetched; ++entry) {
0092         outer_map_value = fetched_values[entry];
0093         inner_map_fd = bpf_map_get_fd_by_id(outer_map_value);
0094         CHECK(inner_map_fd < 0,
0095               "Failed to get inner map fd",
0096               "from id(%d), error=%s\n",
0097               outer_map_value, strerror(errno));
0098         err = bpf_map_get_next_key(inner_map_fd, NULL, &inner_map_key);
0099         CHECK(err != 0,
0100               "Failed to get inner map key",
0101               "error=%s\n", strerror(errno));
0102 
0103         err = bpf_map_lookup_elem(inner_map_fd, &inner_map_key,
0104                       &inner_map_value);
0105 
0106         close(inner_map_fd);
0107 
0108         CHECK(err != 0,
0109               "Failed to get inner map value",
0110               "for key(%d), error=%s\n",
0111               inner_map_key, strerror(errno));
0112 
0113         /* Actual value validation */
0114         CHECK(outer_map_value != inner_map_value,
0115               "Failed to validate inner map value",
0116               "fetched(%d) and lookedup(%d)!\n",
0117               outer_map_value, inner_map_value);
0118     }
0119 }
0120 
0121 static void fetch_and_validate(int outer_map_fd,
0122                    struct bpf_map_batch_opts *opts,
0123                    __u32 batch_size, bool delete_entries)
0124 {
0125     __u32 *fetched_keys, *fetched_values, total_fetched = 0;
0126     __u32 batch_key = 0, fetch_count, step_size;
0127     int err, max_entries = OUTER_MAP_ENTRIES;
0128     __u32 value_size = sizeof(__u32);
0129 
0130     /* Total entries needs to be fetched */
0131     fetched_keys = calloc(max_entries, value_size);
0132     fetched_values = calloc(max_entries, value_size);
0133     CHECK((!fetched_keys || !fetched_values),
0134           "Memory allocation failed for fetched_keys or fetched_values",
0135           "error=%s\n", strerror(errno));
0136 
0137     for (step_size = batch_size;
0138          step_size <= max_entries;
0139          step_size += batch_size) {
0140         fetch_count = step_size;
0141         err = delete_entries
0142               ? bpf_map_lookup_and_delete_batch(outer_map_fd,
0143                       total_fetched ? &batch_key : NULL,
0144                       &batch_key,
0145                       fetched_keys + total_fetched,
0146                       fetched_values + total_fetched,
0147                       &fetch_count, opts)
0148               : bpf_map_lookup_batch(outer_map_fd,
0149                       total_fetched ? &batch_key : NULL,
0150                       &batch_key,
0151                       fetched_keys + total_fetched,
0152                       fetched_values + total_fetched,
0153                       &fetch_count, opts);
0154 
0155         if (err && errno == ENOSPC) {
0156             /* Fetch again with higher batch size */
0157             total_fetched = 0;
0158             continue;
0159         }
0160 
0161         CHECK((err < 0 && (errno != ENOENT)),
0162               "lookup with steps failed",
0163               "error: %s\n", strerror(errno));
0164 
0165         /* Update the total fetched number */
0166         total_fetched += fetch_count;
0167         if (err)
0168             break;
0169     }
0170 
0171     CHECK((total_fetched != max_entries),
0172           "Unable to fetch expected entries !",
0173           "total_fetched(%d) and max_entries(%d) error: (%d):%s\n",
0174           total_fetched, max_entries, errno, strerror(errno));
0175 
0176     /* validate the fetched entries */
0177     validate_fetch_results(outer_map_fd, fetched_keys,
0178                    fetched_values, total_fetched);
0179     printf("batch_op(%s) is successful with batch_size(%d)\n",
0180            delete_entries ? "LOOKUP_AND_DELETE" : "LOOKUP", batch_size);
0181 
0182     free(fetched_keys);
0183     free(fetched_values);
0184 }
0185 
0186 static void _map_in_map_batch_ops(enum bpf_map_type outer_map_type,
0187                   enum bpf_map_type inner_map_type)
0188 {
0189     __u32 *outer_map_keys, *inner_map_fds;
0190     __u32 max_entries = OUTER_MAP_ENTRIES;
0191     LIBBPF_OPTS(bpf_map_batch_opts, opts);
0192     __u32 value_size = sizeof(__u32);
0193     int batch_size[2] = {5, 10};
0194     __u32 map_index, op_index;
0195     int outer_map_fd, ret;
0196 
0197     outer_map_keys = calloc(max_entries, value_size);
0198     inner_map_fds = calloc(max_entries, value_size);
0199     CHECK((!outer_map_keys || !inner_map_fds),
0200           "Memory allocation failed for outer_map_keys or inner_map_fds",
0201           "error=%s\n", strerror(errno));
0202 
0203     create_inner_maps(inner_map_type, inner_map_fds);
0204 
0205     outer_map_fd = create_outer_map(outer_map_type, *inner_map_fds);
0206     /* create outer map keys */
0207     for (map_index = 0; map_index < max_entries; map_index++)
0208         outer_map_keys[map_index] =
0209             ((outer_map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS)
0210              ? 9 : 1000) - map_index;
0211 
0212     /* batch operation - map_update */
0213     ret = bpf_map_update_batch(outer_map_fd, outer_map_keys,
0214                    inner_map_fds, &max_entries, &opts);
0215     CHECK(ret != 0,
0216           "Failed to update the outer map batch ops",
0217           "error=%s\n", strerror(errno));
0218 
0219     /* batch operation - map_lookup */
0220     for (op_index = 0; op_index < 2; ++op_index)
0221         fetch_and_validate(outer_map_fd, &opts,
0222                    batch_size[op_index], false);
0223 
0224     /* batch operation - map_lookup_delete */
0225     if (outer_map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
0226         fetch_and_validate(outer_map_fd, &opts,
0227                    max_entries, true /*delete*/);
0228 
0229     /* close all map fds */
0230     for (map_index = 0; map_index < max_entries; map_index++)
0231         close(inner_map_fds[map_index]);
0232     close(outer_map_fd);
0233 
0234     free(inner_map_fds);
0235     free(outer_map_keys);
0236 }
0237 
0238 void test_map_in_map_batch_ops_array(void)
0239 {
0240     _map_in_map_batch_ops(BPF_MAP_TYPE_ARRAY_OF_MAPS, BPF_MAP_TYPE_ARRAY);
0241     printf("%s:PASS with inner ARRAY map\n", __func__);
0242     _map_in_map_batch_ops(BPF_MAP_TYPE_ARRAY_OF_MAPS, BPF_MAP_TYPE_HASH);
0243     printf("%s:PASS with inner HASH map\n", __func__);
0244 }
0245 
0246 void test_map_in_map_batch_ops_hash(void)
0247 {
0248     _map_in_map_batch_ops(BPF_MAP_TYPE_HASH_OF_MAPS, BPF_MAP_TYPE_ARRAY);
0249     printf("%s:PASS with inner ARRAY map\n", __func__);
0250     _map_in_map_batch_ops(BPF_MAP_TYPE_HASH_OF_MAPS, BPF_MAP_TYPE_HASH);
0251     printf("%s:PASS with inner HASH map\n", __func__);
0252 }