1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright (c) 2019-2020 Linux Test Project
4 */
5
6#define TST_NO_DEFAULT_MAIN
7#include "tst_test.h"
8#include "bpf_common.h"
9
10void rlimit_bump_memlock(void)
11{
12	struct rlimit memlock_r;
13
14	SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
15	memlock_r.rlim_cur += BPF_MEMLOCK_ADD;
16	tst_res(TINFO, "Raising RLIMIT_MEMLOCK to %ld",
17		(long)memlock_r.rlim_cur);
18
19	if (memlock_r.rlim_cur <= memlock_r.rlim_max) {
20		SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
21	} else if ((geteuid() == 0)) {
22		memlock_r.rlim_max += BPF_MEMLOCK_ADD;
23		SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r);
24	} else {
25		tst_res(TINFO, "Can't raise RLIMIT_MEMLOCK, test may fail "
26			"due to lack of max locked memory");
27	}
28}
29
30int bpf_map_create(union bpf_attr *const attr)
31{
32	int ret;
33
34	ret = TST_RETRY_FUNC(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)),
35		TST_RETVAL_GE0);
36
37	if (ret == -1) {
38		if (errno == EPERM) {
39			tst_res(TCONF, "Hint: check also /proc/sys/kernel/unprivileged_bpf_disabled");
40			tst_brk(TCONF | TERRNO,
41				"bpf() requires CAP_SYS_ADMIN or CAP_BPF on this system");
42		} else {
43			tst_brk(TBROK | TERRNO, "Failed to create array map");
44		}
45	}
46
47	return ret;
48}
49
50int bpf_map_array_create(const uint32_t max_entries)
51{
52	union bpf_attr map_attr = {
53		.map_type = BPF_MAP_TYPE_ARRAY,
54		.key_size = 4,
55		.value_size = 8,
56		.max_entries = max_entries,
57		.map_flags = 0
58	};
59
60	return bpf_map_create(&map_attr);
61}
62
63void bpf_map_array_get(const int map_fd,
64		       const uint32_t *const array_indx,
65		       uint64_t *const array_val)
66{
67	union bpf_attr elem_attr = {
68		.map_fd = map_fd,
69		.key = ptr_to_u64(array_indx),
70		.value = ptr_to_u64(array_val),
71		.flags = 0
72	};
73	const int ret = bpf(BPF_MAP_LOOKUP_ELEM, &elem_attr, sizeof(elem_attr));
74
75	if (ret) {
76		tst_brk(TBROK | TTERRNO,
77			"Failed array map lookup: fd=%i [%"PRIu32"]",
78			map_fd, *array_indx);
79	}
80}
81
82void bpf_init_prog_attr(union bpf_attr *const attr,
83			const struct bpf_insn *const prog,
84			const size_t prog_size, char *const log_buf,
85			const size_t log_size)
86{
87	static struct bpf_insn *buf;
88	static size_t buf_size;
89	const size_t prog_len = prog_size / sizeof(*prog);
90
91	/* all guarded buffers will be free()d automatically by LTP library */
92	if (!buf || prog_size > buf_size) {
93		buf = tst_alloc(prog_size);
94		buf_size = prog_size;
95	}
96
97	memcpy(buf, prog, prog_size);
98	memset(attr, 0, sizeof(*attr));
99	attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
100	attr->insns = ptr_to_u64(buf);
101	attr->insn_cnt = prog_len;
102	attr->license = ptr_to_u64("GPL");
103	attr->log_buf = ptr_to_u64(log_buf);
104	attr->log_size = log_size;
105	attr->log_level = 1;
106}
107
108int bpf_load_prog(union bpf_attr *const attr, const char *const log)
109{
110	const int ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)),
111				       TST_RETVAL_GE0);
112
113	if (ret >= 0) {
114		tst_res(TPASS, "Loaded program");
115		return ret;
116	}
117
118	if (ret != -1)
119		tst_brk(TBROK, "Invalid bpf() return value: %d", ret);
120
121	if (log[0] != 0) {
122		tst_printf("%s\n", log);
123		tst_brk(TBROK | TERRNO, "Failed verification");
124	}
125
126	tst_brk(TBROK | TERRNO, "Failed to load program");
127	return ret;
128}
129
130void bpf_run_prog(const int prog_fd,
131		  const char *const msg, const size_t msg_len)
132{
133	int sk[2];
134
135	SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk);
136	SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF,
137			&prog_fd, sizeof(prog_fd));
138
139	SAFE_WRITE(SAFE_WRITE_ALL, sk[0], msg, msg_len);
140
141	SAFE_CLOSE(sk[0]);
142	SAFE_CLOSE(sk[1]);
143}
144