Skip to content

Commit ce9add7

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
selftests/bpf: Add tests for extending sleepable global subprogs
Add tests for freplace behavior with the combination of sleepable and non-sleepable global subprogs. The changes_pkt_data selftest did all the hardwork, so simply rename it and include new support for more summarization tests for might_sleep bit. Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 6e2cc60 commit ce9add7

File tree

5 files changed

+238
-147
lines changed

5 files changed

+238
-147
lines changed

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

Lines changed: 0 additions & 107 deletions
This file was deleted.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include "bpf/libbpf.h"
3+
#include "summarization_freplace.skel.h"
4+
#include "summarization.skel.h"
5+
#include <test_progs.h>
6+
7+
static void print_verifier_log(const char *log)
8+
{
9+
if (env.verbosity >= VERBOSE_VERY)
10+
fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log);
11+
}
12+
13+
static void test_aux(const char *main_prog_name,
14+
const char *to_be_replaced,
15+
const char *replacement,
16+
bool expect_load,
17+
const char *err_msg)
18+
{
19+
struct summarization_freplace *freplace = NULL;
20+
struct bpf_program *freplace_prog = NULL;
21+
struct bpf_program *main_prog = NULL;
22+
LIBBPF_OPTS(bpf_object_open_opts, opts);
23+
struct summarization *main = NULL;
24+
char log[16*1024];
25+
int err;
26+
27+
opts.kernel_log_buf = log;
28+
opts.kernel_log_size = sizeof(log);
29+
if (env.verbosity >= VERBOSE_SUPER)
30+
opts.kernel_log_level = 1 | 2 | 4;
31+
main = summarization__open_opts(&opts);
32+
if (!ASSERT_OK_PTR(main, "summarization__open"))
33+
goto out;
34+
main_prog = bpf_object__find_program_by_name(main->obj, main_prog_name);
35+
if (!ASSERT_OK_PTR(main_prog, "main_prog"))
36+
goto out;
37+
bpf_program__set_autoload(main_prog, true);
38+
err = summarization__load(main);
39+
print_verifier_log(log);
40+
if (!ASSERT_OK(err, "summarization__load"))
41+
goto out;
42+
freplace = summarization_freplace__open_opts(&opts);
43+
if (!ASSERT_OK_PTR(freplace, "summarization_freplace__open"))
44+
goto out;
45+
freplace_prog = bpf_object__find_program_by_name(freplace->obj, replacement);
46+
if (!ASSERT_OK_PTR(freplace_prog, "freplace_prog"))
47+
goto out;
48+
bpf_program__set_autoload(freplace_prog, true);
49+
bpf_program__set_autoattach(freplace_prog, true);
50+
bpf_program__set_attach_target(freplace_prog,
51+
bpf_program__fd(main_prog),
52+
to_be_replaced);
53+
err = summarization_freplace__load(freplace);
54+
print_verifier_log(log);
55+
56+
/* The might_sleep extension doesn't work yet as sleepable calls are not
57+
* allowed, but preserve the check in case it's supported later and then
58+
* this particular combination can be enabled.
59+
*/
60+
if (!strcmp("might_sleep", replacement) && err) {
61+
ASSERT_HAS_SUBSTR(log, "helper call might sleep in a non-sleepable prog", "error log");
62+
ASSERT_EQ(err, -EINVAL, "err");
63+
test__skip();
64+
goto out;
65+
}
66+
67+
if (expect_load) {
68+
ASSERT_OK(err, "summarization_freplace__load");
69+
} else {
70+
ASSERT_ERR(err, "summarization_freplace__load");
71+
ASSERT_HAS_SUBSTR(log, err_msg, "error log");
72+
}
73+
74+
out:
75+
summarization_freplace__destroy(freplace);
76+
summarization__destroy(main);
77+
}
78+
79+
/* There are two global subprograms in both summarization.skel.h:
80+
* - one changes packet data;
81+
* - another does not.
82+
* It is ok to freplace subprograms that change packet data with those
83+
* that either do or do not. It is only ok to freplace subprograms
84+
* that do not change packet data with those that do not as well.
85+
* The below tests check outcomes for each combination of such freplace.
86+
* Also test a case when main subprogram itself is replaced and is a single
87+
* subprogram in a program.
88+
*
89+
* This holds for might_sleep programs. It is ok to replace might_sleep with
90+
* might_sleep and with does_not_sleep, but does_not_sleep cannot be replaced
91+
* with might_sleep.
92+
*/
93+
void test_summarization_freplace(void)
94+
{
95+
struct {
96+
const char *main;
97+
const char *to_be_replaced;
98+
bool has_side_effect;
99+
} mains[2][4] = {
100+
{
101+
{ "main_changes_with_subprogs", "changes_pkt_data", true },
102+
{ "main_changes_with_subprogs", "does_not_change_pkt_data", false },
103+
{ "main_changes", "main_changes", true },
104+
{ "main_does_not_change", "main_does_not_change", false },
105+
},
106+
{
107+
{ "main_might_sleep_with_subprogs", "might_sleep", true },
108+
{ "main_might_sleep_with_subprogs", "does_not_sleep", false },
109+
{ "main_might_sleep", "main_might_sleep", true },
110+
{ "main_does_not_sleep", "main_does_not_sleep", false },
111+
},
112+
};
113+
const char *pkt_err = "Extension program changes packet data";
114+
const char *slp_err = "Extension program may sleep";
115+
struct {
116+
const char *func;
117+
bool has_side_effect;
118+
const char *err_msg;
119+
} replacements[2][2] = {
120+
{
121+
{ "changes_pkt_data", true, pkt_err },
122+
{ "does_not_change_pkt_data", false, pkt_err },
123+
},
124+
{
125+
{ "might_sleep", true, slp_err },
126+
{ "does_not_sleep", false, slp_err },
127+
},
128+
};
129+
char buf[64];
130+
131+
for (int t = 0; t < 2; t++) {
132+
for (int i = 0; i < ARRAY_SIZE(mains); ++i) {
133+
for (int j = 0; j < ARRAY_SIZE(replacements); ++j) {
134+
snprintf(buf, sizeof(buf), "%s_with_%s",
135+
mains[t][i].to_be_replaced, replacements[t][j].func);
136+
if (!test__start_subtest(buf))
137+
continue;
138+
test_aux(mains[t][i].main, mains[t][i].to_be_replaced, replacements[t][j].func,
139+
mains[t][i].has_side_effect || !replacements[t][j].has_side_effect,
140+
replacements[t][j].err_msg);
141+
}
142+
}
143+
}
144+
}

