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