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