root/tools/testing/selftests/bpf/prog_tests/send_signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. sigusr1_handler
  2. test_send_signal_common
  3. test_send_signal_tracepoint
  4. test_send_signal_perf
  5. test_send_signal_nmi
  6. test_send_signal

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <test_progs.h>
   3 
   4 static volatile int sigusr1_received = 0;
   5 
   6 static void sigusr1_handler(int signum)
   7 {
   8         sigusr1_received++;
   9 }
  10 
  11 static void test_send_signal_common(struct perf_event_attr *attr,
  12                                     int prog_type,
  13                                     const char *test_name)
  14 {
  15         int err = -1, pmu_fd, prog_fd, info_map_fd, status_map_fd;
  16         const char *file = "./test_send_signal_kern.o";
  17         struct bpf_object *obj = NULL;
  18         int pipe_c2p[2], pipe_p2c[2];
  19         __u32 key = 0, duration = 0;
  20         char buf[256];
  21         pid_t pid;
  22         __u64 val;
  23 
  24         if (CHECK(pipe(pipe_c2p), test_name,
  25                   "pipe pipe_c2p error: %s\n", strerror(errno)))
  26                 return;
  27 
  28         if (CHECK(pipe(pipe_p2c), test_name,
  29                   "pipe pipe_p2c error: %s\n", strerror(errno))) {
  30                 close(pipe_c2p[0]);
  31                 close(pipe_c2p[1]);
  32                 return;
  33         }
  34 
  35         pid = fork();
  36         if (CHECK(pid < 0, test_name, "fork error: %s\n", strerror(errno))) {
  37                 close(pipe_c2p[0]);
  38                 close(pipe_c2p[1]);
  39                 close(pipe_p2c[0]);
  40                 close(pipe_p2c[1]);
  41                 return;
  42         }
  43 
  44         if (pid == 0) {
  45                 /* install signal handler and notify parent */
  46                 signal(SIGUSR1, sigusr1_handler);
  47 
  48                 close(pipe_c2p[0]); /* close read */
  49                 close(pipe_p2c[1]); /* close write */
  50 
  51                 /* notify parent signal handler is installed */
  52                 write(pipe_c2p[1], buf, 1);
  53 
  54                 /* make sure parent enabled bpf program to send_signal */
  55                 read(pipe_p2c[0], buf, 1);
  56 
  57                 /* wait a little for signal handler */
  58                 sleep(1);
  59 
  60                 if (sigusr1_received)
  61                         write(pipe_c2p[1], "2", 1);
  62                 else
  63                         write(pipe_c2p[1], "0", 1);
  64 
  65                 /* wait for parent notification and exit */
  66                 read(pipe_p2c[0], buf, 1);
  67 
  68                 close(pipe_c2p[1]);
  69                 close(pipe_p2c[0]);
  70                 exit(0);
  71         }
  72 
  73         close(pipe_c2p[1]); /* close write */
  74         close(pipe_p2c[0]); /* close read */
  75 
  76         err = bpf_prog_load(file, prog_type, &obj, &prog_fd);
  77         if (CHECK(err < 0, test_name, "bpf_prog_load error: %s\n",
  78                   strerror(errno)))
  79                 goto prog_load_failure;
  80 
  81         pmu_fd = syscall(__NR_perf_event_open, attr, pid, -1,
  82                          -1 /* group id */, 0 /* flags */);
  83         if (CHECK(pmu_fd < 0, test_name, "perf_event_open error: %s\n",
  84                   strerror(errno))) {
  85                 err = -1;
  86                 goto close_prog;
  87         }
  88 
  89         err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0);
  90         if (CHECK(err < 0, test_name, "ioctl perf_event_ioc_enable error: %s\n",
  91                   strerror(errno)))
  92                 goto disable_pmu;
  93 
  94         err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
  95         if (CHECK(err < 0, test_name, "ioctl perf_event_ioc_set_bpf error: %s\n",
  96                   strerror(errno)))
  97                 goto disable_pmu;
  98 
  99         err = -1;
 100         info_map_fd = bpf_object__find_map_fd_by_name(obj, "info_map");
 101         if (CHECK(info_map_fd < 0, test_name, "find map %s error\n", "info_map"))
 102                 goto disable_pmu;
 103 
 104         status_map_fd = bpf_object__find_map_fd_by_name(obj, "status_map");
 105         if (CHECK(status_map_fd < 0, test_name, "find map %s error\n", "status_map"))
 106                 goto disable_pmu;
 107 
 108         /* wait until child signal handler installed */
 109         read(pipe_c2p[0], buf, 1);
 110 
 111         /* trigger the bpf send_signal */
 112         key = 0;
 113         val = (((__u64)(SIGUSR1)) << 32) | pid;
 114         bpf_map_update_elem(info_map_fd, &key, &val, 0);
 115 
 116         /* notify child that bpf program can send_signal now */
 117         write(pipe_p2c[1], buf, 1);
 118 
 119         /* wait for result */
 120         err = read(pipe_c2p[0], buf, 1);
 121         if (CHECK(err < 0, test_name, "reading pipe error: %s\n", strerror(errno)))
 122                 goto disable_pmu;
 123         if (CHECK(err == 0, test_name, "reading pipe error: size 0\n")) {
 124                 err = -1;
 125                 goto disable_pmu;
 126         }
 127 
 128         CHECK(buf[0] != '2', test_name, "incorrect result\n");
 129 
 130         /* notify child safe to exit */
 131         write(pipe_p2c[1], buf, 1);
 132 
 133 disable_pmu:
 134         close(pmu_fd);
 135 close_prog:
 136         bpf_object__close(obj);
 137 prog_load_failure:
 138         close(pipe_c2p[0]);
 139         close(pipe_p2c[1]);
 140         wait(NULL);
 141 }
 142 
 143 static void test_send_signal_tracepoint(void)
 144 {
 145         const char *id_path = "/sys/kernel/debug/tracing/events/syscalls/sys_enter_nanosleep/id";
 146         struct perf_event_attr attr = {
 147                 .type = PERF_TYPE_TRACEPOINT,
 148                 .sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN,
 149                 .sample_period = 1,
 150                 .wakeup_events = 1,
 151         };
 152         __u32 duration = 0;
 153         int bytes, efd;
 154         char buf[256];
 155 
 156         efd = open(id_path, O_RDONLY, 0);
 157         if (CHECK(efd < 0, "tracepoint",
 158                   "open syscalls/sys_enter_nanosleep/id failure: %s\n",
 159                   strerror(errno)))
 160                 return;
 161 
 162         bytes = read(efd, buf, sizeof(buf));
 163         close(efd);
 164         if (CHECK(bytes <= 0 || bytes >= sizeof(buf), "tracepoint",
 165                   "read syscalls/sys_enter_nanosleep/id failure: %s\n",
 166                   strerror(errno)))
 167                 return;
 168 
 169         attr.config = strtol(buf, NULL, 0);
 170 
 171         test_send_signal_common(&attr, BPF_PROG_TYPE_TRACEPOINT, "tracepoint");
 172 }
 173 
 174 static void test_send_signal_perf(void)
 175 {
 176         struct perf_event_attr attr = {
 177                 .sample_period = 1,
 178                 .type = PERF_TYPE_SOFTWARE,
 179                 .config = PERF_COUNT_SW_CPU_CLOCK,
 180         };
 181 
 182         test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
 183                                 "perf_sw_event");
 184 }
 185 
 186 static void test_send_signal_nmi(void)
 187 {
 188         struct perf_event_attr attr = {
 189                 .sample_freq = 50,
 190                 .freq = 1,
 191                 .type = PERF_TYPE_HARDWARE,
 192                 .config = PERF_COUNT_HW_CPU_CYCLES,
 193         };
 194         int pmu_fd;
 195 
 196         /* Some setups (e.g. virtual machines) might run with hardware
 197          * perf events disabled. If this is the case, skip this test.
 198          */
 199         pmu_fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */,
 200                          -1 /* cpu */, -1 /* group_fd */, 0 /* flags */);
 201         if (pmu_fd == -1) {
 202                 if (errno == ENOENT) {
 203                         printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n",
 204                                __func__);
 205                         test__skip();
 206                         return;
 207                 }
 208                 /* Let the test fail with a more informative message */
 209         } else {
 210                 close(pmu_fd);
 211         }
 212 
 213         test_send_signal_common(&attr, BPF_PROG_TYPE_PERF_EVENT,
 214                                 "perf_hw_event");
 215 }
 216 
 217 void test_send_signal(void)
 218 {
 219         if (test__start_subtest("send_signal_tracepoint"))
 220                 test_send_signal_tracepoint();
 221         if (test__start_subtest("send_signal_perf"))
 222                 test_send_signal_perf();
 223         if (test__start_subtest("send_signal_nmi"))
 224                 test_send_signal_nmi();
 225 }

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