• 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 <sys/resource.h>
15 #include <iostream>
16 
17 #include "BPF.h"
18 
19 const std::string BPF_PROGRAM = R"(
20 #include <linux/sched.h>
21 #include <uapi/linux/ptrace.h>
22 
23 #ifndef CGROUP_FILTER
24 #define CGROUP_FILTER 0
25 #endif
26 
27 struct event_t {
28   int pid;
29   char comm[16];
30   int cpu;
31   int got_bits;
32 };
33 
34 BPF_PERF_OUTPUT(events);
35 BPF_CGROUP_ARRAY(cgroup, 1);
36 
37 int on_urandom_read(struct bpf_raw_tracepoint_args *ctx) {
38   if (CGROUP_FILTER && (cgroup.check_current_task(0) != 1))
39     return 0;
40 
41   struct event_t event = {};
42   event.pid = bpf_get_current_pid_tgid();
43   bpf_get_current_comm(&event.comm, sizeof(event.comm));
44   event.cpu = bpf_get_smp_processor_id();
45   // from include/trace/events/random.h:
46   //    TP_PROTO(int got_bits, int pool_left, int input_left)
47   event.got_bits = ctx->args[0];
48 
49   events.perf_submit(ctx, &event, sizeof(event));
50   return 0;
51 }
52 )";
53 
54 // Define the same struct to use in user space.
55 struct event_t {
56   int pid;
57   char comm[16];
58   int cpu;
59   int got_bits;
60 };
61 
handle_output(void * cb_cookie,void * data,int data_size)62 void handle_output(void* cb_cookie, void* data, int data_size) {
63   auto event = static_cast<event_t*>(data);
64   std::cout << "PID: " << event->pid << " (" << event->comm << ") on CPU "
65             << event->cpu << " read " << event->got_bits << " bits"
66             << std::endl;
67 }
68 
69 ebpf::BPF* bpf;
70 
signal_handler(int s)71 void signal_handler(int s) {
72   std::cerr << "Terminating..." << std::endl;
73   delete bpf;
74   exit(0);
75 }
76 
usage(void)77 void usage(void) {
78   std::cerr << "USAGE: RandomRead [{-r|-u} [cgroup2_path]]" << std::endl;
79 }
80 
main(int argc,char ** argv)81 int main(int argc, char** argv) {
82   if (argc > 3) {
83     usage();
84     return 1;
85   }
86 
87   bool allow_rlimit = true;
88   if (argc >= 2) {
89     // Set a small rlimit for MEMLOCK
90     struct rlimit rlim_new = {4096, 4096};
91     setrlimit(RLIMIT_MEMLOCK, &rlim_new);
92 
93     if (strcmp(argv[1], "-r") == 0) {
94       allow_rlimit = false;
95     } else if (strcmp(argv[1], "-u") == 0) {
96       allow_rlimit = true;
97     } else {
98       usage();
99       return 1;
100     }
101   }
102 
103   std::vector<std::string> cflags = {};
104   if (argc == 3)
105     cflags.emplace_back("-DCGROUP_FILTER=1");
106 
107   bpf = new ebpf::BPF(0, nullptr, true, "", allow_rlimit);
108   auto init_res = bpf->init(BPF_PROGRAM, cflags, {});
109   if (!init_res.ok()) {
110     std::cerr << init_res.msg() << std::endl;
111     return 1;
112   }
113   if (argc == 3) {
114     auto cgroup_array = bpf->get_cgroup_array("cgroup");
115     auto update_res = cgroup_array.update_value(0, argv[2]);
116     if (!update_res.ok()) {
117       std::cerr << update_res.msg() << std::endl;
118       return 1;
119     }
120   }
121 
122   auto attach_res =
123       bpf->attach_raw_tracepoint("urandom_read", "on_urandom_read");
124   if (!attach_res.ok()) {
125     std::cerr << attach_res.msg() << std::endl;
126     return 1;
127   }
128 
129   auto open_res = bpf->open_perf_buffer("events", &handle_output);
130   if (!open_res.ok()) {
131     std::cerr << open_res.msg() << std::endl;
132     return 1;
133   }
134 
135   // done with all initial work, free bcc memory
136   if (bpf->free_bcc_memory()) {
137     std::cerr << "Failed to free llvm/clang memory" << std::endl;
138     return 1;
139   }
140 
141   signal(SIGINT, signal_handler);
142   std::cout << "Started tracing, hit Ctrl-C to terminate." << std::endl;
143   while (true)
144     bpf->poll_perf_buffer("events");
145 
146   return 0;
147 }
148