All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yonghong Song <yhs@fb.com>
To: Kui-Feng Lee <kuifeng@fb.com>,
	bpf@vger.kernel.org, ast@kernel.org, daniel@iogearbox.net,
	andrii@kernel.org, kernel-team@fb.com
Subject: Re: [PATCH bpf-next v5 3/3] selftests/bpf: Test parameterized task BPF iterators.
Date: Sat, 13 Aug 2022 15:50:29 -0700	[thread overview]
Message-ID: <c5d5bfbc-3b25-dad2-450d-405f4b28272d@fb.com> (raw)
In-Reply-To: <20220811001654.1316689-4-kuifeng@fb.com>



On 8/10/22 5:16 PM, Kui-Feng Lee wrote:
> Test iterators of vma, files, and tasks of tasks.
> 
> Ensure the API works appropriately to visit all tasks,
> tasks in a process, or a particular task.
> 
> Signed-off-by: Kui-Feng Lee <kuifeng@fb.com>
> ---
>   .../selftests/bpf/prog_tests/bpf_iter.c       | 204 ++++++++++++++++--
>   .../selftests/bpf/prog_tests/btf_dump.c       |   2 +-
>   .../selftests/bpf/progs/bpf_iter_task.c       |   9 +
>   .../selftests/bpf/progs/bpf_iter_task_file.c  |   7 +
>   .../selftests/bpf/progs/bpf_iter_task_vma.c   |   6 +-
>   5 files changed, 203 insertions(+), 25 deletions(-)
> 
> diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> index a33874b081b6..e66f1f3db562 100644
> --- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> +++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
> @@ -1,6 +1,9 @@
>   // SPDX-License-Identifier: GPL-2.0
>   /* Copyright (c) 2020 Facebook */
>   #include <test_progs.h>
> +#include <sys/syscall.h>
> +#include <unistd.h>
> +#include <signal.h>

do we need unistd.h and signal.h?

>   #include "bpf_iter_ipv6_route.skel.h"
>   #include "bpf_iter_netlink.skel.h"
>   #include "bpf_iter_bpf_map.skel.h"
> @@ -42,13 +45,13 @@ static void test_btf_id_or_null(void)
>   	}
>   }
>   
> -static void do_dummy_read(struct bpf_program *prog)
> +static void do_dummy_read(struct bpf_program *prog, struct bpf_iter_attach_opts *opts)
>   {
>   	struct bpf_link *link;
>   	char buf[16] = {};
>   	int iter_fd, len;
>   
> -	link = bpf_program__attach_iter(prog, NULL);
> +	link = bpf_program__attach_iter(prog, opts);
>   	if (!ASSERT_OK_PTR(link, "attach_iter"))
>   		return;
>   
> @@ -91,7 +94,7 @@ static void test_ipv6_route(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_ipv6_route__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_ipv6_route);
> +	do_dummy_read(skel->progs.dump_ipv6_route, NULL);
>   
>   	bpf_iter_ipv6_route__destroy(skel);
>   }
> @@ -104,7 +107,7 @@ static void test_netlink(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_netlink__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_netlink);
> +	do_dummy_read(skel->progs.dump_netlink, NULL);
>   
>   	bpf_iter_netlink__destroy(skel);
>   }
> @@ -117,24 +120,139 @@ static void test_bpf_map(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_map__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_bpf_map);
> +	do_dummy_read(skel->progs.dump_bpf_map, NULL);
>   
>   	bpf_iter_bpf_map__destroy(skel);
>   }
>   
> -static void test_task(void)
> +static int pidfd_open(pid_t pid, unsigned int flags)
> +{
> +	return syscall(SYS_pidfd_open, pid, flags);
> +}
> +
> +static void check_bpf_link_info(const struct bpf_program *prog)
> +{
> +	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
> +	union bpf_iter_link_info linfo;
> +	struct bpf_link_info info = {};
> +	__u32 info_len;
> +	struct bpf_link *link;
> +	int err;

Reverse christmas tree style?

> +
> +	memset(&linfo, 0, sizeof(linfo));
> +	linfo.task.tid = getpid();
> +	opts.link_info = &linfo;
> +	opts.link_info_len = sizeof(linfo);
> +
> +	link = bpf_program__attach_iter(prog, &opts);
> +	if (!ASSERT_OK_PTR(link, "attach_iter"))
> +		return;
> +
> +	info_len = sizeof(info);
> +	err = bpf_obj_get_info_by_fd(bpf_link__fd(link), &info, &info_len);
> +	if (ASSERT_OK(err, "bpf_obj_get_info_by_fd"))
> +		ASSERT_EQ(info.iter.task.tid, getpid(), "check_task_tid");
> +
> +	bpf_link__destroy(link);
> +}
> +
> +static pthread_mutex_t do_nothing_mutex;
> +
> +static void *do_nothing_wait(void *arg)
> +{
> +	pthread_mutex_lock(&do_nothing_mutex);
> +	pthread_mutex_unlock(&do_nothing_mutex);
> +
> +	pthread_exit(arg);
> +}
> +
> +static void test_task_(struct bpf_iter_attach_opts *opts, int num_unknown, int num_known)

