Skip to content

Commit 7ffa632

Browse files
lmbtsipa
authored andcommitted
Add a test that exercises a basic sockmap / sockhash copy using bpf_iter.
Signed-off-by: Lorenz Bauer <[email protected]> --- .../selftests/bpf/prog_tests/sockmap_basic.c | 88 +++++++++++++++++++ tools/testing/selftests/bpf/progs/bpf_iter.h | 9 ++ .../selftests/bpf/progs/bpf_iter_sockmap.c | 57 ++++++++++++ .../selftests/bpf/progs/bpf_iter_sockmap.h | 3 + 4 files changed, 157 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_sockmap.c create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_sockmap.h
1 parent fc3533e commit 7ffa632

File tree

4 files changed

+157
-0
lines changed

4 files changed

+157
-0
lines changed

tools/testing/selftests/bpf/prog_tests/sockmap_basic.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#include "test_skmsg_load_helpers.skel.h"
77
#include "test_sockmap_update.skel.h"
88
#include "test_sockmap_invalid_update.skel.h"
9+
#include "bpf_iter_sockmap.skel.h"
10+
11+
#include "progs/bpf_iter_sockmap.h"
912

1013
#define TCP_REPAIR 19 /* TCP sock is under repair right now */
1114

@@ -193,6 +196,87 @@ static void test_sockmap_invalid_update(void)
193196
test_sockmap_invalid_update__destroy(skel);
194197
}
195198

199+
static void test_sockmap_copy(enum bpf_map_type map_type)
200+
{
201+
DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
202+
int err, len, src_fd, iter_fd, duration;
203+
union bpf_iter_link_info linfo = {0};
204+
__s64 sock_fd[SOCKMAP_MAX_ENTRIES];
205+
__u32 i, num_sockets, max_elems;
206+
struct bpf_iter_sockmap *skel;
207+
struct bpf_map *src, *dst;
208+
struct bpf_link *link;
209+
char buf[64];
210+
211+
skel = bpf_iter_sockmap__open_and_load();
212+
if (CHECK(!skel, "bpf_iter_sockmap__open_and_load", "skeleton open_and_load failed\n"))
213+
return;
214+
215+
for (i = 0; i < ARRAY_SIZE(sock_fd); i++)
216+
sock_fd[i] = -1;
217+
218+
/* Make sure we have at least one "empty" entry to test iteration of
219+
* an empty slot in an array.
220+
*/
221+
num_sockets = ARRAY_SIZE(sock_fd) - 1;
222+
223+
if (map_type == BPF_MAP_TYPE_SOCKMAP) {
224+
src = skel->maps.sockmap;
225+
max_elems = bpf_map__max_entries(src);
226+
} else {
227+
src = skel->maps.sockhash;
228+
max_elems = num_sockets;
229+
}
230+
231+
dst = skel->maps.dst;
232+
src_fd = bpf_map__fd(src);
233+
234+
for (i = 0; i < num_sockets; i++) {
235+
sock_fd[i] = connected_socket_v4();
236+
if (CHECK(sock_fd[i] == -1, "connected_socket_v4", "cannot connect\n"))
237+
goto out;
238+
239+
err = bpf_map_update_elem(src_fd, &i, &sock_fd[i], BPF_NOEXIST);
240+
if (CHECK(err, "map_update", "failed: %s\n", strerror(errno)))
241+
goto out;
242+
}
243+
244+
linfo.map.map_fd = src_fd;
245+
opts.link_info = &linfo;
246+
opts.link_info_len = sizeof(linfo);
247+
link = bpf_program__attach_iter(skel->progs.copy_sockmap, &opts);
248+
if (CHECK(IS_ERR(link), "attach_iter", "attach_iter failed\n"))
249+
goto out;
250+
251+
iter_fd = bpf_iter_create(bpf_link__fd(link));
252+
if (CHECK(iter_fd < 0, "create_iter", "create_iter failed\n"))
253+
goto free_link;
254+
255+
/* do some tests */
256+
while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
257+
;
258+
if (CHECK(len < 0, "read", "failed: %s\n", strerror(errno)))
259+
goto close_iter;
260+
261+
/* test results */
262+
if (CHECK(skel->bss->elems != max_elems, "elems", "got %u expected %u\n",
263+
skel->bss->elems, max_elems))
264+
goto close_iter;
265+
266+
compare_cookies(src, dst);
267+
268+
close_iter:
269+
close(iter_fd);
270+
free_link:
271+
bpf_link__destroy(link);
272+
out:
273+
for (i = 0; i < num_sockets; i++) {
274+
if (sock_fd[i] >= 0)
275+
close(sock_fd[i]);
276+
}
277+
bpf_iter_sockmap__destroy(skel);
278+
}
279+
196280
void test_sockmap_basic(void)
197281
{
198282
if (test__start_subtest("sockmap create_update_free"))
@@ -209,4 +293,8 @@ void test_sockmap_basic(void)
209293
test_sockmap_update(BPF_MAP_TYPE_SOCKHASH);
210294
if (test__start_subtest("sockmap update in unsafe context"))
211295
test_sockmap_invalid_update();
296+
if (test__start_subtest("sockmap copy"))
297+
test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP);
298+
if (test__start_subtest("sockhash copy"))
299+
test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH);
212300
}

