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 30const char MSG[] = "Ahoj!"; 31static char *msg; 32 33static char *log; 34static union bpf_attr *attr; 35 36int 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, BUFSIZE); 67 return bpf_load_prog(attr, log); 68} 69 70void setup(void) 71{ 72 rlimit_bump_memlock(); 73 74 memcpy(msg, MSG, sizeof(MSG)); 75} 76 77void 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 101static 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