The function test_task_ name is weird. Maybe test_task_common?

>   {
>   	struct bpf_iter_task *skel;
> +	pthread_t thread_id;
> +	void *ret;
>   
>   	skel = bpf_iter_task__open_and_load();
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_task__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_task);
> +	if (!ASSERT_OK(pthread_mutex_init(&do_nothing_mutex, NULL), "pthread_mutex_init"))
> +		goto done;
> +	if (!ASSERT_OK(pthread_mutex_lock(&do_nothing_mutex), "pthread_mutex_lock"))
> +		goto done;
> +
> +	if (!ASSERT_OK(pthread_create(&thread_id, NULL, &do_nothing_wait, NULL),
> +		  "pthread_create"))
> +		goto done;
> +
> +
> +	skel->bss->tid = getpid();
> +
> +	do_dummy_read(skel->progs.dump_task, opts);
> +
> +	if (!ASSERT_OK(pthread_mutex_unlock(&do_nothing_mutex), "pthread_mutex_unlock"))
> +		goto done;
> +
> +	if (num_unknown >= 0)
> +		ASSERT_EQ(skel->bss->num_unknown_tid, num_unknown, "check_num_unknown_tid");
> +	if (num_known >= 0)
> +		ASSERT_EQ(skel->bss->num_known_tid, num_known, "check_num_known_tid");
>   
> +	ASSERT_FALSE(pthread_join(thread_id, &ret) || ret != NULL,
> +		     "pthread_join");
> +
> +done:
>   	bpf_iter_task__destroy(skel);
>   }
>   
> +static void test_task(void)
> +{
> +	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
> +	union bpf_iter_link_info linfo;
> +
> +	memset(&linfo, 0, sizeof(linfo));
> +	linfo.task.tid = getpid();
> +	opts.link_info = &linfo;
> +	opts.link_info_len = sizeof(linfo);
> +
> +	test_task_(&opts, 0, 1);
> +
> +	test_task_(NULL, -1, 1);
> +}
> +
> +static void test_task_tgid(void)
> +{
> +	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
> +	union bpf_iter_link_info linfo;
> +
> +	memset(&linfo, 0, sizeof(linfo));
> +	linfo.task.tgid = getpid();
> +	opts.link_info = &linfo;
> +	opts.link_info_len = sizeof(linfo);
> +
> +	test_task_(&opts, 1, 1);
> +}
> +
> +static void test_task_pidfd(void)
> +{
> +	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
> +	union bpf_iter_link_info linfo;
> +	int pidfd;
> +
> +	pidfd = pidfd_open(getpid(), 0);
> +	if (!ASSERT_GE(pidfd, 0, "pidfd_open"))
> +		return;
> +
> +	memset(&linfo, 0, sizeof(linfo));
> +	linfo.task.pid_fd = pidfd;

In kernel, pidfd has to be > 0 to be effective.
So in the above, you should use ASSERT_GT instead of
ASSERT_GE. For test_progs, pidfd == 0 won't happen
since the program does not close stdin.

> +	opts.link_info = &linfo;
> +	opts.link_info_len = sizeof(linfo);
> +
> +	test_task_(&opts, 1, 1);
> +
> +	close(pidfd);
> +}
> +
>   static void test_task_sleepable(void)
>   {
>   	struct bpf_iter_task *skel;
> @@ -143,7 +261,7 @@ static void test_task_sleepable(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_task__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_task_sleepable);
> +	do_dummy_read(skel->progs.dump_task_sleepable, NULL);
>   
>   	ASSERT_GT(skel->bss->num_expected_failure_copy_from_user_task, 0,
>   		  "num_expected_failure_copy_from_user_task");
> @@ -161,8 +279,8 @@ static void test_task_stack(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_task_stack__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_task_stack);
> -	do_dummy_read(skel->progs.get_task_user_stacks);
> +	do_dummy_read(skel->progs.dump_task_stack, NULL);
> +	do_dummy_read(skel->progs.get_task_user_stacks, NULL);
>   
>   	bpf_iter_task_stack__destroy(skel);
>   }
> @@ -174,7 +292,9 @@ static void *do_nothing(void *arg)
>   
>   static void test_task_file(void)
>   {
> +	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
>   	struct bpf_iter_task_file *skel;
> +	union bpf_iter_link_info linfo;
>   	pthread_t thread_id;
>   	void *ret;
>   
> @@ -188,15 +308,31 @@ static void test_task_file(void)
>   		  "pthread_create"))
>   		goto done;
>   
> -	do_dummy_read(skel->progs.dump_task_file);
> +	memset(&linfo, 0, sizeof(linfo));
> +	linfo.task.tid = getpid();
> +	opts.link_info = &linfo;
> +	opts.link_info_len = sizeof(linfo);
> +
> +	do_dummy_read(skel->progs.dump_task_file, &opts);
>   
>   	if (!ASSERT_FALSE(pthread_join(thread_id, &ret) || ret != NULL,
>   		  "pthread_join"))
>   		goto done;
>   
>   	ASSERT_EQ(skel->bss->count, 0, "check_count");
> +	ASSERT_EQ(skel->bss->unique_tgid_count, 1, "check_unique_tgid_count");
>   
> -done:
> +	skel->bss->count = 0;
> +	skel->bss->unique_tgid_count = 0;
> +
> +	do_dummy_read(skel->progs.dump_task_file, NULL);
> +
> +	ASSERT_GE(skel->bss->count, 0, "check_count");
> +	ASSERT_GE(skel->bss->unique_tgid_count, 1, "check_unique_tgid_count");

