blob: a0e568a3112ef42a8ace53195849201410446872 [file] [log] [blame]
/*
* Copyright (c) 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <sys/epoll.h>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "bcc_exception.h"
#include "bpf_module.h"
#include "libbpf.h"
#include "perf_reader.h"
#include "table_desc.h"
namespace ebpf {
template <class KeyType, class ValueType>
class BPFTableBase {
public:
size_t capacity() { return capacity_; }
protected:
BPFTableBase(BPFModule* bpf_module, const std::string& name) {
size_t id_ = bpf_module->table_id(name);
if (id_ >= bpf_module->num_tables())
throw std::invalid_argument("Table " + name + " does not exist");
fd_ = bpf_module->table_fd(id_);
capacity_ = bpf_module->table_max_entries(id_);
};
explicit BPFTableBase(const TableDesc& desc) {
fd_ = desc.fd;
capacity_ = desc.max_entries;
}
bool lookup(KeyType* key, ValueType* value) {
return bpf_lookup_elem(fd_, static_cast<void*>(key),
static_cast<void*>(value)) >= 0;
}
bool next(KeyType* key, KeyType* next_key) {
return bpf_get_next_key(fd_, static_cast<void*>(key),
static_cast<void*>(next_key)) >= 0;
}
bool update(KeyType* key, ValueType* value) {
return bpf_update_elem(fd_, static_cast<void*>(key),
static_cast<void*>(value), 0) >= 0;
}
bool remove(KeyType* key) {
return bpf_delete_elem(fd_, static_cast<void*>(key)) >= 0;
}
int fd_;
size_t capacity_;
};
template <class KeyType, class ValueType>
class BPFHashTable : protected BPFTableBase<KeyType, ValueType> {
public:
explicit BPFHashTable(const TableDesc& desc) : BPFTableBase<KeyType, ValueType>(desc) {}
BPFHashTable(BPFModule* bpf_module, const std::string& name)
: BPFTableBase<KeyType, ValueType>(bpf_module, name) {}
ValueType get_value(const KeyType& key) {
ValueType res;
if (!this->lookup(const_cast<KeyType*>(&key), &res))
throw std::invalid_argument("Key does not exist in the table");
return res;
}
ValueType operator[](const KeyType& key) { return get_value(key); }
std::vector<std::pair<KeyType, ValueType>> get_table_offline() {
std::vector<std::pair<KeyType, ValueType>> res;
KeyType cur, nxt;
ValueType value;
while (true) {
if (!this->next(&cur, &nxt))
break;
if (!this->lookup(&nxt, &value))
break;
res.emplace_back(nxt, value);
std::swap(cur, nxt);
}
return res;
}
};
// From src/cc/export/helpers.h
static const int BPF_MAX_STACK_DEPTH = 127;
struct stacktrace_t {
intptr_t ip[BPF_MAX_STACK_DEPTH];
};
class BPFStackTable : protected BPFTableBase<int, stacktrace_t> {
public:
BPFStackTable(BPFModule* bpf_module, const std::string& name)
: BPFTableBase<int, stacktrace_t>(bpf_module, name) {}
~BPFStackTable();
std::vector<intptr_t> get_stack_addr(int stack_id);
std::vector<std::string> get_stack_symbol(int stack_id, int pid);
private:
std::map<int, void*> pid_sym_;
};
class BPFPerfBuffer : protected BPFTableBase<int, int> {
public:
BPFPerfBuffer(BPFModule* bpf_module, const std::string& name)
: BPFTableBase<int, int>(bpf_module, name), epfd_(-1) {}
~BPFPerfBuffer();
StatusTuple open_all_cpu(perf_reader_raw_cb cb, void* cb_cookie,
int page_cnt);
StatusTuple close_all_cpu();
void poll(int timeout);
private:
StatusTuple open_on_cpu(perf_reader_raw_cb cb, int cpu, void* cb_cookie,
int page_cnt);
StatusTuple close_on_cpu(int cpu);
std::map<int, perf_reader*> cpu_readers_;
int epfd_;
std::unique_ptr<epoll_event[]> ep_events_;
};
} // namespace ebpf