1/* SPDX-License-Identifier: GPL-2.0-or-later */ 2/* 3 * Copyright (c) 2019-2020 Linux Test Project 4 */ 5 6#define TST_NO_DEFAULT_MAIN 7#include "tst_test.h" 8#include "bpf_common.h" 9 10void rlimit_bump_memlock(void) 11{ 12 struct rlimit memlock_r; 13 14 SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &memlock_r); 15 memlock_r.rlim_cur += BPF_MEMLOCK_ADD; 16 tst_res(TINFO, "Raising RLIMIT_MEMLOCK to %ld", 17 (long)memlock_r.rlim_cur); 18 19 if (memlock_r.rlim_cur <= memlock_r.rlim_max) { 20 SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r); 21 } else if ((geteuid() == 0)) { 22 memlock_r.rlim_max += BPF_MEMLOCK_ADD; 23 SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &memlock_r); 24 } else { 25 tst_res(TINFO, "Can't raise RLIMIT_MEMLOCK, test may fail " 26 "due to lack of max locked memory"); 27 } 28} 29 30int bpf_map_create(union bpf_attr *const attr) 31{ 32 int ret; 33 34 ret = TST_RETRY_FUNC(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)), 35 TST_RETVAL_GE0); 36 37 if (ret == -1) { 38 if (errno == EPERM) { 39 tst_res(TCONF, "Hint: check also /proc/sys/kernel/unprivileged_bpf_disabled"); 40 tst_brk(TCONF | TERRNO, 41 "bpf() requires CAP_SYS_ADMIN or CAP_BPF on this system"); 42 } else { 43 tst_brk(TBROK | TERRNO, "Failed to create array map"); 44 } 45 } 46 47 return ret; 48} 49 50int bpf_map_array_create(const uint32_t max_entries) 51{ 52 union bpf_attr map_attr = { 53 .map_type = BPF_MAP_TYPE_ARRAY, 54 .key_size = 4, 55 .value_size = 8, 56 .max_entries = max_entries, 57 .map_flags = 0 58 }; 59 60 return bpf_map_create(&map_attr); 61} 62 63void bpf_map_array_get(const int map_fd, 64 const uint32_t *const array_indx, 65 uint64_t *const array_val) 66{ 67 union bpf_attr elem_attr = { 68 .map_fd = map_fd, 69 .key = ptr_to_u64(array_indx), 70 .value = ptr_to_u64(array_val), 71 .flags = 0 72 }; 73 const int ret = bpf(BPF_MAP_LOOKUP_ELEM, &elem_attr, sizeof(elem_attr)); 74 75 if (ret) { 76 tst_brk(TBROK | TTERRNO, 77 "Failed array map lookup: fd=%i [%"PRIu32"]", 78 map_fd, *array_indx); 79 } 80} 81 82void bpf_init_prog_attr(union bpf_attr *const attr, 83 const struct bpf_insn *const prog, 84 const size_t prog_size, char *const log_buf, 85 const size_t log_size) 86{ 87 static struct bpf_insn *buf; 88 static size_t buf_size; 89 const size_t prog_len = prog_size / sizeof(*prog); 90 91 /* all guarded buffers will be free()d automatically by LTP library */ 92 if (!buf || prog_size > buf_size) { 93 buf = tst_alloc(prog_size); 94 buf_size = prog_size; 95 } 96 97 memcpy(buf, prog, prog_size); 98 memset(attr, 0, sizeof(*attr)); 99 attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER; 100 attr->insns = ptr_to_u64(buf); 101 attr->insn_cnt = prog_len; 102 attr->license = ptr_to_u64("GPL"); 103 attr->log_buf = ptr_to_u64(log_buf); 104 attr->log_size = log_size; 105 attr->log_level = 1; 106} 107 108int bpf_load_prog(union bpf_attr *const attr, const char *const log) 109{ 110 const int ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)), 111 TST_RETVAL_GE0); 112 113 if (ret >= 0) { 114 tst_res(TPASS, "Loaded program"); 115 return ret; 116 } 117 118 if (ret != -1) 119 tst_brk(TBROK, "Invalid bpf() return value: %d", ret); 120 121 if (log[0] != 0) { 122 tst_printf("%s\n", log); 123 tst_brk(TBROK | TERRNO, "Failed verification"); 124 } 125 126 tst_brk(TBROK | TERRNO, "Failed to load program"); 127 return ret; 128} 129 130void bpf_run_prog(const int prog_fd, 131 const char *const msg, const size_t msg_len) 132{ 133 int sk[2]; 134 135 SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk); 136 SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF, 137 &prog_fd, sizeof(prog_fd)); 138 139 SAFE_WRITE(SAFE_WRITE_ALL, sk[0], msg, msg_len); 140 141 SAFE_CLOSE(sk[0]); 142 SAFE_CLOSE(sk[1]); 143} 144