Skip to content

Commit 492e408

Browse files
laoarKernel Patches Daemon
authored and
Kernel Patches Daemon
committed
selftests/bpf: Add selftests for cpumask iter
Add selftests for the newly added cpumask iter. - cpumask_iter_success - The number of CPUs should be expected when iterating over the cpumask - percpu data extracted from the percpu struct should be expected - It can work in both non-sleepable and sleepable prog - RCU lock is only required by bpf_iter_cpumask_new() - It is fine without calling bpf_iter_cpumask_next() - cpumask_iter_failure - RCU lock is required in sleepable prog - The cpumask to be iterated over can't be NULL - bpf_iter_cpumask_destroy() is required after calling bpf_iter_cpumask_new() - bpf_iter_cpumask_destroy() can only destroy an initilialized iter - bpf_iter_cpumask_next() must use an initilialized iter The result as follows, #64/37 cpumask/test_cpumask_iter:OK #64/38 cpumask/test_cpumask_iter_sleepable:OK #64/39 cpumask/test_cpumask_iter_sleepable:OK #64/40 cpumask/test_cpumask_iter_next_no_rcu:OK #64/41 cpumask/test_cpumask_iter_no_next:OK #64/42 cpumask/test_cpumask_iter:OK #64/43 cpumask/test_cpumask_iter_no_rcu:OK #64/44 cpumask/test_cpumask_iter_no_destroy:OK #64/45 cpumask/test_cpumask_iter_null_pointer:OK #64/46 cpumask/test_cpumask_iter_next_uninit:OK #64/47 cpumask/test_cpumask_iter_destroy_uninit:OK #64 cpumask:OK Signed-off-by: Yafang Shao <[email protected]>
1 parent 784dcfb commit 492e408

File tree

5 files changed

+381
-0
lines changed

5 files changed

+381
-0
lines changed

tools/testing/selftests/bpf/config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ CONFIG_NF_CONNTRACK_MARK=y
7878
CONFIG_NF_DEFRAG_IPV4=y
7979
CONFIG_NF_DEFRAG_IPV6=y
8080
CONFIG_NF_NAT=y
81+
CONFIG_PSI=y
8182
CONFIG_RC_CORE=y
8283
CONFIG_SECURITY=y
8384
CONFIG_SECURITYFS=y

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

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
// SPDX-License-Identifier: GPL-2.0
22
/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
33

4+
#define _GNU_SOURCE
5+
#include <sched.h>
6+
47
#include <test_progs.h>
58
#include "cpumask_failure.skel.h"
69
#include "cpumask_success.skel.h"
10+
#include "cpumask_iter_success.skel.h"
11+
#include "cpumask_iter_failure.skel.h"
12+
#include "cgroup_helpers.h"
713

814
static const char * const cpumask_success_testcases[] = {
915
"test_alloc_free_cpumask",
@@ -61,6 +67,142 @@ static void verify_success(const char *prog_name)
6167
cpumask_success__destroy(skel);
6268
}
6369

