Skip to content

Commit efa3260

Browse files
laoarKernel Patches Daemon
authored and
Kernel Patches Daemon
committed
selftests/bpf: Add selftest for cgroup_task iter
Add selftests for the newly introduced cgroup_task iter. The result: #42/1 cgroup_task_iter/cgroup_task_iter__invalid_order:OK #42/2 cgroup_task_iter/cgroup_task_iter__no_task:OK #42/3 cgroup_task_iter/cgroup_task_iter__task_pid:OK #42/4 cgroup_task_iter/cgroup_task_iter__task_cnt:OK #42 cgroup_task_iter:OK Summary: 1/4 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Yafang Shao <[email protected]>
1 parent 63b3a9c commit efa3260

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2023 Yafang Shao <[email protected]> */
3+
4+
#include <signal.h>
5+
#include <stdint.h>
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <unistd.h>
9+
#include <sys/types.h>
10+
#include <sys/wait.h>
11+
#include <test_progs.h>
12+
#include <bpf/libbpf.h>
13+
#include <bpf/btf.h>
14+
#include "cgroup_helpers.h"
15+
#include "cgroup_task_iter.skel.h"
16+
17+
#define PID_CNT (2)
18+
static char expected_output[128];
19+
20+
static void read_from_cgroup_iter(struct bpf_program *prog, int cgroup_fd,
21+
int order, const char *testname)
22+
{
23+
DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
24+
union bpf_iter_link_info linfo;
25+
struct bpf_link *link;
26+
int len, iter_fd;
27+
static char buf[128];
28+
size_t left;
29+
char *p;
30+
31+
memset(&linfo, 0, sizeof(linfo));
32+
linfo.cgroup.cgroup_fd = cgroup_fd;
33+
linfo.cgroup.order = order;
34+
opts.link_info = &linfo;
35+
opts.link_info_len = sizeof(linfo);
36+
37+
link = bpf_program__attach_iter(prog, &opts);
38+
if (!ASSERT_OK_PTR(link, "attach_iter"))
39+
return;
40+
41+
iter_fd = bpf_iter_create(bpf_link__fd(link));
42+
if (iter_fd < 0)
43+
goto free_link;
44+
45+
memset(buf, 0, sizeof(buf));
46+
left = ARRAY_SIZE(buf);
47+
p = buf;
48+
while ((len = read(iter_fd, p, left)) > 0) {
49+
p += len;
50+
left -= len;
51+
}
52+
53+
ASSERT_STREQ(buf, expected_output, testname);
54+
55+
/* read() after iter finishes should be ok. */
56+
if (len == 0)
57+
ASSERT_OK(read(iter_fd, buf, sizeof(buf)), "second_read");
58+
59+
close(iter_fd);
60+
free_link:
61+
bpf_link__destroy(link);
62+
}
63+
64+
/* Invalid walk order */
65+
static void test_invalid_order(struct cgroup_task_iter *skel, int fd)
66+
{
67+
DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
68+
enum bpf_cgroup_iter_order order;
69+
union bpf_iter_link_info linfo;
70+
struct bpf_link *link;
71+
72+
memset(&linfo, 0, sizeof(linfo));
73+
linfo.cgroup.cgroup_fd = fd;
74+
opts.link_info = &linfo;
75+
opts.link_info_len = sizeof(linfo);
76+
77+
/* Only BPF_CGROUP_ITER_SELF_ONLY is supported */
78+
for (order = 0; order <= BPF_CGROUP_ITER_ANCESTORS_UP; order++) {
79+
if (order == BPF_CGROUP_ITER_SELF_ONLY)
80+
continue;
81+
linfo.cgroup.order = order;
82+
link = bpf_program__attach_iter(skel->progs.cgroup_task_cnt, &opts);
83+
ASSERT_ERR_PTR(link, "attach_task_iter");
84+
ASSERT_EQ(errno, EINVAL, "error code on invalid walk order");
85+
}
86+
}
87+
88+
/* Iterate a cgroup withouth any task */
89+
static void test_walk_no_task(struct cgroup_task_iter *skel, int fd)
90+
{
91+
snprintf(expected_output, sizeof(expected_output), "nr_total 0\n");
92+
93+
read_from_cgroup_iter(skel->progs.cgroup_task_cnt, fd,
94+
BPF_CGROUP_ITER_SELF_ONLY, "self_only");
95+
}
96+
97+
/* The forked child process do nothing. */
98+
static void child_sleep(void)
99+
{
100+
while (1)
101+
sleep(1);
102+
}
103+
104+
/* Get task pid under a cgroup */
105+
static void test_walk_task_pid(struct cgroup_task_iter *skel, int fd)
106+
{
107+
int pid, status, err;
108+
char pid_str[16];
109+
110+
pid = fork();
111+
if (!ASSERT_GE(pid, 0, "fork_task"))
112+
return;
113+
if (pid) {
114+
snprintf(pid_str, sizeof(pid_str), "%u", pid);
115+
err = write_cgroup_file("cgroup_task_iter", "cgroup.procs", pid_str);
116+
if (!ASSERT_EQ(err, 0, "write cgrp file"))
117+
goto out;
118+
snprintf(expected_output, sizeof(expected_output), "pid %u\n", pid);
119+
read_from_cgroup_iter(skel->progs.cgroup_task_pid, fd,
120+
BPF_CGROUP_ITER_SELF_ONLY, "self_only");
121+
out:
122+
kill(pid, SIGKILL);
123+
waitpid(pid, &status, 0);
124+
} else {
125+
child_sleep();
126+
}
127+
}
128+
129+
/* Get task count under a cgroup */
130+
static void test_walk_task_cnt(struct cgroup_task_iter *skel, int fd)
131+
{
132+
int pids[PID_CNT], pid, status, err, i;
133+
char pid_str[16];
134+
135+
for (i = 0; i < PID_CNT; i++)
136+
pids[i] = 0;
137+
138+
for (i = 0; i < PID_CNT; i++) {
139+
pid = fork();
140+
if (!ASSERT_GE(pid, 0, "fork_task"))
141+
goto out;
142+
if (pid) {
143+
pids[i] = pid;
144+
snprintf(pid_str, sizeof(pid_str), "%u", pid);
145+
err = write_cgroup_file("cgroup_task_iter", "cgroup.procs", pid_str);
146+
if (!ASSERT_EQ(err, 0, "write cgrp file"))
147+
goto out;
148+
} else {
149+
child_sleep();
150+
}
151+
}
152+
153+
snprintf(expected_output, sizeof(expected_output), "nr_total %u\n", PID_CNT);
154+
read_from_cgroup_iter(skel->progs.cgroup_task_cnt, fd,
155+
BPF_CGROUP_ITER_SELF_ONLY, "self_only");
156+
157+
out:
158+
for (i = 0; i < PID_CNT; i++) {
159+
if (!pids[i])
160+
continue;
161+
kill(pids[i], SIGKILL);
162+
waitpid(pids[i], &status, 0);
163+
}
164+
}
165+
166+
void test_cgroup_task_iter(void)
167+
{
168+
struct cgroup_task_iter *skel = NULL;
169+
int cgrp_fd;
170+
171+
if (setup_cgroup_environment())
172+
return;
173+
174+
cgrp_fd = create_and_get_cgroup("cgroup_task_iter");
175+
if (!ASSERT_GE(cgrp_fd, 0, "create cgrp"))
176+
goto cleanup_cgrp_env;
177+
178+
skel = cgroup_task_iter__open_and_load();
179+
if (!ASSERT_OK_PTR(skel, "cgroup_task_iter__open_and_load"))
180+
goto out;
181+
182+
if (test__start_subtest("cgroup_task_iter__invalid_order"))
183+
test_invalid_order(skel, cgrp_fd);
184+
if (test__start_subtest("cgroup_task_iter__no_task"))
185+
test_walk_no_task(skel, cgrp_fd);
186+
if (test__start_subtest("cgroup_task_iter__task_pid"))
187+
test_walk_task_pid(skel, cgrp_fd);
188+
if (test__start_subtest("cgroup_task_iter__task_cnt"))
189+
test_walk_task_cnt(skel, cgrp_fd);
190+
191+
out:
192+
cgroup_task_iter__destroy(skel);
193+
close(cgrp_fd);
194+
remove_cgroup("cgroup_task_iter");
195+
cleanup_cgrp_env:
196+
cleanup_cgroup_environment();
197+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2023 Yafang Shao <[email protected]> */
3+
4+
#include "bpf_iter.h"
5+
#include <bpf/bpf_helpers.h>
6+
#include <bpf/bpf_tracing.h>
7+
8+
char _license[] SEC("license") = "GPL";
9+
10+
SEC("iter/cgroup_task")
11+
int cgroup_task_cnt(struct bpf_iter__cgroup_task *ctx)
12+
{
13+
struct seq_file *seq = ctx->meta->seq;
14+
struct task_struct *task = ctx->task;
15+
static __u32 nr_total;
16+
17+
if (!task) {
18+
BPF_SEQ_PRINTF(seq, "nr_total %u\n", nr_total);
19+
return 0;
20+
}
21+
22+
if (ctx->meta->seq_num == 0)
23+
nr_total = 0;
24+
nr_total++;
25+
return 0;
26+
}
27+
28+
SEC("iter/cgroup_task")
29+
int cgroup_task_pid(struct bpf_iter__cgroup_task *ctx)
30+
{
31+
struct seq_file *seq = ctx->meta->seq;
32+
struct task_struct *task = ctx->task;
33+
34+
if (!task)
35+
return 0;
36+
37+
BPF_SEQ_PRINTF(seq, "pid %u\n", task->pid);
38+
return 0;
39+
}

0 commit comments

Comments
 (0)