selftests/bpf: Test parameterized task BPF iterators.
Test iterators of vma, files and 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> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Yonghong Song <yhs@fb.com> Acked-by: Martin KaFai Lau <martin.lau@kernel.org> Link: https://lore.kernel.org/bpf/20220926184957.208194-5-kuifeng@fb.com
This commit is contained in:
parent
2c4fe44fb0
commit
b3e1331eb9
@ -1,6 +1,8 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/* Copyright (c) 2020 Facebook */
|
/* Copyright (c) 2020 Facebook */
|
||||||
#include <test_progs.h>
|
#include <test_progs.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
#include "bpf_iter_ipv6_route.skel.h"
|
#include "bpf_iter_ipv6_route.skel.h"
|
||||||
#include "bpf_iter_netlink.skel.h"
|
#include "bpf_iter_netlink.skel.h"
|
||||||
#include "bpf_iter_bpf_map.skel.h"
|
#include "bpf_iter_bpf_map.skel.h"
|
||||||
@ -14,6 +16,7 @@
|
|||||||
#include "bpf_iter_udp4.skel.h"
|
#include "bpf_iter_udp4.skel.h"
|
||||||
#include "bpf_iter_udp6.skel.h"
|
#include "bpf_iter_udp6.skel.h"
|
||||||
#include "bpf_iter_unix.skel.h"
|
#include "bpf_iter_unix.skel.h"
|
||||||
|
#include "bpf_iter_vma_offset.skel.h"
|
||||||
#include "bpf_iter_test_kern1.skel.h"
|
#include "bpf_iter_test_kern1.skel.h"
|
||||||
#include "bpf_iter_test_kern2.skel.h"
|
#include "bpf_iter_test_kern2.skel.h"
|
||||||
#include "bpf_iter_test_kern3.skel.h"
|
#include "bpf_iter_test_kern3.skel.h"
|
||||||
@ -43,13 +46,13 @@ static void test_btf_id_or_null(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_dummy_read(struct bpf_program *prog)
|
static void do_dummy_read_opts(struct bpf_program *prog, struct bpf_iter_attach_opts *opts)
|
||||||
{
|
{
|
||||||
struct bpf_link *link;
|
struct bpf_link *link;
|
||||||
char buf[16] = {};
|
char buf[16] = {};
|
||||||
int iter_fd, len;
|
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"))
|
if (!ASSERT_OK_PTR(link, "attach_iter"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -68,6 +71,11 @@ free_link:
|
|||||||
bpf_link__destroy(link);
|
bpf_link__destroy(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_dummy_read(struct bpf_program *prog)
|
||||||
|
{
|
||||||
|
do_dummy_read_opts(prog, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void do_read_map_iter_fd(struct bpf_object_skeleton **skel, struct bpf_program *prog,
|
static void do_read_map_iter_fd(struct bpf_object_skeleton **skel, struct bpf_program *prog,
|
||||||
struct bpf_map *map)
|
struct bpf_map *map)
|
||||||
{
|
{
|
||||||
@ -167,19 +175,140 @@ static void test_bpf_map(void)
|
|||||||
bpf_iter_bpf_map__destroy(skel);
|
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)
|
||||||
|
{
|
||||||
|
LIBBPF_OPTS(bpf_iter_attach_opts, opts);
|
||||||
|
union bpf_iter_link_info linfo;
|
||||||
|
struct bpf_link_info info = {};
|
||||||
|
struct bpf_link *link;
|
||||||
|
__u32 info_len;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
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);
|
||||||
|
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_common_nocheck(struct bpf_iter_attach_opts *opts,
|
||||||
|
int *num_unknown, int *num_known)
|
||||||
{
|
{
|
||||||
struct bpf_iter_task *skel;
|
struct bpf_iter_task *skel;
|
||||||
|
pthread_t thread_id;
|
||||||
|
void *ret;
|
||||||
|
|
||||||
skel = bpf_iter_task__open_and_load();
|
skel = bpf_iter_task__open_and_load();
|
||||||
if (!ASSERT_OK_PTR(skel, "bpf_iter_task__open_and_load"))
|
if (!ASSERT_OK_PTR(skel, "bpf_iter_task__open_and_load"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do_dummy_read(skel->progs.dump_task);
|
ASSERT_OK(pthread_mutex_lock(&do_nothing_mutex), "pthread_mutex_lock");
|
||||||
|
|
||||||
|
ASSERT_OK(pthread_create(&thread_id, NULL, &do_nothing_wait, NULL),
|
||||||
|
"pthread_create");
|
||||||
|
|
||||||
|
skel->bss->tid = getpid();
|
||||||
|
|
||||||
|
do_dummy_read_opts(skel->progs.dump_task, opts);
|
||||||
|
|
||||||
|
*num_unknown = skel->bss->num_unknown_tid;
|
||||||
|
*num_known = skel->bss->num_known_tid;
|
||||||
|
|
||||||
|
ASSERT_OK(pthread_mutex_unlock(&do_nothing_mutex), "pthread_mutex_unlock");
|
||||||
|
ASSERT_FALSE(pthread_join(thread_id, &ret) || ret != NULL,
|
||||||
|
"pthread_join");
|
||||||
|
|
||||||
bpf_iter_task__destroy(skel);
|
bpf_iter_task__destroy(skel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_task_common(struct bpf_iter_attach_opts *opts, int num_unknown, int num_known)
|
||||||
|
{
|
||||||
|
int num_unknown_tid, num_known_tid;
|
||||||
|
|
||||||
|
test_task_common_nocheck(opts, &num_unknown_tid, &num_known_tid);
|
||||||
|
ASSERT_EQ(num_unknown_tid, num_unknown, "check_num_unknown_tid");
|
||||||
|
ASSERT_EQ(num_known_tid, num_known, "check_num_known_tid");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_task_tid(void)
|
||||||
|
{
|
||||||
|
LIBBPF_OPTS(bpf_iter_attach_opts, opts);
|
||||||
|
union bpf_iter_link_info linfo;
|
||||||
|
int num_unknown_tid, num_known_tid;
|
||||||
|
|
||||||
|
memset(&linfo, 0, sizeof(linfo));
|
||||||
|
linfo.task.tid = getpid();
|
||||||
|
opts.link_info = &linfo;
|
||||||
|
opts.link_info_len = sizeof(linfo);
|
||||||
|
test_task_common(&opts, 0, 1);
|
||||||
|
|
||||||
|
linfo.task.tid = 0;
|
||||||
|
linfo.task.pid = getpid();
|
||||||
|
test_task_common(&opts, 1, 1);
|
||||||
|
|
||||||
|
test_task_common_nocheck(NULL, &num_unknown_tid, &num_known_tid);
|
||||||
|
ASSERT_GT(num_unknown_tid, 1, "check_num_unknown_tid");
|
||||||
|
ASSERT_EQ(num_known_tid, 1, "check_num_known_tid");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_task_pid(void)
|
||||||
|
{
|
||||||
|
LIBBPF_OPTS(bpf_iter_attach_opts, opts);
|
||||||
|
union bpf_iter_link_info linfo;
|
||||||
|
|
||||||
|
memset(&linfo, 0, sizeof(linfo));
|
||||||
|
linfo.task.pid = getpid();
|
||||||
|
opts.link_info = &linfo;
|
||||||
|
opts.link_info_len = sizeof(linfo);
|
||||||
|
|
||||||
|
test_task_common(&opts, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_task_pidfd(void)
|
||||||
|
{
|
||||||
|
LIBBPF_OPTS(bpf_iter_attach_opts, opts);
|
||||||
|
union bpf_iter_link_info linfo;
|
||||||
|
int pidfd;
|
||||||
|
|
||||||
|
pidfd = pidfd_open(getpid(), 0);
|
||||||
|
if (!ASSERT_GT(pidfd, 0, "pidfd_open"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset(&linfo, 0, sizeof(linfo));
|
||||||
|
linfo.task.pid_fd = pidfd;
|
||||||
|
opts.link_info = &linfo;
|
||||||
|
opts.link_info_len = sizeof(linfo);
|
||||||
|
|
||||||
|
test_task_common(&opts, 1, 1);
|
||||||
|
|
||||||
|
close(pidfd);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_task_sleepable(void)
|
static void test_task_sleepable(void)
|
||||||
{
|
{
|
||||||
struct bpf_iter_task *skel;
|
struct bpf_iter_task *skel;
|
||||||
@ -212,14 +341,11 @@ static void test_task_stack(void)
|
|||||||
bpf_iter_task_stack__destroy(skel);
|
bpf_iter_task_stack__destroy(skel);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *do_nothing(void *arg)
|
|
||||||
{
|
|
||||||
pthread_exit(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_task_file(void)
|
static void test_task_file(void)
|
||||||
{
|
{
|
||||||
|
LIBBPF_OPTS(bpf_iter_attach_opts, opts);
|
||||||
struct bpf_iter_task_file *skel;
|
struct bpf_iter_task_file *skel;
|
||||||
|
union bpf_iter_link_info linfo;
|
||||||
pthread_t thread_id;
|
pthread_t thread_id;
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
@ -229,19 +355,36 @@ static void test_task_file(void)
|
|||||||
|
|
||||||
skel->bss->tgid = getpid();
|
skel->bss->tgid = getpid();
|
||||||
|
|
||||||
if (!ASSERT_OK(pthread_create(&thread_id, NULL, &do_nothing, NULL),
|
ASSERT_OK(pthread_mutex_lock(&do_nothing_mutex), "pthread_mutex_lock");
|
||||||
"pthread_create"))
|
|
||||||
goto done;
|
ASSERT_OK(pthread_create(&thread_id, NULL, &do_nothing_wait, NULL),
|
||||||
|
"pthread_create");
|
||||||
|
|
||||||
|
memset(&linfo, 0, sizeof(linfo));
|
||||||
|
linfo.task.tid = getpid();
|
||||||
|
opts.link_info = &linfo;
|
||||||
|
opts.link_info_len = sizeof(linfo);
|
||||||
|
|
||||||
|
do_dummy_read_opts(skel->progs.dump_task_file, &opts);
|
||||||
|
|
||||||
|
ASSERT_EQ(skel->bss->count, 0, "check_count");
|
||||||
|
ASSERT_EQ(skel->bss->unique_tgid_count, 1, "check_unique_tgid_count");
|
||||||
|
|
||||||
|
skel->bss->last_tgid = 0;
|
||||||
|
skel->bss->count = 0;
|
||||||
|
skel->bss->unique_tgid_count = 0;
|
||||||
|
|
||||||
do_dummy_read(skel->progs.dump_task_file);
|
do_dummy_read(skel->progs.dump_task_file);
|
||||||
|
|
||||||
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->count, 0, "check_count");
|
||||||
|
ASSERT_GT(skel->bss->unique_tgid_count, 1, "check_unique_tgid_count");
|
||||||
|
|
||||||
|
check_bpf_link_info(skel->progs.dump_task_file);
|
||||||
|
|
||||||
|
ASSERT_OK(pthread_mutex_unlock(&do_nothing_mutex), "pthread_mutex_unlock");
|
||||||
|
ASSERT_OK(pthread_join(thread_id, &ret), "pthread_join");
|
||||||
|
ASSERT_NULL(ret, "pthread_join");
|
||||||
|
|
||||||
done:
|
|
||||||
bpf_iter_task_file__destroy(skel);
|
bpf_iter_task_file__destroy(skel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1249,7 +1392,7 @@ static void str_strip_first_line(char *str)
|
|||||||
*dst = '\0';
|
*dst = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_task_vma(void)
|
static void test_task_vma_common(struct bpf_iter_attach_opts *opts)
|
||||||
{
|
{
|
||||||
int err, iter_fd = -1, proc_maps_fd = -1;
|
int err, iter_fd = -1, proc_maps_fd = -1;
|
||||||
struct bpf_iter_task_vma *skel;
|
struct bpf_iter_task_vma *skel;
|
||||||
@ -1261,13 +1404,14 @@ static void test_task_vma(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
skel->bss->pid = getpid();
|
skel->bss->pid = getpid();
|
||||||
|
skel->bss->one_task = opts ? 1 : 0;
|
||||||
|
|
||||||
err = bpf_iter_task_vma__load(skel);
|
err = bpf_iter_task_vma__load(skel);
|
||||||
if (!ASSERT_OK(err, "bpf_iter_task_vma__load"))
|
if (!ASSERT_OK(err, "bpf_iter_task_vma__load"))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
skel->links.proc_maps = bpf_program__attach_iter(
|
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")) {
|
if (!ASSERT_OK_PTR(skel->links.proc_maps, "bpf_program__attach_iter")) {
|
||||||
skel->links.proc_maps = NULL;
|
skel->links.proc_maps = NULL;
|
||||||
@ -1291,6 +1435,8 @@ static void test_task_vma(void)
|
|||||||
goto out;
|
goto out;
|
||||||
len += err;
|
len += err;
|
||||||
}
|
}
|
||||||
|
if (opts)
|
||||||
|
ASSERT_EQ(skel->bss->one_task_error, 0, "unexpected task");
|
||||||
|
|
||||||
/* read CMP_BUFFER_SIZE (1kB) from /proc/pid/maps */
|
/* read CMP_BUFFER_SIZE (1kB) from /proc/pid/maps */
|
||||||
snprintf(maps_path, 64, "/proc/%u/maps", skel->bss->pid);
|
snprintf(maps_path, 64, "/proc/%u/maps", skel->bss->pid);
|
||||||
@ -1306,6 +1452,9 @@ static void test_task_vma(void)
|
|||||||
str_strip_first_line(proc_maps_output);
|
str_strip_first_line(proc_maps_output);
|
||||||
|
|
||||||
ASSERT_STREQ(task_vma_output, proc_maps_output, "compare_output");
|
ASSERT_STREQ(task_vma_output, proc_maps_output, "compare_output");
|
||||||
|
|
||||||
|
check_bpf_link_info(skel->progs.proc_maps);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
close(proc_maps_fd);
|
close(proc_maps_fd);
|
||||||
close(iter_fd);
|
close(iter_fd);
|
||||||
@ -1325,8 +1474,93 @@ void test_bpf_sockmap_map_iter_fd(void)
|
|||||||
bpf_iter_sockmap__destroy(skel);
|
bpf_iter_sockmap__destroy(skel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_task_vma(void)
|
||||||
|
{
|
||||||
|
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_common(&opts);
|
||||||
|
test_task_vma_common(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* uprobe attach point */
|
||||||
|
static noinline int trigger_func(int arg)
|
||||||
|
{
|
||||||
|
asm volatile ("");
|
||||||
|
return arg + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_task_vma_offset_common(struct bpf_iter_attach_opts *opts, bool one_proc)
|
||||||
|
{
|
||||||
|
struct bpf_iter_vma_offset *skel;
|
||||||
|
struct bpf_link *link;
|
||||||
|
char buf[16] = {};
|
||||||
|
int iter_fd, len;
|
||||||
|
int pgsz, shift;
|
||||||
|
|
||||||
|
skel = bpf_iter_vma_offset__open_and_load();
|
||||||
|
if (!ASSERT_OK_PTR(skel, "bpf_iter_vma_offset__open_and_load"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
skel->bss->pid = getpid();
|
||||||
|
skel->bss->address = (uintptr_t)trigger_func;
|
||||||
|
for (pgsz = getpagesize(), shift = 0; pgsz > 1; pgsz >>= 1, shift++)
|
||||||
|
;
|
||||||
|
skel->bss->page_shift = shift;
|
||||||
|
|
||||||
|
link = bpf_program__attach_iter(skel->progs.get_vma_offset, opts);
|
||||||
|
if (!ASSERT_OK_PTR(link, "attach_iter"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
iter_fd = bpf_iter_create(bpf_link__fd(link));
|
||||||
|
if (!ASSERT_GT(iter_fd, 0, "create_iter"))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
|
||||||
|
;
|
||||||
|
buf[15] = 0;
|
||||||
|
ASSERT_EQ(strcmp(buf, "OK\n"), 0, "strcmp");
|
||||||
|
|
||||||
|
ASSERT_EQ(skel->bss->offset, get_uprobe_offset(trigger_func), "offset");
|
||||||
|
if (one_proc)
|
||||||
|
ASSERT_EQ(skel->bss->unique_tgid_cnt, 1, "unique_tgid_count");
|
||||||
|
else
|
||||||
|
ASSERT_GT(skel->bss->unique_tgid_cnt, 1, "unique_tgid_count");
|
||||||
|
|
||||||
|
close(iter_fd);
|
||||||
|
|
||||||
|
exit:
|
||||||
|
bpf_link__destroy(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_task_vma_offset(void)
|
||||||
|
{
|
||||||
|
LIBBPF_OPTS(bpf_iter_attach_opts, opts);
|
||||||
|
union bpf_iter_link_info linfo;
|
||||||
|
|
||||||
|
memset(&linfo, 0, sizeof(linfo));
|
||||||
|
linfo.task.pid = getpid();
|
||||||
|
opts.link_info = &linfo;
|
||||||
|
opts.link_info_len = sizeof(linfo);
|
||||||
|
|
||||||
|
test_task_vma_offset_common(&opts, true);
|
||||||
|
|
||||||
|
linfo.task.pid = 0;
|
||||||
|
linfo.task.tid = getpid();
|
||||||
|
test_task_vma_offset_common(&opts, true);
|
||||||
|
|
||||||
|
test_task_vma_offset_common(NULL, false);
|
||||||
|
}
|
||||||
|
|
||||||
void test_bpf_iter(void)
|
void test_bpf_iter(void)
|
||||||
{
|
{
|
||||||
|
ASSERT_OK(pthread_mutex_init(&do_nothing_mutex, NULL), "pthread_mutex_init");
|
||||||
|
|
||||||
if (test__start_subtest("btf_id_or_null"))
|
if (test__start_subtest("btf_id_or_null"))
|
||||||
test_btf_id_or_null();
|
test_btf_id_or_null();
|
||||||
if (test__start_subtest("ipv6_route"))
|
if (test__start_subtest("ipv6_route"))
|
||||||
@ -1335,8 +1569,12 @@ void test_bpf_iter(void)
|
|||||||
test_netlink();
|
test_netlink();
|
||||||
if (test__start_subtest("bpf_map"))
|
if (test__start_subtest("bpf_map"))
|
||||||
test_bpf_map();
|
test_bpf_map();
|
||||||
if (test__start_subtest("task"))
|
if (test__start_subtest("task_tid"))
|
||||||
test_task();
|
test_task_tid();
|
||||||
|
if (test__start_subtest("task_pid"))
|
||||||
|
test_task_pid();
|
||||||
|
if (test__start_subtest("task_pidfd"))
|
||||||
|
test_task_pidfd();
|
||||||
if (test__start_subtest("task_sleepable"))
|
if (test__start_subtest("task_sleepable"))
|
||||||
test_task_sleepable();
|
test_task_sleepable();
|
||||||
if (test__start_subtest("task_stack"))
|
if (test__start_subtest("task_stack"))
|
||||||
@ -1397,4 +1635,6 @@ void test_bpf_iter(void)
|
|||||||
test_ksym_iter();
|
test_ksym_iter();
|
||||||
if (test__start_subtest("bpf_sockmap_map_iter_fd"))
|
if (test__start_subtest("bpf_sockmap_map_iter_fd"))
|
||||||
test_bpf_sockmap_map_iter_fd();
|
test_bpf_sockmap_map_iter_fd();
|
||||||
|
if (test__start_subtest("vma_offset"))
|
||||||
|
test_task_vma_offset();
|
||||||
}
|
}
|
||||||
|
@ -764,7 +764,7 @@ static void test_btf_dump_struct_data(struct btf *btf, struct btf_dump *d,
|
|||||||
|
|
||||||
/* union with nested struct */
|
/* union with nested struct */
|
||||||
TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT,
|
TEST_BTF_DUMP_DATA(btf, d, "union", str, union bpf_iter_link_info, BTF_F_COMPACT,
|
||||||
"(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},.cgroup = (struct){.order = (enum bpf_cgroup_iter_order)BPF_CGROUP_ITER_SELF_ONLY,.cgroup_fd = (__u32)1,},}",
|
"(union bpf_iter_link_info){.map = (struct){.map_fd = (__u32)1,},.cgroup = (struct){.order = (enum bpf_cgroup_iter_order)BPF_CGROUP_ITER_SELF_ONLY,.cgroup_fd = (__u32)1,},.task = (struct){.tid = (__u32)1,.pid = (__u32)1,},}",
|
||||||
{ .cgroup = { .order = 1, .cgroup_fd = 1, }});
|
{ .cgroup = { .order = 1, .cgroup_fd = 1, }});
|
||||||
|
|
||||||
/* struct skb with nested structs/unions; because type output is so
|
/* struct skb with nested structs/unions; because type output is so
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
char _license[] SEC("license") = "GPL";
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
|
uint32_t tid = 0;
|
||||||
|
int num_unknown_tid = 0;
|
||||||
|
int num_known_tid = 0;
|
||||||
|
|
||||||
SEC("iter/task")
|
SEC("iter/task")
|
||||||
int dump_task(struct bpf_iter__task *ctx)
|
int dump_task(struct bpf_iter__task *ctx)
|
||||||
{
|
{
|
||||||
@ -18,6 +22,11 @@ int dump_task(struct bpf_iter__task *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task->pid != tid)
|
||||||
|
num_unknown_tid++;
|
||||||
|
else
|
||||||
|
num_known_tid++;
|
||||||
|
|
||||||
if (ctx->meta->seq_num == 0)
|
if (ctx->meta->seq_num == 0)
|
||||||
BPF_SEQ_PRINTF(seq, " tgid gid\n");
|
BPF_SEQ_PRINTF(seq, " tgid gid\n");
|
||||||
|
|
||||||
|
@ -7,14 +7,16 @@ char _license[] SEC("license") = "GPL";
|
|||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int tgid = 0;
|
int tgid = 0;
|
||||||
|
int last_tgid = 0;
|
||||||
|
int unique_tgid_count = 0;
|
||||||
|
|
||||||
SEC("iter/task_file")
|
SEC("iter/task_file")
|
||||||
int dump_task_file(struct bpf_iter__task_file *ctx)
|
int dump_task_file(struct bpf_iter__task_file *ctx)
|
||||||
{
|
{
|
||||||
struct seq_file *seq = ctx->meta->seq;
|
struct seq_file *seq = ctx->meta->seq;
|
||||||
struct task_struct *task = ctx->task;
|
struct task_struct *task = ctx->task;
|
||||||
__u32 fd = ctx->fd;
|
|
||||||
struct file *file = ctx->file;
|
struct file *file = ctx->file;
|
||||||
|
__u32 fd = ctx->fd;
|
||||||
|
|
||||||
if (task == (void *)0 || file == (void *)0)
|
if (task == (void *)0 || file == (void *)0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -27,6 +29,11 @@ int dump_task_file(struct bpf_iter__task_file *ctx)
|
|||||||
if (tgid == task->tgid && task->tgid != task->pid)
|
if (tgid == task->tgid && task->tgid != task->pid)
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
|
if (last_tgid != task->tgid) {
|
||||||
|
last_tgid = task->tgid;
|
||||||
|
unique_tgid_count++;
|
||||||
|
}
|
||||||
|
|
||||||
BPF_SEQ_PRINTF(seq, "%8d %8d %8d %lx\n", task->tgid, task->pid, fd,
|
BPF_SEQ_PRINTF(seq, "%8d %8d %8d %lx\n", task->tgid, task->pid, fd,
|
||||||
(long)file->f_op);
|
(long)file->f_op);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -20,6 +20,8 @@ char _license[] SEC("license") = "GPL";
|
|||||||
#define D_PATH_BUF_SIZE 1024
|
#define D_PATH_BUF_SIZE 1024
|
||||||
char d_path_buf[D_PATH_BUF_SIZE] = {};
|
char d_path_buf[D_PATH_BUF_SIZE] = {};
|
||||||
__u32 pid = 0;
|
__u32 pid = 0;
|
||||||
|
__u32 one_task = 0;
|
||||||
|
__u32 one_task_error = 0;
|
||||||
|
|
||||||
SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx)
|
SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx)
|
||||||
{
|
{
|
||||||
@ -33,8 +35,11 @@ SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
file = vma->vm_file;
|
file = vma->vm_file;
|
||||||
if (task->tgid != pid)
|
if (task->tgid != pid) {
|
||||||
|
if (one_task)
|
||||||
|
one_task_error = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
perm_str[0] = (vma->vm_flags & VM_READ) ? 'r' : '-';
|
perm_str[0] = (vma->vm_flags & VM_READ) ? 'r' : '-';
|
||||||
perm_str[1] = (vma->vm_flags & VM_WRITE) ? 'w' : '-';
|
perm_str[1] = (vma->vm_flags & VM_WRITE) ? 'w' : '-';
|
||||||
perm_str[2] = (vma->vm_flags & VM_EXEC) ? 'x' : '-';
|
perm_str[2] = (vma->vm_flags & VM_EXEC) ? 'x' : '-';
|
||||||
|
37
tools/testing/selftests/bpf/progs/bpf_iter_vma_offset.c
Normal file
37
tools/testing/selftests/bpf/progs/bpf_iter_vma_offset.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
|
||||||
|
#include "bpf_iter.h"
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
|
||||||
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
|
__u32 unique_tgid_cnt = 0;
|
||||||
|
uintptr_t address = 0;
|
||||||
|
uintptr_t offset = 0;
|
||||||
|
__u32 last_tgid = 0;
|
||||||
|
__u32 pid = 0;
|
||||||
|
__u32 page_shift = 0;
|
||||||
|
|
||||||
|
SEC("iter/task_vma")
|
||||||
|
int get_vma_offset(struct bpf_iter__task_vma *ctx)
|
||||||
|
{
|
||||||
|
struct vm_area_struct *vma = ctx->vma;
|
||||||
|
struct seq_file *seq = ctx->meta->seq;
|
||||||
|
struct task_struct *task = ctx->task;
|
||||||
|
|
||||||
|
if (task == NULL || vma == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (last_tgid != task->tgid)
|
||||||
|
unique_tgid_cnt++;
|
||||||
|
last_tgid = task->tgid;
|
||||||
|
|
||||||
|
if (task->tgid != pid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (vma->vm_start <= address && vma->vm_end > address) {
|
||||||
|
offset = address - vma->vm_start + (vma->vm_pgoff << page_shift);
|
||||||
|
BPF_SEQ_PRINTF(seq, "OK\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user