142 lines
3.3 KiB
C
142 lines
3.3 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright (c) 2019-2020 Linux Test Project
|
|
*/
|
|
|
|
#define TST_NO_DEFAULT_MAIN
|
|
#include "tst_test.h"
|
|
#include "bpf_common.h"
|
|
|
|
void rlimit_bump_memlock(void)
|
|
{
|
|
struct rlimit memlock_r;
|
|
|
|
SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
|
|
memlock_r.rlim_cur += BPF_MEMLOCK_ADD;
|
|
tst_res(TINFO, "Raising RLIMIT_MEMLOCK to %ld",
|
|
(long)memlock_r.rlim_cur);
|
|
|
|
if (memlock_r.rlim_cur <= memlock_r.rlim_max) {
|
|
SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
|
|
} else if ((geteuid() == 0)) {
|
|
memlock_r.rlim_max += BPF_MEMLOCK_ADD;
|
|
SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
|
|
} else {
|
|
tst_res(TINFO, "Can't raise RLIMIT_MEMLOCK, test may fail "
|
|
"due to lack of max locked memory");
|
|
}
|
|
}
|
|
|
|
int bpf_map_create(union bpf_attr *const attr)
|
|
{
|
|
int ret;
|
|
|
|
ret = TST_RETRY_FUNC(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)),
|
|
TST_RETVAL_GE0);
|
|
|
|
if (ret == -1) {
|
|
if (errno == EPERM) {
|
|
tst_res(TCONF, "Hint: check also /proc/sys/kernel/unprivileged_bpf_disabled");
|
|
tst_brk(TCONF | TERRNO,
|
|
"bpf() requires CAP_SYS_ADMIN on this system");
|
|
} else {
|
|
tst_brk(TBROK | TERRNO, "Failed to create array map");
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int bpf_map_array_create(const uint32_t max_entries)
|
|
{
|
|
union bpf_attr map_attr = {
|
|
.map_type = BPF_MAP_TYPE_ARRAY,
|
|
.key_size = 4,
|
|
.value_size = 8,
|
|
.max_entries = max_entries,
|
|
.map_flags = 0
|
|
};
|
|
|
|
return bpf_map_create(&map_attr);
|
|
}
|
|
|
|
void bpf_map_array_get(const int map_fd,
|
|
const uint32_t *const array_indx,
|
|
uint64_t *const array_val)
|
|
{
|
|
union bpf_attr elem_attr = {
|
|
.map_fd = map_fd,
|
|
.key = ptr_to_u64(array_indx),
|
|
.value = ptr_to_u64(array_val),
|
|
.flags = 0
|
|
};
|
|
const int ret = bpf(BPF_MAP_LOOKUP_ELEM, &elem_attr, sizeof(elem_attr));
|
|
|
|
if (ret) {
|
|
tst_brk(TBROK | TTERRNO,
|
|
"Failed array map lookup: fd=%i [%"PRIu32"]",
|
|
map_fd, *array_indx);
|
|
}
|
|
}
|
|
|
|
void bpf_init_prog_attr(union bpf_attr *const attr,
|
|
const struct bpf_insn *const prog,
|
|
const size_t prog_size, char *const log_buf,
|
|
const size_t log_size)
|
|
{
|
|
static struct bpf_insn *buf;
|
|
static size_t buf_size;
|
|
const size_t prog_len = prog_size / sizeof(*prog);
|
|
|
|
/* all guarded buffers will be free()d automatically by LTP library */
|
|
if (!buf || prog_size > buf_size) {
|
|
buf = tst_alloc(prog_size);
|
|
buf_size = prog_size;
|
|
}
|
|
|
|
memcpy(buf, prog, prog_size);
|
|
memset(attr, 0, sizeof(*attr));
|
|
attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
|
attr->insns = ptr_to_u64(buf);
|
|
attr->insn_cnt = prog_len;
|
|
attr->license = ptr_to_u64("GPL");
|
|
attr->log_buf = ptr_to_u64(log_buf);
|
|
attr->log_size = log_size;
|
|
attr->log_level = 1;
|
|
}
|
|
|
|
int bpf_load_prog(union bpf_attr *const attr, const char *const log)
|
|
{
|
|
const int ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)),
|
|
TST_RETVAL_GE0);
|
|
|
|
if (ret >= 0) {
|
|
tst_res(TPASS, "Loaded program");
|
|
return ret;
|
|
}
|
|
|
|
if (ret != -1)
|
|
tst_brk(TBROK, "Invalid bpf() return value: %d", ret);
|
|
|
|
if (log[0] != 0)
|
|
tst_brk(TBROK | TERRNO, "Failed verification: %s", log);
|
|
|
|
tst_brk(TBROK | TERRNO, "Failed to load program");
|
|
return ret;
|
|
}
|
|
|
|
void bpf_run_prog(const int prog_fd,
|
|
const char *const msg, const size_t msg_len)
|
|
{
|
|
int sk[2];
|
|
|
|
SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk);
|
|
SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF,
|
|
&prog_fd, sizeof(prog_fd));
|
|
|
|
SAFE_WRITE(1, sk[0], msg, msg_len);
|
|
|
|
SAFE_CLOSE(sk[0]);
|
|
SAFE_CLOSE(sk[1]);
|
|
}
|