brintos

brintos / linux-shallow public Read only

0
0
Text · 8.6 KiB · 574d9a0 Raw
334 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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           012#define PARENT         113#define CHILD1         214#define CHILD2         315#define NUM_CGROUPS    416 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 has209	 * epilogue in the output210	 */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 the235	 * 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}334