Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2022 Google */
  3
  4#include <test_progs.h>
  5#include <bpf/libbpf.h>
  6#include <bpf/btf.h>
  7#include "iters_css_task.skel.h"
  8#include "cgroup_iter.skel.h"
  9#include "cgroup_helpers.h"
 10
 11#define ROOT           0
 12#define PARENT         1
 13#define CHILD1         2
 14#define CHILD2         3
 15#define NUM_CGROUPS    4
 16
 17#define PROLOGUE       "prologue\n"
 18#define EPILOGUE       "epilogue\n"
 19
 20static const char *cg_path[] = {
 21	"/", "/parent", "/parent/child1", "/parent/child2"
 22};
 23
 24static int cg_fd[] = {-1, -1, -1, -1};
 25static unsigned long long cg_id[] = {0, 0, 0, 0};
 26static char expected_output[64];
 27
 28static int setup_cgroups(void)
 29{
 30	int fd, i = 0;
 31
 32	for (i = 0; i < NUM_CGROUPS; i++) {
 33		fd = create_and_get_cgroup(cg_path[i]);
 34		if (fd < 0)
 35			return fd;
 36
 37		cg_fd[i] = fd;
 38		cg_id[i] = get_cgroup_id(cg_path[i]);
 39	}
 40	return 0;
 41}
 42
 43static void cleanup_cgroups(void)
 44{
 45	int i;
 46
 47	for (i = 0; i < NUM_CGROUPS; i++)
 48		close(cg_fd[i]);
 49}
 50
 51static void read_from_cgroup_iter(struct bpf_program *prog, int cgroup_fd,
 52				  int order, const char *testname)
 53{
 54	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
 55	union bpf_iter_link_info linfo;
 56	struct bpf_link *link;
 57	int len, iter_fd;
 58	static char buf[128];
 59	size_t left;
 60	char *p;
 61
 62	memset(&linfo, 0, sizeof(linfo));
 63	linfo.cgroup.cgroup_fd = cgroup_fd;
 64	linfo.cgroup.order = order;
 65	opts.link_info = &linfo;
 66	opts.link_info_len = sizeof(linfo);
 67
 68	link = bpf_program__attach_iter(prog, &opts);
 69	if (!ASSERT_OK_PTR(link, "attach_iter"))
 70		return;
 71
 72	iter_fd = bpf_iter_create(bpf_link__fd(link));
 73	if (iter_fd < 0)
 74		goto free_link;
 75
 76	memset(buf, 0, sizeof(buf));
 77	left = ARRAY_SIZE(buf);
 78	p = buf;
 79	while ((len = read(iter_fd, p, left)) > 0) {
 80		p += len;
 81		left -= len;
 82	}
 83
 84	ASSERT_STREQ(buf, expected_output, testname);
 85
 86	/* read() after iter finishes should be ok. */
 87	if (len == 0)
 88		ASSERT_OK(read(iter_fd, buf, sizeof(buf)), "second_read");
 89
 90	close(iter_fd);
 91free_link:
 92	bpf_link__destroy(link);
 93}
 94
 95/* Invalid cgroup. */
 96static void test_invalid_cgroup(struct cgroup_iter *skel)
 97{
 98	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
 99	union bpf_iter_link_info linfo;
100	struct bpf_link *link;
101
102	memset(&linfo, 0, sizeof(linfo));
103	linfo.cgroup.cgroup_fd = (__u32)-1;
104	opts.link_info = &linfo;
105	opts.link_info_len = sizeof(linfo);
106
107	link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
108	ASSERT_ERR_PTR(link, "attach_iter");
109	bpf_link__destroy(link);
110}
111
112/* Specifying both cgroup_fd and cgroup_id is invalid. */
113static void test_invalid_cgroup_spec(struct cgroup_iter *skel)
114{
115	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
116	union bpf_iter_link_info linfo;
117	struct bpf_link *link;
118
119	memset(&linfo, 0, sizeof(linfo));
120	linfo.cgroup.cgroup_fd = (__u32)cg_fd[PARENT];
121	linfo.cgroup.cgroup_id = (__u64)cg_id[PARENT];
122	opts.link_info = &linfo;
123	opts.link_info_len = sizeof(linfo);
124
125	link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
126	ASSERT_ERR_PTR(link, "attach_iter");
127	bpf_link__destroy(link);
128}
129
130/* Preorder walk prints parent and child in order. */
131static void test_walk_preorder(struct cgroup_iter *skel)
132{
133	snprintf(expected_output, sizeof(expected_output),
134		 PROLOGUE "%8llu\n%8llu\n%8llu\n" EPILOGUE,
135		 cg_id[PARENT], cg_id[CHILD1], cg_id[CHILD2]);
136
137	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
138			      BPF_CGROUP_ITER_DESCENDANTS_PRE, "preorder");
139}
140
141/* Postorder walk prints child and parent in order. */
142static void test_walk_postorder(struct cgroup_iter *skel)
143{
144	snprintf(expected_output, sizeof(expected_output),
145		 PROLOGUE "%8llu\n%8llu\n%8llu\n" EPILOGUE,
146		 cg_id[CHILD1], cg_id[CHILD2], cg_id[PARENT]);
147
148	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
149			      BPF_CGROUP_ITER_DESCENDANTS_POST, "postorder");
150}
151
152/* Walking parents prints parent and then root. */
153static void test_walk_ancestors_up(struct cgroup_iter *skel)
154{
155	/* terminate the walk when ROOT is met. */
156	skel->bss->terminal_cgroup = cg_id[ROOT];
157
158	snprintf(expected_output, sizeof(expected_output),
159		 PROLOGUE "%8llu\n%8llu\n" EPILOGUE,
160		 cg_id[PARENT], cg_id[ROOT]);
161
162	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
163			      BPF_CGROUP_ITER_ANCESTORS_UP, "ancestors_up");
164
165	skel->bss->terminal_cgroup = 0;
166}
167
168/* Early termination prints parent only. */
169static void test_early_termination(struct cgroup_iter *skel)
170{
171	/* terminate the walk after the first element is processed. */
172	skel->bss->terminate_early = 1;
173
174	snprintf(expected_output, sizeof(expected_output),
175		 PROLOGUE "%8llu\n" EPILOGUE, cg_id[PARENT]);
176
177	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
178			      BPF_CGROUP_ITER_DESCENDANTS_PRE, "early_termination");
179
180	skel->bss->terminate_early = 0;
181}
182
183/* Waling self prints self only. */
184static void test_walk_self_only(struct cgroup_iter *skel)
185{
186	snprintf(expected_output, sizeof(expected_output),
187		 PROLOGUE "%8llu\n" EPILOGUE, cg_id[PARENT]);
188
189	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
190			      BPF_CGROUP_ITER_SELF_ONLY, "self_only");
191}
192
193static void test_walk_dead_self_only(struct cgroup_iter *skel)
194{
195	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
196	char expected_output[128], buf[128];
197	const char *cgrp_name = "/dead";
198	union bpf_iter_link_info linfo;
199	int len, cgrp_fd, iter_fd;
200	struct bpf_link *link;
201	size_t left;
202	char *p;
203
204	cgrp_fd = create_and_get_cgroup(cgrp_name);
205	if (!ASSERT_GE(cgrp_fd, 0, "create cgrp"))
206		return;
207
208	/* The cgroup will be dead during read() iteration, so it only has
209	 * epilogue in the output
210	 */
211	snprintf(expected_output, sizeof(expected_output), EPILOGUE);
212
213	memset(&linfo, 0, sizeof(linfo));
214	linfo.cgroup.cgroup_fd = cgrp_fd;
215	linfo.cgroup.order = BPF_CGROUP_ITER_SELF_ONLY;
216	opts.link_info = &linfo;
217	opts.link_info_len = sizeof(linfo);
218
219	link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
220	if (!ASSERT_OK_PTR(link, "attach_iter"))
221		goto close_cgrp;
222
223	iter_fd = bpf_iter_create(bpf_link__fd(link));
224	if (!ASSERT_GE(iter_fd, 0, "iter_create"))
225		goto free_link;
226
227	/* Close link fd and cgroup fd */
228	bpf_link__destroy(link);
229	close(cgrp_fd);
230
231	/* Remove cgroup to mark it as dead */
232	remove_cgroup(cgrp_name);
233
234	/* Two kern_sync_rcu() and usleep() pairs are used to wait for the
235	 * releases of cgroup css, and the last kern_sync_rcu() and usleep()
236	 * pair is used to wait for the free of cgroup itself.
237	 */
238	kern_sync_rcu();
239	usleep(8000);
240	kern_sync_rcu();
241	usleep(8000);
242	kern_sync_rcu();
243	usleep(1000);
244
245	memset(buf, 0, sizeof(buf));
246	left = ARRAY_SIZE(buf);
247	p = buf;
248	while ((len = read(iter_fd, p, left)) > 0) {
249		p += len;
250		left -= len;
251	}
252
253	ASSERT_STREQ(buf, expected_output, "dead cgroup output");
254
255	/* read() after iter finishes should be ok. */
256	if (len == 0)
257		ASSERT_OK(read(iter_fd, buf, sizeof(buf)), "second_read");
258
259	close(iter_fd);
260	return;
261free_link:
262	bpf_link__destroy(link);
263close_cgrp:
264	close(cgrp_fd);
265}
266
267static void test_walk_self_only_css_task(void)
268{
269	struct iters_css_task *skel;
270	int err;
271
272	skel = iters_css_task__open();
273	if (!ASSERT_OK_PTR(skel, "skel_open"))
274		return;
275
276	bpf_program__set_autoload(skel->progs.cgroup_id_printer, true);
277
278	err = iters_css_task__load(skel);
279	if (!ASSERT_OK(err, "skel_load"))
280		goto cleanup;
281
282	err = join_cgroup(cg_path[CHILD2]);
283	if (!ASSERT_OK(err, "join_cgroup"))
284		goto cleanup;
285
286	skel->bss->target_pid = getpid();
287	snprintf(expected_output, sizeof(expected_output),
288		PROLOGUE "%8llu\n" EPILOGUE, cg_id[CHILD2]);
289	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[CHILD2],
290		BPF_CGROUP_ITER_SELF_ONLY, "test_walk_self_only_css_task");
291	ASSERT_EQ(skel->bss->css_task_cnt, 1, "css_task_cnt");
292cleanup:
293	iters_css_task__destroy(skel);
294}
295
296void test_cgroup_iter(void)
297{
298	struct cgroup_iter *skel = NULL;
299
300	if (setup_cgroup_environment())
301		return;
302
303	if (setup_cgroups())
304		goto out;
305
306	skel = cgroup_iter__open_and_load();
307	if (!ASSERT_OK_PTR(skel, "cgroup_iter__open_and_load"))
308		goto out;
309
310	if (test__start_subtest("cgroup_iter__invalid_cgroup"))
311		test_invalid_cgroup(skel);
312	if (test__start_subtest("cgroup_iter__invalid_cgroup_spec"))
313		test_invalid_cgroup_spec(skel);
314	if (test__start_subtest("cgroup_iter__preorder"))
315		test_walk_preorder(skel);
316	if (test__start_subtest("cgroup_iter__postorder"))
317		test_walk_postorder(skel);
318	if (test__start_subtest("cgroup_iter__ancestors_up_walk"))
319		test_walk_ancestors_up(skel);
320	if (test__start_subtest("cgroup_iter__early_termination"))
321		test_early_termination(skel);
322	if (test__start_subtest("cgroup_iter__self_only"))
323		test_walk_self_only(skel);
324	if (test__start_subtest("cgroup_iter__dead_self_only"))
325		test_walk_dead_self_only(skel);
326	if (test__start_subtest("cgroup_iter__self_only_css_task"))
327		test_walk_self_only_css_task();
328
329out:
330	cgroup_iter__destroy(skel);
331	cleanup_cgroups();
332	cleanup_cgroup_environment();
333}
v6.2
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2022 Google */
  3
  4#include <test_progs.h>
  5#include <bpf/libbpf.h>
  6#include <bpf/btf.h>
 
  7#include "cgroup_iter.skel.h"
  8#include "cgroup_helpers.h"
  9
 10#define ROOT           0
 11#define PARENT         1
 12#define CHILD1         2
 13#define CHILD2         3
 14#define NUM_CGROUPS    4
 15
 16#define PROLOGUE       "prologue\n"
 17#define EPILOGUE       "epilogue\n"
 18
 19static const char *cg_path[] = {
 20	"/", "/parent", "/parent/child1", "/parent/child2"
 21};
 22
 23static int cg_fd[] = {-1, -1, -1, -1};
 24static unsigned long long cg_id[] = {0, 0, 0, 0};
 25static char expected_output[64];
 26
 27static int setup_cgroups(void)
 28{
 29	int fd, i = 0;
 30
 31	for (i = 0; i < NUM_CGROUPS; i++) {
 32		fd = create_and_get_cgroup(cg_path[i]);
 33		if (fd < 0)
 34			return fd;
 35
 36		cg_fd[i] = fd;
 37		cg_id[i] = get_cgroup_id(cg_path[i]);
 38	}
 39	return 0;
 40}
 41
 42static void cleanup_cgroups(void)
 43{
 44	int i;
 45
 46	for (i = 0; i < NUM_CGROUPS; i++)
 47		close(cg_fd[i]);
 48}
 49
 50static void read_from_cgroup_iter(struct bpf_program *prog, int cgroup_fd,
 51				  int order, const char *testname)
 52{
 53	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
 54	union bpf_iter_link_info linfo;
 55	struct bpf_link *link;
 56	int len, iter_fd;
 57	static char buf[128];
 58	size_t left;
 59	char *p;
 60
 61	memset(&linfo, 0, sizeof(linfo));
 62	linfo.cgroup.cgroup_fd = cgroup_fd;
 63	linfo.cgroup.order = order;
 64	opts.link_info = &linfo;
 65	opts.link_info_len = sizeof(linfo);
 66
 67	link = bpf_program__attach_iter(prog, &opts);
 68	if (!ASSERT_OK_PTR(link, "attach_iter"))
 69		return;
 70
 71	iter_fd = bpf_iter_create(bpf_link__fd(link));
 72	if (iter_fd < 0)
 73		goto free_link;
 74
 75	memset(buf, 0, sizeof(buf));
 76	left = ARRAY_SIZE(buf);
 77	p = buf;
 78	while ((len = read(iter_fd, p, left)) > 0) {
 79		p += len;
 80		left -= len;
 81	}
 82
 83	ASSERT_STREQ(buf, expected_output, testname);
 84
 85	/* read() after iter finishes should be ok. */
 86	if (len == 0)
 87		ASSERT_OK(read(iter_fd, buf, sizeof(buf)), "second_read");
 88
 89	close(iter_fd);
 90free_link:
 91	bpf_link__destroy(link);
 92}
 93
 94/* Invalid cgroup. */
 95static void test_invalid_cgroup(struct cgroup_iter *skel)
 96{
 97	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
 98	union bpf_iter_link_info linfo;
 99	struct bpf_link *link;
100
101	memset(&linfo, 0, sizeof(linfo));
102	linfo.cgroup.cgroup_fd = (__u32)-1;
103	opts.link_info = &linfo;
104	opts.link_info_len = sizeof(linfo);
105
106	link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
107	ASSERT_ERR_PTR(link, "attach_iter");
108	bpf_link__destroy(link);
109}
110
111/* Specifying both cgroup_fd and cgroup_id is invalid. */
112static void test_invalid_cgroup_spec(struct cgroup_iter *skel)
113{
114	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
115	union bpf_iter_link_info linfo;
116	struct bpf_link *link;
117
118	memset(&linfo, 0, sizeof(linfo));
119	linfo.cgroup.cgroup_fd = (__u32)cg_fd[PARENT];
120	linfo.cgroup.cgroup_id = (__u64)cg_id[PARENT];
121	opts.link_info = &linfo;
122	opts.link_info_len = sizeof(linfo);
123
124	link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
125	ASSERT_ERR_PTR(link, "attach_iter");
126	bpf_link__destroy(link);
127}
128
129/* Preorder walk prints parent and child in order. */
130static void test_walk_preorder(struct cgroup_iter *skel)
131{
132	snprintf(expected_output, sizeof(expected_output),
133		 PROLOGUE "%8llu\n%8llu\n%8llu\n" EPILOGUE,
134		 cg_id[PARENT], cg_id[CHILD1], cg_id[CHILD2]);
135
136	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
137			      BPF_CGROUP_ITER_DESCENDANTS_PRE, "preorder");
138}
139
140/* Postorder walk prints child and parent in order. */
141static void test_walk_postorder(struct cgroup_iter *skel)
142{
143	snprintf(expected_output, sizeof(expected_output),
144		 PROLOGUE "%8llu\n%8llu\n%8llu\n" EPILOGUE,
145		 cg_id[CHILD1], cg_id[CHILD2], cg_id[PARENT]);
146
147	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
148			      BPF_CGROUP_ITER_DESCENDANTS_POST, "postorder");
149}
150
151/* Walking parents prints parent and then root. */
152static void test_walk_ancestors_up(struct cgroup_iter *skel)
153{
154	/* terminate the walk when ROOT is met. */
155	skel->bss->terminal_cgroup = cg_id[ROOT];
156
157	snprintf(expected_output, sizeof(expected_output),
158		 PROLOGUE "%8llu\n%8llu\n" EPILOGUE,
159		 cg_id[PARENT], cg_id[ROOT]);
160
161	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
162			      BPF_CGROUP_ITER_ANCESTORS_UP, "ancestors_up");
163
164	skel->bss->terminal_cgroup = 0;
165}
166
167/* Early termination prints parent only. */
168static void test_early_termination(struct cgroup_iter *skel)
169{
170	/* terminate the walk after the first element is processed. */
171	skel->bss->terminate_early = 1;
172
173	snprintf(expected_output, sizeof(expected_output),
174		 PROLOGUE "%8llu\n" EPILOGUE, cg_id[PARENT]);
175
176	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
177			      BPF_CGROUP_ITER_DESCENDANTS_PRE, "early_termination");
178
179	skel->bss->terminate_early = 0;
180}
181
182/* Waling self prints self only. */
183static void test_walk_self_only(struct cgroup_iter *skel)
184{
185	snprintf(expected_output, sizeof(expected_output),
186		 PROLOGUE "%8llu\n" EPILOGUE, cg_id[PARENT]);
187
188	read_from_cgroup_iter(skel->progs.cgroup_id_printer, cg_fd[PARENT],
189			      BPF_CGROUP_ITER_SELF_ONLY, "self_only");
190}
191
192static void test_walk_dead_self_only(struct cgroup_iter *skel)
193{
194	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
195	char expected_output[128], buf[128];
196	const char *cgrp_name = "/dead";
197	union bpf_iter_link_info linfo;
198	int len, cgrp_fd, iter_fd;
199	struct bpf_link *link;
200	size_t left;
201	char *p;
202
203	cgrp_fd = create_and_get_cgroup(cgrp_name);
204	if (!ASSERT_GE(cgrp_fd, 0, "create cgrp"))
205		return;
206
207	/* The cgroup will be dead during read() iteration, so it only has
208	 * epilogue in the output
209	 */
210	snprintf(expected_output, sizeof(expected_output), EPILOGUE);
211
212	memset(&linfo, 0, sizeof(linfo));
213	linfo.cgroup.cgroup_fd = cgrp_fd;
214	linfo.cgroup.order = BPF_CGROUP_ITER_SELF_ONLY;
215	opts.link_info = &linfo;
216	opts.link_info_len = sizeof(linfo);
217
218	link = bpf_program__attach_iter(skel->progs.cgroup_id_printer, &opts);
219	if (!ASSERT_OK_PTR(link, "attach_iter"))
220		goto close_cgrp;
221
222	iter_fd = bpf_iter_create(bpf_link__fd(link));
223	if (!ASSERT_GE(iter_fd, 0, "iter_create"))
224		goto free_link;
225
226	/* Close link fd and cgroup fd */
227	bpf_link__destroy(link);
228	close(cgrp_fd);
229
230	/* Remove cgroup to mark it as dead */
231	remove_cgroup(cgrp_name);
232
233	/* Two kern_sync_rcu() and usleep() pairs are used to wait for the
234	 * releases of cgroup css, and the last kern_sync_rcu() and usleep()
235	 * pair is used to wait for the free of cgroup itself.
236	 */
237	kern_sync_rcu();
238	usleep(8000);
239	kern_sync_rcu();
240	usleep(8000);
241	kern_sync_rcu();
242	usleep(1000);
243
244	memset(buf, 0, sizeof(buf));
245	left = ARRAY_SIZE(buf);
246	p = buf;
247	while ((len = read(iter_fd, p, left)) > 0) {
248		p += len;
249		left -= len;
250	}
251
252	ASSERT_STREQ(buf, expected_output, "dead cgroup output");
253
254	/* read() after iter finishes should be ok. */
255	if (len == 0)
256		ASSERT_OK(read(iter_fd, buf, sizeof(buf)), "second_read");
257
258	close(iter_fd);
259	return;
260free_link:
261	bpf_link__destroy(link);
262close_cgrp:
263	close(cgrp_fd);
264}
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266void test_cgroup_iter(void)
267{
268	struct cgroup_iter *skel = NULL;
269
270	if (setup_cgroup_environment())
271		return;
272
273	if (setup_cgroups())
274		goto out;
275
276	skel = cgroup_iter__open_and_load();
277	if (!ASSERT_OK_PTR(skel, "cgroup_iter__open_and_load"))
278		goto out;
279
280	if (test__start_subtest("cgroup_iter__invalid_cgroup"))
281		test_invalid_cgroup(skel);
282	if (test__start_subtest("cgroup_iter__invalid_cgroup_spec"))
283		test_invalid_cgroup_spec(skel);
284	if (test__start_subtest("cgroup_iter__preorder"))
285		test_walk_preorder(skel);
286	if (test__start_subtest("cgroup_iter__postorder"))
287		test_walk_postorder(skel);
288	if (test__start_subtest("cgroup_iter__ancestors_up_walk"))
289		test_walk_ancestors_up(skel);
290	if (test__start_subtest("cgroup_iter__early_termination"))
291		test_early_termination(skel);
292	if (test__start_subtest("cgroup_iter__self_only"))
293		test_walk_self_only(skel);
294	if (test__start_subtest("cgroup_iter__dead_self_only"))
295		test_walk_dead_self_only(skel);
 
 
 
296out:
297	cgroup_iter__destroy(skel);
298	cleanup_cgroups();
299	cleanup_cgroup_environment();
300}