Skip to content

Commit 257c885

Browse files
rdnaAlexei Starovoitov
authored andcommitted
selftests/bpf: Convert test_cgroup_attach to prog_tests
Convert test_cgroup_attach to prog_tests. This change does a lot of things but in many cases it's pretty expensive to separate them, so they go in one commit. Nevertheless the logic is ketp as is and changes made are just moving things around, simplifying them (w/o changing the meaning of the tests) and making prog_tests compatible: * split the 3 tests in the file into 3 separate files in prog_tests/; * rename the test functions to test_<file_base_name>; * remove unused includes, constants, variables and functions from every test; * replace `if`-s with or `if (CHECK())` where additional context should be logged and with `if (CHECK_FAIL())` where line number is enough; * switch from `log_err()` to logging via `CHECK()`; * replace `assert`-s with `CHECK_FAIL()` to avoid crashing the whole test_progs if one assertion fails; * replace cgroup_helpers with test__join_cgroup() in cgroup_attach_override only, other tests need more fine-grained control for cgroup creation/deletion so cgroup_helpers are still used there; * simplify cgroup_attach_autodetach by switching to easiest possible program since this test doesn't really need such a complicated program as cgroup_attach_multi does; * remove test_cgroup_attach.c itself. Signed-off-by: Andrey Ignatov <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/0ff19cc64d2dc5cf404349f07131119480e10e32.1576741281.git.rdna@fb.com
1 parent cdbee38 commit 257c885

File tree

6 files changed

+498
-574
lines changed

6 files changed

+498
-574
lines changed

tools/testing/selftests/bpf/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ test_lirc_mode2_user
2121
get_cgroup_id_user
2222
test_skb_cgroup_id_user
2323
test_socket_cookie
24-
test_cgroup_attach
2524
test_cgroup_storage
2625
test_select_reuseport
2726
test_flow_dissector

tools/testing/selftests/bpf/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
3232
test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \
3333
test_cgroup_storage \
3434
test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \
35-
test_cgroup_attach test_progs-no_alu32
35+
test_progs-no_alu32
3636

3737
# Also test bpf-gcc, if present
3838
ifneq ($(BPF_GCC),)
@@ -136,7 +136,6 @@ $(OUTPUT)/test_cgroup_storage: cgroup_helpers.c
136136
$(OUTPUT)/test_netcnt: cgroup_helpers.c
137137
$(OUTPUT)/test_sock_fields: cgroup_helpers.c
138138
$(OUTPUT)/test_sysctl: cgroup_helpers.c
139-
$(OUTPUT)/test_cgroup_attach: cgroup_helpers.c
140139

