Skip to content

Commit d42d1cc

Browse files
zhuyifei1999Alexei Starovoitov
authored and
Alexei Starovoitov
committed
selftests/bpf: Test load and dump metadata with btftool and skel
This is a simple test to check that loading and dumping metadata in btftool works, whether or not metadata contents are used by the program. A C test is also added to make sure the skeleton code can read the metadata values. Signed-off-by: YiFei Zhu <[email protected]> Signed-off-by: Stanislav Fomichev <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Cc: YiFei Zhu <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent aff52e6 commit d42d1cc

File tree

5 files changed

+255
-1
lines changed

5 files changed

+255
-1
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ TEST_PROGS := test_kmod.sh \
6868
test_tc_edt.sh \
6969
test_xdping.sh \
7070
test_bpftool_build.sh \
71-
test_bpftool.sh
71+
test_bpftool.sh \
72+
test_bpftool_metadata.sh \
7273

7374
TEST_PROGS_EXTENDED := with_addr.sh \
7475
with_tunnels.sh \
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
/*
4+
* Copyright 2020 Google LLC.
5+
*/
6+
7+
#include <test_progs.h>
8+
#include <cgroup_helpers.h>
9+
#include <network_helpers.h>
10+
11+
#include "metadata_unused.skel.h"
12+
#include "metadata_used.skel.h"
13+
14+
static int duration;
15+
16+
static int prog_holds_map(int prog_fd, int map_fd)
17+
{
18+
struct bpf_prog_info prog_info = {};
19+
struct bpf_prog_info map_info = {};
20+
__u32 prog_info_len;
21+
__u32 map_info_len;
22+
__u32 *map_ids;
23+
int nr_maps;
24+
int ret;
25+
int i;
26+
27+
map_info_len = sizeof(map_info);
28+
ret = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len);
29+
if (ret)
30+
return -errno;
31+
32+
prog_info_len = sizeof(prog_info);
33+
ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
34+
if (ret)
35+
return -errno;
36+
37+
map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32));
38+
if (!map_ids)
39+
return -ENOMEM;
40+
41+
nr_maps = prog_info.nr_map_ids;
42+
memset(&prog_info, 0, sizeof(prog_info));
43+
prog_info.nr_map_ids = nr_maps;
44+
prog_info.map_ids = ptr_to_u64(map_ids);
45+
prog_info_len = sizeof(prog_info);
46+
47+
ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len);
48+
if (ret) {
49+
ret = -errno;
50+
goto free_map_ids;
51+
}
52+
53+
ret = -ENOENT;
54+
for (i = 0; i < prog_info.nr_map_ids; i++) {
55+
if (map_ids[i] == map_info.id) {
56+
ret = 0;
57+
break;
58+
}
59+
}
60+
61+
free_map_ids:
62+
free(map_ids);
63+
return ret;
64+
}
65+
66+
static void test_metadata_unused(void)
67+
{
68+
struct metadata_unused *obj;
69+
int err;
70+
71+
obj = metadata_unused__open_and_load();
72+
if (CHECK(!obj, "skel-load", "errno %d", errno))
73+
return;
74+
75+
err = prog_holds_map(bpf_program__fd(obj->progs.prog),
76+
bpf_map__fd(obj->maps.rodata));
77+
if (CHECK(err, "prog-holds-rodata", "errno: %d", err))
78+
return;
79+
80+
/* Assert that we can access the metadata in skel and the values are
81+
* what we expect.
82+
*/
83+
if (CHECK(strncmp(obj->rodata->bpf_metadata_a, "foo",
84+
sizeof(obj->rodata->bpf_metadata_a)),
85+
"bpf_metadata_a", "expected \"foo\", value differ"))
86+
goto close_bpf_object;
87+
if (CHECK(obj->rodata->bpf_metadata_b != 1, "bpf_metadata_b",
88+
"expected 1, got %d", obj->rodata->bpf_metadata_b))
89+
goto close_bpf_object;
90+
91+
/* Assert that binding metadata map to prog again succeeds. */
92+
err = bpf_prog_bind_map(bpf_program__fd(obj->progs.prog),
93+
bpf_map__fd(obj->maps.rodata), NULL);
94+
CHECK(err, "rebind_map", "errno %d, expected 0", errno);
95+
96+
close_bpf_object:
97+
metadata_unused__destroy(obj);
98+
}
99+
100+
static void test_metadata_used(void)
101+
{
102+
struct metadata_used *obj;
103+
int err;
104+
105+
obj = metadata_used__open_and_load();
106+
if (CHECK(!obj, "skel-load", "errno %d", errno))
107+
return;
108+
109+
err = prog_holds_map(bpf_program__fd(obj->progs.prog),
110+
bpf_map__fd(obj->maps.rodata));
111+
if (CHECK(err, "prog-holds-rodata", "errno: %d", err))
112+
return;
113+
114+
/* Assert that we can access the metadata in skel and the values are
115+
* what we expect.
116+
*/
117+
if (CHECK(strncmp(obj->rodata->bpf_metadata_a, "bar",
118+
sizeof(obj->rodata->bpf_metadata_a)),
119+
"metadata_a", "expected \"bar\", value differ"))
120+
goto close_bpf_object;
121+
if (CHECK(obj->rodata->bpf_metadata_b != 2, "metadata_b",
122+
"expected 2, got %d", obj->rodata->bpf_metadata_b))
123+
goto close_bpf_object;
124+
125+
/* Assert that binding metadata map to prog again succeeds. */
126+
err = bpf_prog_bind_map(bpf_program__fd(obj->progs.prog),
127+
bpf_map__fd(obj->maps.rodata), NULL);
128+
CHECK(err, "rebind_map", "errno %d, expected 0", errno);
129+
130+
close_bpf_object:
131+
metadata_used__destroy(obj);
132+
}
133+
134+
void test_metadata(void)
135+
{
136+
if (test__start_subtest("unused"))
137+
test_metadata_unused();
138+
139+
if (test__start_subtest("used"))
140+
test_metadata_used();
141+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
volatile const char bpf_metadata_a[] SEC(".rodata") = "foo";
7+
volatile const int bpf_metadata_b SEC(".rodata") = 1;
8+
9+
SEC("cgroup_skb/egress")
10+
int prog(struct xdp_md *ctx)
11+
{
12+
return 0;
13+
}
14+
15+
char _license[] SEC("license") = "GPL";
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
volatile const char bpf_metadata_a[] SEC(".rodata") = "bar";
7+
volatile const int bpf_metadata_b SEC(".rodata") = 2;
8+
9+
SEC("cgroup_skb/egress")
10+
int prog(struct xdp_md *ctx)
11+
{
12+
return bpf_metadata_b ? 1 : 0;
13+
}
14+
15+
char _license[] SEC("license") = "GPL";
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/bin/sh
2+
# SPDX-License-Identifier: GPL-2.0
3+
4+
# Kselftest framework requirement - SKIP code is 4.
5+
ksft_skip=4
6+
7+
TESTNAME=bpftool_metadata
8+
BPF_FS=$(awk '$3 == "bpf" {print $2; exit}' /proc/mounts)
9+
BPF_DIR=$BPF_FS/test_$TESTNAME
10+
11+
_cleanup()
12+
{
13+
set +e
14+
rm -rf $BPF_DIR 2> /dev/null
15+
}
16+
17+
cleanup_skip()
18+
{
19+
echo "selftests: $TESTNAME [SKIP]"
20+
_cleanup
21+
22+
exit $ksft_skip
23+
}
24+
25+
cleanup()
26+
{
27+
if [ "$?" = 0 ]; then
28+
echo "selftests: $TESTNAME [PASS]"
29+
else
30+
echo "selftests: $TESTNAME [FAILED]"
31+
fi
32+
_cleanup
33+
}
34+
35+
if [ $(id -u) -ne 0 ]; then
36+
echo "selftests: $TESTNAME [SKIP] Need root privileges"
37+
exit $ksft_skip
38+
fi
39+
40+
if [ -z "$BPF_FS" ]; then
41+
echo "selftests: $TESTNAME [SKIP] Could not run test without bpffs mounted"
42+
exit $ksft_skip
43+
fi
44+
45+
if ! bpftool version > /dev/null 2>&1; then
46+
echo "selftests: $TESTNAME [SKIP] Could not run test without bpftool"
47+
exit $ksft_skip
48+
fi
49+
50+
set -e
51+
52+
trap cleanup_skip EXIT
53+
54+
mkdir $BPF_DIR
55+
56+
trap cleanup EXIT
57+
58+
bpftool prog load metadata_unused.o $BPF_DIR/unused
59+
60+
METADATA_PLAIN="$(bpftool prog)"
61+
echo "$METADATA_PLAIN" | grep 'a = "foo"' > /dev/null
62+
echo "$METADATA_PLAIN" | grep 'b = 1' > /dev/null
63+
64+
bpftool prog --json | grep '"metadata":{"a":"foo","b":1}' > /dev/null
65+
66+
bpftool map | grep 'metadata.rodata' > /dev/null
67+
68+
rm $BPF_DIR/unused
69+
70+
bpftool prog load metadata_used.o $BPF_DIR/used
71+
72+
METADATA_PLAIN="$(bpftool prog)"
73+
echo "$METADATA_PLAIN" | grep 'a = "bar"' > /dev/null
74+
echo "$METADATA_PLAIN" | grep 'b = 2' > /dev/null
75+
76+
bpftool prog --json | grep '"metadata":{"a":"bar","b":2}' > /dev/null
77+
78+
bpftool map | grep 'metadata.rodata' > /dev/null
79+
80+
rm $BPF_DIR/used
81+
82+
exit 0

0 commit comments

Comments
 (0)