Commit d5506591 authored by Roman Gushchin's avatar Roman Gushchin Committed by Alexei Starovoitov
Browse files

selftests/bpf: add auto-detach test



Add a kselftest to cover bpf auto-detachment functionality.
The test creates a cgroup, associates some resources with it,
attaches a couple of bpf programs and deletes the cgroup.

Then it checks that bpf programs are going away in 5 seconds.

Expected output:
  $ ./test_cgroup_attach
  #override:PASS
  #multi:PASS
  #autodetach:PASS
  test_cgroup_attach:PASS

On a kernel without auto-detaching:
  $ ./test_cgroup_attach
  #override:PASS
  #multi:PASS
  #autodetach:FAIL
  test_cgroup_attach:FAIL

Signed-off-by: default avatarRoman Gushchin <guro@fb.com>
Acked-by: default avatarYonghong Song <yhs@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 596092ef
Loading
Loading
Loading
Loading
+97 −1
Original line number Diff line number Diff line
@@ -456,9 +456,105 @@ out:
	return rc;
}

static int test_autodetach(void)
{
	__u32 prog_cnt = 4, attach_flags;
	int allow_prog[2] = {0};
	__u32 prog_ids[2] = {0};
	int cg = 0, i, rc = -1;
	void *ptr = NULL;
	int attempts;

	for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
		allow_prog[i] = prog_load_cnt(1, 1 << i);
		if (!allow_prog[i])
			goto err;
	}

	if (setup_cgroup_environment())
		goto err;

	/* create a cgroup, attach two programs and remember their ids */
	cg = create_and_get_cgroup("/cg_autodetach");
	if (cg < 0)
		goto err;

	if (join_cgroup("/cg_autodetach"))
		goto err;

	for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
		if (bpf_prog_attach(allow_prog[i], cg, BPF_CGROUP_INET_EGRESS,
				    BPF_F_ALLOW_MULTI)) {
			log_err("Attaching prog[%d] to cg:egress", i);
			goto err;
		}
	}

	/* make sure that programs are attached and run some traffic */
	assert(bpf_prog_query(cg, BPF_CGROUP_INET_EGRESS, 0, &attach_flags,
			      prog_ids, &prog_cnt) == 0);
	assert(system(PING_CMD) == 0);

	/* allocate some memory (4Mb) to pin the original cgroup */
	ptr = malloc(4 * (1 << 20));
	if (!ptr)
		goto err;

	/* close programs and cgroup fd */
	for (i = 0; i < ARRAY_SIZE(allow_prog); i++) {
		close(allow_prog[i]);
		allow_prog[i] = 0;
	}

	close(cg);
	cg = 0;

	/* leave the cgroup and remove it. don't detach programs */
	cleanup_cgroup_environment();

	/* wait for the asynchronous auto-detachment.
	 * wait for no more than 5 sec and give up.
	 */
	for (i = 0; i < ARRAY_SIZE(prog_ids); i++) {
		for (attempts = 5; attempts >= 0; attempts--) {
			int fd = bpf_prog_get_fd_by_id(prog_ids[i]);

			if (fd < 0)
				break;

			/* don't leave the fd open */
			close(fd);

			if (!attempts)
				goto err;

			sleep(1);
		}
	}

	rc = 0;
err:
	for (i = 0; i < ARRAY_SIZE(allow_prog); i++)
		if (allow_prog[i] > 0)
			close(allow_prog[i]);
	if (cg)
		close(cg);
	free(ptr);
	cleanup_cgroup_environment();
	if (!rc)
		printf("#autodetach:PASS\n");
	else
		printf("#autodetach:FAIL\n");
	return rc;
}

int main(void)
{
	int (*tests[])(void) = {test_foo_bar, test_multiprog};
	int (*tests[])(void) = {
		test_foo_bar,
		test_multiprog,
		test_autodetach,
	};
	int errors = 0;
	int i;