1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2020 Facebook */ 3 4 #include <test_progs.h> 5 #include <sys/stat.h> 6 7 #include "test_link_pinning.skel.h" 8 9 static int duration = 0; 10 11 void test_link_pinning_subtest(struct bpf_program *prog, 12 struct test_link_pinning__bss *bss) 13 { 14 const char *link_pin_path = "/sys/fs/bpf/pinned_link_test"; 15 struct stat statbuf = {}; 16 struct bpf_link *link; 17 int err, i; 18 19 link = bpf_program__attach(prog); 20 if (CHECK(IS_ERR(link), "link_attach", "err: %ld\n", PTR_ERR(link))) 21 goto cleanup; 22 23 bss->in = 1; 24 usleep(1); 25 CHECK(bss->out != 1, "res_check1", "exp %d, got %d\n", 1, bss->out); 26 27 /* pin link */ 28 err = bpf_link__pin(link, link_pin_path); 29 if (CHECK(err, "link_pin", "err: %d\n", err)) 30 goto cleanup; 31 32 CHECK(strcmp(link_pin_path, bpf_link__pin_path(link)), "pin_path1", 33 "exp %s, got %s\n", link_pin_path, bpf_link__pin_path(link)); 34 35 /* check that link was pinned */ 36 err = stat(link_pin_path, &statbuf); 37 if (CHECK(err, "stat_link", "err %d errno %d\n", err, errno)) 38 goto cleanup; 39 40 bss->in = 2; 41 usleep(1); 42 CHECK(bss->out != 2, "res_check2", "exp %d, got %d\n", 2, bss->out); 43 44 /* destroy link, pinned link should keep program attached */ 45 bpf_link__destroy(link); 46 link = NULL; 47 48 bss->in = 3; 49 usleep(1); 50 CHECK(bss->out != 3, "res_check3", "exp %d, got %d\n", 3, bss->out); 51 52 /* re-open link from BPFFS */ 53 link = bpf_link__open(link_pin_path); 54 if (CHECK(IS_ERR(link), "link_open", "err: %ld\n", PTR_ERR(link))) 55 goto cleanup; 56 57 CHECK(strcmp(link_pin_path, bpf_link__pin_path(link)), "pin_path2", 58 "exp %s, got %s\n", link_pin_path, bpf_link__pin_path(link)); 59 60 /* unpin link from BPFFS, program still attached */ 61 err = bpf_link__unpin(link); 62 if (CHECK(err, "link_unpin", "err: %d\n", err)) 63 goto cleanup; 64 65 /* still active, as we have FD open now */ 66 bss->in = 4; 67 usleep(1); 68 CHECK(bss->out != 4, "res_check4", "exp %d, got %d\n", 4, bss->out); 69 70 bpf_link__destroy(link); 71 link = NULL; 72 73 /* Validate it's finally detached. 74 * Actual detachment might get delayed a bit, so there is no reliable 75 * way to validate it immediately here, let's count up for long enough 76 * and see if eventually output stops being updated 77 */ 78 for (i = 5; i < 10000; i++) { 79 bss->in = i; 80 usleep(1); 81 if (bss->out == i - 1) 82 break; 83 } 84 CHECK(i == 10000, "link_attached", "got to iteration #%d\n", i); 85 86 cleanup: 87 if (!IS_ERR(link)) 88 bpf_link__destroy(link); 89 } 90 91 void test_link_pinning(void) 92 { 93 struct test_link_pinning* skel; 94 95 skel = test_link_pinning__open_and_load(); 96 if (CHECK(!skel, "skel_open", "failed to open skeleton\n")) 97 return; 98 99 if (test__start_subtest("pin_raw_tp")) 100 test_link_pinning_subtest(skel->progs.raw_tp_prog, skel->bss); 101 if (test__start_subtest("pin_tp_btf")) 102 test_link_pinning_subtest(skel->progs.tp_btf_prog, skel->bss); 103 104 test_link_pinning__destroy(skel); 105 } 106