1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci * Trivial Extended Berkeley Packet Filter (eBPF) test.
6f08c3bdfSopenharmony_ci *
7f08c3bdfSopenharmony_ci * Sanity check loading and running bytecode.
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Test flow:
10f08c3bdfSopenharmony_ci * 1. Create array map
11f08c3bdfSopenharmony_ci * 2. Load eBPF program
12f08c3bdfSopenharmony_ci * 3. Attach program to socket
13f08c3bdfSopenharmony_ci * 4. Send packet on socket
14f08c3bdfSopenharmony_ci * 5. This should trigger eBPF program which writes to array map
15f08c3bdfSopenharmony_ci * 6. Verify array map was written to
16f08c3bdfSopenharmony_ci */
17f08c3bdfSopenharmony_ci/*
18f08c3bdfSopenharmony_ci * If test is executed in a loop and limit for locked memory (ulimit -l) is
19f08c3bdfSopenharmony_ci * too low bpf() call can fail with EPERM due to deffered freeing.
20f08c3bdfSopenharmony_ci */
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_ci#include <limits.h>
23f08c3bdfSopenharmony_ci#include <string.h>
24f08c3bdfSopenharmony_ci#include <stdio.h>
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci#include "config.h"
27f08c3bdfSopenharmony_ci#include "tst_test.h"
28f08c3bdfSopenharmony_ci#include "bpf_common.h"
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_ciconst char MSG[] = "Ahoj!";
31f08c3bdfSopenharmony_cistatic char *msg;
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic char *log;
34f08c3bdfSopenharmony_cistatic union bpf_attr *attr;
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_ciint load_prog(int fd)
37f08c3bdfSopenharmony_ci{
38f08c3bdfSopenharmony_ci	/*
39f08c3bdfSopenharmony_ci	 * The following is a byte code template. We copy it to a guarded buffer and
40f08c3bdfSopenharmony_ci	 * substitute the runtime value of our map file descriptor.
41f08c3bdfSopenharmony_ci	 *
42f08c3bdfSopenharmony_ci	 * r0 - r10 = registers 0 to 10
43f08c3bdfSopenharmony_ci	 * r0 = return code
44f08c3bdfSopenharmony_ci	 * r1 - r5 = scratch registers, used for function arguments
45f08c3bdfSopenharmony_ci	 * r6 - r9 = registers preserved across function calls
46f08c3bdfSopenharmony_ci	 * fp/r10 = stack frame pointer
47f08c3bdfSopenharmony_ci	 */
48f08c3bdfSopenharmony_ci	struct bpf_insn PROG[] = {
49f08c3bdfSopenharmony_ci		/* Load the map FD into r1 (place holder) */
50f08c3bdfSopenharmony_ci		BPF_LD_MAP_FD(BPF_REG_1, fd),
51f08c3bdfSopenharmony_ci		/* Put (key = 0) on stack and key ptr into r2 */
52f08c3bdfSopenharmony_ci		BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),   /* r2 = fp */
53f08c3bdfSopenharmony_ci		BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),  /* r2 = r2 - 8 */
54f08c3bdfSopenharmony_ci		BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),    /* *r2 = 0 */
55f08c3bdfSopenharmony_ci		/* r0 = bpf_map_lookup_elem(r1, r2) */
56f08c3bdfSopenharmony_ci		BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
57f08c3bdfSopenharmony_ci		/* if r0 == 0 goto exit */
58f08c3bdfSopenharmony_ci		BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
59f08c3bdfSopenharmony_ci		/* Set map[0] = 1 */
60f08c3bdfSopenharmony_ci		BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),     /* r1 = r0 */
61f08c3bdfSopenharmony_ci		BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 1),     /* *r1 = 1 */
62f08c3bdfSopenharmony_ci		BPF_MOV64_IMM(BPF_REG_0, 0),             /* r0 = 0 */
63f08c3bdfSopenharmony_ci		BPF_EXIT_INSN(),		         /* return r0 */
64f08c3bdfSopenharmony_ci	};
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_ci	bpf_init_prog_attr(attr, PROG, sizeof(PROG), log, BUFSIZE);
67f08c3bdfSopenharmony_ci	return bpf_load_prog(attr, log);
68f08c3bdfSopenharmony_ci}
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_civoid setup(void)
71f08c3bdfSopenharmony_ci{
72f08c3bdfSopenharmony_ci	rlimit_bump_memlock();
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	memcpy(msg, MSG, sizeof(MSG));
75f08c3bdfSopenharmony_ci}
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_civoid run(void)
78f08c3bdfSopenharmony_ci{
79f08c3bdfSopenharmony_ci	int map_fd, prog_fd;
80f08c3bdfSopenharmony_ci	uint32_t key = 0;
81f08c3bdfSopenharmony_ci	uint64_t val;
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci	map_fd = bpf_map_array_create(1);
84f08c3bdfSopenharmony_ci	prog_fd = load_prog(map_fd);
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	bpf_run_prog(prog_fd, msg, sizeof(MSG));
87f08c3bdfSopenharmony_ci	SAFE_CLOSE(prog_fd);
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	bpf_map_array_get(map_fd, &key, &val);
90f08c3bdfSopenharmony_ci	if (val != 1) {
91f08c3bdfSopenharmony_ci		tst_res(TFAIL,
92f08c3bdfSopenharmony_ci			"val = %lu, but should be val = 1",
93f08c3bdfSopenharmony_ci			val);
94f08c3bdfSopenharmony_ci        } else {
95f08c3bdfSopenharmony_ci	        tst_res(TPASS, "val = 1");
96f08c3bdfSopenharmony_ci	}
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	SAFE_CLOSE(map_fd);
99f08c3bdfSopenharmony_ci}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_cistatic struct tst_test test = {
102f08c3bdfSopenharmony_ci	.setup = setup,
103f08c3bdfSopenharmony_ci	.test_all = run,
104f08c3bdfSopenharmony_ci	.min_kver = "3.19",
105f08c3bdfSopenharmony_ci	.bufs = (struct tst_buffers []) {
106f08c3bdfSopenharmony_ci		{&log, .size = BUFSIZ},
107f08c3bdfSopenharmony_ci		{&attr, .size = sizeof(*attr)},
108f08c3bdfSopenharmony_ci		{&msg, .size = sizeof(MSG)},
109f08c3bdfSopenharmony_ci		{},
110f08c3bdfSopenharmony_ci	}
111f08c3bdfSopenharmony_ci};
112