root/tools/perf/tests/bpf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. epoll_pwait_loop
  2. llseek_loop
  3. do_test
  4. prepare_bpf
  5. __test__bpf
  6. test__bpf_subtest_get_nr
  7. test__bpf_subtest_get_desc
  8. check_env
  9. test__bpf
  10. test__bpf_subtest_get_nr
  11. test__bpf_subtest_get_desc
  12. test__bpf

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <errno.h>
   3 #include <stdio.h>
   4 #include <sys/epoll.h>
   5 #include <sys/types.h>
   6 #include <sys/stat.h>
   7 #include <fcntl.h>
   8 #include <util/record.h>
   9 #include <util/util.h>
  10 #include <util/bpf-loader.h>
  11 #include <util/evlist.h>
  12 #include <linux/bpf.h>
  13 #include <linux/filter.h>
  14 #include <linux/kernel.h>
  15 #include <linux/string.h>
  16 #include <api/fs/fs.h>
  17 #include <bpf/bpf.h>
  18 #include "tests.h"
  19 #include "llvm.h"
  20 #include "debug.h"
  21 #include "parse-events.h"
  22 #include "util/mmap.h"
  23 #define NR_ITERS       111
  24 #define PERF_TEST_BPF_PATH "/sys/fs/bpf/perf_test"
  25 
  26 #ifdef HAVE_LIBBPF_SUPPORT
  27 
  28 static int epoll_pwait_loop(void)
  29 {
  30         int i;
  31 
  32         /* Should fail NR_ITERS times */
  33         for (i = 0; i < NR_ITERS; i++)
  34                 epoll_pwait(-(i + 1), NULL, 0, 0, NULL);
  35         return 0;
  36 }
  37 
  38 #ifdef HAVE_BPF_PROLOGUE
  39 
  40 static int llseek_loop(void)
  41 {
  42         int fds[2], i;
  43 
  44         fds[0] = open("/dev/null", O_RDONLY);
  45         fds[1] = open("/dev/null", O_RDWR);
  46 
  47         if (fds[0] < 0 || fds[1] < 0)
  48                 return -1;
  49 
  50         for (i = 0; i < NR_ITERS; i++) {
  51                 lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
  52                 lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
  53         }
  54         close(fds[0]);
  55         close(fds[1]);
  56         return 0;
  57 }
  58 
  59 #endif
  60 
  61 static struct {
  62         enum test_llvm__testcase prog_id;
  63         const char *desc;
  64         const char *name;
  65         const char *msg_compile_fail;
  66         const char *msg_load_fail;
  67         int (*target_func)(void);
  68         int expect_result;
  69         bool    pin;
  70 } bpf_testcase_table[] = {
  71         {
  72                 .prog_id          = LLVM_TESTCASE_BASE,
  73                 .desc             = "Basic BPF filtering",
  74                 .name             = "[basic_bpf_test]",
  75                 .msg_compile_fail = "fix 'perf test LLVM' first",
  76                 .msg_load_fail    = "load bpf object failed",
  77                 .target_func      = &epoll_pwait_loop,
  78                 .expect_result    = (NR_ITERS + 1) / 2,
  79         },
  80         {
  81                 .prog_id          = LLVM_TESTCASE_BASE,
  82                 .desc             = "BPF pinning",
  83                 .name             = "[bpf_pinning]",
  84                 .msg_compile_fail = "fix kbuild first",
  85                 .msg_load_fail    = "check your vmlinux setting?",
  86                 .target_func      = &epoll_pwait_loop,
  87                 .expect_result    = (NR_ITERS + 1) / 2,
  88                 .pin              = true,
  89         },
  90 #ifdef HAVE_BPF_PROLOGUE
  91         {
  92                 .prog_id          = LLVM_TESTCASE_BPF_PROLOGUE,
  93                 .desc             = "BPF prologue generation",
  94                 .name             = "[bpf_prologue_test]",
  95                 .msg_compile_fail = "fix kbuild first",
  96                 .msg_load_fail    = "check your vmlinux setting?",
  97                 .target_func      = &llseek_loop,
  98                 .expect_result    = (NR_ITERS + 1) / 4,
  99         },
 100 #endif
 101         {
 102                 .prog_id          = LLVM_TESTCASE_BPF_RELOCATION,
 103                 .desc             = "BPF relocation checker",
 104                 .name             = "[bpf_relocation_test]",
 105                 .msg_compile_fail = "fix 'perf test LLVM' first",
 106                 .msg_load_fail    = "libbpf error when dealing with relocation",
 107         },
 108 };
 109 
 110 static int do_test(struct bpf_object *obj, int (*func)(void),
 111                    int expect)
 112 {
 113         struct record_opts opts = {
 114                 .target = {
 115                         .uid = UINT_MAX,
 116                         .uses_mmap = true,
 117                 },
 118                 .freq         = 0,
 119                 .mmap_pages   = 256,
 120                 .default_interval = 1,
 121         };
 122 
 123         char pid[16];
 124         char sbuf[STRERR_BUFSIZE];
 125         struct evlist *evlist;
 126         int i, ret = TEST_FAIL, err = 0, count = 0;
 127 
 128         struct parse_events_state parse_state;
 129         struct parse_events_error parse_error;
 130 
 131         bzero(&parse_error, sizeof(parse_error));
 132         bzero(&parse_state, sizeof(parse_state));
 133         parse_state.error = &parse_error;
 134         INIT_LIST_HEAD(&parse_state.list);
 135 
 136         err = parse_events_load_bpf_obj(&parse_state, &parse_state.list, obj, NULL);
 137         if (err || list_empty(&parse_state.list)) {
 138                 pr_debug("Failed to add events selected by BPF\n");
 139                 return TEST_FAIL;
 140         }
 141 
 142         snprintf(pid, sizeof(pid), "%d", getpid());
 143         pid[sizeof(pid) - 1] = '\0';
 144         opts.target.tid = opts.target.pid = pid;
 145 
 146         /* Instead of perf_evlist__new_default, don't add default events */
 147         evlist = evlist__new();
 148         if (!evlist) {
 149                 pr_debug("Not enough memory to create evlist\n");
 150                 return TEST_FAIL;
 151         }
 152 
 153         err = perf_evlist__create_maps(evlist, &opts.target);
 154         if (err < 0) {
 155                 pr_debug("Not enough memory to create thread/cpu maps\n");
 156                 goto out_delete_evlist;
 157         }
 158 
 159         perf_evlist__splice_list_tail(evlist, &parse_state.list);
 160         evlist->nr_groups = parse_state.nr_groups;
 161 
 162         perf_evlist__config(evlist, &opts, NULL);
 163 
 164         err = evlist__open(evlist);
 165         if (err < 0) {
 166                 pr_debug("perf_evlist__open: %s\n",
 167                          str_error_r(errno, sbuf, sizeof(sbuf)));
 168                 goto out_delete_evlist;
 169         }
 170 
 171         err = evlist__mmap(evlist, opts.mmap_pages);
 172         if (err < 0) {
 173                 pr_debug("evlist__mmap: %s\n",
 174                          str_error_r(errno, sbuf, sizeof(sbuf)));
 175                 goto out_delete_evlist;
 176         }
 177 
 178         evlist__enable(evlist);
 179         (*func)();
 180         evlist__disable(evlist);
 181 
 182         for (i = 0; i < evlist->core.nr_mmaps; i++) {
 183                 union perf_event *event;
 184                 struct mmap *md;
 185 
 186                 md = &evlist->mmap[i];
 187                 if (perf_mmap__read_init(md) < 0)
 188                         continue;
 189 
 190                 while ((event = perf_mmap__read_event(md)) != NULL) {
 191                         const u32 type = event->header.type;
 192 
 193                         if (type == PERF_RECORD_SAMPLE)
 194                                 count ++;
 195                 }
 196                 perf_mmap__read_done(md);
 197         }
 198 
 199         if (count != expect) {
 200                 pr_debug("BPF filter result incorrect, expected %d, got %d samples\n", expect, count);
 201                 goto out_delete_evlist;
 202         }
 203 
 204         ret = TEST_OK;
 205 
 206 out_delete_evlist:
 207         evlist__delete(evlist);
 208         return ret;
 209 }
 210 
 211 static struct bpf_object *
 212 prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
 213 {
 214         struct bpf_object *obj;
 215 
 216         obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
 217         if (IS_ERR(obj)) {
 218                 pr_debug("Compile BPF program failed.\n");
 219                 return NULL;
 220         }
 221         return obj;
 222 }
 223 
 224 static int __test__bpf(int idx)
 225 {
 226         int ret;
 227         void *obj_buf;
 228         size_t obj_buf_sz;
 229         struct bpf_object *obj;
 230 
 231         ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
 232                                        bpf_testcase_table[idx].prog_id,
 233                                        true, NULL);
 234         if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
 235                 pr_debug("Unable to get BPF object, %s\n",
 236                          bpf_testcase_table[idx].msg_compile_fail);
 237                 if (idx == 0)
 238                         return TEST_SKIP;
 239                 else
 240                         return TEST_FAIL;
 241         }
 242 
 243         obj = prepare_bpf(obj_buf, obj_buf_sz,
 244                           bpf_testcase_table[idx].name);
 245         if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
 246                 if (!obj)
 247                         pr_debug("Fail to load BPF object: %s\n",
 248                                  bpf_testcase_table[idx].msg_load_fail);
 249                 else
 250                         pr_debug("Success unexpectedly: %s\n",
 251                                  bpf_testcase_table[idx].msg_load_fail);
 252                 ret = TEST_FAIL;
 253                 goto out;
 254         }
 255 
 256         if (obj) {
 257                 ret = do_test(obj,
 258                               bpf_testcase_table[idx].target_func,
 259                               bpf_testcase_table[idx].expect_result);
 260                 if (ret != TEST_OK)
 261                         goto out;
 262                 if (bpf_testcase_table[idx].pin) {
 263                         int err;
 264 
 265                         if (!bpf_fs__mount()) {
 266                                 pr_debug("BPF filesystem not mounted\n");
 267                                 ret = TEST_FAIL;
 268                                 goto out;
 269                         }
 270                         err = mkdir(PERF_TEST_BPF_PATH, 0777);
 271                         if (err && errno != EEXIST) {
 272                                 pr_debug("Failed to make perf_test dir: %s\n",
 273                                          strerror(errno));
 274                                 ret = TEST_FAIL;
 275                                 goto out;
 276                         }
 277                         if (bpf_object__pin(obj, PERF_TEST_BPF_PATH))
 278                                 ret = TEST_FAIL;
 279                         if (rm_rf(PERF_TEST_BPF_PATH))
 280                                 ret = TEST_FAIL;
 281                 }
 282         }
 283 
 284 out:
 285         bpf__clear();
 286         return ret;
 287 }
 288 
 289 int test__bpf_subtest_get_nr(void)
 290 {
 291         return (int)ARRAY_SIZE(bpf_testcase_table);
 292 }
 293 
 294 const char *test__bpf_subtest_get_desc(int i)
 295 {
 296         if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
 297                 return NULL;
 298         return bpf_testcase_table[i].desc;
 299 }
 300 
 301 static int check_env(void)
 302 {
 303         int err;
 304         unsigned int kver_int;
 305         char license[] = "GPL";
 306 
 307         struct bpf_insn insns[] = {
 308                 BPF_MOV64_IMM(BPF_REG_0, 1),
 309                 BPF_EXIT_INSN(),
 310         };
 311 
 312         err = fetch_kernel_version(&kver_int, NULL, 0);
 313         if (err) {
 314                 pr_debug("Unable to get kernel version\n");
 315                 return err;
 316         }
 317 
 318         err = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns,
 319                                sizeof(insns) / sizeof(insns[0]),
 320                                license, kver_int, NULL, 0);
 321         if (err < 0) {
 322                 pr_err("Missing basic BPF support, skip this test: %s\n",
 323                        strerror(errno));
 324                 return err;
 325         }
 326         close(err);
 327 
 328         return 0;
 329 }
 330 
 331 int test__bpf(struct test *test __maybe_unused, int i)
 332 {
 333         int err;
 334 
 335         if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
 336                 return TEST_FAIL;
 337 
 338         if (geteuid() != 0) {
 339                 pr_debug("Only root can run BPF test\n");
 340                 return TEST_SKIP;
 341         }
 342 
 343         if (check_env())
 344                 return TEST_SKIP;
 345 
 346         err = __test__bpf(i);
 347         return err;
 348 }
 349 
 350 #else
 351 int test__bpf_subtest_get_nr(void)
 352 {
 353         return 0;
 354 }
 355 
 356 const char *test__bpf_subtest_get_desc(int i __maybe_unused)
 357 {
 358         return NULL;
 359 }
 360 
 361 int test__bpf(struct test *test __maybe_unused, int i __maybe_unused)
 362 {
 363         pr_debug("Skip BPF test because BPF support is not compiled\n");
 364         return TEST_SKIP;
 365 }
 366 #endif

/* [<][>][^][v][top][bottom][index][help] */