tools/testing/selftests/bpf/progs/bpf_iter.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define udp6_sock udp6_sock___not_used
1414
#define bpf_iter__bpf_map_elem bpf_iter__bpf_map_elem___not_used
1515
#define bpf_iter__bpf_sk_storage_map bpf_iter__bpf_sk_storage_map___not_used
16+
#define bpf_iter__sockmap bpf_iter__sockmap___not_used
1617
#include "vmlinux.h"
1718
#undef bpf_iter_meta
1819
#undef bpf_iter__bpf_map
@@ -26,6 +27,7 @@
2627
#undef udp6_sock
2728
#undef bpf_iter__bpf_map_elem
2829
#undef bpf_iter__bpf_sk_storage_map
30+
#undef bpf_iter__sockmap
2931

3032
struct bpf_iter_meta {
3133
struct seq_file *seq;
@@ -96,3 +98,10 @@ struct bpf_iter__bpf_sk_storage_map {
9698
struct sock *sk;
9799
void *value;
98100
};
101+
102+
struct bpf_iter__sockmap {
103+
struct bpf_iter_meta *meta;
104+
struct bpf_map *map;
105+
void *key;
106+
struct sock *sk;
107+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2020 Cloudflare */
3+
#include "bpf_iter.h"
4+
#include "bpf_tracing_net.h"
5+
#include "bpf_iter_sockmap.h"
6+
#include <bpf/bpf_helpers.h>
7+
#include <bpf/bpf_tracing.h>
8+
#include <errno.h>
9+
10+
char _license[] SEC("license") = "GPL";
11+
12+
struct {
13+
__uint(type, BPF_MAP_TYPE_SOCKMAP);
14+
__uint(max_entries, SOCKMAP_MAX_ENTRIES);
15+
__type(key, __u32);
16+
__type(value, __u64);
17+
} sockmap SEC(".maps");
18+
19+
struct {
20+
__uint(type, BPF_MAP_TYPE_SOCKHASH);
21+
__uint(max_entries, SOCKMAP_MAX_ENTRIES);
22+
__type(key, __u32);
23+
__type(value, __u64);
24+
} sockhash SEC(".maps");
25+
26+
struct {
27+
__uint(type, BPF_MAP_TYPE_SOCKHASH);
28+
__uint(max_entries, SOCKMAP_MAX_ENTRIES);
29+
__type(key, __u32);
30+
__type(value, __u64);
31+
} dst SEC(".maps");
32+
33+
__u32 elems = 0;
34+
35+
SEC("iter/sockmap")
36+
int copy_sockmap(struct bpf_iter__sockmap *ctx)
37+
{
38+
struct sock *sk = ctx->sk;
39+
__u32 tmp, *key = ctx->key;
40+
int ret;
41+
42+
if (!key)
43+
return 0;
44+
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)
53+
return bpf_map_update_elem(&dst, &tmp, sk, 0) != 0;
54+
55+
ret = bpf_map_delete_elem(&dst, &tmp);
56+
return ret && ret != -ENOENT;
57+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#define SOCKMAP_MAX_ENTRIES (64)

0 commit comments

Comments
 (0)