0001
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
0029
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
0049
0050
0051 inner_map_fds[map_index] = map_fd;
0052
0053
0054
0055
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
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
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
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
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
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
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
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
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
0225 if (outer_map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
0226 fetch_and_validate(outer_map_fd, &opts,
0227 max_entries, true );
0228
0229
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 }