This is not precise. ASSERT_EQ will be better, right?
Maybe reset last_tgid as well?

> +
> +	check_bpf_link_info(skel->progs.dump_task_file);
> +
> + done:
>   	bpf_iter_task_file__destroy(skel);
>   }
>   
> @@ -274,7 +410,7 @@ static void test_tcp4(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_tcp4__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_tcp4);
> +	do_dummy_read(skel->progs.dump_tcp4, NULL);
>   
>   	bpf_iter_tcp4__destroy(skel);
>   }
> @@ -287,7 +423,7 @@ static void test_tcp6(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_tcp6__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_tcp6);
> +	do_dummy_read(skel->progs.dump_tcp6, NULL);
>   
>   	bpf_iter_tcp6__destroy(skel);
>   }
> @@ -300,7 +436,7 @@ static void test_udp4(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_udp4__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_udp4);
> +	do_dummy_read(skel->progs.dump_udp4, NULL);
>   
>   	bpf_iter_udp4__destroy(skel);
>   }
> @@ -313,7 +449,7 @@ static void test_udp6(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_udp6__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_udp6);
> +	do_dummy_read(skel->progs.dump_udp6, NULL);
>   
>   	bpf_iter_udp6__destroy(skel);
>   }
> @@ -326,7 +462,7 @@ static void test_unix(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_unix__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_unix);
> +	do_dummy_read(skel->progs.dump_unix, NULL);
>   
>   	bpf_iter_unix__destroy(skel);
>   }
> @@ -988,7 +1124,7 @@ static void test_bpf_sk_storage_get(void)
>   	if (!ASSERT_OK(err, "bpf_map_update_elem"))
>   		goto close_socket;
>   
> -	do_dummy_read(skel->progs.fill_socket_owner);
> +	do_dummy_read(skel->progs.fill_socket_owner, NULL);
>   
>   	err = bpf_map_lookup_elem(map_fd, &sock_fd, &val);
>   	if (CHECK(err || val != getpid(), "bpf_map_lookup_elem",
> @@ -996,7 +1132,7 @@ static void test_bpf_sk_storage_get(void)
>   	    getpid(), val, err))
>   		goto close_socket;
>   
> -	do_dummy_read(skel->progs.negate_socket_local_storage);
> +	do_dummy_read(skel->progs.negate_socket_local_storage, NULL);
>   
>   	err = bpf_map_lookup_elem(map_fd, &sock_fd, &val);
>   	CHECK(err || val != -getpid(), "bpf_map_lookup_elem",
> @@ -1116,7 +1252,7 @@ static void test_link_iter(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_bpf_link__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_bpf_link);
> +	do_dummy_read(skel->progs.dump_bpf_link, NULL);
>   
>   	bpf_iter_bpf_link__destroy(skel);
>   }
> @@ -1129,7 +1265,7 @@ static void test_ksym_iter(void)
>   	if (!ASSERT_OK_PTR(skel, "bpf_iter_ksym__open_and_load"))
>   		return;
>   
> -	do_dummy_read(skel->progs.dump_ksym);
> +	do_dummy_read(skel->progs.dump_ksym, NULL);
>   
>   	bpf_iter_ksym__destroy(skel);
>   }
> @@ -1154,7 +1290,7 @@ static void str_strip_first_line(char *str)
>   	*dst = '\0';
>   }
>   
> -static void test_task_vma(void)
> +static void test_task_vma_(struct bpf_iter_attach_opts *opts)

test_task_vma_common?