141140
.PHONY: force
142141

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <test_progs.h>
4+
5+
#include "cgroup_helpers.h"
6+
7+
#define PING_CMD "ping -q -c1 -w1 127.0.0.1 > /dev/null"
8+
9+
char bpf_log_buf[BPF_LOG_BUF_SIZE];
10+
11+
static int prog_load(void)
12+
{
13+
struct bpf_insn prog[] = {
14+
BPF_MOV64_IMM(BPF_REG_0, 1), /* r0 = 1 */
15+
BPF_EXIT_INSN(),
16+
};
17+
size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
18+
19+
return bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
20+
prog, insns_cnt, "GPL", 0,
21+
bpf_log_buf, BPF_LOG_BUF_SIZE);
22+
}
23+
24+
void test_cgroup_attach_autodetach(void)
25+
{
26+
__u32 duration = 0, prog_cnt = 4, attach_flags;
27+
int allow_prog[2] = {-1};
28+
__u32 prog_ids[2] = {0};
29+
void *ptr = NULL;
30+
int cg = 0, i;
31+
int attempts;
32+
33+
for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
34+
allow_prog[i] = prog_load();
35+
if (CHECK(allow_prog[i] < 0, "prog_load",
36+
"verifier output:\n%s\n-------\n", bpf_log_buf))
37+
goto err;
38+
}
39+
40+
if (CHECK_FAIL(setup_cgroup_environment()))
41+
goto err;
42+
43+
/* create a cgroup, attach two programs and remember their ids */
44+
cg = create_and_get_cgroup("/cg_autodetach");
45+
if (CHECK_FAIL(cg < 0))
46+
goto err;
47+
48+
if (CHECK_FAIL(join_cgroup("/cg_autodetach")))
49+
goto err;
50+
51+
for (i = 0; i < ARRAY_SIZE(allow_prog); i++)
52+
if (CHECK(bpf_prog_attach(allow_prog[i], cg,
53+
BPF_CGROUP_INET_EGRESS,
54+
BPF_F_ALLOW_MULTI),
55+
"prog_attach", "prog[%d], errno=%d\n", i, errno))
56+
goto err;
57+
58+
/* make sure that programs are attached and run some traffic */
59+
if (CHECK(bpf_prog_query(cg, BPF_CGROUP_INET_EGRESS, 0, &attach_flags,
60+
prog_ids, &prog_cnt),
61+
"prog_query", "errno=%d\n", errno))
62+
goto err;
63+
if (CHECK_FAIL(system(PING_CMD)))
64+
goto err;
65+
66+
/* allocate some memory (4Mb) to pin the original cgroup */
67+
ptr = malloc(4 * (1 << 20));
68+
if (CHECK_FAIL(!ptr))
69+
goto err;
70+
71+
/* close programs and cgroup fd */
72+
for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
73+
close(allow_prog[i]);
74+
allow_prog[i] = -1;
75+
}
76+
77+
close(cg);
78+
cg = 0;
79+
80+
/* leave the cgroup and remove it. don't detach programs */
81+
cleanup_cgroup_environment();
82+
83+
/* wait for the asynchronous auto-detachment.
84+
* wait for no more than 5 sec and give up.
85+
*/
86+
for (i = 0; i < ARRAY_SIZE(prog_ids); i++) {
87+
for (attempts = 5; attempts >= 0; attempts--) {
88+
int fd = bpf_prog_get_fd_by_id(prog_ids[i]);
89+
90+
if (fd < 0)
91+
break;
92+
93+
/* don't leave the fd open */
94+
close(fd);
95+
96+
if (CHECK_FAIL(!attempts))
97+
goto err;
98+
99+
sleep(1);
100+
}
101+
}
102+
103+
err:
104+
for (i = 0; i < ARRAY_SIZE(allow_prog); i++)
105+
if (allow_prog[i] >= 0)
106+
close(allow_prog[i]);
107+
if (cg)
108+
close(cg);
109+
free(ptr);
110+
cleanup_cgroup_environment();
111+
}
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <test_progs.h>
4+
5+
#include "cgroup_helpers.h"
6+
7+
#define PING_CMD "ping -q -c1 -w1 127.0.0.1 > /dev/null"
8+
9+
char bpf_log_buf[BPF_LOG_BUF_SIZE];
10+
11+
static int map_fd = -1;
12+
13+
static int prog_load_cnt(int verdict, int val)
14+
{
15+
int cgroup_storage_fd, percpu_cgroup_storage_fd;
16+
17+
if (map_fd < 0)
18+
map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 4, 8, 1, 0);
19+
if (map_fd < 0) {
20+
printf("failed to create map '%s'\n", strerror(errno));
21+
return -1;
22+
}
23+
24+
cgroup_storage_fd = bpf_create_map(BPF_MAP_TYPE_CGROUP_STORAGE,
25+
sizeof(struct bpf_cgroup_storage_key), 8, 0, 0);
26+
if (cgroup_storage_fd < 0) {
27+
printf("failed to create map '%s'\n", strerror(errno));
28+
return -1;
29+
}
30+
31+
percpu_cgroup_storage_fd = bpf_create_map(
32+
BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
33+
sizeof(struct bpf_cgroup_storage_key), 8, 0, 0);
34+
if (percpu_cgroup_storage_fd < 0) {
35+
printf("failed to create map '%s'\n", strerror(errno));
36+
return -1;
37+
}
38+
39+
struct bpf_insn prog[] = {
40+
BPF_MOV32_IMM(BPF_REG_0, 0),
41+
BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */
42+
BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
43+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */
44+
BPF_LD_MAP_FD(BPF_REG_1, map_fd),
45+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
46+
BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2),
47+
BPF_MOV64_IMM(BPF_REG_1, val), /* r1 = 1 */
48+
BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */
49+
50+
BPF_LD_MAP_FD(BPF_REG_1, cgroup_storage_fd),
51+
BPF_MOV64_IMM(BPF_REG_2, 0),
52+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage),
53+
BPF_MOV64_IMM(BPF_REG_1, val),
54+
BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_W, BPF_REG_0, BPF_REG_1, 0, 0),
55+
56+
BPF_LD_MAP_FD(BPF_REG_1, percpu_cgroup_storage_fd),
57+
BPF_MOV64_IMM(BPF_REG_2, 0),
58+
BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_get_local_storage),
59+
BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_0, 0),
60+
BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 0x1),
61+
BPF_STX_MEM(BPF_W, BPF_REG_0, BPF_REG_3, 0),
62+
63+
BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */
64+
BPF_EXIT_INSN(),
65+
};
66+
size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn);
67+
int ret;
68+
69+
ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB,
70+
prog, insns_cnt, "GPL", 0,
71+
bpf_log_buf, BPF_LOG_BUF_SIZE);
72+
73+
close(cgroup_storage_fd);
74+
return ret;
75+
}
76+
77+
void test_cgroup_attach_multi(void)
78+
{
79+
__u32 prog_ids[4], prog_cnt = 0, attach_flags, saved_prog_id;
80+
int cg1 = 0, cg2 = 0, cg3 = 0, cg4 = 0, cg5 = 0, key = 0;
81+
int allow_prog[6] = {-1};
82+
unsigned long long value;
83+
__u32 duration = 0;
84+
int i = 0;
85+
86+
for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
87+
allow_prog[i] = prog_load_cnt(1, 1 << i);
88+
if (CHECK(allow_prog[i] < 0, "prog_load",
89+
"verifier output:\n%s\n-------\n", bpf_log_buf))
90+
goto err;
91+
}
92+
93+
if (CHECK_FAIL(setup_cgroup_environment()))
94+
goto err;
95+
96+
cg1 = create_and_get_cgroup("/cg1");
97+
if (CHECK_FAIL(cg1 < 0))
98+
goto err;
99+
cg2 = create_and_get_cgroup("/cg1/cg2");
100+
if (CHECK_FAIL(cg2 < 0))
101+
goto err;
102+
cg3 = create_and_get_cgroup("/cg1/cg2/cg3");
103+
if (CHECK_FAIL(cg3 < 0))
104+
goto err;
105+
cg4 = create_and_get_cgroup("/cg1/cg2/cg3/cg4");
106+
if (CHECK_FAIL(cg4 < 0))
107+
goto err;
108+
cg5 = create_and_get_cgroup("/cg1/cg2/cg3/cg4/cg5");
109+
if (CHECK_FAIL(cg5 < 0))
110+
goto err;
111+
112+
if (CHECK_FAIL(join_cgroup("/cg1/cg2/cg3/cg4/cg5")))
113+
goto err;
114+
115+
if (CHECK(bpf_prog_attach(allow_prog[0], cg1, BPF_CGROUP_INET_EGRESS,
116+
BPF_F_ALLOW_MULTI),
117+
"prog0_attach_to_cg1_multi", "errno=%d\n", errno))
118+
goto err;
119+
120+
if (CHECK(!bpf_prog_attach(allow_prog[0], cg1, BPF_CGROUP_INET_EGRESS,
121+
BPF_F_ALLOW_MULTI),
122+
"fail_same_prog_attach_to_cg1", "unexpected success\n"))
123+
goto err;
124+
125+
if (CHECK(bpf_prog_attach(allow_prog[1], cg1, BPF_CGROUP_INET_EGRESS,
126+
BPF_F_ALLOW_MULTI),
127+
"prog1_attach_to_cg1_multi", "errno=%d\n", errno))
128+
goto err;
129+
130+
if (CHECK(bpf_prog_attach(allow_prog[2], cg2, BPF_CGROUP_INET_EGRESS,
131+
BPF_F_ALLOW_OVERRIDE),
132+
"prog2_attach_to_cg2_override", "errno=%d\n", errno))
133+
goto err;
134+
135+
if (CHECK(bpf_prog_attach(allow_prog[3], cg3, BPF_CGROUP_INET_EGRESS,
136+
BPF_F_ALLOW_MULTI),
137+
"prog3_attach_to_cg3_multi", "errno=%d\n", errno))
138+
goto err;
139+
140+
if (CHECK(bpf_prog_attach(allow_prog[4], cg4, BPF_CGROUP_INET_EGRESS,
141+
BPF_F_ALLOW_OVERRIDE),
142+
"prog4_attach_to_cg4_override", "errno=%d\n", errno))
143+
goto err;
144+
145+
if (CHECK(bpf_prog_attach(allow_prog[5], cg5, BPF_CGROUP_INET_EGRESS, 0),
146+
"prog5_attach_to_cg5_none", "errno=%d\n", errno))
147+
goto err;
148+
149+
CHECK_FAIL(system(PING_CMD));
150+
CHECK_FAIL(bpf_map_lookup_elem(map_fd, &key, &value));
151+
CHECK_FAIL(value != 1 + 2 + 8 + 32);
152+
153+
/* query the number of effective progs in cg5 */
154+
CHECK_FAIL(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS,
155+
BPF_F_QUERY_EFFECTIVE, NULL, NULL, &prog_cnt));
156+
CHECK_FAIL(prog_cnt != 4);
157+
/* retrieve prog_ids of effective progs in cg5 */
158+
CHECK_FAIL(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS,
159+
BPF_F_QUERY_EFFECTIVE, &attach_flags,
160+
prog_ids, &prog_cnt));
161+
CHECK_FAIL(prog_cnt != 4);
162+
CHECK_FAIL(attach_flags != 0);
163+
saved_prog_id = prog_ids[0];
164+
/* check enospc handling */
165+
prog_ids[0] = 0;
166+
prog_cnt = 2;
167+
CHECK_FAIL(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS,
168+
BPF_F_QUERY_EFFECTIVE, &attach_flags,
169+
prog_ids, &prog_cnt) != -1);
170+
CHECK_FAIL(errno != ENOSPC);
171+
CHECK_FAIL(prog_cnt != 4);
172+
/* check that prog_ids are returned even when buffer is too small */
173+
CHECK_FAIL(prog_ids[0] != saved_prog_id);
174+
/* retrieve prog_id of single attached prog in cg5 */
175+
prog_ids[0] = 0;
176+
CHECK_FAIL(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, 0, NULL,
177+
prog_ids, &prog_cnt));
178+
CHECK_FAIL(prog_cnt != 1);
179+
CHECK_FAIL(prog_ids[0] != saved_prog_id);
180+
181+
/* detach bottom program and ping again */
182+
if (CHECK(bpf_prog_detach2(-1, cg5, BPF_CGROUP_INET_EGRESS),
183+
"prog_detach_from_cg5", "errno=%d\n", errno))
184+
goto err;
185+
186+
value = 0;
187+
CHECK_FAIL(bpf_map_update_elem(map_fd, &key, &value, 0));
188+
CHECK_FAIL(system(PING_CMD));
189+
CHECK_FAIL(bpf_map_lookup_elem(map_fd, &key, &value));
190+
CHECK_FAIL(value != 1 + 2 + 8 + 16);
191+
192+
/* detach 3rd from bottom program and ping again */
193+
if (CHECK(!bpf_prog_detach2(0, cg3, BPF_CGROUP_INET_EGRESS),
194+
"fail_prog_detach_from_cg3", "unexpected success\n"))
195+
goto err;
196+
197+
if (CHECK(bpf_prog_detach2(allow_prog[3], cg3, BPF_CGROUP_INET_EGRESS),
198+
"prog3_detach_from_cg3", "errno=%d\n", errno))
199+
goto err;
200+
201+
value = 0;
202+
CHECK_FAIL(bpf_map_update_elem(map_fd, &key, &value, 0));
203+
CHECK_FAIL(system(PING_CMD));
204+
CHECK_FAIL(bpf_map_lookup_elem(map_fd, &key, &value));
205+
CHECK_FAIL(value != 1 + 2 + 16);
206+
207+
/* detach 2nd from bottom program and ping again */
208+
if (CHECK(bpf_prog_detach2(-1, cg4, BPF_CGROUP_INET_EGRESS),
209+
"prog_detach_from_cg4", "errno=%d\n", errno))
210+
goto err;
211+
212+
value = 0;
213+
CHECK_FAIL(bpf_map_update_elem(map_fd, &key, &value, 0));
214+
CHECK_FAIL(system(PING_CMD));
215+
CHECK_FAIL(bpf_map_lookup_elem(map_fd, &key, &value));
216+
CHECK_FAIL(value != 1 + 2 + 4);
217+
218+
prog_cnt = 4;
219+
CHECK_FAIL(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS,
220+
BPF_F_QUERY_EFFECTIVE, &attach_flags,
221+
prog_ids, &prog_cnt));
222+
CHECK_FAIL(prog_cnt != 3);
223+
CHECK_FAIL(attach_flags != 0);
224+
CHECK_FAIL(bpf_prog_query(cg5, BPF_CGROUP_INET_EGRESS, 0, NULL,
225+
prog_ids, &prog_cnt));
226+
CHECK_FAIL(prog_cnt != 0);
227+
228+
err:
229+
for (i = 0; i < ARRAY_SIZE(allow_prog); i++)
230+
if (allow_prog[i] >= 0)
231+
close(allow_prog[i]);
232+
close(cg1);
233+
close(cg2);
234+
close(cg3);
235+
close(cg4);
236+
close(cg5);
237+
cleanup_cgroup_environment();
238+
}

0 commit comments

Comments
 (0)