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