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

selftest: bpf: Test copying a sockmap and sockhash

Since we can now call map_update_elem(sockmap) from bpf_iter context
it's possible to copy a sockmap or sockhash in the kernel. Add a
selftest which exercises this.

Signed-off-by: Lorenz Bauer <lmb@cloudflare.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200928090805.23343-5-lmb@cloudflare.com

authored by

Lorenz Bauer and committed by
Alexei Starovoitov
5b87adc3 27870317

+30 -11
+8 -6
tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
··· 194 194 test_sockmap_invalid_update__destroy(skel); 195 195 } 196 196 197 - static void test_sockmap_iter(enum bpf_map_type map_type) 197 + static void test_sockmap_copy(enum bpf_map_type map_type) 198 198 { 199 199 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts); 200 200 int err, len, src_fd, iter_fd, duration = 0; ··· 242 242 linfo.map.map_fd = src_fd; 243 243 opts.link_info = &linfo; 244 244 opts.link_info_len = sizeof(linfo); 245 - link = bpf_program__attach_iter(skel->progs.count_elems, &opts); 245 + link = bpf_program__attach_iter(skel->progs.copy, &opts); 246 246 if (CHECK(IS_ERR(link), "attach_iter", "attach_iter failed\n")) 247 247 goto out; 248 248 ··· 264 264 if (CHECK(skel->bss->socks != num_sockets, "socks", "got %u expected %u\n", 265 265 skel->bss->socks, num_sockets)) 266 266 goto close_iter; 267 + 268 + compare_cookies(src, skel->maps.dst); 267 269 268 270 close_iter: 269 271 close(iter_fd); ··· 296 294 test_sockmap_update(BPF_MAP_TYPE_SOCKHASH); 297 295 if (test__start_subtest("sockmap update in unsafe context")) 298 296 test_sockmap_invalid_update(); 299 - if (test__start_subtest("sockmap iter")) 300 - test_sockmap_iter(BPF_MAP_TYPE_SOCKMAP); 301 - if (test__start_subtest("sockhash iter")) 302 - test_sockmap_iter(BPF_MAP_TYPE_SOCKHASH); 297 + if (test__start_subtest("sockmap copy")) 298 + test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP); 299 + if (test__start_subtest("sockhash copy")) 300 + test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH); 303 301 }
+22 -5
tools/testing/selftests/bpf/progs/bpf_iter_sockmap.c
··· 22 22 __type(value, __u64); 23 23 } sockhash SEC(".maps"); 24 24 25 + struct { 26 + __uint(type, BPF_MAP_TYPE_SOCKHASH); 27 + __uint(max_entries, 64); 28 + __type(key, __u32); 29 + __type(value, __u64); 30 + } dst SEC(".maps"); 31 + 25 32 __u32 elems = 0; 26 33 __u32 socks = 0; 27 34 28 35 SEC("iter/sockmap") 29 - int count_elems(struct bpf_iter__sockmap *ctx) 36 + int copy(struct bpf_iter__sockmap *ctx) 30 37 { 31 38 struct sock *sk = ctx->sk; 32 39 __u32 tmp, *key = ctx->key; 33 40 int ret; 34 41 35 - if (key) 36 - elems++; 42 + if (!key) 43 + return 0; 37 44 38 - if (sk) 45 + elems++; 46 + 47 + /* We need a temporary buffer on the stack, since the verifier doesn't 48 + * let us use the pointer from the context as an argument to the helper. 49 + */ 50 + tmp = *key; 51 + 52 + if (sk) { 39 53 socks++; 54 + return bpf_map_update_elem(&dst, &tmp, sk, 0) != 0; 55 + } 40 56 41 - return 0; 57 + ret = bpf_map_delete_elem(&dst, &tmp); 58 + return ret && ret != -ENOENT; 42 59 }