mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
selftests/bpf: Add selftests for new cgroup local storage
Add four tests for new cgroup local storage, (1) testing bpf program helpers and user space map APIs, (2) testing recursive fentry triggering won't deadlock, (3) testing progs attached to cgroups, and (4) a negative test if the bpf_cgrp_storage_get() helper key is not a cgroup btf id. Signed-off-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/r/20221026042911.675546-1-yhs@fb.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
fd4ca6c1fa
commit
12bb6ca4e2
171
tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
Normal file
171
tools/testing/selftests/bpf/prog_tests/cgrp_local_storage.c
Normal file
@ -0,0 +1,171 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates.*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <test_progs.h>
|
||||
#include "cgrp_ls_tp_btf.skel.h"
|
||||
#include "cgrp_ls_recursion.skel.h"
|
||||
#include "cgrp_ls_attach_cgroup.skel.h"
|
||||
#include "cgrp_ls_negative.skel.h"
|
||||
#include "network_helpers.h"
|
||||
|
||||
struct socket_cookie {
|
||||
__u64 cookie_key;
|
||||
__u32 cookie_value;
|
||||
};
|
||||
|
||||
static void test_tp_btf(int cgroup_fd)
|
||||
{
|
||||
struct cgrp_ls_tp_btf *skel;
|
||||
long val1 = 1, val2 = 0;
|
||||
int err;
|
||||
|
||||
skel = cgrp_ls_tp_btf__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
|
||||
return;
|
||||
|
||||
/* populate a value in map_b */
|
||||
err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val1, BPF_ANY);
|
||||
if (!ASSERT_OK(err, "map_update_elem"))
|
||||
goto out;
|
||||
|
||||
/* check value */
|
||||
err = bpf_map_lookup_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val2);
|
||||
if (!ASSERT_OK(err, "map_lookup_elem"))
|
||||
goto out;
|
||||
if (!ASSERT_EQ(val2, 1, "map_lookup_elem, invalid val"))
|
||||
goto out;
|
||||
|
||||
/* delete value */
|
||||
err = bpf_map_delete_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd);
|
||||
if (!ASSERT_OK(err, "map_delete_elem"))
|
||||
goto out;
|
||||
|
||||
skel->bss->target_pid = syscall(SYS_gettid);
|
||||
|
||||
err = cgrp_ls_tp_btf__attach(skel);
|
||||
if (!ASSERT_OK(err, "skel_attach"))
|
||||
goto out;
|
||||
|
||||
syscall(SYS_gettid);
|
||||
syscall(SYS_gettid);
|
||||
|
||||
skel->bss->target_pid = 0;
|
||||
|
||||
/* 3x syscalls: 1x attach and 2x gettid */
|
||||
ASSERT_EQ(skel->bss->enter_cnt, 3, "enter_cnt");
|
||||
ASSERT_EQ(skel->bss->exit_cnt, 3, "exit_cnt");
|
||||
ASSERT_EQ(skel->bss->mismatch_cnt, 0, "mismatch_cnt");
|
||||
out:
|
||||
cgrp_ls_tp_btf__destroy(skel);
|
||||
}
|
||||
|
||||
static void test_attach_cgroup(int cgroup_fd)
|
||||
{
|
||||
int server_fd = 0, client_fd = 0, err = 0;
|
||||
socklen_t addr_len = sizeof(struct sockaddr_in6);
|
||||
struct cgrp_ls_attach_cgroup *skel;
|
||||
__u32 cookie_expected_value;
|
||||
struct sockaddr_in6 addr;
|
||||
struct socket_cookie val;
|
||||
|
||||
skel = cgrp_ls_attach_cgroup__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open"))
|
||||
return;
|
||||
|
||||
skel->links.set_cookie = bpf_program__attach_cgroup(
|
||||
skel->progs.set_cookie, cgroup_fd);
|
||||
if (!ASSERT_OK_PTR(skel->links.set_cookie, "prog_attach"))
|
||||
goto out;
|
||||
|
||||
skel->links.update_cookie_sockops = bpf_program__attach_cgroup(
|
||||
skel->progs.update_cookie_sockops, cgroup_fd);
|
||||
if (!ASSERT_OK_PTR(skel->links.update_cookie_sockops, "prog_attach"))
|
||||
goto out;
|
||||
|
||||
skel->links.update_cookie_tracing = bpf_program__attach(
|
||||
skel->progs.update_cookie_tracing);
|
||||
if (!ASSERT_OK_PTR(skel->links.update_cookie_tracing, "prog_attach"))
|
||||
goto out;
|
||||
|
||||
server_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
|
||||
if (!ASSERT_GE(server_fd, 0, "start_server"))
|
||||
goto out;
|
||||
|
||||
client_fd = connect_to_fd(server_fd, 0);
|
||||
if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
|
||||
goto close_server_fd;
|
||||
|
||||
err = bpf_map_lookup_elem(bpf_map__fd(skel->maps.socket_cookies),
|
||||
&cgroup_fd, &val);
|
||||
if (!ASSERT_OK(err, "map_lookup(socket_cookies)"))
|
||||
goto close_client_fd;
|
||||
|
||||
err = getsockname(client_fd, (struct sockaddr *)&addr, &addr_len);
|
||||
if (!ASSERT_OK(err, "getsockname"))
|
||||
goto close_client_fd;
|
||||
|
||||
cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF;
|
||||
ASSERT_EQ(val.cookie_value, cookie_expected_value, "cookie_value");
|
||||
|
||||
close_client_fd:
|
||||
close(client_fd);
|
||||
close_server_fd:
|
||||
close(server_fd);
|
||||
out:
|
||||
cgrp_ls_attach_cgroup__destroy(skel);
|
||||
}
|
||||
|
||||
static void test_recursion(int cgroup_fd)
|
||||
{
|
||||
struct cgrp_ls_recursion *skel;
|
||||
int err;
|
||||
|
||||
skel = cgrp_ls_recursion__open_and_load();
|
||||
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
|
||||
return;
|
||||
|
||||
err = cgrp_ls_recursion__attach(skel);
|
||||
if (!ASSERT_OK(err, "skel_attach"))
|
||||
goto out;
|
||||
|
||||
/* trigger sys_enter, make sure it does not cause deadlock */
|
||||
syscall(SYS_gettid);
|
||||
|
||||
out:
|
||||
cgrp_ls_recursion__destroy(skel);
|
||||
}
|
||||
|
||||
static void test_negative(void)
|
||||
{
|
||||
struct cgrp_ls_negative *skel;
|
||||
|
||||
skel = cgrp_ls_negative__open_and_load();
|
||||
if (!ASSERT_ERR_PTR(skel, "skel_open_and_load")) {
|
||||
cgrp_ls_negative__destroy(skel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void test_cgrp_local_storage(void)
|
||||
{
|
||||
int cgroup_fd;
|
||||
|
||||
cgroup_fd = test__join_cgroup("/cgrp_local_storage");
|
||||
if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /cgrp_local_storage"))
|
||||
return;
|
||||
|
||||
if (test__start_subtest("tp_btf"))
|
||||
test_tp_btf(cgroup_fd);
|
||||
if (test__start_subtest("attach_cgroup"))
|
||||
test_attach_cgroup(cgroup_fd);
|
||||
if (test__start_subtest("recursion"))
|
||||
test_recursion(cgroup_fd);
|
||||
if (test__start_subtest("negative"))
|
||||
test_negative();
|
||||
|
||||
close(cgroup_fd);
|
||||
}
|
101
tools/testing/selftests/bpf/progs/cgrp_ls_attach_cgroup.c
Normal file
101
tools/testing/selftests/bpf/progs/cgrp_ls_attach_cgroup.c
Normal file
@ -0,0 +1,101 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
#include "bpf_tracing_net.h"
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
struct socket_cookie {
|
||||
__u64 cookie_key;
|
||||
__u64 cookie_value;
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__type(key, int);
|
||||
__type(value, struct socket_cookie);
|
||||
} socket_cookies SEC(".maps");
|
||||
|
||||
SEC("cgroup/connect6")
|
||||
int set_cookie(struct bpf_sock_addr *ctx)
|
||||
{
|
||||
struct socket_cookie *p;
|
||||
struct tcp_sock *tcp_sk;
|
||||
struct bpf_sock *sk;
|
||||
|
||||
if (ctx->family != AF_INET6 || ctx->user_family != AF_INET6)
|
||||
return 1;
|
||||
|
||||
sk = ctx->sk;
|
||||
if (!sk)
|
||||
return 1;
|
||||
|
||||
tcp_sk = bpf_skc_to_tcp_sock(sk);
|
||||
if (!tcp_sk)
|
||||
return 1;
|
||||
|
||||
p = bpf_cgrp_storage_get(&socket_cookies,
|
||||
tcp_sk->inet_conn.icsk_inet.sk.sk_cgrp_data.cgroup, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (!p)
|
||||
return 1;
|
||||
|
||||
p->cookie_value = 0xF;
|
||||
p->cookie_key = bpf_get_socket_cookie(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("sockops")
|
||||
int update_cookie_sockops(struct bpf_sock_ops *ctx)
|
||||
{
|
||||
struct socket_cookie *p;
|
||||
struct tcp_sock *tcp_sk;
|
||||
struct bpf_sock *sk;
|
||||
|
||||
if (ctx->family != AF_INET6 || ctx->op != BPF_SOCK_OPS_TCP_CONNECT_CB)
|
||||
return 1;
|
||||
|
||||
sk = ctx->sk;
|
||||
if (!sk)
|
||||
return 1;
|
||||
|
||||
tcp_sk = bpf_skc_to_tcp_sock(sk);
|
||||
if (!tcp_sk)
|
||||
return 1;
|
||||
|
||||
p = bpf_cgrp_storage_get(&socket_cookies,
|
||||
tcp_sk->inet_conn.icsk_inet.sk.sk_cgrp_data.cgroup, 0, 0);
|
||||
if (!p)
|
||||
return 1;
|
||||
|
||||
if (p->cookie_key != bpf_get_socket_cookie(ctx))
|
||||
return 1;
|
||||
|
||||
p->cookie_value |= (ctx->local_port << 8);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SEC("fexit/inet_stream_connect")
|
||||
int BPF_PROG(update_cookie_tracing, struct socket *sock,
|
||||
struct sockaddr *uaddr, int addr_len, int flags)
|
||||
{
|
||||
struct socket_cookie *p;
|
||||
struct tcp_sock *tcp_sk;
|
||||
|
||||
if (uaddr->sa_family != AF_INET6)
|
||||
return 0;
|
||||
|
||||
p = bpf_cgrp_storage_get(&socket_cookies, sock->sk->sk_cgrp_data.cgroup, 0, 0);
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
if (p->cookie_key != bpf_get_socket_cookie(sock->sk))
|
||||
return 0;
|
||||
|
||||
p->cookie_value |= 0xF0;
|
||||
return 0;
|
||||
}
|
26
tools/testing/selftests/bpf/progs/cgrp_ls_negative.c
Normal file
26
tools/testing/selftests/bpf/progs/cgrp_ls_negative.c
Normal file
@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__type(key, int);
|
||||
__type(value, long);
|
||||
} map_a SEC(".maps");
|
||||
|
||||
SEC("tp_btf/sys_enter")
|
||||
int BPF_PROG(on_enter, struct pt_regs *regs, long id)
|
||||
{
|
||||
struct task_struct *task;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
(void)bpf_cgrp_storage_get(&map_a, (struct cgroup *)task, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
return 0;
|
||||
}
|
70
tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c
Normal file
70
tools/testing/selftests/bpf/progs/cgrp_ls_recursion.c
Normal file
@ -0,0 +1,70 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__type(key, int);
|
||||
__type(value, long);
|
||||
} map_a SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__type(key, int);
|
||||
__type(value, long);
|
||||
} map_b SEC(".maps");
|
||||
|
||||
SEC("fentry/bpf_local_storage_lookup")
|
||||
int BPF_PROG(on_lookup)
|
||||
{
|
||||
struct task_struct *task = bpf_get_current_task_btf();
|
||||
|
||||
bpf_cgrp_storage_delete(&map_a, task->cgroups->dfl_cgrp);
|
||||
bpf_cgrp_storage_delete(&map_b, task->cgroups->dfl_cgrp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("fentry/bpf_local_storage_update")
|
||||
int BPF_PROG(on_update)
|
||||
{
|
||||
struct task_struct *task = bpf_get_current_task_btf();
|
||||
long *ptr;
|
||||
|
||||
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (ptr)
|
||||
*ptr += 1;
|
||||
|
||||
ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (ptr)
|
||||
*ptr += 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/sys_enter")
|
||||
int BPF_PROG(on_enter, struct pt_regs *regs, long id)
|
||||
{
|
||||
struct task_struct *task;
|
||||
long *ptr;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (ptr)
|
||||
*ptr = 200;
|
||||
|
||||
ptr = bpf_cgrp_storage_get(&map_b, task->cgroups->dfl_cgrp, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (ptr)
|
||||
*ptr = 100;
|
||||
return 0;
|
||||
}
|
88
tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c
Normal file
88
tools/testing/selftests/bpf/progs/cgrp_ls_tp_btf.c
Normal file
@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
|
||||
|
||||
#include "vmlinux.h"
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_tracing.h>
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__type(key, int);
|
||||
__type(value, long);
|
||||
} map_a SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
|
||||
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||
__type(key, int);
|
||||
__type(value, long);
|
||||
} map_b SEC(".maps");
|
||||
|
||||
#define MAGIC_VALUE 0xabcd1234
|
||||
|
||||
pid_t target_pid = 0;
|
||||
int mismatch_cnt = 0;
|
||||
int enter_cnt = 0;
|
||||
int exit_cnt = 0;
|
||||
|
||||
SEC("tp_btf/sys_enter")
|
||||
int BPF_PROG(on_enter, struct pt_regs *regs, long id)
|
||||
{
|
||||
struct task_struct *task;
|
||||
long *ptr;
|
||||
int err;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
if (task->pid != target_pid)
|
||||
return 0;
|
||||
|
||||
/* populate value 0 */
|
||||
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (!ptr)
|
||||
return 0;
|
||||
|
||||
/* delete value 0 */
|
||||
err = bpf_cgrp_storage_delete(&map_a, task->cgroups->dfl_cgrp);
|
||||
if (err)
|
||||
return 0;
|
||||
|
||||
/* value is not available */
|
||||
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0, 0);
|
||||
if (ptr)
|
||||
return 0;
|
||||
|
||||
/* re-populate the value */
|
||||
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (!ptr)
|
||||
return 0;
|
||||
__sync_fetch_and_add(&enter_cnt, 1);
|
||||
*ptr = MAGIC_VALUE + enter_cnt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tp_btf/sys_exit")
|
||||
int BPF_PROG(on_exit, struct pt_regs *regs, long id)
|
||||
{
|
||||
struct task_struct *task;
|
||||
long *ptr;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
if (task->pid != target_pid)
|
||||
return 0;
|
||||
|
||||
ptr = bpf_cgrp_storage_get(&map_a, task->cgroups->dfl_cgrp, 0,
|
||||
BPF_LOCAL_STORAGE_GET_F_CREATE);
|
||||
if (!ptr)
|
||||
return 0;
|
||||
|
||||
__sync_fetch_and_add(&exit_cnt, 1);
|
||||
if (*ptr != MAGIC_VALUE + exit_cnt)
|
||||
__sync_fetch_and_add(&mismatch_cnt, 1);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user