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