Commit 3bb44859 authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #1716 from palmtenor/cppmisc

Misc improvements to C++ API and example
parents bbc3fbfe ce657b11
...@@ -83,10 +83,11 @@ int main(int argc, char** argv) { ...@@ -83,10 +83,11 @@ int main(int argc, char** argv) {
auto table_handle = bpf.get_hash_table<query_probe_t, int>("queries"); auto table_handle = bpf.get_hash_table<query_probe_t, int>("queries");
auto table = table_handle.get_table_offline(); auto table = table_handle.get_table_offline();
std::sort(table.begin(), table.end(), [](std::pair<query_probe_t, int> a, std::sort(
std::pair<query_probe_t, int> b) { table.begin(), table.end(),
return a.first.ts < b.first.ts; [](std::pair<query_probe_t, int> a, std::pair<query_probe_t, int> b) {
}); return a.first.ts < b.first.ts;
});
std::cout << table.size() << " queries recorded:" << std::endl; std::cout << table.size() << " queries recorded:" << std::endl;
for (auto it : table) { for (auto it : table) {
std::cout << "Time: " << it.first.ts << " PID: " << it.first.pid std::cout << "Time: " << it.first.ts << " PID: " << it.first.pid
......
...@@ -27,17 +27,15 @@ struct stack_key_t { ...@@ -27,17 +27,15 @@ struct stack_key_t {
int kernel_stack; int kernel_stack;
}; };
BPF_STACK_TRACE(stack_traces, 10240); BPF_STACK_TRACE(stack_traces, 16384);
BPF_HASH(counts, struct stack_key_t, uint64_t); BPF_HASH(counts, struct stack_key_t, uint64_t);
int on_tcp_send(struct pt_regs *ctx) { int on_tcp_send(struct pt_regs *ctx) {
struct stack_key_t key = {}; struct stack_key_t key = {};
key.pid = bpf_get_current_pid_tgid() >> 32; key.pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&key.name, sizeof(key.name)); bpf_get_current_comm(&key.name, sizeof(key.name));
key.kernel_stack = stack_traces.get_stackid(ctx, BPF_F_REUSE_STACKID); key.kernel_stack = stack_traces.get_stackid(ctx, 0);
key.user_stack = stack_traces.get_stackid( key.user_stack = stack_traces.get_stackid(ctx, BPF_F_USER_STACK);
ctx, BPF_F_REUSE_STACKID | BPF_F_USER_STACK
);
u64 zero = 0, *val; u64 zero = 0, *val;
val = counts.lookup_or_init(&key, &zero); val = counts.lookup_or_init(&key, &zero);
...@@ -76,39 +74,56 @@ int main(int argc, char** argv) { ...@@ -76,39 +74,56 @@ int main(int argc, char** argv) {
std::cout << "Probing for " << probe_time << " seconds" << std::endl; std::cout << "Probing for " << probe_time << " seconds" << std::endl;
sleep(probe_time); sleep(probe_time);
auto detach_res = bpf.detach_kprobe("tcp_sendmsg");
if (detach_res.code() != 0) {
std::cerr << detach_res.msg() << std::endl;
return 1;
}
auto table = auto table =
bpf.get_hash_table<stack_key_t, uint64_t>("counts").get_table_offline(); bpf.get_hash_table<stack_key_t, uint64_t>("counts").get_table_offline();
std::sort(table.begin(), table.end(), [](std::pair<stack_key_t, uint64_t> a, std::sort(
std::pair<stack_key_t, uint64_t> b) { table.begin(), table.end(),
return a.second < b.second; [](std::pair<stack_key_t, uint64_t> a,
}); std::pair<stack_key_t, uint64_t> b) { return a.second < b.second; });
auto stacks = bpf.get_stack_table("stack_traces"); auto stacks = bpf.get_stack_table("stack_traces");
int lost_stacks = 0;
for (auto it : table) { for (auto it : table) {
std::cout << "PID: " << it.first.pid << " (" << it.first.name << ") " std::cout << "PID: " << it.first.pid << " (" << it.first.name << ") "
<< "made " << it.second << "made " << it.second
<< " TCP sends on following stack: " << std::endl; << " TCP sends on following stack: " << std::endl;
std::cout << " Kernel Stack:" << std::endl;
if (it.first.kernel_stack >= 0) { if (it.first.kernel_stack >= 0) {
std::cout << " Kernel Stack:" << std::endl;
auto syms = stacks.get_stack_symbol(it.first.kernel_stack, -1); auto syms = stacks.get_stack_symbol(it.first.kernel_stack, -1);
for (auto sym : syms) for (auto sym : syms)
std::cout << " " << sym << std::endl; std::cout << " " << sym << std::endl;
} else } else {
std::cout << " " << it.first.kernel_stack << std::endl; // -EFAULT normally means the stack is not availiable and not an error
std::cout << " User Stack:" << std::endl; if (it.first.kernel_stack != -EFAULT) {
lost_stacks++;
std::cout << " [Lost Kernel Stack" << it.first.kernel_stack << "]"
<< std::endl;
}
}
if (it.first.user_stack >= 0) { if (it.first.user_stack >= 0) {
std::cout << " User Stack:" << std::endl;
auto syms = stacks.get_stack_symbol(it.first.user_stack, it.first.pid); auto syms = stacks.get_stack_symbol(it.first.user_stack, it.first.pid);
for (auto sym : syms) for (auto sym : syms)
std::cout << " " << sym << std::endl; std::cout << " " << sym << std::endl;
} else } else {
std::cout << " " << it.first.user_stack << std::endl; // -EFAULT normally means the stack is not availiable and not an error
if (it.first.user_stack != -EFAULT) {
lost_stacks++;
std::cout << " [Lost User Stack " << it.first.user_stack << "]"
<< std::endl;
}
}
} }
auto detach_res = bpf.detach_kprobe("tcp_sendmsg"); if (lost_stacks > 0)
if (detach_res.code() != 0) { std::cout << "Total " << lost_stacks << " stack-traces lost due to "
std::cerr << detach_res.msg() << std::endl; << "hash collision or stack table full" << std::endl;
return 1;
}
return 0; return 0;
} }
...@@ -39,9 +39,9 @@ ...@@ -39,9 +39,9 @@
namespace ebpf { namespace ebpf {
static const char *syscall_prefix[] = { static const char* syscall_prefix[] = {
"sys_", "sys_",
"__x64_sys_", "__x64_sys_",
}; };
std::string uint_to_hex(uint64_t value) { std::string uint_to_hex(uint64_t value) {
...@@ -63,7 +63,7 @@ StatusTuple BPF::init(const std::string& bpf_program, ...@@ -63,7 +63,7 @@ StatusTuple BPF::init(const std::string& bpf_program,
const std::vector<USDT>& usdt) { const std::vector<USDT>& usdt) {
std::string all_bpf_program; std::string all_bpf_program;
bcc_symbol_option symbol_option = {}; bcc_symbol_option symbol_option = {};
void *ksym_cache; void* ksym_cache;
uint64_t addr; uint64_t addr;
int ret; int ret;
...@@ -284,8 +284,8 @@ StatusTuple BPF::attach_tracepoint(const std::string& tracepoint, ...@@ -284,8 +284,8 @@ StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
int probe_fd; int probe_fd;
TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd)); TRY2(load_func(probe_func, BPF_PROG_TYPE_TRACEPOINT, probe_fd));
int res_fd = bpf_attach_tracepoint(probe_fd, tp_category.c_str(), int res_fd =
tp_name.c_str()); bpf_attach_tracepoint(probe_fd, tp_category.c_str(), tp_name.c_str());
if (res_fd < 0) { if (res_fd < 0) {
TRY2(unload_func(probe_func)); TRY2(unload_func(probe_func));
...@@ -341,8 +341,8 @@ StatusTuple BPF::attach_perf_event(uint32_t ev_type, uint32_t ev_config, ...@@ -341,8 +341,8 @@ StatusTuple BPF::attach_perf_event(uint32_t ev_type, uint32_t ev_config,
} }
StatusTuple BPF::attach_perf_event_raw(void* perf_event_attr, StatusTuple BPF::attach_perf_event_raw(void* perf_event_attr,
const std::string& probe_func, const std::string& probe_func, pid_t pid,
pid_t pid, int cpu, int group_fd) { int cpu, int group_fd) {
auto attr = static_cast<struct perf_event_attr*>(perf_event_attr); auto attr = static_cast<struct perf_event_attr*>(perf_event_attr);
auto ev_pair = std::make_pair(attr->type, attr->config); auto ev_pair = std::make_pair(attr->type, attr->config);
if (perf_events_.find(ev_pair) != perf_events_.end()) if (perf_events_.find(ev_pair) != perf_events_.end())
...@@ -377,7 +377,6 @@ StatusTuple BPF::attach_perf_event_raw(void* perf_event_attr, ...@@ -377,7 +377,6 @@ StatusTuple BPF::attach_perf_event_raw(void* perf_event_attr,
p.per_cpu_fd = fds; p.per_cpu_fd = fds;
perf_events_[ev_pair] = std::move(p); perf_events_[ev_pair] = std::move(p);
return StatusTuple(0); return StatusTuple(0);
} }
StatusTuple BPF::detach_kprobe(const std::string& kernel_func, StatusTuple BPF::detach_kprobe(const std::string& kernel_func,
...@@ -567,7 +566,7 @@ StatusTuple BPF::unload_func(const std::string& func_name) { ...@@ -567,7 +566,7 @@ StatusTuple BPF::unload_func(const std::string& func_name) {
return StatusTuple(0); return StatusTuple(0);
} }
std::string BPF::get_syscall_fnname(const std::string &name) { std::string BPF::get_syscall_fnname(const std::string& name) {
std::string fn_name = syscall_prefix[syscall_prefix_idx_] + name; std::string fn_name = syscall_prefix[syscall_prefix_idx_] + name;
return std::move(fn_name); return std::move(fn_name);
} }
......
...@@ -47,7 +47,8 @@ class BPF { ...@@ -47,7 +47,8 @@ class BPF {
explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr, explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr,
bool rw_engine_enabled = true) bool rw_engine_enabled = true)
: flag_(flag), syscall_prefix_idx_(0), : flag_(flag),
syscall_prefix_idx_(0),
bpf_module_(new BPFModule(flag, ts, rw_engine_enabled)) {} bpf_module_(new BPFModule(flag, ts, rw_engine_enabled)) {}
StatusTuple init(const std::string& bpf_program, StatusTuple init(const std::string& bpf_program,
const std::vector<std::string>& cflags = {}, const std::vector<std::string>& cflags = {},
...@@ -91,7 +92,7 @@ class BPF { ...@@ -91,7 +92,7 @@ class BPF {
int group_fd = -1); int group_fd = -1);
StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config); StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config);
StatusTuple detach_perf_event_raw(void* perf_event_attr); StatusTuple detach_perf_event_raw(void* perf_event_attr);
std::string get_syscall_fnname(const std::string &name); std::string get_syscall_fnname(const std::string& name);
BPFTable get_table(const std::string& name) { BPFTable get_table(const std::string& name) {
TableStorage::iterator it; TableStorage::iterator it;
...@@ -109,7 +110,8 @@ class BPF { ...@@ -109,7 +110,8 @@ class BPF {
} }
template <class ValueType> template <class ValueType>
BPFPercpuArrayTable<ValueType> get_percpu_array_table(const std::string& name) { BPFPercpuArrayTable<ValueType> get_percpu_array_table(
const std::string& name) {
TableStorage::iterator it; TableStorage::iterator it;
if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
return BPFPercpuArrayTable<ValueType>(it->second); return BPFPercpuArrayTable<ValueType>(it->second);
...@@ -125,7 +127,8 @@ class BPF { ...@@ -125,7 +127,8 @@ class BPF {
} }
template <class KeyType, class ValueType> template <class KeyType, class ValueType>
BPFPercpuHashTable<KeyType, ValueType> get_percpu_hash_table(const std::string& name) { BPFPercpuHashTable<KeyType, ValueType> get_percpu_hash_table(
const std::string& name) {
TableStorage::iterator it; TableStorage::iterator it;
if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it)) if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
return BPFPercpuHashTable<KeyType, ValueType>(it->second); return BPFPercpuHashTable<KeyType, ValueType>(it->second);
...@@ -159,9 +162,9 @@ class BPF { ...@@ -159,9 +162,9 @@ class BPF {
BPFPerfBuffer* get_perf_buffer(const std::string& name); BPFPerfBuffer* get_perf_buffer(const std::string& name);
// Poll an opened Perf Buffer of given name with given timeout, using callback // Poll an opened Perf Buffer of given name with given timeout, using callback
// provided when opening. Do nothing if such open Perf Buffer doesn't exist. // provided when opening. Do nothing if such open Perf Buffer doesn't exist.
// Returns: // Returns:
// -1 on error or if perf buffer with such name doesn't exist; // -1 on error or if perf buffer with such name doesn't exist;
// 0, if no data was available before timeout; // 0, if no data was available before timeout;
// number of CPUs that have new data, otherwise. // number of CPUs that have new data, otherwise.
int poll_perf_buffer(const std::string& name, int timeout_ms = -1); int poll_perf_buffer(const std::string& name, int timeout_ms = -1);
......
...@@ -14,10 +14,10 @@ ...@@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
#include <fcntl.h>
#include <linux/elf.h> #include <linux/elf.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <cerrno> #include <cerrno>
#include <cinttypes> #include <cinttypes>
...@@ -145,28 +145,25 @@ StatusTuple BPFTable::remove_value(const std::string& key_str) { ...@@ -145,28 +145,25 @@ StatusTuple BPFTable::remove_value(const std::string& key_str) {
} }
StatusTuple BPFTable::clear_table_non_atomic() { StatusTuple BPFTable::clear_table_non_atomic() {
if (desc.type == BPF_MAP_TYPE_HASH || if (desc.type == BPF_MAP_TYPE_HASH || desc.type == BPF_MAP_TYPE_PERCPU_HASH ||
desc.type == BPF_MAP_TYPE_PERCPU_HASH ||
desc.type == BPF_MAP_TYPE_LRU_HASH || desc.type == BPF_MAP_TYPE_LRU_HASH ||
desc.type == BPF_MAP_TYPE_PERCPU_HASH || desc.type == BPF_MAP_TYPE_PERCPU_HASH ||
desc.type == BPF_MAP_TYPE_HASH_OF_MAPS) { desc.type == BPF_MAP_TYPE_HASH_OF_MAPS) {
// For hash maps, use the first() interface (which uses get_next_key) to // For hash maps, use the first() interface (which uses get_next_key) to
// iterate through the map and clear elements // iterate through the map and clear elements
auto key = std::unique_ptr<void, decltype(::free)*>( auto key = std::unique_ptr<void, decltype(::free)*>(::malloc(desc.key_size),
::malloc(desc.key_size), ::free);
::free);
while (this->first(key.get())) while (this->first(key.get()))
if (!this->remove(key.get())) { if (!this->remove(key.get())) {
return StatusTuple( return StatusTuple(-1,
-1, "Failed to delete element when clearing table %s",
"Failed to delete element when clearing table %s", desc.name.c_str());
desc.name.c_str());
} }
} else if (desc.type == BPF_MAP_TYPE_ARRAY || } else if (desc.type == BPF_MAP_TYPE_ARRAY ||
desc.type == BPF_MAP_TYPE_PERCPU_ARRAY) { desc.type == BPF_MAP_TYPE_PERCPU_ARRAY) {
return StatusTuple( return StatusTuple(-1, "Array map %s do not support clearing elements",
-1, "Array map %s do not support clearing elements", desc.name.c_str()); desc.name.c_str());
} else if (desc.type == BPF_MAP_TYPE_PROG_ARRAY || } else if (desc.type == BPF_MAP_TYPE_PROG_ARRAY ||
desc.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || desc.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY ||
desc.type == BPF_MAP_TYPE_STACK_TRACE || desc.type == BPF_MAP_TYPE_STACK_TRACE ||
...@@ -176,26 +173,25 @@ StatusTuple BPFTable::clear_table_non_atomic() { ...@@ -176,26 +173,25 @@ StatusTuple BPFTable::clear_table_non_atomic() {
this->remove(&i); this->remove(&i);
} }
} else { } else {
return StatusTuple( return StatusTuple(-1, "Clearing for map type of %s not supported yet",
-1, "Clearing for map type of %s not supported yet", desc.name.c_str()); desc.name.c_str());
} }
return StatusTuple(0); return StatusTuple(0);
} }
size_t BPFTable::get_possible_cpu_count() { size_t BPFTable::get_possible_cpu_count() { return get_possible_cpus().size(); }
return get_possible_cpus().size();
}
BPFStackTable::BPFStackTable(const TableDesc& desc, BPFStackTable::BPFStackTable(const TableDesc& desc, bool use_debug_file,
bool use_debug_file,
bool check_debug_file_crc) bool check_debug_file_crc)
: BPFTableBase<int, stacktrace_t>(desc) { : BPFTableBase<int, stacktrace_t>(desc) {
symbol_option_ = { if (desc.type != BPF_MAP_TYPE_STACK_TRACE)
.use_debug_file = use_debug_file, throw std::invalid_argument("Table '" + desc.name +
.check_debug_file_crc = check_debug_file_crc, "' is not a stack table");
.use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)
}; symbol_option_ = {.use_debug_file = use_debug_file,
.check_debug_file_crc = check_debug_file_crc,
.use_symbol_type = (1 << STT_FUNC) | (1 << STT_GNU_IFUNC)};
} }
BPFStackTable::BPFStackTable(BPFStackTable&& that) BPFStackTable::BPFStackTable(BPFStackTable&& that)
...@@ -254,6 +250,13 @@ std::vector<std::string> BPFStackTable::get_stack_symbol(int stack_id, ...@@ -254,6 +250,13 @@ std::vector<std::string> BPFStackTable::get_stack_symbol(int stack_id,
return res; return res;
} }
BPFPerfBuffer::BPFPerfBuffer(const TableDesc& desc)
: BPFTableBase<int, int>(desc), epfd_(-1) {
if (desc.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
throw std::invalid_argument("Table '" + desc.name +
"' is not a perf buffer");
}
StatusTuple BPFPerfBuffer::open_on_cpu(perf_reader_raw_cb cb, StatusTuple BPFPerfBuffer::open_on_cpu(perf_reader_raw_cb cb,
perf_reader_lost_cb lost_cb, int cpu, perf_reader_lost_cb lost_cb, int cpu,
void* cb_cookie, int page_cnt) { void* cb_cookie, int page_cnt) {
...@@ -350,7 +353,8 @@ StatusTuple BPFPerfBuffer::close_all_cpu() { ...@@ -350,7 +353,8 @@ StatusTuple BPFPerfBuffer::close_all_cpu() {
int BPFPerfBuffer::poll(int timeout_ms) { int BPFPerfBuffer::poll(int timeout_ms) {
if (epfd_ < 0) if (epfd_ < 0)
return -1; return -1;
int cnt = epoll_wait(epfd_, ep_events_.get(), cpu_readers_.size(), timeout_ms); int cnt =
epoll_wait(epfd_, ep_events_.get(), cpu_readers_.size(), timeout_ms);
for (int i = 0; i < cnt; i++) for (int i = 0; i < cnt; i++)
perf_reader_event_read(static_cast<perf_reader*>(ep_events_[i].data.ptr)); perf_reader_event_read(static_cast<perf_reader*>(ep_events_[i].data.ptr));
return cnt; return cnt;
...@@ -363,6 +367,13 @@ BPFPerfBuffer::~BPFPerfBuffer() { ...@@ -363,6 +367,13 @@ BPFPerfBuffer::~BPFPerfBuffer() {
<< std::endl; << std::endl;
} }
BPFPerfEventArray::BPFPerfEventArray(const TableDesc& desc)
: BPFTableBase<int, int>(desc) {
if (desc.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY)
throw std::invalid_argument("Table '" + desc.name +
"' is not a perf event array");
}
StatusTuple BPFPerfEventArray::open_all_cpu(uint32_t type, uint64_t config) { StatusTuple BPFPerfEventArray::open_all_cpu(uint32_t type, uint64_t config) {
if (cpu_fds_.size() != 0) if (cpu_fds_.size() != 0)
return StatusTuple(-1, "Previously opened perf event not cleaned"); return StatusTuple(-1, "Previously opened perf event not cleaned");
...@@ -411,8 +422,8 @@ StatusTuple BPFPerfEventArray::open_on_cpu(int cpu, uint32_t type, ...@@ -411,8 +422,8 @@ StatusTuple BPFPerfEventArray::open_on_cpu(int cpu, uint32_t type,
} }
if (!update(&cpu, &fd)) { if (!update(&cpu, &fd)) {
bpf_close_perf_event_fd(fd); bpf_close_perf_event_fd(fd);
return StatusTuple(-1, "Unable to open perf event on CPU %d: %s", return StatusTuple(-1, "Unable to open perf event on CPU %d: %s", cpu,
cpu, std::strerror(errno)); std::strerror(errno));
} }
cpu_fds_[cpu] = fd; cpu_fds_[cpu] = fd;
return StatusTuple(0); return StatusTuple(0);
...@@ -436,6 +447,13 @@ BPFPerfEventArray::~BPFPerfEventArray() { ...@@ -436,6 +447,13 @@ BPFPerfEventArray::~BPFPerfEventArray() {
} }
} }
BPFProgTable::BPFProgTable(const TableDesc& desc)
: BPFTableBase<int, int>(desc) {
if (desc.type != BPF_MAP_TYPE_PROG_ARRAY)
throw std::invalid_argument("Table '" + desc.name +
"' is not a prog table");
}
StatusTuple BPFProgTable::update_value(const int& index, const int& prog_fd) { StatusTuple BPFProgTable::update_value(const int& index, const int& prog_fd) {
if (!this->update(const_cast<int*>(&index), const_cast<int*>(&prog_fd))) if (!this->update(const_cast<int*>(&index), const_cast<int*>(&prog_fd)))
return StatusTuple(-1, "Error updating value: %s", std::strerror(errno)); return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
...@@ -448,6 +466,13 @@ StatusTuple BPFProgTable::remove_value(const int& index) { ...@@ -448,6 +466,13 @@ StatusTuple BPFProgTable::remove_value(const int& index) {
return StatusTuple(0); return StatusTuple(0);
} }
BPFCgroupArray::BPFCgroupArray(const TableDesc& desc)
: BPFTableBase<int, int>(desc) {
if (desc.type != BPF_MAP_TYPE_CGROUP_ARRAY)
throw std::invalid_argument("Table '" + desc.name +
"' is not a cgroup array");
}
StatusTuple BPFCgroupArray::update_value(const int& index, StatusTuple BPFCgroupArray::update_value(const int& index,
const int& cgroup2_fd) { const int& cgroup2_fd) {
if (!this->update(const_cast<int*>(&index), const_cast<int*>(&cgroup2_fd))) if (!this->update(const_cast<int*>(&index), const_cast<int*>(&cgroup2_fd)))
......
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
#pragma once #pragma once
#include <cstring>
#include <errno.h> #include <errno.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <cstring>
#include <exception> #include <exception>
#include <map> #include <map>
#include <memory> #include <memory>
...@@ -83,9 +83,7 @@ class BPFTableBase { ...@@ -83,9 +83,7 @@ class BPFTableBase {
return bpf_update_elem(desc.fd, key, value, 0) >= 0; return bpf_update_elem(desc.fd, key, value, 0) >= 0;
} }
bool remove(void* key) { bool remove(void* key) { return bpf_delete_elem(desc.fd, key) >= 0; }
return bpf_delete_elem(desc.fd, key) >= 0;
}
const TableDesc& desc; const TableDesc& desc;
}; };
...@@ -111,19 +109,23 @@ class BPFTable : public BPFTableBase<void, void> { ...@@ -111,19 +109,23 @@ class BPFTable : public BPFTableBase<void, void> {
}; };
template <class ValueType> template <class ValueType>
void * get_value_addr(ValueType& t) { return &t; } void* get_value_addr(ValueType& t) {
return &t;
}
template <class ValueType> template <class ValueType>
void * get_value_addr(std::vector<ValueType>& t) { return t.data(); } void* get_value_addr(std::vector<ValueType>& t) {
return t.data();
}
template <class ValueType> template <class ValueType>
class BPFArrayTable : public BPFTableBase<int, ValueType> { class BPFArrayTable : public BPFTableBase<int, ValueType> {
public: public:
BPFArrayTable(const TableDesc& desc) BPFArrayTable(const TableDesc& desc) : BPFTableBase<int, ValueType>(desc) {
: BPFTableBase<int, ValueType>(desc) {
if (desc.type != BPF_MAP_TYPE_ARRAY && if (desc.type != BPF_MAP_TYPE_ARRAY &&
desc.type != BPF_MAP_TYPE_PERCPU_ARRAY) desc.type != BPF_MAP_TYPE_PERCPU_ARRAY)
throw std::invalid_argument("Table '" + desc.name + "' is not an array table"); throw std::invalid_argument("Table '" + desc.name +
"' is not an array table");
} }
virtual StatusTuple get_value(const int& index, ValueType& value) { virtual StatusTuple get_value(const int& index, ValueType& value) {
...@@ -133,7 +135,8 @@ public: ...@@ -133,7 +135,8 @@ public:
} }
virtual StatusTuple update_value(const int& index, const ValueType& value) { virtual StatusTuple update_value(const int& index, const ValueType& value) {
if (!this->update(const_cast<int*>(&index), get_value_addr(const_cast<ValueType&>(value)))) if (!this->update(const_cast<int*>(&index),
get_value_addr(const_cast<ValueType&>(value))))
return StatusTuple(-1, "Error updating value: %s", std::strerror(errno)); return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
return StatusTuple(0); return StatusTuple(0);
} }
...@@ -147,7 +150,7 @@ public: ...@@ -147,7 +150,7 @@ public:
std::vector<ValueType> get_table_offline() { std::vector<ValueType> get_table_offline() {
std::vector<ValueType> res(this->capacity()); std::vector<ValueType> res(this->capacity());
for (int i = 0; i < (int) this->capacity(); i++) { for (int i = 0; i < (int)this->capacity(); i++) {
get_value(i, res[i]); get_value(i, res[i]);
} }
...@@ -162,8 +165,10 @@ class BPFPercpuArrayTable : public BPFArrayTable<std::vector<ValueType>> { ...@@ -162,8 +165,10 @@ class BPFPercpuArrayTable : public BPFArrayTable<std::vector<ValueType>> {
: BPFArrayTable<std::vector<ValueType>>(desc), : BPFArrayTable<std::vector<ValueType>>(desc),
ncpus(BPFTable::get_possible_cpu_count()) { ncpus(BPFTable::get_possible_cpu_count()) {
if (desc.type != BPF_MAP_TYPE_PERCPU_ARRAY) if (desc.type != BPF_MAP_TYPE_PERCPU_ARRAY)
throw std::invalid_argument("Table '" + desc.name + "' is not a percpu array table"); throw std::invalid_argument("Table '" + desc.name +
// leaf structures have to be aligned to 8 bytes as hardcoded in the linux kernel. "' is not a percpu array table");
// leaf structures have to be aligned to 8 bytes as hardcoded in the linux
// kernel.
if (sizeof(ValueType) % 8) if (sizeof(ValueType) % 8)
throw std::invalid_argument("leaf must be aligned to 8 bytes"); throw std::invalid_argument("leaf must be aligned to 8 bytes");
} }
...@@ -173,11 +178,13 @@ class BPFPercpuArrayTable : public BPFArrayTable<std::vector<ValueType>> { ...@@ -173,11 +178,13 @@ class BPFPercpuArrayTable : public BPFArrayTable<std::vector<ValueType>> {
return BPFArrayTable<std::vector<ValueType>>::get_value(index, value); return BPFArrayTable<std::vector<ValueType>>::get_value(index, value);
} }
StatusTuple update_value(const int& index, const std::vector<ValueType>& value) { StatusTuple update_value(const int& index,
const std::vector<ValueType>& value) {
if (value.size() != ncpus) if (value.size() != ncpus)
return StatusTuple(-1, "bad value size"); return StatusTuple(-1, "bad value size");
return BPFArrayTable<std::vector<ValueType>>::update_value(index, value); return BPFArrayTable<std::vector<ValueType>>::update_value(index, value);
} }
private: private:
unsigned int ncpus; unsigned int ncpus;
}; };
...@@ -191,7 +198,8 @@ class BPFHashTable : public BPFTableBase<KeyType, ValueType> { ...@@ -191,7 +198,8 @@ class BPFHashTable : public BPFTableBase<KeyType, ValueType> {
desc.type != BPF_MAP_TYPE_PERCPU_HASH && desc.type != BPF_MAP_TYPE_PERCPU_HASH &&
desc.type != BPF_MAP_TYPE_LRU_HASH && desc.type != BPF_MAP_TYPE_LRU_HASH &&
desc.type != BPF_MAP_TYPE_LRU_PERCPU_HASH) desc.type != BPF_MAP_TYPE_LRU_PERCPU_HASH)
throw std::invalid_argument("Table '" + desc.name + "' is not a hash table"); throw std::invalid_argument("Table '" + desc.name +
"' is not a hash table");
} }
virtual StatusTuple get_value(const KeyType& key, ValueType& value) { virtual StatusTuple get_value(const KeyType& key, ValueType& value) {
...@@ -201,7 +209,8 @@ class BPFHashTable : public BPFTableBase<KeyType, ValueType> { ...@@ -201,7 +209,8 @@ class BPFHashTable : public BPFTableBase<KeyType, ValueType> {
} }
virtual StatusTuple update_value(const KeyType& key, const ValueType& value) { virtual StatusTuple update_value(const KeyType& key, const ValueType& value) {
if (!this->update(const_cast<KeyType*>(&key), get_value_addr(const_cast<ValueType&>(value)))) if (!this->update(const_cast<KeyType*>(&key),
get_value_addr(const_cast<ValueType&>(value))))
return StatusTuple(-1, "Error updating value: %s", std::strerror(errno)); return StatusTuple(-1, "Error updating value: %s", std::strerror(errno));
return StatusTuple(0); return StatusTuple(0);
} }
...@@ -247,15 +256,18 @@ class BPFHashTable : public BPFTableBase<KeyType, ValueType> { ...@@ -247,15 +256,18 @@ class BPFHashTable : public BPFTableBase<KeyType, ValueType> {
}; };
template <class KeyType, class ValueType> template <class KeyType, class ValueType>
class BPFPercpuHashTable : public BPFHashTable<KeyType, std::vector<ValueType>> { class BPFPercpuHashTable
: public BPFHashTable<KeyType, std::vector<ValueType>> {
public: public:
explicit BPFPercpuHashTable(const TableDesc& desc) explicit BPFPercpuHashTable(const TableDesc& desc)
: BPFHashTable<KeyType, std::vector<ValueType>>(desc), : BPFHashTable<KeyType, std::vector<ValueType>>(desc),
ncpus(BPFTable::get_possible_cpu_count()) { ncpus(BPFTable::get_possible_cpu_count()) {
if (desc.type != BPF_MAP_TYPE_PERCPU_HASH && if (desc.type != BPF_MAP_TYPE_PERCPU_HASH &&
desc.type != BPF_MAP_TYPE_LRU_PERCPU_HASH) desc.type != BPF_MAP_TYPE_LRU_PERCPU_HASH)
throw std::invalid_argument("Table '" + desc.name + "' is not a percpu hash table"); throw std::invalid_argument("Table '" + desc.name +
// leaf structures have to be aligned to 8 bytes as hardcoded in the linux kernel. "' is not a percpu hash table");
// leaf structures have to be aligned to 8 bytes as hardcoded in the linux
// kernel.
if (sizeof(ValueType) % 8) if (sizeof(ValueType) % 8)
throw std::invalid_argument("leaf must be aligned to 8 bytes"); throw std::invalid_argument("leaf must be aligned to 8 bytes");
} }
...@@ -265,11 +277,14 @@ class BPFPercpuHashTable : public BPFHashTable<KeyType, std::vector<ValueType>> ...@@ -265,11 +277,14 @@ class BPFPercpuHashTable : public BPFHashTable<KeyType, std::vector<ValueType>>
return BPFHashTable<KeyType, std::vector<ValueType>>::get_value(key, value); return BPFHashTable<KeyType, std::vector<ValueType>>::get_value(key, value);
} }
StatusTuple update_value(const KeyType& key, const std::vector<ValueType>& value) { StatusTuple update_value(const KeyType& key,
const std::vector<ValueType>& value) {
if (value.size() != ncpus) if (value.size() != ncpus)
return StatusTuple(-1, "bad value size"); return StatusTuple(-1, "bad value size");
return BPFHashTable<KeyType, std::vector<ValueType>>::update_value(key, value); return BPFHashTable<KeyType, std::vector<ValueType>>::update_value(key,
value);
} }
private: private:
unsigned int ncpus; unsigned int ncpus;
}; };
...@@ -282,8 +297,7 @@ struct stacktrace_t { ...@@ -282,8 +297,7 @@ struct stacktrace_t {
class BPFStackTable : public BPFTableBase<int, stacktrace_t> { class BPFStackTable : public BPFTableBase<int, stacktrace_t> {
public: public:
BPFStackTable(const TableDesc& desc, BPFStackTable(const TableDesc& desc, bool use_debug_file,
bool use_debug_file,
bool check_debug_file_crc); bool check_debug_file_crc);
BPFStackTable(BPFStackTable&& that); BPFStackTable(BPFStackTable&& that);
~BPFStackTable(); ~BPFStackTable();
...@@ -299,8 +313,7 @@ class BPFStackTable : public BPFTableBase<int, stacktrace_t> { ...@@ -299,8 +313,7 @@ class BPFStackTable : public BPFTableBase<int, stacktrace_t> {
class BPFPerfBuffer : public BPFTableBase<int, int> { class BPFPerfBuffer : public BPFTableBase<int, int> {
public: public:
BPFPerfBuffer(const TableDesc& desc) BPFPerfBuffer(const TableDesc& desc);
: BPFTableBase<int, int>(desc), epfd_(-1) {}
~BPFPerfBuffer(); ~BPFPerfBuffer();
StatusTuple open_all_cpu(perf_reader_raw_cb cb, perf_reader_lost_cb lost_cb, StatusTuple open_all_cpu(perf_reader_raw_cb cb, perf_reader_lost_cb lost_cb,
...@@ -321,8 +334,7 @@ class BPFPerfBuffer : public BPFTableBase<int, int> { ...@@ -321,8 +334,7 @@ class BPFPerfBuffer : public BPFTableBase<int, int> {
class BPFPerfEventArray : public BPFTableBase<int, int> { class BPFPerfEventArray : public BPFTableBase<int, int> {
public: public:
BPFPerfEventArray(const TableDesc& desc) BPFPerfEventArray(const TableDesc& desc);
: BPFTableBase<int, int>(desc) {}
~BPFPerfEventArray(); ~BPFPerfEventArray();
StatusTuple open_all_cpu(uint32_t type, uint64_t config); StatusTuple open_all_cpu(uint32_t type, uint64_t config);
...@@ -336,24 +348,16 @@ class BPFPerfEventArray : public BPFTableBase<int, int> { ...@@ -336,24 +348,16 @@ class BPFPerfEventArray : public BPFTableBase<int, int> {
}; };
class BPFProgTable : public BPFTableBase<int, int> { class BPFProgTable : public BPFTableBase<int, int> {
public: public:
BPFProgTable(const TableDesc& desc) BPFProgTable(const TableDesc& desc);
: BPFTableBase<int, int>(desc) {
if (desc.type != BPF_MAP_TYPE_PROG_ARRAY)
throw std::invalid_argument("Table '" + desc.name + "' is not a prog table");
}
StatusTuple update_value(const int& index, const int& prog_fd); StatusTuple update_value(const int& index, const int& prog_fd);
StatusTuple remove_value(const int& index); StatusTuple remove_value(const int& index);
}; };
class BPFCgroupArray : public BPFTableBase<int, int> { class BPFCgroupArray : public BPFTableBase<int, int> {
public: public:
BPFCgroupArray(const TableDesc& desc) BPFCgroupArray(const TableDesc& desc);
: BPFTableBase<int, int>(desc) {
if (desc.type != BPF_MAP_TYPE_CGROUP_ARRAY)
throw std::invalid_argument("Table '" + desc.name + "' is not a cgroup array");
}
StatusTuple update_value(const int& index, const int& cgroup2_fd); StatusTuple update_value(const int& index, const int& cgroup2_fd);
StatusTuple update_value(const int& index, const std::string& cgroup2_path); StatusTuple update_value(const int& index, const std::string& cgroup2_path);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment