Skip to content

Commit bca6dfb

Browse files
tohojokernel-patches-bot
authored andcommitted
From: Toke Høiland-Jørgensen <[email protected]>
This adds a selftest for attaching an freplace program to multiple targets simultaneously. Signed-off-by: Toke Høiland-Jørgensen <[email protected]> --- .../selftests/bpf/prog_tests/fexit_bpf2bpf.c | 171 ++++++++++++++++---- .../selftests/bpf/progs/freplace_get_constant.c | 15 ++ 2 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 tools/testing/selftests/bpf/progs/freplace_get_constant.c
1 parent e5deca7 commit bca6dfb

File tree

2 files changed

+154
-32
lines changed

2 files changed

+154
-32
lines changed

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

Lines changed: 139 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,79 @@
22
/* Copyright (c) 2019 Facebook */
33
#include <test_progs.h>
44
#include <network_helpers.h>
5+
#include <bpf/btf.h>
6+
7+
typedef int (*test_cb)(struct bpf_object *obj);
8+
9+
static int check_data_map(struct bpf_object *obj, int prog_cnt, bool reset)
10+
{
11+
struct bpf_map *data_map = NULL, *map;
12+
__u64 *result = NULL;
13+
const int zero = 0;
14+
__u32 duration = 0;
15+
int ret = -1, i;
16+
17+
result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));
18+
if (CHECK(!result, "alloc_memory", "failed to alloc memory"))
19+
return -ENOMEM;
20+
21+
bpf_object__for_each_map(map, obj)
22+
if (bpf_map__is_internal(map)) {
23+
data_map = map;
24+
break;
25+
}
26+
if (CHECK(!data_map, "find_data_map", "data map not found\n"))
27+
goto out;
28+
29+
ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
30+
if (CHECK(ret, "get_result",
31+
"failed to get output data: %d\n", ret))
32+
goto out;
33+
34+
for (i = 0; i < prog_cnt; i++) {
35+
if (CHECK(result[i] != 1, "result",
36+
"fexit_bpf2bpf result[%d] failed err %llu\n",
37+
i, result[i]))
38+
goto out;
39+
result[i] = 0;
40+
}
41+
if (reset) {
42+
ret = bpf_map_update_elem(bpf_map__fd(data_map), &zero, result, 0);
43+
if (CHECK(ret, "reset_result", "failed to reset result\n"))
44+
goto out;
45+
}
46+
47+
ret = 0;
48+
out:
49+
free(result);
50+
return ret;
51+
}
552

653
static void test_fexit_bpf2bpf_common(const char *obj_file,
754
const char *target_obj_file,
855
int prog_cnt,
956
const char **prog_name,
10-
bool run_prog)
57+
bool run_prog,
58+
test_cb cb)
1159
{
12-
struct bpf_object *obj = NULL, *pkt_obj;
13-
int err, pkt_fd, i;
14-
struct bpf_link **link = NULL;
60+
struct bpf_object *obj = NULL, *tgt_obj;
1561
struct bpf_program **prog = NULL;
62+
struct bpf_link **link = NULL;
1663
__u32 duration = 0, retval;
17-
struct bpf_map *data_map;
18-
const int zero = 0;
19-
__u64 *result = NULL;
64+
int err, tgt_fd, i;
2065

2166
err = bpf_prog_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,
22-
&pkt_obj, &pkt_fd);
67+
&tgt_obj, &tgt_fd);
2368
if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",
2469
target_obj_file, err, errno))
2570
return;
2671
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
27-
.attach_prog_fd = pkt_fd,
72+
.attach_prog_fd = tgt_fd,
2873
);
2974

3075
link = calloc(sizeof(struct bpf_link *), prog_cnt);
3176
prog = calloc(sizeof(struct bpf_program *), prog_cnt);
32-
result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));
33-
if (CHECK(!link || !prog || !result, "alloc_memory",
34-
"failed to alloc memory"))
77+
if (CHECK(!link || !prog, "alloc_memory", "failed to alloc memory"))
3578
goto close_prog;
3679

3780
obj = bpf_object__open_file(obj_file, &opts);
@@ -53,39 +96,33 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,
5396
goto close_prog;
5497
}
5598

56-
if (!run_prog)
57-
goto close_prog;
99+
if (cb) {
100+
err = cb(obj);
101+
if (err)
102+
goto close_prog;
103+
}
58104

59-
data_map = bpf_object__find_map_by_name(obj, "fexit_bp.bss");
60-
if (CHECK(!data_map, "find_data_map", "data map not found\n"))
105+
if (!run_prog)
61106
goto close_prog;
62107

63-
err = bpf_prog_test_run(pkt_fd, 1, &pkt_v6, sizeof(pkt_v6),
108+
err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
64109
NULL, NULL, &retval, &duration);
65110
CHECK(err || retval, "ipv6",
66111
"err %d errno %d retval %d duration %d\n",
67112
err, errno, retval, duration);
68113

69-
err = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);
70-
if (CHECK(err, "get_result",
71-
"failed to get output data: %d\n", err))
114+
if (check_data_map(obj, prog_cnt, false))
72115
goto close_prog;
73116

74-
for (i = 0; i < prog_cnt; i++)
75-
if (CHECK(result[i] != 1, "result", "fexit_bpf2bpf failed err %llu\n",
76-
result[i]))
77-
goto close_prog;
78-
79117
close_prog:
80118
for (i = 0; i < prog_cnt; i++)
81119
if (!IS_ERR_OR_NULL(link[i]))
82120
bpf_link__destroy(link[i]);
83121
if (!IS_ERR_OR_NULL(obj))
84122
bpf_object__close(obj);
85-
bpf_object__close(pkt_obj);
123+
bpf_object__close(tgt_obj);
86124
free(link);
87125
free(prog);
88-
free(result);
89126
}
90127

