• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * RandomRead Monitor random number read events.
3  *            For Linux, uses BCC, eBPF. Embedded C.
4  *
5  * Basic example of BCC Tracepoint and perf buffer.
6  *
7  * USAGE: RandomRead
8  *
9  * Copyright (c) Facebook, Inc.
10  * Licensed under the Apache License, Version 2.0 (the "License")
11  */
12 
13 #include <signal.h>
14 #include <iostream>
15 
16 #include "BPF.h"
17 
18 const std::string BPF_PROGRAM = R"(
19 #include <linux/sched.h>
20 #include <uapi/linux/ptrace.h>
21 
22 #ifndef CGROUP_FILTER
23 #define CGROUP_FILTER 0
24 #endif
25 
26 struct urandom_read_args {
27   // See /sys/kernel/debug/tracing/events/random/urandom_read/format
28   uint64_t common__unused;
29   int got_bits;
30   int pool_left;
31   int input_left;
32 };
33 
34 struct event_t {
35   int pid;
36   char comm[16];
37   int cpu;
38   int got_bits;
39 };
40 
41 BPF_PERF_OUTPUT(events);
42 BPF_CGROUP_ARRAY(cgroup, 1);
43 
44 int on_urandom_read(struct urandom_read_args* attr) {
45   if (CGROUP_FILTER && (cgroup.check_current_task(0) != 1))
46     return 0;
47 
48   struct event_t event = {};
49   event.pid = bpf_get_current_pid_tgid();
50   bpf_get_current_comm(&event.comm, sizeof(event.comm));
51   event.cpu = bpf_get_smp_processor_id();
52   event.got_bits = attr->got_bits;
53 
54   events.perf_submit(attr, &event, sizeof(event));
55   return 0;
56 }
57 )";
58 
59 // Define the same struct to use in user space.
60 struct event_t {
61   int pid;
62   char comm[16];
63   int cpu;
64   int got_bits;
65 };
66 
handle_output(void * cb_cookie,void * data,int data_size)67 void handle_output(void* cb_cookie, void* data, int data_size) {
68   auto event = static_cast<event_t*>(data);
69   std::cout << "PID: " << event->pid << " (" << event->comm << ") on CPU "
70             << event->cpu << " read " << event->got_bits << " bits"
71             << std::endl;
72 }
73 
74 ebpf::BPF* bpf;
75 
signal_handler(int s)76 void signal_handler(int s) {
77   std::cerr << "Terminating..." << std::endl;
78   delete bpf;
79   exit(0);
80 }
81 
main(int argc,char ** argv)82 int main(int argc, char** argv) {
83   if (argc != 1 && argc != 2) {
84     std::cerr << "USAGE: RandomRead [cgroup2_path]" << std::endl;
85     return 1;
86   }
87 
88   std::vector<std::string> cflags = {};
89   if (argc == 2)
90     cflags.emplace_back("-DCGROUP_FILTER=1");
91 
92   bpf = new ebpf::BPF();
93   auto init_res = bpf->init(BPF_PROGRAM, cflags, {});
94   if (init_res.code() != 0) {
95     std::cerr << init_res.msg() << std::endl;
96     return 1;
97   }
98   if (argc == 2) {
99     auto cgroup_array = bpf->get_cgroup_array("cgroup");
100     auto update_res = cgroup_array.update_value(0, argv[1]);
101     if (update_res.code() != 0) {
102       std::cerr << update_res.msg() << std::endl;
103       return 1;
104     }
105   }
106 
107   auto attach_res =
108       bpf->attach_tracepoint("random:urandom_read", "on_urandom_read");
109   if (attach_res.code() != 0) {
110     std::cerr << attach_res.msg() << std::endl;
111     return 1;
112   }
113 
114   auto open_res = bpf->open_perf_buffer("events", &handle_output);
115   if (open_res.code() != 0) {
116     std::cerr << open_res.msg() << std::endl;
117     return 1;
118   }
119 
120   signal(SIGINT, signal_handler);
121   std::cout << "Started tracing, hit Ctrl-C to terminate." << std::endl;
122   while (true)
123     bpf->poll_perf_buffer("events");
124 
125   return 0;
126 }
127