70+
static const char * const cpumask_iter_success_testcases[] = {
71+
"test_cpumask_iter",
72+
"test_cpumask_iter_sleepable",
73+
};
74+
75+
static int read_percpu_data(struct bpf_link *link, int nr_cpu_exp, int nr_running_exp)
76+
{
77+
int iter_fd, len, item, nr_running, psi_running, nr_cpus, err = -1;
78+
char buf[128];
79+
size_t left;
80+
char *p;
81+
82+
iter_fd = bpf_iter_create(bpf_link__fd(link));
83+
if (!ASSERT_GE(iter_fd, 0, "iter_fd"))
84+
return -1;
85+
86+
memset(buf, 0, sizeof(buf));
87+
left = ARRAY_SIZE(buf);
88+
p = buf;
89+
while ((len = read(iter_fd, p, left)) > 0) {
90+
p += len;
91+
left -= len;
92+
}
93+
94+
item = sscanf(buf, "nr_running %u nr_cpus %u psi_running %u\n",
95+
&nr_running, &nr_cpus, &psi_running);
96+
if (!ASSERT_EQ(item, 3, "seq_format"))
97+
goto out;
98+
if (!ASSERT_EQ(nr_cpus, nr_cpu_exp, "nr_cpus"))
99+
goto out;
100+
if (!ASSERT_GE(nr_running, nr_running_exp, "nr_running"))
101+
goto out;
102+
if (!ASSERT_GE(psi_running, nr_running_exp, "psi_running"))
103+
goto out;
104+
105+
err = 0;
106+
out:
107+
close(iter_fd);
108+
return err;
109+
}
110+
111+
static void verify_iter_success(const char *prog_name)
112+
{
113+
DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
114+
int cgrp_fd, nr_cpus, err, i, chosen = 0;
115+
struct cpumask_iter_success *skel;
116+
union bpf_iter_link_info linfo;
117+
struct bpf_program *prog;
118+
struct bpf_link *link;
119+
cpu_set_t set;
120+
121+
if (setup_cgroup_environment())
122+
return;
123+
124+
/* Utilize the cgroup iter */
125+
cgrp_fd = get_root_cgroup();
126+
if (!ASSERT_GE(cgrp_fd, 0, "create_cgrp"))
127+
goto cleanup;
128+
129+
skel = cpumask_iter_success__open();
130+
if (!ASSERT_OK_PTR(skel, "cpumask_iter_success__open"))
131+
goto close_fd;
132+
133+
skel->bss->pid = getpid();
134+
nr_cpus = libbpf_num_possible_cpus();
135+
136+
err = cpumask_iter_success__load(skel);
137+
if (!ASSERT_OK(err, "cpumask_iter_success__load"))
138+
goto destroy;
139+
140+
prog = bpf_object__find_program_by_name(skel->obj, prog_name);
141+
if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
142+
goto destroy;
143+
144+
memset(&linfo, 0, sizeof(linfo));
145+
linfo.cgroup.cgroup_fd = cgrp_fd;
146+
linfo.cgroup.order = BPF_CGROUP_ITER_SELF_ONLY;
147+
opts.link_info = &linfo;
148+
opts.link_info_len = sizeof(linfo);
149+
link = bpf_program__attach_iter(prog, &opts);
150+
if (!ASSERT_OK_PTR(link, "bpf_program__attach"))
151+
goto destroy;
152+
153+
/* Case 1): Enable all possible CPUs */
154+
CPU_ZERO(&set);
155+
for (i = 0; i < nr_cpus; i++)
156+
CPU_SET(i, &set);
157+
err = sched_setaffinity(skel->bss->pid, sizeof(set), &set);
158+
if (!ASSERT_OK(err, "setaffinity_all_cpus"))
159+
goto free_link;
160+
err = read_percpu_data(link, nr_cpus, 1);
161+
if (!ASSERT_OK(err, "read_percpu_data"))
162+
goto free_link;
163+
if (!ASSERT_OK(skel->bss->err, "null_rq"))
164+
goto free_link;
165+
166+
/* Case 2): CPU0 only */
167+
CPU_ZERO(&set);
168+
CPU_SET(0, &set);
169+
err = sched_setaffinity(skel->bss->pid, sizeof(set), &set);
170+
if (!ASSERT_OK(err, "setaffinity_cpu0"))
171+
goto free_link;
172+
err = read_percpu_data(link, 1, 1);
173+
if (!ASSERT_OK(err, "read_percpu_data"))
174+
goto free_link;
175+
if (!ASSERT_OK(skel->bss->err, "null_rq_psi"))
176+
goto free_link;
177+
178+
/* Case 3): Partial CPUs */
179+
CPU_ZERO(&set);
180+
for (i = 0; i < nr_cpus; i++) {
181+
if (i < 4 && i & 0x1)
182+
continue;
183+
if (i > 8 && i & 0x2)
184+
continue;
185+
CPU_SET(i, &set);
186+
chosen++;
187+
}
188+
err = sched_setaffinity(skel->bss->pid, sizeof(set), &set);
189+
if (!ASSERT_OK(err, "setaffinity_partial_cpus"))
190+
goto free_link;
191+
err = read_percpu_data(link, chosen, 1);
192+
if (!ASSERT_OK(err, "read_percpu_data"))
193+
goto free_link;
194+
ASSERT_OK(skel->bss->err, "null_rq_psi");
195+
196+
free_link:
197+
bpf_link__destroy(link);
198+
destroy:
199+
cpumask_iter_success__destroy(skel);
200+
close_fd:
201+
close(cgrp_fd);
202+
cleanup:
203+
cleanup_cgroup_environment();
204+
}
205+
64206
void test_cpumask(void)
65207
{
66208
int i;
@@ -74,4 +216,14 @@ void test_cpumask(void)
74216

75217
RUN_TESTS(cpumask_success);
76218
RUN_TESTS(cpumask_failure);
219+
220+
for (i = 0; i < ARRAY_SIZE(cpumask_iter_success_testcases); i++) {
221+
if (!test__start_subtest(cpumask_iter_success_testcases[i]))
222+
continue;
223+
224+
verify_iter_success(cpumask_iter_success_testcases[i]);
225+
}
226+
227+
RUN_TESTS(cpumask_iter_success);
228+
RUN_TESTS(cpumask_iter_failure);
77229
}