91128
static void test_target_no_callees(void)
@@ -96,7 +133,7 @@ static void test_target_no_callees(void)
96133
test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.o",
97134
"./test_pkt_md_access.o",
98135
ARRAY_SIZE(prog_name),
99-
prog_name, true);
136+
prog_name, true, NULL);
100137
}
101138

102139
static void test_target_yes_callees(void)
@@ -110,7 +147,7 @@ static void test_target_yes_callees(void)
110147
test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
111148
"./test_pkt_access.o",
112149
ARRAY_SIZE(prog_name),
113-
prog_name, true);
150+
prog_name, true, NULL);
114151
}
115152

116153
static void test_func_replace(void)
@@ -128,7 +165,7 @@ static void test_func_replace(void)
128165
test_fexit_bpf2bpf_common("./fexit_bpf2bpf.o",
129166
"./test_pkt_access.o",
130167
ARRAY_SIZE(prog_name),
131-
prog_name, true);
168+
prog_name, true, NULL);
132169
}
133170

134171
static void test_func_replace_verify(void)
@@ -139,7 +176,75 @@ static void test_func_replace_verify(void)
139176
test_fexit_bpf2bpf_common("./freplace_connect4.o",
140177
"./connect4_prog.o",
141178
ARRAY_SIZE(prog_name),
142-
prog_name, false);
179+
prog_name, false, NULL);
180+
}
181+
182+
static int test_second_attach(struct bpf_object *obj)
183+
{
184+
const char *prog_name = "freplace/get_constant";
185+
const char *tgt_name = prog_name + 9; /* cut off freplace/ */
186+
const char *tgt_obj_file = "./test_pkt_access.o";
187+
int err = 0, tgt_fd, tgt_btf_id, link_fd = -1;
188+
struct bpf_program *prog = NULL;
189+
struct bpf_object *tgt_obj;
190+
__u32 duration = 0, retval;
191+
struct btf *btf;
192+
193+
prog = bpf_object__find_program_by_title(obj, prog_name);
194+
if (CHECK(!prog, "find_prog", "prog %s not found\n", prog_name))
195+
return -ENOENT;
196+
197+
err = bpf_prog_load(tgt_obj_file, BPF_PROG_TYPE_UNSPEC,
198+
&tgt_obj, &tgt_fd);
199+
if (CHECK(err, "second_prog_load", "file %s err %d errno %d\n",
200+
tgt_obj_file, err, errno))
201+
return err;
202+
203+
btf = bpf_object__btf(tgt_obj);
204+
tgt_btf_id = btf__find_by_name_kind(btf, tgt_name, BTF_KIND_FUNC);
205+
if (CHECK(tgt_btf_id < 0, "find_btf", "no BTF ID found for func %s\n", prog_name)) {
206+
err = -ENOENT;
207+
goto out;
208+
}
209+
210+
DECLARE_LIBBPF_OPTS(bpf_raw_tracepoint_opts, opts,
211+
.tgt_prog_fd = tgt_fd,
212+
.tgt_btf_id = tgt_btf_id,
213+
);
214+
link_fd = bpf_raw_tracepoint_open_opts(NULL, bpf_program__fd(prog), &opts);
215+
if (CHECK(link_fd < 0, "second_link", "err %d errno %d",
216+
link_fd, errno)) {
217+
err = link_fd;
218+
goto out;
219+
}
220+
221+
err = bpf_prog_test_run(tgt_fd, 1, &pkt_v6, sizeof(pkt_v6),
222+
NULL, NULL, &retval, &duration);
223+
if (CHECK(err || retval, "ipv6",
224+
"err %d errno %d retval %d duration %d\n",
225+
err, errno, retval, duration))
226+
goto out;
227+
228+
err = check_data_map(obj, 1, true);
229+
if (err)
230+
goto out;
231+
232+
out:
233+
if (link_fd >= 0)
234+
close(link_fd);
235+
bpf_object__close(tgt_obj);
236+
return err;
237+
}
238+
239+
static void test_func_replace_multi(void)
240+
{
241+
const char *prog_name[] = {
242+
"freplace/get_constant",
243+
};
244+
test_fexit_bpf2bpf_common("./freplace_get_constant.o",
245+
"./test_pkt_access.o",
246+
ARRAY_SIZE(prog_name),
247+
prog_name, true, test_second_attach);
143248
}
144249

145250
static void test_func_sockmap_update(void)
@@ -150,7 +255,7 @@ static void test_func_sockmap_update(void)
150255
test_fexit_bpf2bpf_common("./freplace_cls_redirect.o",
151256
"./test_cls_redirect.o",
152257
ARRAY_SIZE(prog_name),
153-
prog_name, false);
258+
prog_name, false, NULL);
154259
}
155260

156261
static void test_obj_load_failure_common(const char *obj_file,
@@ -222,4 +327,6 @@ void test_fexit_bpf2bpf(void)
222327
test_func_replace_return_code();
223328
if (test__start_subtest("func_map_prog_compatibility"))
224329
test_func_map_prog_compatibility();
330+
if (test__start_subtest("func_replace_multi"))
331+
test_func_replace_multi();
225332
}
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
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_helpers.h>
4+
#include <bpf/bpf_endian.h>
5+
6+
volatile __u64 test_get_constant = 0;
7+
SEC("freplace/get_constant")
8+
int new_get_constant(long val)
9+
{
10+
if (val != 123)
11+
return 0;
12+
test_get_constant = 1;
13+
return test_get_constant; /* original get_constant() returns val - 122 */
14+
}
15+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)