Commit faea8c84 authored by Brenden Blanco's avatar Brenden Blanco

Add TableStorage class for wrapping bpf map tracking

Adds a TableStorage class for use by language frontends to store/access
references to loaded bpf maps. Includes support for shared and
namespaced maps, in a directory-like hierarchy.

Add a FileDesc helper class to automatically wrap open file descriptors.
The object prevents implicit copying of the fd (allows only
rvalue/move()), and takes care of the close() call.

Add a reference implementation of a TableStorageImpl that performs the
current default behavior expected by BPF_TABLE_PUBLIC, which is to share
maps between BPFModules in the same-process only. A stub implementation
for bpffs is started.

Update b/clang frontends to use this new class.

Also included is a framework for extracting the type information of maps
in an extensible way. Migrate BMapDeclVisitor to use this as the first
consumer.
Signed-off-by: default avatarBrenden Blanco <bblanco@gmail.com>
parent 271056f9
...@@ -3,4 +3,4 @@ BasedOnStyle: Google ...@@ -3,4 +3,4 @@ BasedOnStyle: Google
AllowShortIfStatementsOnASingleLine: false AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false AllowShortLoopsOnASingleLine: false
IndentCaseLabels: false IndentCaseLabels: false
AccessModifierOffset: -2 AccessModifierOffset: -1
...@@ -28,9 +28,10 @@ ...@@ -28,9 +28,10 @@
#include "bcc_exception.h" #include "bcc_exception.h"
#include "bcc_syms.h" #include "bcc_syms.h"
#include "bpf_module.h" #include "bpf_module.h"
#include "common.h"
#include "libbpf.h" #include "libbpf.h"
#include "perf_reader.h" #include "perf_reader.h"
#include "common.h" #include "table_storage.h"
#include "usdt.h" #include "usdt.h"
#include "BPF.h" #include "BPF.h"
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "bpf_module.h" #include "bpf_module.h"
#include "compat/linux/bpf.h" #include "compat/linux/bpf.h"
#include "libbpf.h" #include "libbpf.h"
#include "table_storage.h"
static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8; static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8;
...@@ -38,12 +39,14 @@ struct open_probe_t { ...@@ -38,12 +39,14 @@ struct open_probe_t {
}; };
class USDT; class USDT;
class TableStorage;
class BPF { class BPF {
public: public:
static const int BPF_MAX_STACK_DEPTH = 127; static const int BPF_MAX_STACK_DEPTH = 127;
explicit BPF(unsigned int flag = 0) : bpf_module_(new BPFModule(flag)) {} explicit BPF(unsigned int flag = 0, TableStorage* ts = nullptr)
: bpf_module_(new BPFModule(flag, ts)), ts_(ts) {}
StatusTuple init(const std::string& bpf_program, StatusTuple init(const std::string& bpf_program,
std::vector<std::string> cflags = {}, std::vector<std::string> cflags = {},
std::vector<USDT> usdt = {}); std::vector<USDT> usdt = {});
...@@ -90,6 +93,11 @@ public: ...@@ -90,6 +93,11 @@ public:
template <class KeyType, class ValueType> template <class KeyType, class ValueType>
BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) { BPFHashTable<KeyType, ValueType> get_hash_table(const std::string& name) {
if (ts_) {
TableStorage::iterator it;
if (ts_->Find(Path({name}), it))
return BPFHashTable<KeyType, ValueType>(it->second);
}
return BPFHashTable<KeyType, ValueType>(bpf_module_.get(), name); return BPFHashTable<KeyType, ValueType>(bpf_module_.get(), name);
} }
...@@ -152,6 +160,7 @@ private: ...@@ -152,6 +160,7 @@ private:
uint64_t symbol_addr, bcc_symbol* output); uint64_t symbol_addr, bcc_symbol* output);
std::unique_ptr<BPFModule> bpf_module_; std::unique_ptr<BPFModule> bpf_module_;
TableStorage* ts_;
std::map<std::string, int> funcs_; std::map<std::string, int> funcs_;
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "bpf_module.h" #include "bpf_module.h"
#include "libbpf.h" #include "libbpf.h"
#include "perf_reader.h" #include "perf_reader.h"
#include "table_desc.h"
namespace ebpf { namespace ebpf {
...@@ -44,6 +45,10 @@ protected: ...@@ -44,6 +45,10 @@ protected:
fd_ = bpf_module->table_fd(id_); fd_ = bpf_module->table_fd(id_);
capacity_ = bpf_module->table_max_entries(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) { bool lookup(KeyType* key, ValueType* value) {
return bpf_lookup_elem(fd_, static_cast<void*>(key), return bpf_lookup_elem(fd_, static_cast<void*>(key),
...@@ -70,7 +75,8 @@ protected: ...@@ -70,7 +75,8 @@ protected:
template <class KeyType, class ValueType> template <class KeyType, class ValueType>
class BPFHashTable : protected BPFTableBase<KeyType, ValueType> { class BPFHashTable : protected BPFTableBase<KeyType, ValueType> {
public: public:
explicit BPFHashTable(const TableDesc& desc) : BPFTableBase<KeyType, ValueType>(desc) {}
BPFHashTable(BPFModule* bpf_module, const std::string& name) BPFHashTable(BPFModule* bpf_module, const std::string& name)
: BPFTableBase<KeyType, ValueType>(bpf_module, name) {} : BPFTableBase<KeyType, ValueType>(bpf_module, name) {}
......
...@@ -35,12 +35,12 @@ if (CMAKE_COMPILER_IS_GNUCC AND LIBCLANG_ISSTATIC) ...@@ -35,12 +35,12 @@ if (CMAKE_COMPILER_IS_GNUCC AND LIBCLANG_ISSTATIC)
endif() endif()
endif() endif()
add_library(bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c shared_table.cc exported_files.cc bcc_elf.c bcc_perf_map.c bcc_proc.c bcc_syms.cc usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc) add_library(bcc-shared SHARED bpf_common.cc bpf_module.cc libbpf.c perf_reader.c table_storage.cc shared_table.cc bpffs_table.cc json_map_decl_visitor.cc exported_files.cc bcc_elf.c bcc_perf_map.c bcc_proc.c bcc_syms.cc usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc)
set_target_properties(bcc-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0) set_target_properties(bcc-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0)
set_target_properties(bcc-shared PROPERTIES OUTPUT_NAME bcc) set_target_properties(bcc-shared PROPERTIES OUTPUT_NAME bcc)
add_library(bcc-loader-static STATIC libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c bcc_proc.c) add_library(bcc-loader-static STATIC libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c bcc_proc.c)
add_library(bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc) add_library(bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc bpffs_table.cc json_map_decl_visitor.cc table_storage.cc exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc)
set_target_properties(bcc-static PROPERTIES OUTPUT_NAME bcc) set_target_properties(bcc-static PROPERTIES OUTPUT_NAME bcc)
set(llvm_raw_libs bitwriter bpfcodegen irreader linker set(llvm_raw_libs bitwriter bpfcodegen irreader linker
...@@ -67,7 +67,7 @@ target_link_libraries(bcc-static b_frontend clang_frontend bcc-loader-static ${c ...@@ -67,7 +67,7 @@ target_link_libraries(bcc-static b_frontend clang_frontend bcc-loader-static ${c
install(TARGETS bcc-shared LIBRARY COMPONENT libbcc install(TARGETS bcc-shared LIBRARY COMPONENT libbcc
DESTINATION ${CMAKE_INSTALL_LIBDIR}) DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES bpf_common.h bpf_module.h bcc_syms.h bcc_exception.h libbpf.h perf_reader.h BPF.h BPFTable.h shared_table.h COMPONENT libbcc install(FILES bpf_common.h bpf_module.h bcc_syms.h bcc_exception.h libbpf.h perf_reader.h BPF.h BPFTable.h shared_table.h table_desc.h COMPONENT libbcc
DESTINATION include/bcc) DESTINATION include/bcc)
install(DIRECTORY compat/linux/ COMPONENT libbcc install(DIRECTORY compat/linux/ COMPONENT libbcc
DESTINATION include/bcc/compat/linux DESTINATION include/bcc/compat/linux
......
...@@ -101,8 +101,8 @@ class MyMemoryManager : public SectionMemoryManager { ...@@ -101,8 +101,8 @@ class MyMemoryManager : public SectionMemoryManager {
map<string, tuple<uint8_t *, uintptr_t>> *sections_; map<string, tuple<uint8_t *, uintptr_t>> *sections_;
}; };
BPFModule::BPFModule(unsigned flags) BPFModule::BPFModule(unsigned flags, TableStorage *ts)
: flags_(flags), ctx_(new LLVMContext) { : flags_(flags), ctx_(new LLVMContext), ts_(ts) {
InitializeNativeTarget(); InitializeNativeTarget();
InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmPrinter();
LLVMInitializeBPFTarget(); LLVMInitializeBPFTarget();
...@@ -110,21 +110,17 @@ BPFModule::BPFModule(unsigned flags) ...@@ -110,21 +110,17 @@ BPFModule::BPFModule(unsigned flags)
LLVMInitializeBPFTargetInfo(); LLVMInitializeBPFTargetInfo();
LLVMInitializeBPFAsmPrinter(); LLVMInitializeBPFAsmPrinter();
LLVMLinkInMCJIT(); /* call empty function to force linking of MCJIT */ LLVMLinkInMCJIT(); /* call empty function to force linking of MCJIT */
if (!ts_) {
local_ts_ = createSharedTableStorage();
ts_ = &*local_ts_;
}
} }
BPFModule::~BPFModule() { BPFModule::~BPFModule() {
engine_.reset(); engine_.reset();
rw_engine_.reset(); rw_engine_.reset();
ctx_.reset(); ctx_.reset();
if (tables_) { ts_->DeletePrefix(Path({std::to_string((uintptr_t)this)}));
for (auto table : *tables_) {
if (table.is_shared) {
SharedTables::instance()->remove_fd(table.name);
} else if (!table.is_extern) {
close(table.fd);
}
}
}
} }
static void debug_printf(Module *mod, IRBuilder<> &B, const string &fmt, vector<Value *> args) { static void debug_printf(Module *mod, IRBuilder<> &B, const string &fmt, vector<Value *> args) {
...@@ -326,7 +322,8 @@ unique_ptr<ExecutionEngine> BPFModule::finalize_rw(unique_ptr<Module> m) { ...@@ -326,7 +322,8 @@ unique_ptr<ExecutionEngine> BPFModule::finalize_rw(unique_ptr<Module> m) {
// load an entire c file as a module // load an entire c file as a module
int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags[], int ncflags) { int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags[], int ncflags) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_, flags_); clang_loader_ = make_unique<ClangLoader>(&*ctx_, flags_);
if (clang_loader_->parse(&mod_, &tables_, file, in_memory, cflags, ncflags)) if (clang_loader_->parse(&mod_, *ts_, file, in_memory, cflags, ncflags,
std::to_string((uintptr_t)this)))
return -1; return -1;
return 0; return 0;
} }
...@@ -338,7 +335,7 @@ int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags ...@@ -338,7 +335,7 @@ int BPFModule::load_cfile(const string &file, bool in_memory, const char *cflags
// build an ExecutionEngine. // build an ExecutionEngine.
int BPFModule::load_includes(const string &text) { int BPFModule::load_includes(const string &text) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_, flags_); clang_loader_ = make_unique<ClangLoader>(&*ctx_, flags_);
if (clang_loader_->parse(&mod_, &tables_, text, true, nullptr, 0)) if (clang_loader_->parse(&mod_, *ts_, text, true, nullptr, 0, ""))
return -1; return -1;
return 0; return 0;
} }
...@@ -352,7 +349,10 @@ int BPFModule::annotate() { ...@@ -352,7 +349,10 @@ int BPFModule::annotate() {
auto m = make_unique<Module>("sscanf", *ctx_); auto m = make_unique<Module>("sscanf", *ctx_);
size_t id = 0; size_t id = 0;
for (auto &table : *tables_) { Path path({std::to_string((uintptr_t)this)});
for (auto it = ts_->lower_bound(path), up = ts_->upper_bound(path); it != up; ++it) {
TableDesc &table = it->second;
tables_.push_back(&it->second);
table_names_[table.name] = id++; table_names_[table.name] = id++;
GlobalValue *gvar = mod_->getNamedValue(table.name); GlobalValue *gvar = mod_->getNamedValue(table.name);
if (!gvar) continue; if (!gvar) continue;
...@@ -507,9 +507,7 @@ unsigned BPFModule::kern_version() const { ...@@ -507,9 +507,7 @@ unsigned BPFModule::kern_version() const {
return *(unsigned *)get<0>(section->second); return *(unsigned *)get<0>(section->second);
} }
size_t BPFModule::num_tables() const { size_t BPFModule::num_tables() const { return tables_.size(); }
return tables_->size();
}
size_t BPFModule::table_id(const string &name) const { size_t BPFModule::table_id(const string &name) const {
auto it = table_names_.find(name); auto it = table_names_.find(name);
...@@ -522,8 +520,9 @@ int BPFModule::table_fd(const string &name) const { ...@@ -522,8 +520,9 @@ int BPFModule::table_fd(const string &name) const {
} }
int BPFModule::table_fd(size_t id) const { int BPFModule::table_fd(size_t id) const {
if (id >= tables_->size()) return -1; if (id >= tables_.size())
return (*tables_)[id].fd; return -1;
return tables_[id]->fd;
} }
int BPFModule::table_type(const string &name) const { int BPFModule::table_type(const string &name) const {
...@@ -531,8 +530,9 @@ int BPFModule::table_type(const string &name) const { ...@@ -531,8 +530,9 @@ int BPFModule::table_type(const string &name) const {
} }
int BPFModule::table_type(size_t id) const { int BPFModule::table_type(size_t id) const {
if (id >= tables_->size()) return -1; if (id >= tables_.size())
return (*tables_)[id].type; return -1;
return tables_[id]->type;
} }
size_t BPFModule::table_max_entries(const string &name) const { size_t BPFModule::table_max_entries(const string &name) const {
...@@ -540,8 +540,9 @@ size_t BPFModule::table_max_entries(const string &name) const { ...@@ -540,8 +540,9 @@ size_t BPFModule::table_max_entries(const string &name) const {
} }
size_t BPFModule::table_max_entries(size_t id) const { size_t BPFModule::table_max_entries(size_t id) const {
if (id >= tables_->size()) return 0; if (id >= tables_.size())
return (*tables_)[id].max_entries; return 0;
return tables_[id]->max_entries;
} }
int BPFModule::table_flags(const string &name) const { int BPFModule::table_flags(const string &name) const {
...@@ -549,19 +550,22 @@ int BPFModule::table_flags(const string &name) const { ...@@ -549,19 +550,22 @@ int BPFModule::table_flags(const string &name) const {
} }
int BPFModule::table_flags(size_t id) const { int BPFModule::table_flags(size_t id) const {
if (id >= tables_->size()) return -1; if (id >= tables_.size())
return (*tables_)[id].flags; return -1;
return tables_[id]->flags;
} }
const char * BPFModule::table_name(size_t id) const { const char * BPFModule::table_name(size_t id) const {
if (id >= tables_->size()) return nullptr; if (id >= tables_.size())
return (*tables_)[id].name.c_str(); return nullptr;
return tables_[id]->name.c_str();
} }
const char * BPFModule::table_key_desc(size_t id) const { const char * BPFModule::table_key_desc(size_t id) const {
if (b_loader_) return nullptr; if (b_loader_) return nullptr;
if (id >= tables_->size()) return nullptr; if (id >= tables_.size())
return (*tables_)[id].key_desc.c_str(); return nullptr;
return tables_[id]->key_desc.c_str();
} }
const char * BPFModule::table_key_desc(const string &name) const { const char * BPFModule::table_key_desc(const string &name) const {
...@@ -570,24 +574,27 @@ const char * BPFModule::table_key_desc(const string &name) const { ...@@ -570,24 +574,27 @@ const char * BPFModule::table_key_desc(const string &name) const {
const char * BPFModule::table_leaf_desc(size_t id) const { const char * BPFModule::table_leaf_desc(size_t id) const {
if (b_loader_) return nullptr; if (b_loader_) return nullptr;
if (id >= tables_->size()) return nullptr; if (id >= tables_.size())
return (*tables_)[id].leaf_desc.c_str(); return nullptr;
return tables_[id]->leaf_desc.c_str();
} }
const char * BPFModule::table_leaf_desc(const string &name) const { const char * BPFModule::table_leaf_desc(const string &name) const {
return table_leaf_desc(table_id(name)); return table_leaf_desc(table_id(name));
} }
size_t BPFModule::table_key_size(size_t id) const { size_t BPFModule::table_key_size(size_t id) const {
if (id >= tables_->size()) return 0; if (id >= tables_.size())
return (*tables_)[id].key_size; return 0;
return tables_[id]->key_size;
} }
size_t BPFModule::table_key_size(const string &name) const { size_t BPFModule::table_key_size(const string &name) const {
return table_key_size(table_id(name)); return table_key_size(table_id(name));
} }
size_t BPFModule::table_leaf_size(size_t id) const { size_t BPFModule::table_leaf_size(size_t id) const {
if (id >= tables_->size()) return 0; if (id >= tables_.size())
return (*tables_)[id].leaf_size; return 0;
return tables_[id]->leaf_size;
} }
size_t BPFModule::table_leaf_size(const string &name) const { size_t BPFModule::table_leaf_size(const string &name) const {
return table_leaf_size(table_id(name)); return table_leaf_size(table_id(name));
...@@ -603,8 +610,9 @@ struct TableIterator { ...@@ -603,8 +610,9 @@ struct TableIterator {
}; };
int BPFModule::table_key_printf(size_t id, char *buf, size_t buflen, const void *key) { int BPFModule::table_key_printf(size_t id, char *buf, size_t buflen, const void *key) {
if (id >= tables_->size()) return -1; if (id >= tables_.size())
const TableDesc &desc = (*tables_)[id]; return -1;
const TableDesc &desc = *tables_[id];
if (!desc.key_snprintf) { if (!desc.key_snprintf) {
fprintf(stderr, "Key snprintf not available\n"); fprintf(stderr, "Key snprintf not available\n");
return -1; return -1;
...@@ -627,8 +635,9 @@ int BPFModule::table_key_printf(size_t id, char *buf, size_t buflen, const void ...@@ -627,8 +635,9 @@ int BPFModule::table_key_printf(size_t id, char *buf, size_t buflen, const void
} }
int BPFModule::table_leaf_printf(size_t id, char *buf, size_t buflen, const void *leaf) { int BPFModule::table_leaf_printf(size_t id, char *buf, size_t buflen, const void *leaf) {
if (id >= tables_->size()) return -1; if (id >= tables_.size())
const TableDesc &desc = (*tables_)[id]; return -1;
const TableDesc &desc = *tables_[id];
if (!desc.leaf_snprintf) { if (!desc.leaf_snprintf) {
fprintf(stderr, "Key snprintf not available\n"); fprintf(stderr, "Key snprintf not available\n");
return -1; return -1;
...@@ -651,8 +660,9 @@ int BPFModule::table_leaf_printf(size_t id, char *buf, size_t buflen, const void ...@@ -651,8 +660,9 @@ int BPFModule::table_leaf_printf(size_t id, char *buf, size_t buflen, const void
} }
int BPFModule::table_key_scanf(size_t id, const char *key_str, void *key) { int BPFModule::table_key_scanf(size_t id, const char *key_str, void *key) {
if (id >= tables_->size()) return -1; if (id >= tables_.size())
const TableDesc &desc = (*tables_)[id]; return -1;
const TableDesc &desc = *tables_[id];
if (!desc.key_sscanf) { if (!desc.key_sscanf) {
fprintf(stderr, "Key sscanf not available\n"); fprintf(stderr, "Key sscanf not available\n");
return -1; return -1;
...@@ -672,8 +682,9 @@ int BPFModule::table_key_scanf(size_t id, const char *key_str, void *key) { ...@@ -672,8 +682,9 @@ int BPFModule::table_key_scanf(size_t id, const char *key_str, void *key) {
} }
int BPFModule::table_leaf_scanf(size_t id, const char *leaf_str, void *leaf) { int BPFModule::table_leaf_scanf(size_t id, const char *leaf_str, void *leaf) {
if (id >= tables_->size()) return -1; if (id >= tables_.size())
const TableDesc &desc = (*tables_)[id]; return -1;
const TableDesc &desc = *tables_[id];
if (!desc.leaf_sscanf) { if (!desc.leaf_sscanf) {
fprintf(stderr, "Key sscanf not available\n"); fprintf(stderr, "Key sscanf not available\n");
return -1; return -1;
...@@ -714,7 +725,8 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) { ...@@ -714,7 +725,8 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) {
return rc; return rc;
b_loader_.reset(new BLoader(flags_)); b_loader_.reset(new BLoader(flags_));
if (int rc = b_loader_->parse(&*mod_, filename, proto_filename, &tables_)) if (int rc =
b_loader_->parse(&*mod_, filename, proto_filename, *ts_, std::to_string((uintptr_t)this)))
return rc; return rc;
if (int rc = annotate()) if (int rc = annotate())
return rc; return rc;
......
...@@ -31,7 +31,8 @@ class Type; ...@@ -31,7 +31,8 @@ class Type;
} }
namespace ebpf { namespace ebpf {
struct TableDesc; class TableDesc;
class TableStorage;
class BLoader; class BLoader;
class ClangLoader; class ClangLoader;
...@@ -52,7 +53,7 @@ class BPFModule { ...@@ -52,7 +53,7 @@ class BPFModule {
int kbuild_flags(const char *uname_release, std::vector<std::string> *cflags); int kbuild_flags(const char *uname_release, std::vector<std::string> *cflags);
int run_pass_manager(llvm::Module &mod); int run_pass_manager(llvm::Module &mod);
public: public:
BPFModule(unsigned flags); BPFModule(unsigned flags, TableStorage *ts = nullptr);
~BPFModule(); ~BPFModule();
int load_b(const std::string &filename, const std::string &proto_filename); int load_b(const std::string &filename, const std::string &proto_filename);
int load_c(const std::string &filename, const char *cflags[], int ncflags); int load_c(const std::string &filename, const char *cflags[], int ncflags);
...@@ -99,11 +100,13 @@ class BPFModule { ...@@ -99,11 +100,13 @@ class BPFModule {
std::unique_ptr<BLoader> b_loader_; std::unique_ptr<BLoader> b_loader_;
std::unique_ptr<ClangLoader> clang_loader_; std::unique_ptr<ClangLoader> clang_loader_;
std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_; std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
std::unique_ptr<std::vector<TableDesc>> tables_; std::vector<TableDesc *> tables_;
std::map<std::string, size_t> table_names_; std::map<std::string, size_t> table_names_;
std::vector<std::string> function_names_; std::vector<std::string> function_names_;
std::map<llvm::Type *, llvm::Function *> readers_; std::map<llvm::Type *, llvm::Function *> readers_;
std::map<llvm::Type *, llvm::Function *> writers_; std::map<llvm::Type *, llvm::Function *> writers_;
TableStorage *ts_;
std::unique_ptr<TableStorage> local_ts_;
}; };
} // namespace ebpf } // namespace ebpf
/*
* Copyright (c) 2017 VMware, 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.
*/
#include "common.h"
#include "table_storage_impl.h"
namespace ebpf {
using std::string;
using std::unique_ptr;
/// A filesystem backed table storage
class BpfFsTableStorage : public TableStorageImpl {
public:
class iterator : public TableStorageIteratorImpl {
public:
virtual ~iterator() {}
virtual unique_ptr<self_type> clone() const override;
virtual self_type &operator++() override;
virtual value_type &operator*() const override;
virtual pointer operator->() const override;
};
virtual ~BpfFsTableStorage() {}
virtual bool Find(const string &name, TableStorage::iterator &result) const override;
virtual bool Insert(const string &name, TableDesc &&desc) override;
virtual bool Delete(const string &name) override;
virtual unique_ptr<TableStorageIteratorImpl> begin() override;
virtual unique_ptr<TableStorageIteratorImpl> end() override;
virtual unique_ptr<TableStorageIteratorImpl> lower_bound(const string &k) override;
virtual unique_ptr<TableStorageIteratorImpl> upper_bound(const string &k) override;
virtual unique_ptr<TableStorageIteratorImpl> erase(const TableStorageIteratorImpl &it) override;
private:
};
bool BpfFsTableStorage::Find(const string &name, TableStorage::iterator &result) const {
return false;
}
bool BpfFsTableStorage::Insert(const string &name, TableDesc &&desc) { return false; }
bool BpfFsTableStorage::Delete(const string &name) { return false; }
unique_ptr<TableStorageIteratorImpl> BpfFsTableStorage::begin() { return unique_ptr<iterator>(); }
unique_ptr<TableStorageIteratorImpl> BpfFsTableStorage::end() { return unique_ptr<iterator>(); }
unique_ptr<TableStorageIteratorImpl> BpfFsTableStorage::lower_bound(const string &k) {
return unique_ptr<iterator>();
}
unique_ptr<TableStorageIteratorImpl> BpfFsTableStorage::upper_bound(const string &k) {
return unique_ptr<iterator>();
}
unique_ptr<TableStorageIteratorImpl> BpfFsTableStorage::erase(const TableStorageIteratorImpl &it) {
return unique_ptr<iterator>();
}
unique_ptr<TableStorage> createBpfFsTableStorage() {
auto t = make_unique<TableStorage>();
t->Init(make_unique<BpfFsTableStorage>());
return t;
}
} // namespace ebpf
...@@ -35,10 +35,10 @@ ...@@ -35,10 +35,10 @@
#include "bcc_exception.h" #include "bcc_exception.h"
#include "codegen_llvm.h" #include "codegen_llvm.h"
#include "lexer.h" #include "lexer.h"
#include "table_desc.h"
#include "type_helper.h"
#include "linux/bpf.h"
#include "libbpf.h" #include "libbpf.h"
#include "linux/bpf.h"
#include "table_storage.h"
#include "type_helper.h"
namespace ebpf { namespace ebpf {
namespace cc { namespace cc {
...@@ -1220,7 +1220,7 @@ StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) { ...@@ -1220,7 +1220,7 @@ StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) {
return StatusTuple(0); return StatusTuple(0);
} }
StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) { StatusTuple CodegenLLVM::visit(Node *root, TableStorage &ts, const string &id) {
scopes_->set_current(scopes_->top_state()); scopes_->set_current(scopes_->top_state());
scopes_->set_current(scopes_->top_var()); scopes_->set_current(scopes_->top_var());
...@@ -1239,16 +1239,12 @@ StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) { ...@@ -1239,16 +1239,12 @@ StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) {
map_type = BPF_MAP_TYPE_HASH; map_type = BPF_MAP_TYPE_HASH;
else if (table.first->type_id()->name_ == "INDEXED") else if (table.first->type_id()->name_ == "INDEXED")
map_type = BPF_MAP_TYPE_ARRAY; map_type = BPF_MAP_TYPE_ARRAY;
tables.push_back({ ts.Insert(Path({id, table.first->id_->name_}),
table.first->id_->name_, {
table_fds_[table.first], table.first->id_->name_, table_fds_[table.first], map_type,
map_type, table.first->key_type_->bit_width_ >> 3, table.first->leaf_type_->bit_width_ >> 3,
table.first->key_type_->bit_width_ >> 3, table.first->size_, 0,
table.first->leaf_type_->bit_width_ >> 3, });
table.first->size_,
0,
"", "",
});
} }
return StatusTuple(0); return StatusTuple(0);
} }
......
...@@ -41,7 +41,8 @@ class GlobalVariable; ...@@ -41,7 +41,8 @@ class GlobalVariable;
} }
namespace ebpf { namespace ebpf {
struct TableDesc;
class TableStorage;
namespace cc { namespace cc {
...@@ -63,7 +64,7 @@ class CodegenLLVM : public Visitor { ...@@ -63,7 +64,7 @@ class CodegenLLVM : public Visitor {
EXPAND_NODES(VISIT) EXPAND_NODES(VISIT)
#undef VISIT #undef VISIT
STATUS_RETURN visit(Node* n, std::vector<TableDesc> &tables); STATUS_RETURN visit(Node *n, TableStorage &ts, const std::string &id);
int get_table_fd(const std::string &name) const; int get_table_fd(const std::string &name) const;
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include "type_check.h" #include "type_check.h"
#include "codegen_llvm.h" #include "codegen_llvm.h"
#include "loader.h" #include "loader.h"
#include "table_desc.h"
using std::string; using std::string;
using std::unique_ptr; using std::unique_ptr;
...@@ -34,7 +33,7 @@ BLoader::~BLoader() { ...@@ -34,7 +33,7 @@ BLoader::~BLoader() {
} }
int BLoader::parse(llvm::Module *mod, const string &filename, const string &proto_filename, int BLoader::parse(llvm::Module *mod, const string &filename, const string &proto_filename,
unique_ptr<vector<TableDesc>> *tables) { TableStorage &ts, const string &id) {
int rc; int rc;
proto_parser_ = make_unique<ebpf::cc::Parser>(proto_filename); proto_parser_ = make_unique<ebpf::cc::Parser>(proto_filename);
...@@ -61,10 +60,8 @@ int BLoader::parse(llvm::Module *mod, const string &filename, const string &prot ...@@ -61,10 +60,8 @@ int BLoader::parse(llvm::Module *mod, const string &filename, const string &prot
return -1; return -1;
} }
*tables = make_unique<vector<TableDesc>>();
codegen_ = ebpf::make_unique<ebpf::cc::CodegenLLVM>(mod, parser_->scopes_.get(), proto_parser_->scopes_.get()); codegen_ = ebpf::make_unique<ebpf::cc::CodegenLLVM>(mod, parser_->scopes_.get(), proto_parser_->scopes_.get());
ret = codegen_->visit(parser_->root_node_, **tables); ret = codegen_->visit(parser_->root_node_, ts, id);
if (ret.code() != 0 || ret.msg().size()) { if (ret.code() != 0 || ret.msg().size()) {
fprintf(stderr, "Codegen error @line=%d: %s\n", ret.code(), ret.msg().c_str()); fprintf(stderr, "Codegen error @line=%d: %s\n", ret.code(), ret.msg().c_str());
return ret.code(); return ret.code();
......
...@@ -20,14 +20,14 @@ ...@@ -20,14 +20,14 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "table_storage.h"
namespace llvm { namespace llvm {
class Module; class Module;
} }
namespace ebpf { namespace ebpf {
struct TableDesc;
namespace cc { namespace cc {
class Parser; class Parser;
class CodegenLLVM; class CodegenLLVM;
...@@ -38,7 +38,8 @@ class BLoader { ...@@ -38,7 +38,8 @@ class BLoader {
explicit BLoader(unsigned flags); explicit BLoader(unsigned flags);
~BLoader(); ~BLoader();
int parse(llvm::Module *mod, const std::string &filename, const std::string &proto_filename, int parse(llvm::Module *mod, const std::string &filename, const std::string &proto_filename,
std::unique_ptr<std::vector<TableDesc>> *tables); TableStorage &ts, const std::string &id);
private: private:
unsigned flags_; unsigned flags_;
std::unique_ptr<cc::Parser> parser_; std::unique_ptr<cc::Parser> parser_;
......
This diff is collapsed.
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <clang/Frontend/FrontendAction.h> #include <clang/Frontend/FrontendAction.h>
#include <clang/Rewrite/Core/Rewriter.h> #include <clang/Rewrite/Core/Rewriter.h>
#include "table_desc.h" #include "table_storage.h"
#define DEBUG_PREPROCESSOR 0x4 #define DEBUG_PREPROCESSOR 0x4
...@@ -41,21 +41,7 @@ class StringRef; ...@@ -41,21 +41,7 @@ class StringRef;
namespace ebpf { namespace ebpf {
// Helper visitor for constructing a string representation of a key/leaf decl class BFrontendAction;
class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> {
public:
explicit BMapDeclVisitor(clang::ASTContext &C, std::string &result);
bool TraverseRecordDecl(clang::RecordDecl *Decl);
bool VisitRecordDecl(clang::RecordDecl *Decl);
bool VisitFieldDecl(clang::FieldDecl *Decl);
bool VisitBuiltinType(const clang::BuiltinType *T);
bool VisitTypedefType(const clang::TypedefType *T);
bool VisitTagType(const clang::TagType *T);
bool VisitPointerType(const clang::PointerType *T);
private:
clang::ASTContext &C;
std::string &result_;
};
// Type visitor and rewriter for B programs. // Type visitor and rewriter for B programs.
// It will look for B-specific features and rewrite them into a valid // It will look for B-specific features and rewrite them into a valid
...@@ -63,8 +49,7 @@ class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> { ...@@ -63,8 +49,7 @@ class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> {
// and store the open handles in a map of table-to-fd's. // and store the open handles in a map of table-to-fd's.
class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> { class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
public: public:
explicit BTypeVisitor(clang::ASTContext &C, clang::Rewriter &rewriter, explicit BTypeVisitor(clang::ASTContext &C, BFrontendAction &fe);
std::vector<TableDesc> &tables);
bool TraverseCallExpr(clang::CallExpr *Call); bool TraverseCallExpr(clang::CallExpr *Call);
bool VisitFunctionDecl(clang::FunctionDecl *D); bool VisitFunctionDecl(clang::FunctionDecl *D);
bool VisitCallExpr(clang::CallExpr *Call); bool VisitCallExpr(clang::CallExpr *Call);
...@@ -82,9 +67,9 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> { ...@@ -82,9 +67,9 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
clang::ASTContext &C; clang::ASTContext &C;
clang::DiagnosticsEngine &diag_; clang::DiagnosticsEngine &diag_;
BFrontendAction &fe_;
clang::Rewriter &rewriter_; /// modifications to the source go into this class clang::Rewriter &rewriter_; /// modifications to the source go into this class
llvm::raw_ostream &out_; /// for debugging llvm::raw_ostream &out_; /// for debugging
std::vector<TableDesc> &tables_; /// store the open FDs
std::vector<clang::ParmVarDecl *> fn_args_; std::vector<clang::ParmVarDecl *> fn_args_;
std::set<clang::Expr *> visited_; std::set<clang::Expr *> visited_;
std::string current_fn_; std::string current_fn_;
...@@ -115,8 +100,7 @@ class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> { ...@@ -115,8 +100,7 @@ class ProbeVisitor : public clang::RecursiveASTVisitor<ProbeVisitor> {
// A helper class to the frontend action, walks the decls // A helper class to the frontend action, walks the decls
class BTypeConsumer : public clang::ASTConsumer { class BTypeConsumer : public clang::ASTConsumer {
public: public:
explicit BTypeConsumer(clang::ASTContext &C, clang::Rewriter &rewriter, explicit BTypeConsumer(clang::ASTContext &C, BFrontendAction &fe);
std::vector<TableDesc> &tables);
bool HandleTopLevelDecl(clang::DeclGroupRef Group) override; bool HandleTopLevelDecl(clang::DeclGroupRef Group) override;
private: private:
BTypeVisitor visitor_; BTypeVisitor visitor_;
...@@ -138,7 +122,7 @@ class BFrontendAction : public clang::ASTFrontendAction { ...@@ -138,7 +122,7 @@ class BFrontendAction : public clang::ASTFrontendAction {
public: public:
// Initialize with the output stream where the new source file contents // Initialize with the output stream where the new source file contents
// should be written. // should be written.
BFrontendAction(llvm::raw_ostream &os, unsigned flags); BFrontendAction(llvm::raw_ostream &os, unsigned flags, TableStorage &ts, const std::string &id);
// Called by clang when the AST has been completed, here the output stream // Called by clang when the AST has been completed, here the output stream
// will be flushed. // will be flushed.
...@@ -147,13 +131,16 @@ class BFrontendAction : public clang::ASTFrontendAction { ...@@ -147,13 +131,16 @@ class BFrontendAction : public clang::ASTFrontendAction {
std::unique_ptr<clang::ASTConsumer> std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) override; CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) override;
// take ownership of the table-to-fd mapping data structure clang::Rewriter &rewriter() const { return *rewriter_; }
std::unique_ptr<std::vector<TableDesc>> take_tables() { return move(tables_); } TableStorage &table_storage() const { return ts_; }
std::string id() const { return id_; }
private: private:
llvm::raw_ostream &os_; llvm::raw_ostream &os_;
unsigned flags_; unsigned flags_;
TableStorage &ts_;
std::string id_;
std::unique_ptr<clang::Rewriter> rewriter_; std::unique_ptr<clang::Rewriter> rewriter_;
std::unique_ptr<std::vector<TableDesc>> tables_;
}; };
} // namespace visitor } // namespace visitor
...@@ -104,8 +104,8 @@ std::pair<bool, string> get_kernel_path_info(const string kdir) ...@@ -104,8 +104,8 @@ std::pair<bool, string> get_kernel_path_info(const string kdir)
} }
int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDesc>> *tables, int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, const string &file,
const string &file, bool in_memory, const char *cflags[], int ncflags) { bool in_memory, const char *cflags[], int ncflags, const std::string &id) {
using namespace clang; using namespace clang;
string main_path = "/virtual/main.c"; string main_path = "/virtual/main.c";
...@@ -266,12 +266,10 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes ...@@ -266,12 +266,10 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDes
// capture the rewritten c file // capture the rewritten c file
string out_str1; string out_str1;
llvm::raw_string_ostream os1(out_str1); llvm::raw_string_ostream os1(out_str1);
BFrontendAction bact(os1, flags_); BFrontendAction bact(os1, flags_, ts, id);
if (!compiler1.ExecuteAction(bact)) if (!compiler1.ExecuteAction(bact))
return -1; return -1;
unique_ptr<llvm::MemoryBuffer> out_buf1 = llvm::MemoryBuffer::getMemBuffer(out_str1); unique_ptr<llvm::MemoryBuffer> out_buf1 = llvm::MemoryBuffer::getMemBuffer(out_str1);
// this contains the open FDs
*tables = bact.take_tables();
// second pass, clear input and take rewrite buffer // second pass, clear input and take rewrite buffer
CompilerInstance compiler2; CompilerInstance compiler2;
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include "table_storage.h"
namespace llvm { namespace llvm {
class Module; class Module;
class LLVMContext; class LLVMContext;
...@@ -28,14 +30,13 @@ class MemoryBuffer; ...@@ -28,14 +30,13 @@ class MemoryBuffer;
namespace ebpf { namespace ebpf {
struct TableDesc;
class ClangLoader { class ClangLoader {
public: public:
explicit ClangLoader(llvm::LLVMContext *ctx, unsigned flags); explicit ClangLoader(llvm::LLVMContext *ctx, unsigned flags);
~ClangLoader(); ~ClangLoader();
int parse(std::unique_ptr<llvm::Module> *mod, std::unique_ptr<std::vector<TableDesc>> *tables, int parse(std::unique_ptr<llvm::Module> *mod, TableStorage &ts, const std::string &file,
const std::string &file, bool in_memory, const char *cflags[], int ncflags); bool in_memory, const char *cflags[], int ncflags, const std::string &id);
private: private:
static std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>> remapped_files_; static std::map<std::string, std::unique_ptr<llvm::MemoryBuffer>> remapped_files_;
llvm::LLVMContext *ctx_; llvm::LLVMContext *ctx_;
......
/*
* Copyright (c) 2017 VMware, 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.
*/
#include <memory>
#include <string>
#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include "common.h"
#include "table_desc.h"
namespace ebpf {
using std::string;
using std::to_string;
using std::unique_ptr;
using namespace clang;
// Helper visitor for constructing a string representation of a key/leaf decl
class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> {
public:
explicit BMapDeclVisitor(clang::ASTContext &C, std::string &result);
bool TraverseRecordDecl(clang::RecordDecl *Decl);
bool VisitRecordDecl(clang::RecordDecl *Decl);
bool VisitFieldDecl(clang::FieldDecl *Decl);
bool VisitBuiltinType(const clang::BuiltinType *T);
bool VisitTypedefType(const clang::TypedefType *T);
bool VisitTagType(const clang::TagType *T);
bool VisitPointerType(const clang::PointerType *T);
private:
clang::ASTContext &C;
std::string &result_;
};
// Encode the struct layout as a json description
BMapDeclVisitor::BMapDeclVisitor(ASTContext &C, string &result) : C(C), result_(result) {}
bool BMapDeclVisitor::VisitFieldDecl(FieldDecl *D) {
result_ += "\"";
result_ += D->getName();
result_ += "\",";
return true;
}
bool BMapDeclVisitor::TraverseRecordDecl(RecordDecl *D) {
// skip children, handled in Visit...
if (!WalkUpFromRecordDecl(D))
return false;
return true;
}
bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) {
result_ += "[\"";
result_ += D->getName();
result_ += "\", [";
for (auto F : D->getDefinition()->fields()) {
if (F->isAnonymousStructOrUnion()) {
if (const RecordType *R = dyn_cast<RecordType>(F->getType()))
TraverseDecl(R->getDecl());
result_ += ", ";
continue;
}
result_ += "[";
TraverseDecl(F);
if (const ConstantArrayType *T = dyn_cast<ConstantArrayType>(F->getType()))
result_ += ", [" + T->getSize().toString(10, false) + "]";
if (F->isBitField())
result_ += ", " + to_string(F->getBitWidthValue(C));
result_ += "], ";
}
if (!D->getDefinition()->field_empty())
result_.erase(result_.end() - 2);
result_ += "]";
if (D->isUnion())
result_ += ", \"union\"";
else if (D->isStruct())
result_ += ", \"struct\"";
result_ += "]";
return true;
}
// pointer to anything should be treated as terminal, don't recurse further
bool BMapDeclVisitor::VisitPointerType(const PointerType *T) {
result_ += "\"unsigned long long\"";
return false;
}
bool BMapDeclVisitor::VisitTagType(const TagType *T) {
return TraverseDecl(T->getDecl()->getDefinition());
}
bool BMapDeclVisitor::VisitTypedefType(const TypedefType *T) { return TraverseDecl(T->getDecl()); }
bool BMapDeclVisitor::VisitBuiltinType(const BuiltinType *T) {
result_ += "\"";
result_ += T->getName(C.getPrintingPolicy());
result_ += "\"";
return true;
}
class JsonMapTypesVisitor : public virtual MapTypesVisitor {
public:
virtual void Visit(TableDesc &desc, clang::ASTContext &C, clang::QualType key_type,
clang::QualType leaf_type) {
BMapDeclVisitor v1(C, desc.key_desc), v2(C, desc.leaf_desc);
v1.TraverseType(key_type);
v2.TraverseType(leaf_type);
}
};
unique_ptr<MapTypesVisitor> createJsonMapTypesVisitor() {
return make_unique<JsonMapTypesVisitor>();
}
} // namespace ebpf
...@@ -15,51 +15,100 @@ ...@@ -15,51 +15,100 @@
*/ */
#include <unistd.h> #include <unistd.h>
#include <iostream>
#include "shared_table.h" #include "common.h"
#include "compat/linux/bpf.h" #include "compat/linux/bpf.h"
#include "table_storage.h"
#include "table_storage_impl.h"
namespace ebpf { namespace ebpf {
using std::string; using std::string;
using std::unique_ptr;
SharedTables * SharedTables::instance_; /// A process-wide singleton of shared tables
class SharedTableStorage : public TableStorageImpl {
public:
class iterator : public TableStorageIteratorImpl {
std::map<string, TableDesc>::iterator it_;
SharedTables * SharedTables::instance() { public:
if (!instance_) { explicit iterator(const std::map<string, TableDesc>::iterator &it) : it_(it) {}
instance_ = new SharedTables; virtual ~iterator() {}
} virtual unique_ptr<self_type> clone() const override { return make_unique<iterator>(it_); }
return instance_; virtual self_type &operator++() override {
} ++it_;
return *this;
}
virtual value_type &operator*() const override { return *it_; }
virtual pointer operator->() const override { return &*it_; }
};
virtual ~SharedTableStorage() {}
virtual bool Find(const string &name, TableStorage::iterator &result) const override;
virtual bool Insert(const string &name, TableDesc &&desc) override;
virtual bool Delete(const string &name) override;
virtual unique_ptr<TableStorageIteratorImpl> begin() override;
virtual unique_ptr<TableStorageIteratorImpl> end() override;
virtual unique_ptr<TableStorageIteratorImpl> lower_bound(const string &k) override;
virtual unique_ptr<TableStorageIteratorImpl> upper_bound(const string &k) override;
virtual unique_ptr<TableStorageIteratorImpl> erase(const TableStorageIteratorImpl &it) override;
int SharedTables::lookup_fd(const string &name) const { private:
auto table = tables_.find(name); static std::map<string, TableDesc> tables_;
if (table == tables_.end()) };
return -1;
return table->second.first;
}
int SharedTables::lookup_type(const string &name) const { bool SharedTableStorage::Find(const string &name, TableStorage::iterator &result) const {
auto table = tables_.find(name); auto it = tables_.find(name);
if (table == tables_.end()) if (it == tables_.end())
return BPF_MAP_TYPE_UNSPEC; return false;
return table->second.second; result = TableStorage::iterator(make_unique<iterator>(it));
return true;
} }
bool SharedTables::insert_fd(const string &name, int fd, int type) { bool SharedTableStorage::Insert(const string &name, TableDesc &&desc) {
if (tables_.find(name) != tables_.end()) auto it = tables_.find(name);
if (it != tables_.end())
return false; return false;
tables_[name] = std::make_pair(fd, type); tables_[name] = std::move(desc);
return true; return true;
} }
bool SharedTables::remove_fd(const string &name) { bool SharedTableStorage::Delete(const string &name) {
auto table = tables_.find(name); auto it = tables_.find(name);
if (table == tables_.end()) if (it == tables_.end())
return false; return false;
close(table->second.first); tables_.erase(it);
tables_.erase(table);
return true; return true;
} }
unique_ptr<TableStorageIteratorImpl> SharedTableStorage::begin() {
return make_unique<iterator>(tables_.begin());
}
unique_ptr<TableStorageIteratorImpl> SharedTableStorage::end() {
return make_unique<iterator>(tables_.end());
}
unique_ptr<TableStorageIteratorImpl> SharedTableStorage::lower_bound(const string &k) {
return make_unique<iterator>(tables_.lower_bound(k));
}
unique_ptr<TableStorageIteratorImpl> SharedTableStorage::upper_bound(const string &k) {
return make_unique<iterator>(tables_.upper_bound(k));
}
unique_ptr<TableStorageIteratorImpl> SharedTableStorage::erase(const TableStorageIteratorImpl &it) {
auto i = tables_.find((*it).first);
if (i == tables_.end())
return unique_ptr<iterator>();
return make_unique<iterator>(tables_.erase(i));
}
// All maps for this process are kept in global static storage.
std::map<string, TableDesc> SharedTableStorage::tables_;
unique_ptr<TableStorage> createSharedTableStorage() {
auto t = make_unique<TableStorage>();
t->Init(make_unique<SharedTableStorage>());
t->AddMapTypesVisitor(createJsonMapTypesVisitor());
return t;
}
} }
...@@ -16,27 +16,3 @@ ...@@ -16,27 +16,3 @@
#pragma once #pragma once
#include <map>
#include <string>
namespace ebpf {
struct TableDesc;
class SharedTables {
public:
static SharedTables * instance();
// add an fd to the shared table, return true if successfully inserted
bool insert_fd(const std::string &name, int fd, int type);
// lookup an fd in the shared table, or -1 if not found
int lookup_fd(const std::string &name) const;
// lookup on map type in the shared table, or BPF_MAP_TYPE_UNSPEC if not found
int lookup_type(const std::string &name) const;
// close and remove a shared fd. return true if the value was found
bool remove_fd(const std::string &name);
private:
static SharedTables *instance_;
std::map<std::string, std::pair<int, int>> tables_;
};
}
...@@ -16,18 +16,101 @@ ...@@ -16,18 +16,101 @@
#pragma once #pragma once
#include <unistd.h>
#include <cstdint> #include <cstdint>
#include <memory>
#include <string> #include <string>
namespace llvm { namespace llvm {
class Function; class Function;
} }
namespace clang {
class ASTContext;
class QualType;
}
namespace ebpf { namespace ebpf {
struct TableDesc { class TableDesc;
std::string name;
/// FileDesc is a helper class for managing open file descriptors. Copy is
/// disallowed (call dup instead), and cleanup happens automatically.
class FileDesc {
friend TableDesc;
private:
FileDesc &operator=(const FileDesc &that) {
fd = ::dup(that.fd);
return *this;
}
FileDesc(const FileDesc &that) { *this = that; }
public:
FileDesc(int fd = -1) : fd(fd) {}
FileDesc &operator=(FileDesc &&that) {
fd = that.fd;
that.fd = -1;
return *this;
}
FileDesc(FileDesc &&that) { *this = std::move(that); }
~FileDesc() {
if (fd >= 0)
::close(fd);
}
FileDesc dup() const { return FileDesc(*this); }
operator int() { return fd; }
operator int() const { return fd; }
private:
int fd; int fd;
};
/// TableDesc uniquely stores all of the runtime state for an active bpf table.
/// The copy constructor/assign operator are disabled since the file handles
/// owned by this table are not implicitly copyable. One should call the dup()
/// method if an explicit new handle is required. We define the move operators
/// so that objects of this class can reside in stl containers.
class TableDesc {
private:
TableDesc(const TableDesc &) = default;
TableDesc &operator=(const TableDesc &) = default;
public:
TableDesc()
: type(0),
key_size(0),
leaf_size(0),
max_entries(0),
flags(0),
key_sscanf(nullptr),
leaf_sscanf(nullptr),
key_snprintf(nullptr),
leaf_snprintf(nullptr),
is_shared(false),
is_extern(false) {}
TableDesc(const std::string &name, FileDesc &&fd, int type, size_t key_size,
size_t leaf_size, size_t max_entries, int flags)
: name(name),
fd(std::move(fd)),
type(type),
key_size(key_size),
leaf_size(leaf_size),
max_entries(max_entries),
flags(flags),
key_sscanf(nullptr),
leaf_sscanf(nullptr),
key_snprintf(nullptr),
leaf_snprintf(nullptr),
is_shared(false),
is_extern(false) {}
TableDesc(TableDesc &&that) = default;
TableDesc &operator=(TableDesc &&that) = default;
TableDesc dup() const { return TableDesc(*this); }
std::string name;
FileDesc fd;
int type; int type;
size_t key_size; // sizes are in bytes size_t key_size; // sizes are in bytes
size_t leaf_size; size_t leaf_size;
...@@ -43,4 +126,17 @@ struct TableDesc { ...@@ -43,4 +126,17 @@ struct TableDesc {
bool is_extern; bool is_extern;
}; };
/// MapTypesVisitor gets notified of new bpf tables, and has a chance to parse
/// the key and leaf types for their own usage. Subclass this abstract class and
/// implement the Visit method, then add an instance of this class to the
/// StorageTable instance to be notified of each new key/leaf type.
class MapTypesVisitor {
public:
virtual ~MapTypesVisitor() {}
virtual void Visit(TableDesc &desc, clang::ASTContext &C, clang::QualType key_type,
clang::QualType leaf_type) = 0;
};
std::unique_ptr<MapTypesVisitor> createJsonMapTypesVisitor();
} // namespace ebpf } // namespace ebpf
/*
* Copyright (c) 2017 VMware, 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.
*/
#include <unistd.h>
#include <clang/AST/Type.h>
#include "table_storage_impl.h"
namespace ebpf {
using std::move;
using std::string;
using std::unique_ptr;
const string Path::DELIM = "/";
TableStorage::TableStorage() {}
TableStorage::~TableStorage() {}
void TableStorage::Init(unique_ptr<TableStorageImpl> impl) { impl_ = move(impl); }
bool TableStorage::Find(const Path &path, TableStorage::iterator &result) const {
return impl_->Find(path.to_string(), result);
}
bool TableStorage::Insert(const Path &path, TableDesc &&desc) {
return impl_->Insert(path.to_string(), move(desc));
}
bool TableStorage::Delete(const Path &path) { return impl_->Delete(path.to_string()); }
size_t TableStorage::DeletePrefix(const Path &path) {
size_t i = 0;
auto it = lower_bound(path);
auto upper = upper_bound(path);
while (it != upper) {
it = impl_->erase(*it.impl_);
++i;
}
return i;
}
void TableStorage::AddMapTypesVisitor(unique_ptr<MapTypesVisitor> visitor) {
visitors_.push_back(move(visitor));
}
void TableStorage::VisitMapType(TableDesc &desc, clang::ASTContext &C, clang::QualType key_type,
clang::QualType leaf_type) {
for (auto &v : visitors_)
v->Visit(desc, C, key_type, leaf_type);
}
TableStorage::iterator TableStorage::begin() { return impl_->begin(); }
TableStorage::iterator TableStorage::end() { return impl_->end(); }
TableStorage::iterator TableStorage::lower_bound(const Path &p) {
return impl_->lower_bound(p.to_string());
}
TableStorage::iterator TableStorage::upper_bound(const Path &p) {
return impl_->upper_bound(p.to_string() + "\x7f");
}
/// TableStorage::iterator implementation
TableStorage::iterator::iterator() {}
TableStorage::iterator::iterator(unique_ptr<TableStorageIteratorImpl> impl) : impl_(move(impl)) {}
TableStorage::iterator::iterator(const iterator &that) : impl_(that.impl_->clone()) {}
TableStorage::iterator::~iterator() {}
TableStorage::iterator::iterator(iterator &&that) { *this = move(that); }
TableStorage::iterator &TableStorage::iterator::operator=(iterator &&that) {
impl_ = move(that.impl_);
return *this;
}
TableStorage::iterator &TableStorage::iterator::operator++() {
++*impl_;
return *this;
}
TableStorage::iterator TableStorage::iterator::operator++(int) {
iterator tmp(*this);
operator++();
return tmp;
}
bool TableStorage::iterator::operator==(const iterator &rhs) const {
// assumes that the underlying pair is stored in only one place
return &**impl_ == &**rhs.impl_;
}
bool TableStorage::iterator::operator!=(const iterator &rhs) const {
return &**impl_ != &**rhs.impl_;
}
TableStorage::iterator::reference TableStorage::iterator::operator*() const { return **impl_; }
TableStorage::iterator::pointer TableStorage::iterator::operator->() const { return &**impl_; }
} // namespace ebpf
/*
* Copyright (c) 2017 VMware, 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 <cstddef>
#include <iterator>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "table_desc.h"
namespace ebpf {
class TableStorageImpl;
class TableStorageIteratorImpl;
class Path {
public:
static const std::string DELIM;
Path() = default;
Path(const Path &other) = default;
Path &operator=(const Path &other) = default;
Path(std::initializer_list<std::string> parts) {
size_t len = parts.size() * DELIM.size();
for (const auto &s : parts)
len += s.size();
path_.reserve(len);
for (const auto &s : parts)
path_ += DELIM + s;
}
const std::string &to_string() const { return path_; }
private:
std::string path_;
};
class TableStorage {
public:
/// iterator is an abstract class for traversing the map entries in a table
/// storage object.
class iterator {
private:
friend class TableStorage;
iterator(const iterator &);
public:
typedef std::pair<const std::string, TableDesc> value_type;
typedef std::ptrdiff_t difference_type;
typedef value_type *pointer;
typedef value_type &reference;
typedef std::forward_iterator_tag iterator_category;
typedef iterator self_type;
iterator();
iterator(std::unique_ptr<TableStorageIteratorImpl>);
~iterator();
iterator(iterator &&);
iterator &operator=(iterator &&);
self_type &operator++();
self_type operator++(int);
bool operator==(const self_type &) const;
bool operator!=(const self_type &) const;
value_type &operator*() const;
pointer operator->() const;
private:
std::unique_ptr<TableStorageIteratorImpl> impl_;
};
TableStorage();
~TableStorage();
void Init(std::unique_ptr<TableStorageImpl>);
bool Find(const Path &path, TableStorage::iterator &result) const;
bool Insert(const Path &path, TableDesc &&desc);
bool Delete(const Path &path);
size_t DeletePrefix(const Path &path);
void AddMapTypesVisitor(std::unique_ptr<MapTypesVisitor>);
void VisitMapType(TableDesc &desc, clang::ASTContext &C, clang::QualType key_type,
clang::QualType leaf_type);
iterator begin();
iterator end();
iterator lower_bound(const Path &p);
iterator upper_bound(const Path &p);
private:
std::unique_ptr<TableStorageImpl> impl_;
std::vector<std::unique_ptr<MapTypesVisitor>> visitors_;
};
std::unique_ptr<TableStorage> createSharedTableStorage();
std::unique_ptr<TableStorage> createBpfFsTableStorage();
}
/*
* Copyright (c) 2017 VMware, 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 "table_storage.h"
namespace ebpf {
class TableStorageIteratorImpl {
public:
typedef std::pair<const std::string, TableDesc> value_type;
typedef value_type *pointer;
typedef value_type &reference;
typedef TableStorageIteratorImpl self_type;
virtual ~TableStorageIteratorImpl() {}
virtual std::unique_ptr<self_type> clone() const = 0;
virtual self_type &operator++() = 0;
virtual value_type &operator*() const = 0;
virtual pointer operator->() const = 0;
private:
};
class TableStorageImpl {
public:
virtual ~TableStorageImpl(){};
virtual bool Find(const std::string &name, TableStorage::iterator &result) const = 0;
virtual bool Insert(const std::string &name, TableDesc &&desc) = 0;
virtual bool Delete(const std::string &name) = 0;
virtual std::unique_ptr<TableStorageIteratorImpl> begin() = 0;
virtual std::unique_ptr<TableStorageIteratorImpl> end() = 0;
virtual std::unique_ptr<TableStorageIteratorImpl> lower_bound(const std::string &k) = 0;
virtual std::unique_ptr<TableStorageIteratorImpl> upper_bound(const std::string &k) = 0;
virtual std::unique_ptr<TableStorageIteratorImpl> erase(const TableStorageIteratorImpl &it) = 0;
};
} // namespace ebpf
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