>   {
>   	int err, iter_fd = -1, proc_maps_fd = -1;
>   	struct bpf_iter_task_vma *skel;
> @@ -1166,13 +1302,14 @@ static void test_task_vma(void)
>   		return;
>   
>   	skel->bss->pid = getpid();
> +	skel->bss->one_task = opts ? 1 : 0;
>   
>   	err = bpf_iter_task_vma__load(skel);
>   	if (!ASSERT_OK(err, "bpf_iter_task_vma__load"))
>   		goto out;
>   
>   	skel->links.proc_maps = bpf_program__attach_iter(
> -		skel->progs.proc_maps, NULL);
> +		skel->progs.proc_maps, opts);
>   
>   	if (!ASSERT_OK_PTR(skel->links.proc_maps, "bpf_program__attach_iter")) {
>   		skel->links.proc_maps = NULL;
> @@ -1211,12 +1348,29 @@ static void test_task_vma(void)
>   	str_strip_first_line(proc_maps_output);
>   
>   	ASSERT_STREQ(task_vma_output, proc_maps_output, "compare_output");
> +
> +	check_bpf_link_info(skel->progs.proc_maps);
> +
>   out:
>   	close(proc_maps_fd);
>   	close(iter_fd);
>   	bpf_iter_task_vma__destroy(skel);
>   }
>   
> +static void test_task_vma(void)
> +{
> +	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
> +	union bpf_iter_link_info linfo;
> +
> +	memset(&linfo, 0, sizeof(linfo));
> +	linfo.task.tid = getpid();
> +	opts.link_info = &linfo;
> +	opts.link_info_len = sizeof(linfo);
> +
> +	test_task_vma_(&opts);
> +	test_task_vma_(NULL);
> +}
> +
[...]
> diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c b/tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c
> index 4ea6a37d1345..44f4a31c2ddd 100644
> --- a/tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c
> +++ b/tools/testing/selftests/bpf/progs/bpf_iter_task_vma.c
> @@ -20,6 +20,7 @@ char _license[] SEC("license") = "GPL";
>   #define D_PATH_BUF_SIZE 1024
>   char d_path_buf[D_PATH_BUF_SIZE] = {};
>   __u32 pid = 0;
> +__u32 one_task = 0;
>   
>   SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx)
>   {
> @@ -33,8 +34,11 @@ SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx)
>   		return 0;
>   
>   	file = vma->vm_file;
> -	if (task->tgid != pid)
> +	if (task->tgid != pid) {
> +		if (one_task)
> +			BPF_SEQ_PRINTF(seq, "unexpected task (%d != %d)", task->tgid, pid);

This doesn't sound good. Is it possible we add a global variable to 
indicate this condition and do an ASSERT in bpf_iter.c file?

>   		return 0;
> +	}
>   	perm_str[0] = (vma->vm_flags & VM_READ) ? 'r' : '-';
>   	perm_str[1] = (vma->vm_flags & VM_WRITE) ? 'w' : '-';
>   	perm_str[2] = (vma->vm_flags & VM_EXEC) ? 'x' : '-';

  reply	other threads:[~2022-08-13 22:50 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-11  0:16 [PATCH bpf-next v5 0/3] Parameterize task iterators Kui-Feng Lee
2022-08-11  0:16 ` [PATCH bpf-next v5 1/3] bpf: " Kui-Feng Lee
2022-08-13 22:17   ` Yonghong Song
2022-08-15  1:01     ` Alexei Starovoitov
2022-08-16  4:42     ` Andrii Nakryiko
2022-08-18  3:40       ` Yonghong Song
2022-08-16  5:25     ` Andrii Nakryiko
2022-08-18  4:31       ` Yonghong Song
2022-08-25 17:50         ` Andrii Nakryiko
2022-08-16 17:00     ` Kui-Feng Lee
2022-08-14 20:24   ` Jiri Olsa
2022-08-16 17:21     ` Kui-Feng Lee
2022-08-15 23:08   ` Hao Luo
2022-08-16 19:11     ` Kui-Feng Lee
2022-08-16  5:02   ` Andrii Nakryiko
2022-08-16 18:45     ` Kui-Feng Lee
2022-08-11  0:16 ` [PATCH bpf-next v5 2/3] bpf: Handle bpf_link_info for the parameterized task BPF iterators Kui-Feng Lee
2022-08-13 22:23   ` Yonghong Song
2022-08-11  0:16 ` [PATCH bpf-next v5 3/3] selftests/bpf: Test " Kui-Feng Lee
2022-08-13 22:50   ` Yonghong Song [this message]
2022-08-18 17:24     ` Kui-Feng Lee
2022-08-16  5:15   ` Andrii Nakryiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c5d5bfbc-3b25-dad2-450d-405f4b28272d@fb.com \
    --to=yhs@fb.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=kernel-team@fb.com \
    --cc=kuifeng@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.