tools/testing/selftests/bpf/progs/changes_pkt_data.c

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <vmlinux.h>
4+
#include <bpf/bpf_helpers.h>
5+
#include "bpf_misc.h"
6+
7+
__noinline
8+
long changes_pkt_data(struct __sk_buff *sk)
9+
{
10+
return bpf_skb_pull_data(sk, 0);
11+
}
12+
13+
__noinline __weak
14+
long does_not_change_pkt_data(struct __sk_buff *sk)
15+
{
16+
return 0;
17+
}
18+
19+
SEC("?tc")
20+
int main_changes_with_subprogs(struct __sk_buff *sk)
21+
{
22+
changes_pkt_data(sk);
23+
does_not_change_pkt_data(sk);
24+
return 0;
25+
}
26+
27+
SEC("?tc")
28+
int main_changes(struct __sk_buff *sk)
29+
{
30+
bpf_skb_pull_data(sk, 0);
31+
return 0;
32+
}
33+
34+
SEC("?tc")
35+
int main_does_not_change(struct __sk_buff *sk)
36+
{
37+
return 0;
38+
}
39+
40+
__noinline
41+
long might_sleep(struct pt_regs *ctx __arg_ctx)
42+
{
43+
int i;
44+
45+
bpf_copy_from_user(&i, sizeof(i), NULL);
46+
return i;
47+
}
48+
49+
__noinline __weak
50+
long does_not_sleep(struct pt_regs *ctx __arg_ctx)
51+
{
52+
return 0;
53+
}
54+
55+
SEC("?uprobe.s")
56+
int main_might_sleep_with_subprogs(struct pt_regs *ctx)
57+
{
58+
might_sleep(ctx);
59+
does_not_sleep(ctx);
60+
return 0;
61+
}
62+
63+
SEC("?uprobe.s")
64+
int main_might_sleep(struct pt_regs *ctx)
65+
{
66+
int i;
67+
68+
bpf_copy_from_user(&i, sizeof(i), NULL);
69+
return i;
70+
}
71+
72+
SEC("?uprobe.s")
73+
int main_does_not_sleep(struct pt_regs *ctx)
74+
{
75+
return 0;
76+
}
77+
78+
char _license[] SEC("license") = "GPL";

tools/testing/selftests/bpf/progs/changes_pkt_data_freplace.c renamed to tools/testing/selftests/bpf/progs/summarization_freplace.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3-
#include <linux/bpf.h>
3+
#include <vmlinux.h>
44
#include <bpf/bpf_helpers.h>
55

66
SEC("?freplace")
@@ -15,4 +15,19 @@ long does_not_change_pkt_data(struct __sk_buff *sk)
1515
return 0;
1616
}
1717

18+
SEC("?freplace")
19+
long might_sleep(struct pt_regs *ctx)
20+
{
21+
int i;
22+
23+
bpf_copy_from_user(&i, sizeof(i), NULL);
24+
return i;
25+
}
26+
27+
SEC("?freplace")
28+
long does_not_sleep(struct pt_regs *ctx)
29+
{
30+
return 0;
31+
}
32+
1833
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)