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