tools/testing/selftests/bpf/progs/cpumask_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ void bpf_cpumask_copy(struct bpf_cpumask *dst, const struct cpumask *src) __ksym
5555
u32 bpf_cpumask_any_distribute(const struct cpumask *src) __ksym;
5656
u32 bpf_cpumask_any_and_distribute(const struct cpumask *src1, const struct cpumask *src2) __ksym;
5757
u32 bpf_cpumask_weight(const struct cpumask *cpumask) __ksym;
58+
int bpf_iter_cpumask_new(struct bpf_iter_cpumask *it, const struct cpumask *mask) __ksym;
59+
int *bpf_iter_cpumask_next(struct bpf_iter_cpumask *it) __ksym;
60+
void bpf_iter_cpumask_destroy(struct bpf_iter_cpumask *it) __ksym;
5861

5962
void bpf_rcu_read_lock(void) __ksym;
6063
void bpf_rcu_read_unlock(void) __ksym;
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Copyright (c) 2024 Yafang Shao <[email protected]> */
3+
4+
#include "vmlinux.h"
5+
#include <bpf/bpf_helpers.h>
6+
#include <bpf/bpf_tracing.h>
7+
8+
#include "bpf_misc.h"
9+
#include "task_kfunc_common.h"
10+
#include "cpumask_common.h"
11+
12+
char _license[] SEC("license") = "GPL";
13+
14+
SEC("iter.s/cgroup")
15+
__failure __msg("R2 must be a rcu pointer")
16+
int BPF_PROG(test_cpumask_iter_no_rcu, struct bpf_iter_meta *meta, struct cgroup *cgrp)
17+
{
18+
struct task_struct *p;
19+
int *cpu;
20+
21+
p = bpf_task_from_pid(1);
22+
if (!p)
23+
return 1;
24+
25+
bpf_for_each(cpumask, cpu, p->cpus_ptr) {
26+
}
27+
bpf_task_release(p);
28+
return 0;
29+
}
30+
31+
SEC("iter/cgroup")
32+
__failure __msg("Possibly NULL pointer passed to trusted arg1")
33+
int BPF_PROG(test_cpumask_iter_null_pointer, struct bpf_iter_meta *meta, struct cgroup *cgrp)
34+
{
35+
struct cpumask *mask = NULL;
36+
int *cpu;
37+
38+
bpf_for_each(cpumask, cpu, mask) {
39+
}
40+
return 0;
41+
}
42+
43+
SEC("iter.s/cgroup")
44+
__failure __msg("Unreleased reference id=3 alloc_insn=10")
45+
int BPF_PROG(test_cpumask_iter_no_destroy, struct bpf_iter_meta *meta, struct cgroup *cgrp)
46+
{
47+
struct bpf_iter_cpumask it;
48+
struct task_struct *p;
49+
50+
p = bpf_task_from_pid(1);
51+
if (!p)
52+
return 1;
53+
54+
bpf_rcu_read_lock();
55+
bpf_iter_cpumask_new(&it, p->cpus_ptr);
56+
bpf_rcu_read_unlock();
57+
58+
bpf_iter_cpumask_next(&it);
59+
bpf_task_release(p);
60+
return 0;
61+
}
62+
63+
SEC("iter/cgroup")
64+
__failure __msg("expected an initialized iter_cpumask as arg #1")
65+
int BPF_PROG(test_cpumask_iter_next_uninit, struct bpf_iter_meta *meta, struct cgroup *cgrp)
66+
{
67+
struct bpf_iter_cpumask *it = NULL;
68+
69+
bpf_iter_cpumask_next(it);
70+
return 0;
71+
}
72+
73+
SEC("iter/cgroup")
74+
__failure __msg("expected an initialized iter_cpumask as arg #1")
75+
int BPF_PROG(test_cpumask_iter_next_uninit2, struct bpf_iter_meta *meta, struct cgroup *cgrp)
76+
{
77+
struct bpf_iter_cpumask it = {};
78+
79+
bpf_iter_cpumask_next(&it);
80+
return 0;
81+
}
82+
83+
SEC("iter/cgroup")
84+
__failure __msg("expected an initialized iter_cpumask as arg #1")
85+
int BPF_PROG(test_cpumask_iter_destroy_uninit, struct bpf_iter_meta *meta, struct cgroup *cgrp)
86+
{
87+
struct bpf_iter_cpumask_kern it = {.cpu = -1};
88+
struct bpf_cpumask *mask;
89+
90+
mask = bpf_cpumask_create();
91+
if (!mask)
92+
return 1;
93+
94+
bpf_cpumask_setall(mask);
95+
it.mask = &mask->cpumask;
96+
bpf_iter_cpumask_destroy((struct bpf_iter_cpumask *)&it);
97+
bpf_cpumask_release(mask);
98+
return 0;
99+
}

0 commit comments

Comments
 (0)