Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Test the update operations for htab of maps

Add test cases to verify the following four update operations on htab of
maps don't trigger lockdep warning:

(1) add then delete
(2) add, overwrite, then delete
(3) add, then lookup_and_delete
(4) add two elements, then lookup_and_delete_batch

Test cases are added for pre-allocated and non-preallocated htab of maps
respectively.

Signed-off-by: Hou Tao <houtao1@huawei.com>
Link: https://lore.kernel.org/r/20241106063542.357743-4-houtao@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

authored by

Hou Tao and committed by
Andrii Nakryiko
cb55657c 503cfb10

+161 -1
+131 -1
tools/testing/selftests/bpf/prog_tests/map_in_map.c
··· 5 5 #include <sys/syscall.h> 6 6 #include <test_progs.h> 7 7 #include <bpf/btf.h> 8 + 8 9 #include "access_map_in_map.skel.h" 10 + #include "update_map_in_htab.skel.h" 9 11 10 12 struct thread_ctx { 11 13 pthread_barrier_t barrier; ··· 129 127 access_map_in_map__destroy(skel); 130 128 } 131 129 130 + static void add_del_fd_htab(int outer_fd) 131 + { 132 + int inner_fd, err; 133 + int key = 1; 134 + 135 + inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr1", 4, 4, 1, NULL); 136 + if (!ASSERT_OK_FD(inner_fd, "inner1")) 137 + return; 138 + err = bpf_map_update_elem(outer_fd, &key, &inner_fd, BPF_NOEXIST); 139 + close(inner_fd); 140 + if (!ASSERT_OK(err, "add")) 141 + return; 142 + 143 + /* Delete */ 144 + err = bpf_map_delete_elem(outer_fd, &key); 145 + ASSERT_OK(err, "del"); 146 + } 147 + 148 + static void overwrite_fd_htab(int outer_fd) 149 + { 150 + int inner_fd, err; 151 + int key = 1; 152 + 153 + inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr1", 4, 4, 1, NULL); 154 + if (!ASSERT_OK_FD(inner_fd, "inner1")) 155 + return; 156 + err = bpf_map_update_elem(outer_fd, &key, &inner_fd, BPF_NOEXIST); 157 + close(inner_fd); 158 + if (!ASSERT_OK(err, "add")) 159 + return; 160 + 161 + /* Overwrite */ 162 + inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr2", 4, 4, 1, NULL); 163 + if (!ASSERT_OK_FD(inner_fd, "inner2")) 164 + goto out; 165 + err = bpf_map_update_elem(outer_fd, &key, &inner_fd, BPF_EXIST); 166 + close(inner_fd); 167 + if (!ASSERT_OK(err, "overwrite")) 168 + goto out; 169 + 170 + err = bpf_map_delete_elem(outer_fd, &key); 171 + ASSERT_OK(err, "del"); 172 + return; 173 + out: 174 + bpf_map_delete_elem(outer_fd, &key); 175 + } 176 + 177 + static void lookup_delete_fd_htab(int outer_fd) 178 + { 179 + int key = 1, value; 180 + int inner_fd, err; 181 + 182 + inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr1", 4, 4, 1, NULL); 183 + if (!ASSERT_OK_FD(inner_fd, "inner1")) 184 + return; 185 + err = bpf_map_update_elem(outer_fd, &key, &inner_fd, BPF_NOEXIST); 186 + close(inner_fd); 187 + if (!ASSERT_OK(err, "add")) 188 + return; 189 + 190 + /* lookup_and_delete is not supported for htab of maps */ 191 + err = bpf_map_lookup_and_delete_elem(outer_fd, &key, &value); 192 + ASSERT_EQ(err, -ENOTSUPP, "lookup_del"); 193 + 194 + err = bpf_map_delete_elem(outer_fd, &key); 195 + ASSERT_OK(err, "del"); 196 + } 197 + 198 + static void batched_lookup_delete_fd_htab(int outer_fd) 199 + { 200 + int keys[2] = {1, 2}, values[2]; 201 + unsigned int cnt, batch; 202 + int inner_fd, err; 203 + 204 + inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr1", 4, 4, 1, NULL); 205 + if (!ASSERT_OK_FD(inner_fd, "inner1")) 206 + return; 207 + 208 + err = bpf_map_update_elem(outer_fd, &keys[0], &inner_fd, BPF_NOEXIST); 209 + close(inner_fd); 210 + if (!ASSERT_OK(err, "add1")) 211 + return; 212 + 213 + inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, "arr2", 4, 4, 1, NULL); 214 + if (!ASSERT_OK_FD(inner_fd, "inner2")) 215 + goto out; 216 + err = bpf_map_update_elem(outer_fd, &keys[1], &inner_fd, BPF_NOEXIST); 217 + close(inner_fd); 218 + if (!ASSERT_OK(err, "add2")) 219 + goto out; 220 + 221 + /* batched lookup_and_delete */ 222 + cnt = ARRAY_SIZE(keys); 223 + err = bpf_map_lookup_and_delete_batch(outer_fd, NULL, &batch, keys, values, &cnt, NULL); 224 + ASSERT_TRUE((!err || err == -ENOENT), "delete_batch ret"); 225 + ASSERT_EQ(cnt, ARRAY_SIZE(keys), "delete_batch cnt"); 226 + 227 + out: 228 + bpf_map_delete_elem(outer_fd, &keys[0]); 229 + } 230 + 231 + static void test_update_map_in_htab(bool preallocate) 232 + { 233 + struct update_map_in_htab *skel; 234 + int err, fd; 235 + 236 + skel = update_map_in_htab__open(); 237 + if (!ASSERT_OK_PTR(skel, "open")) 238 + return; 239 + 240 + err = update_map_in_htab__load(skel); 241 + if (!ASSERT_OK(err, "load")) 242 + goto out; 243 + 244 + fd = preallocate ? bpf_map__fd(skel->maps.outer_htab_map) : 245 + bpf_map__fd(skel->maps.outer_alloc_htab_map); 246 + 247 + add_del_fd_htab(fd); 248 + overwrite_fd_htab(fd); 249 + lookup_delete_fd_htab(fd); 250 + batched_lookup_delete_fd_htab(fd); 251 + out: 252 + update_map_in_htab__destroy(skel); 253 + } 254 + 132 255 void test_map_in_map(void) 133 256 { 134 257 if (test__start_subtest("acc_map_in_array")) ··· 264 137 test_map_in_map_access("access_map_in_htab", "outer_htab_map"); 265 138 if (test__start_subtest("sleepable_acc_map_in_htab")) 266 139 test_map_in_map_access("sleepable_access_map_in_htab", "outer_htab_map"); 140 + if (test__start_subtest("update_map_in_htab")) 141 + test_update_map_in_htab(true); 142 + if (test__start_subtest("update_map_in_alloc_htab")) 143 + test_update_map_in_htab(false); 267 144 } 268 -
+30
tools/testing/selftests/bpf/progs/update_map_in_htab.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (C) 2024. Huawei Technologies Co., Ltd */ 3 + #include <linux/bpf.h> 4 + #include <bpf/bpf_helpers.h> 5 + 6 + struct inner_map_type { 7 + __uint(type, BPF_MAP_TYPE_ARRAY); 8 + __uint(key_size, 4); 9 + __uint(value_size, 4); 10 + __uint(max_entries, 1); 11 + } inner_map SEC(".maps"); 12 + 13 + struct { 14 + __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); 15 + __type(key, int); 16 + __type(value, int); 17 + __uint(max_entries, 2); 18 + __array(values, struct inner_map_type); 19 + } outer_htab_map SEC(".maps"); 20 + 21 + struct { 22 + __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); 23 + __uint(map_flags, BPF_F_NO_PREALLOC); 24 + __type(key, int); 25 + __type(value, int); 26 + __uint(max_entries, 2); 27 + __array(values, struct inner_map_type); 28 + } outer_alloc_htab_map SEC(".maps"); 29 + 30 + char _license[] SEC("license") = "GPL";