Commit 949e9eb1 authored by 4ast's avatar 4ast

Merge pull request #119 from iovisor/bblanco_dev

Patch series: reorganize bpf_module and add sscanf feature for fuse
parents fdb3f74e 5c387ba4
...@@ -33,7 +33,8 @@ add_library(bpfprog SHARED bpf_common.cc bpf_module.cc libbpf.c) ...@@ -33,7 +33,8 @@ add_library(bpfprog SHARED bpf_common.cc bpf_module.cc libbpf.c)
# BPF is still experimental otherwise it should be available # BPF is still experimental otherwise it should be available
#llvm_map_components_to_libnames(llvm_libs bpf mcjit irreader passes) #llvm_map_components_to_libnames(llvm_libs bpf mcjit irreader passes)
llvm_map_components_to_libnames(llvm_libs mcjit irreader passes linker instrumentation objcarcopts bitwriter option) llvm_map_components_to_libnames(llvm_libs mcjit irreader passes linker
instrumentation objcarcopts bitwriter option x86codegen)
# order is important # order is important
set(clang_libs ${libclangFrontend} ${libclangSerialization} ${libclangDriver} ${libclangParse} set(clang_libs ${libclangFrontend} ${libclangSerialization} ${libclangDriver} ${libclangParse}
${libclangSema} ${libclangCodeGen} ${libclangAnalysis} ${libclangRewrite} ${libclangEdit} ${libclangSema} ${libclangCodeGen} ${libclangAnalysis} ${libclangRewrite} ${libclangEdit}
......
...@@ -146,4 +146,40 @@ const char * bpf_table_leaf_desc_id(void *program, size_t id) { ...@@ -146,4 +146,40 @@ const char * bpf_table_leaf_desc_id(void *program, size_t id) {
return mod->table_leaf_desc(id); return mod->table_leaf_desc(id);
} }
size_t bpf_table_key_size(void *program, const char *table_name) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_key_size(table_name);
}
size_t bpf_table_key_size_id(void *program, size_t id) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_key_size(id);
}
size_t bpf_table_leaf_size(void *program, const char *table_name) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_leaf_size(table_name);
}
size_t bpf_table_leaf_size_id(void *program, size_t id) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_leaf_size(id);
}
int bpf_table_update(void *program, const char *table_name, const char *key, const char *leaf) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_update(table_name, key, leaf);
}
int bpf_table_update_id(void *program, size_t id, const char *key, const char *leaf) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return 0;
return mod->table_update(id, key, leaf);
}
} }
...@@ -44,6 +44,12 @@ const char * bpf_table_key_desc(void *program, const char *table_name); ...@@ -44,6 +44,12 @@ const char * bpf_table_key_desc(void *program, const char *table_name);
const char * bpf_table_key_desc_id(void *program, size_t id); const char * bpf_table_key_desc_id(void *program, size_t id);
const char * bpf_table_leaf_desc(void *program, const char *table_name); const char * bpf_table_leaf_desc(void *program, const char *table_name);
const char * bpf_table_leaf_desc_id(void *program, size_t id); const char * bpf_table_leaf_desc_id(void *program, size_t id);
size_t bpf_table_key_size(void *program, const char *table_name);
size_t bpf_table_key_size_id(void *program, size_t id);
size_t bpf_table_leaf_size(void *program, const char *table_name);
size_t bpf_table_leaf_size_id(void *program, size_t id);
int bpf_table_update(void *program, const char *table_name, const char *key, const char *leaf);
int bpf_table_update_id(void *program, size_t id, const char *key, const char *leaf);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
...@@ -26,9 +26,11 @@ ...@@ -26,9 +26,11 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <llvm/ADT/STLExtras.h> #include <llvm/ADT/STLExtras.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/ExecutionEngine/MCJIT.h> #include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h> #include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/IRReader/IRReader.h> #include <llvm/IRReader/IRReader.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/IRPrintingPasses.h> #include <llvm/IR/IRPrintingPasses.h>
#include <llvm/IR/LegacyPassManager.h> #include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
...@@ -38,6 +40,7 @@ ...@@ -38,6 +40,7 @@
#include <llvm/Support/FormattedStream.h> #include <llvm/Support/FormattedStream.h>
#include <llvm/Support/Host.h> #include <llvm/Support/Host.h>
#include <llvm/Support/SourceMgr.h> #include <llvm/Support/SourceMgr.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Transforms/IPO.h> #include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h> #include <llvm/Transforms/IPO/PassManagerBuilder.h>
...@@ -95,6 +98,8 @@ class MyMemoryManager : public SectionMemoryManager { ...@@ -95,6 +98,8 @@ class MyMemoryManager : public SectionMemoryManager {
BPFModule::BPFModule(unsigned flags) BPFModule::BPFModule(unsigned flags)
: flags_(flags), ctx_(new LLVMContext) { : flags_(flags), ctx_(new LLVMContext) {
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
LLVMInitializeBPFTarget(); LLVMInitializeBPFTarget();
LLVMInitializeBPFTargetMC(); LLVMInitializeBPFTargetMC();
LLVMInitializeBPFTargetInfo(); LLVMInitializeBPFTargetInfo();
...@@ -107,31 +112,117 @@ BPFModule::~BPFModule() { ...@@ -107,31 +112,117 @@ BPFModule::~BPFModule() {
ctx_.reset(); ctx_.reset();
} }
// load an entire c file as a module // recursive helper to capture the arguments
int BPFModule::load_cfile(const string &file, bool in_memory) { void parse_type(IRBuilder<> &B, vector<Value *> *args, string *fmt, Type *type, Value *out) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_); if (StructType *st = dyn_cast<StructType>(type)) {
unique_ptr<Module> mod; *fmt += "{ ";
if (clang_loader_->parse(&mod, &tables_, file, in_memory)) unsigned idx = 0;
return -1; for (auto field : st->elements()) {
mod_ = &*mod; parse_type(B, args, fmt, field, B.CreateStructGEP(type, out, idx++));
*fmt += " ";
}
*fmt += "}";
} else if (IntegerType *it = dyn_cast<IntegerType>(type)) {
if (it->getBitWidth() <= 8)
*fmt += "%hhi";
else if (it->getBitWidth() <= 16)
*fmt += "%hi";
else if (it->getBitWidth() <= 32)
*fmt += "%i";
else if (it->getBitWidth() <= 64)
*fmt += "%li";
else
*fmt += "%lli";
args->push_back(out);
}
}
mod_->setDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); Function * BPFModule::make_reader(Module *mod, Type *type) {
mod_->setTargetTriple("bpf-pc-linux"); auto fn_it = readers_.find(type);
if (fn_it != readers_.end())
return fn_it->second;
// int read(const char *in, Type *out) {
// int n = sscanf(in, "{ %i ... }", &out->field1, ...);
// if (n != num_fields) return -1;
// return 0;
// }
IRBuilder<> B(*ctx_);
// The JIT currently supports a limited number of function prototypes, use the
// int (*) (int, char **, const char **) version
vector<Type *> fn_args({B.getInt32Ty(), B.getInt8PtrTy(), PointerType::getUnqual(type)});
FunctionType *fn_type = FunctionType::get(B.getInt32Ty(), fn_args, /*isVarArg=*/false);
Function *fn = Function::Create(fn_type, GlobalValue::ExternalLinkage,
"reader" + std::to_string(readers_.size()), mod);
auto arg_it = fn->arg_begin();
Argument *arg_argc = arg_it++;
arg_argc->setName("argc");
Argument *arg_in = arg_it++;
arg_in->setName("in");
Argument *arg_out = arg_it++;
arg_out->setName("out");
BasicBlock *label_entry = BasicBlock::Create(*ctx_, "entry", fn);
BasicBlock *label_exit = BasicBlock::Create(*ctx_, "exit", fn);
B.SetInsertPoint(label_entry);
vector<Value *> args;
string fmt;
parse_type(B, &args, &fmt, type, arg_out);
GlobalVariable *fmt_gvar = B.CreateGlobalString(fmt, "fmt");
args.insert(args.begin(), B.CreateInBoundsGEP(fmt_gvar, vector<Value *>({B.getInt64(0), B.getInt64(0)})));
args.insert(args.begin(), arg_in);
vector<Type *> sscanf_fn_args({B.getInt8PtrTy(), B.getInt8PtrTy()});
FunctionType *sscanf_fn_type = FunctionType::get(B.getInt32Ty(), sscanf_fn_args, /*isVarArg=*/true);
Function *sscanf_fn = mod->getFunction("sscanf");
if (!sscanf_fn)
sscanf_fn = Function::Create(sscanf_fn_type, GlobalValue::ExternalLinkage, "sscanf", mod);
sscanf_fn->setCallingConv(CallingConv::C);
sscanf_fn->addFnAttr(Attribute::NoUnwind);
CallInst *call = B.CreateCall(sscanf_fn, args);
call->setTailCall(true);
BasicBlock *label_then = BasicBlock::Create(*ctx_, "then", fn);
Value *is_neq = B.CreateICmpNE(call, B.getInt32(args.size() - 2));
B.CreateCondBr(is_neq, label_then, label_exit);
B.SetInsertPoint(label_then);
B.CreateRet(B.getInt32(-1));
B.SetInsertPoint(label_exit);
B.CreateRet(B.getInt32(0));
readers_[type] = fn;
return fn;
}
for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn) unique_ptr<ExecutionEngine> BPFModule::finalize_reader(unique_ptr<Module> m) {
fn->addFnAttr(Attribute::AlwaysInline); Module *mod = &*m;
run_pass_manager(*mod);
string err; string err;
engine_ = unique_ptr<ExecutionEngine>(EngineBuilder(move(mod)) EngineBuilder builder(move(m));
.setErrorStr(&err) builder.setErrorStr(&err);
.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections_)) builder.setUseOrcMCJITReplacement(true);
.setMArch("bpf") auto engine = unique_ptr<ExecutionEngine>(builder.create());
.create()); if (!engine)
if (!engine_) {
fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str()); fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str());
return -1; return engine;
} }
// load an entire c file as a module
int BPFModule::load_cfile(const string &file, bool in_memory) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_);
if (clang_loader_->parse(&mod_, &tables_, file, in_memory))
return -1;
return 0; return 0;
} }
...@@ -142,41 +233,59 @@ int BPFModule::load_cfile(const string &file, bool in_memory) { ...@@ -142,41 +233,59 @@ int BPFModule::load_cfile(const string &file, bool in_memory) {
// build an ExecutionEngine. // build an ExecutionEngine.
int BPFModule::load_includes(const string &tmpfile) { int BPFModule::load_includes(const string &tmpfile) {
clang_loader_ = make_unique<ClangLoader>(&*ctx_); clang_loader_ = make_unique<ClangLoader>(&*ctx_);
unique_ptr<Module> mod; if (clang_loader_->parse(&mod_, &tables_, tmpfile, false))
if (clang_loader_->parse(&mod, &tables_, tmpfile, false))
return -1; return -1;
mod_ = &*mod; return 0;
}
mod_->setDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
mod_->setTargetTriple("bpf-pc-linux");
int BPFModule::annotate() {
for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn) for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn)
fn->addFnAttr(Attribute::AlwaysInline); fn->addFnAttr(Attribute::AlwaysInline);
string err; // separate module to hold the reader functions
engine_ = unique_ptr<ExecutionEngine>(EngineBuilder(move(mod)) auto m = make_unique<Module>("sscanf", *ctx_);
.setErrorStr(&err)
.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections_)) size_t id = 0;
.setMArch("bpf") for (auto &table : *tables_) {
.create()); table_names_[table.name] = id++;
if (!engine_) { GlobalValue *gvar = mod_->getNamedValue(table.name);
fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str()); if (!gvar) continue;
return -1; if (PointerType *pt = dyn_cast<PointerType>(gvar->getType())) {
if (StructType *st = dyn_cast<StructType>(pt->getElementType())) {
if (st->getNumElements() < 2) continue;
Type *key_type = st->elements()[0];
Type *leaf_type = st->elements()[1];
table.key_reader = make_reader(&*m, key_type);
if (!table.key_reader) {
errs() << "Failed to compile reader for " << *key_type << "\n";
continue;
}
table.leaf_reader = make_reader(&*m, leaf_type);
if (!table.leaf_reader) {
errs() << "Failed to compile reader for " << *leaf_type << "\n";
continue;
}
}
}
} }
reader_engine_ = finalize_reader(move(m));
if (reader_engine_)
reader_engine_->finalizeObject();
return 0; return 0;
} }
void BPFModule::dump_ir() { void BPFModule::dump_ir(Module &mod) {
legacy::PassManager PM; legacy::PassManager PM;
PM.add(createPrintModulePass(outs())); PM.add(createPrintModulePass(errs()));
PM.run(*mod_); PM.run(mod);
} }
int BPFModule::finalize() { int BPFModule::run_pass_manager(Module &mod) {
if (verifyModule(*mod_, &errs())) { if (verifyModule(mod, &errs())) {
if (flags_ & 1) if (flags_ & 1)
dump_ir(); dump_ir(mod);
return -1; return -1;
} }
...@@ -188,7 +297,30 @@ int BPFModule::finalize() { ...@@ -188,7 +297,30 @@ int BPFModule::finalize() {
PMB.populateModulePassManager(PM); PMB.populateModulePassManager(PM);
if (flags_ & 1) if (flags_ & 1)
PM.add(createPrintModulePass(outs())); PM.add(createPrintModulePass(outs()));
PM.run(*mod_); PM.run(mod);
return 0;
}
int BPFModule::finalize() {
Module *mod = &*mod_;
mod->setDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128");
mod->setTargetTriple("bpf-pc-linux");
string err;
EngineBuilder builder(move(mod_));
builder.setErrorStr(&err);
builder.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections_));
builder.setMArch("bpf");
builder.setUseOrcMCJITReplacement(true);
engine_ = unique_ptr<ExecutionEngine>(builder.create());
if (!engine_) {
fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str());
return -1;
}
if (int rc = run_pass_manager(*mod))
return rc;
engine_->finalizeObject(); engine_->finalizeObject();
...@@ -197,9 +329,6 @@ int BPFModule::finalize() { ...@@ -197,9 +329,6 @@ int BPFModule::finalize() {
if (!strncmp(FN_PREFIX.c_str(), section.first.c_str(), FN_PREFIX.size())) if (!strncmp(FN_PREFIX.c_str(), section.first.c_str(), FN_PREFIX.size()))
function_names_.push_back(section.first); function_names_.push_back(section.first);
for (auto table : *tables_)
table_names_.push_back(table.first);
return 0; return 0;
} }
...@@ -264,49 +393,99 @@ unsigned BPFModule::kern_version() const { ...@@ -264,49 +393,99 @@ unsigned BPFModule::kern_version() const {
} }
size_t BPFModule::num_tables() const { size_t BPFModule::num_tables() const {
return table_names_.size(); return tables_->size();
} }
int BPFModule::table_fd(const string &name) const { int BPFModule::table_fd(const string &name) const {
int fd = b_loader_ ? b_loader_->get_table_fd(name) : -1; auto it = table_names_.find(name);
if (fd >= 0) return fd; if (it == table_names_.end()) return -1;
auto table_it = tables_->find(name); return table_fd(it->second);
if (table_it == tables_->end()) return -1;
return table_it->second.fd;
} }
int BPFModule::table_fd(size_t id) const { int BPFModule::table_fd(size_t id) const {
if (id >= table_names_.size()) return -1; if (id >= tables_->size()) return -1;
return table_fd(table_names_[id]); return (*tables_)[id].fd;
} }
const char * BPFModule::table_name(size_t id) const { const char * BPFModule::table_name(size_t id) const {
if (id >= table_names_.size()) return nullptr; if (id >= tables_->size()) return nullptr;
return table_names_[id].c_str(); 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 (id >= table_names_.size()) return nullptr; if (b_loader_) return nullptr;
return table_key_desc(table_names_[id]); if (id >= tables_->size()) 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 {
if (b_loader_) return nullptr; auto it = table_names_.find(name);
auto table_it = tables_->find(name); if (it == table_names_.end()) return nullptr;
if (table_it == tables_->end()) return nullptr; return table_key_desc(it->second);
return table_it->second.key_desc.c_str();
} }
const char * BPFModule::table_leaf_desc(size_t id) const { const char * BPFModule::table_leaf_desc(size_t id) const {
if (id >= table_names_.size()) return nullptr; if (b_loader_) return nullptr;
return table_leaf_desc(table_names_[id]); if (id >= tables_->size()) 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 {
if (b_loader_) return nullptr; auto it = table_names_.find(name);
auto table_it = tables_->find(name); if (it == table_names_.end()) return nullptr;
if (table_it == tables_->end()) return nullptr; return table_leaf_desc(it->second);
return table_it->second.leaf_desc.c_str(); }
size_t BPFModule::table_key_size(size_t id) const {
if (id >= tables_->size()) return 0;
return (*tables_)[id].key_size;
}
size_t BPFModule::table_key_size(const string &name) const {
auto it = table_names_.find(name);
if (it == table_names_.end()) return 0;
return table_key_size(it->second);
}
size_t BPFModule::table_leaf_size(size_t id) const {
if (id >= tables_->size()) return 0;
return (*tables_)[id].leaf_size;
}
size_t BPFModule::table_leaf_size(const string &name) const {
auto it = table_names_.find(name);
if (it == table_names_.end()) return 0;
return table_leaf_size(it->second);
}
int BPFModule::table_update(const string &name, const char *key_str, const char *leaf_str) {
auto it = table_names_.find(name);
if (it == table_names_.end()) return 0;
return table_update(it->second, key_str, leaf_str);
}
int BPFModule::table_update(size_t id, const char *key_str, const char *leaf_str) {
if (id >= tables_->size()) return -1;
const TableDesc &desc = (*tables_)[id];
if (desc.fd < 0) return -1;
if (!reader_engine_ || !desc.key_reader || !desc.leaf_reader) {
fprintf(stderr, "Table sscanf not available\n");
return -1;
}
unique_ptr<uint8_t[]> key(new uint8_t[desc.key_size]);
unique_ptr<uint8_t[]> leaf(new uint8_t[desc.leaf_size]);
GenericValue rc;
rc = reader_engine_->runFunction(desc.key_reader, vector<GenericValue>({GenericValue(),
GenericValue((void *)key_str),
GenericValue((void *)key.get())}));
if (rc.IntVal != 0)
return -1;
rc = reader_engine_->runFunction(desc.leaf_reader, vector<GenericValue>({GenericValue(),
GenericValue((void *)leaf_str),
GenericValue((void *)leaf.get())}));
if (rc.IntVal != 0)
return -1;
return bpf_update_elem(desc.fd, key.get(), leaf.get(), 0);
} }
// load a B file, which comes in two parts // load a B file, which comes in two parts
...@@ -326,7 +505,9 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) { ...@@ -326,7 +505,9 @@ int BPFModule::load_b(const string &filename, const string &proto_filename) {
return rc; return rc;
b_loader_.reset(new BLoader); b_loader_.reset(new BLoader);
if (int rc = b_loader_->parse(mod_, filename, proto_filename)) if (int rc = b_loader_->parse(&*mod_, filename, proto_filename, &tables_))
return rc;
if (int rc = annotate())
return rc; return rc;
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
...@@ -345,6 +526,8 @@ int BPFModule::load_c(const string &filename) { ...@@ -345,6 +526,8 @@ int BPFModule::load_c(const string &filename) {
} }
if (int rc = load_cfile(filename, false)) if (int rc = load_cfile(filename, false))
return rc; return rc;
if (int rc = annotate())
return rc;
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
return 0; return 0;
...@@ -358,6 +541,8 @@ int BPFModule::load_string(const string &text) { ...@@ -358,6 +541,8 @@ int BPFModule::load_string(const string &text) {
} }
if (int rc = load_cfile(text, true)) if (int rc = load_cfile(text, true))
return rc; return rc;
if (int rc = annotate())
return rc;
if (int rc = finalize()) if (int rc = finalize())
return rc; return rc;
......
...@@ -24,12 +24,14 @@ ...@@ -24,12 +24,14 @@
namespace llvm { namespace llvm {
class ExecutionEngine; class ExecutionEngine;
class Function;
class LLVMContext; class LLVMContext;
class Module; class Module;
class Type;
} }
namespace ebpf { namespace ebpf {
class BPFTable; class TableDesc;
class BLoader; class BLoader;
class ClangLoader; class ClangLoader;
...@@ -39,11 +41,15 @@ class BPFModule { ...@@ -39,11 +41,15 @@ class BPFModule {
int init_engine(); int init_engine();
int parse(llvm::Module *mod); int parse(llvm::Module *mod);
int finalize(); int finalize();
void dump_ir(); int annotate();
std::unique_ptr<llvm::ExecutionEngine> finalize_reader(std::unique_ptr<llvm::Module> mod);
llvm::Function * make_reader(llvm::Module *mod, llvm::Type *type);
void dump_ir(llvm::Module &mod);
int load_file_module(std::unique_ptr<llvm::Module> *mod, const std::string &file, bool in_memory); int load_file_module(std::unique_ptr<llvm::Module> *mod, const std::string &file, bool in_memory);
int load_includes(const std::string &tmpfile); int load_includes(const std::string &tmpfile);
int load_cfile(const std::string &file, bool in_memory); int load_cfile(const std::string &file, bool in_memory);
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);
public: public:
BPFModule(unsigned flags); BPFModule(unsigned flags);
~BPFModule(); ~BPFModule();
...@@ -62,8 +68,14 @@ class BPFModule { ...@@ -62,8 +68,14 @@ class BPFModule {
const char * table_name(size_t id) const; const char * table_name(size_t id) const;
const char * table_key_desc(size_t id) const; const char * table_key_desc(size_t id) const;
const char * table_key_desc(const std::string &name) const; const char * table_key_desc(const std::string &name) const;
size_t table_key_size(size_t id) const;
size_t table_key_size(const std::string &name) const;
const char * table_leaf_desc(size_t id) const; const char * table_leaf_desc(size_t id) const;
const char * table_leaf_desc(const std::string &name) const; const char * table_leaf_desc(const std::string &name) const;
size_t table_leaf_size(size_t id) const;
size_t table_leaf_size(const std::string &name) const;
int table_update(size_t id, const char *key, const char *leaf);
int table_update(const std::string &name, const char *key, const char *leaf);
char * license() const; char * license() const;
unsigned kern_version() const; unsigned kern_version() const;
private: private:
...@@ -72,13 +84,15 @@ class BPFModule { ...@@ -72,13 +84,15 @@ class BPFModule {
std::string proto_filename_; std::string proto_filename_;
std::unique_ptr<llvm::LLVMContext> ctx_; std::unique_ptr<llvm::LLVMContext> ctx_;
std::unique_ptr<llvm::ExecutionEngine> engine_; std::unique_ptr<llvm::ExecutionEngine> engine_;
llvm::Module *mod_; std::unique_ptr<llvm::ExecutionEngine> reader_engine_;
std::unique_ptr<llvm::Module> mod_;
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::map<std::string, BPFTable>> tables_; std::unique_ptr<std::vector<TableDesc>> tables_;
std::vector<std::string> 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_;
}; };
} // namespace ebpf } // namespace ebpf
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "exception.h" #include "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 "type_helper.h"
#include "linux/bpf.h" #include "linux/bpf.h"
#include "libbpf.h" #include "libbpf.h"
...@@ -47,6 +48,7 @@ using namespace llvm; ...@@ -47,6 +48,7 @@ using namespace llvm;
using std::for_each; using std::for_each;
using std::make_tuple; using std::make_tuple;
using std::map;
using std::pair; using std::pair;
using std::set; using std::set;
using std::string; using std::string;
...@@ -1085,20 +1087,17 @@ StatusTuple CodegenLLVM::visit_table_decl_stmt_node(TableDeclStmtNode *n) { ...@@ -1085,20 +1087,17 @@ StatusTuple CodegenLLVM::visit_table_decl_stmt_node(TableDeclStmtNode *n) {
else else
return mkstatus_(n, "Table type %s not implemented", n->type_id()->name_.c_str()); return mkstatus_(n, "Table type %s not implemented", n->type_id()->name_.c_str());
StructType *key_stype, *leaf_stype;
TRY2(lookup_struct_type(n->key_type_, &key_stype));
TRY2(lookup_struct_type(n->leaf_type_, &leaf_stype));
StructType *decl_struct = mod_->getTypeByName("_struct." + n->id_->name_); StructType *decl_struct = mod_->getTypeByName("_struct." + n->id_->name_);
if (!decl_struct) if (!decl_struct)
decl_struct = StructType::create(ctx(), "_struct." + n->id_->name_); decl_struct = StructType::create(ctx(), "_struct." + n->id_->name_);
if (decl_struct->isOpaque()) if (decl_struct->isOpaque())
decl_struct->setBody(std::vector<Type *>({Type::getInt32Ty(ctx()), Type::getInt32Ty(ctx()), decl_struct->setBody(vector<Type *>({key_stype, leaf_stype}), /*isPacked=*/false);
Type::getInt32Ty(ctx()), Type::getInt32Ty(ctx())}),
/*isPacked=*/false);
GlobalVariable *decl_gvar = new GlobalVariable(*mod_, decl_struct, false, GlobalVariable *decl_gvar = new GlobalVariable(*mod_, decl_struct, false,
GlobalValue::ExternalLinkage, 0, n->id_->name_); GlobalValue::ExternalLinkage, 0, n->id_->name_);
decl_gvar->setSection("maps"); decl_gvar->setSection("maps");
vector<Constant *> struct_init = { B.getInt32(map_type), B.getInt32(key->bit_width_ / 8),
B.getInt32(leaf->bit_width_ / 8), B.getInt32(n->size_)};
Constant *const_struct = ConstantStruct::get(decl_struct, struct_init);
decl_gvar->setInitializer(const_struct);
tables_[n] = decl_gvar; tables_[n] = decl_gvar;
int map_fd = bpf_create_map(map_type, key->bit_width_ / 8, leaf->bit_width_ / 8, n->size_); int map_fd = bpf_create_map(map_type, key->bit_width_ / 8, leaf->bit_width_ / 8, n->size_);
...@@ -1168,7 +1167,7 @@ StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) { ...@@ -1168,7 +1167,7 @@ StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) {
BasicBlock *label_entry = BasicBlock::Create(ctx(), "entry", fn); BasicBlock *label_entry = BasicBlock::Create(ctx(), "entry", fn);
B.SetInsertPoint(label_entry); B.SetInsertPoint(label_entry);
string scoped_entry_label = std::to_string((uintptr_t)fn) + "::entry"; string scoped_entry_label = to_string((uintptr_t)fn) + "::entry";
labels_[scoped_entry_label] = label_entry; labels_[scoped_entry_label] = label_entry;
BasicBlock *label_return = resolve_label("DONE"); BasicBlock *label_return = resolve_label("DONE");
retval_ = new AllocaInst(fn->getReturnType(), "ret", label_entry); retval_ = new AllocaInst(fn->getReturnType(), "ret", label_entry);
...@@ -1219,7 +1218,7 @@ StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) { ...@@ -1219,7 +1218,7 @@ StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) {
return mkstatus(0); return mkstatus(0);
} }
StatusTuple CodegenLLVM::visit(Node* root) { StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) {
scopes_->set_current(scopes_->top_state()); scopes_->set_current(scopes_->top_state());
scopes_->set_current(scopes_->top_var()); scopes_->set_current(scopes_->top_var());
...@@ -1232,6 +1231,16 @@ StatusTuple CodegenLLVM::visit(Node* root) { ...@@ -1232,6 +1231,16 @@ StatusTuple CodegenLLVM::visit(Node* root) {
TRY2((*it)->accept(this)); TRY2((*it)->accept(this));
//TRY2(print_parser()); //TRY2(print_parser());
for (auto table : tables_) {
tables.push_back({
table.first->id_->name_,
table_fds_[table.first],
table.first->key_type_->bit_width_ >> 3,
table.first->leaf_type_->bit_width_ >> 3,
table.first->size_,
"", "",
});
}
return mkstatus(0); return mkstatus(0);
} }
...@@ -1263,7 +1272,7 @@ StatusTuple CodegenLLVM::print_header() { ...@@ -1263,7 +1272,7 @@ StatusTuple CodegenLLVM::print_header() {
return mkstatus(0); return mkstatus(0);
} }
int CodegenLLVM::get_table_fd(const std::string &name) const { int CodegenLLVM::get_table_fd(const string &name) const {
TableDeclStmtNode *table = scopes_->top_table()->lookup(name); TableDeclStmtNode *table = scopes_->top_table()->lookup(name);
if (!table) if (!table)
return -1; return -1;
...@@ -1291,7 +1300,7 @@ Value * CodegenLLVM::pop_expr() { ...@@ -1291,7 +1300,7 @@ Value * CodegenLLVM::pop_expr() {
BasicBlock * CodegenLLVM::resolve_label(const string &label) { BasicBlock * CodegenLLVM::resolve_label(const string &label) {
Function *parent = B.GetInsertBlock()->getParent(); Function *parent = B.GetInsertBlock()->getParent();
string scoped_label = std::to_string((uintptr_t)parent) + "::" + label; string scoped_label = to_string((uintptr_t)parent) + "::" + label;
auto it = labels_.find(scoped_label); auto it = labels_.find(scoped_label);
if (it != labels_.end()) return it->second; if (it != labels_.end()) return it->second;
BasicBlock *label_new = BasicBlock::Create(ctx(), label, parent); BasicBlock *label_new = BasicBlock::Create(ctx(), label, parent);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#pragma once #pragma once
#include <map>
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
#include <string> #include <string>
...@@ -40,6 +41,8 @@ class GlobalVariable; ...@@ -40,6 +41,8 @@ class GlobalVariable;
} }
namespace ebpf { namespace ebpf {
class TableDesc;
namespace cc { namespace cc {
class BlockStack; class BlockStack;
...@@ -60,7 +63,7 @@ class CodegenLLVM : public Visitor { ...@@ -60,7 +63,7 @@ class CodegenLLVM : public Visitor {
EXPAND_NODES(VISIT) EXPAND_NODES(VISIT)
#undef VISIT #undef VISIT
virtual STATUS_RETURN visit(Node* n); virtual STATUS_RETURN visit(Node* n, std::vector<TableDesc> &tables);
int get_table_fd(const std::string &name) const; int get_table_fd(const std::string &name) const;
......
...@@ -18,9 +18,12 @@ ...@@ -18,9 +18,12 @@
#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::get; using std::get;
using std::string; using std::string;
using std::unique_ptr;
using std::vector;
namespace ebpf { namespace ebpf {
...@@ -30,7 +33,8 @@ BLoader::BLoader() { ...@@ -30,7 +33,8 @@ BLoader::BLoader() {
BLoader::~BLoader() { 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) {
int rc; int rc;
proto_parser_ = make_unique<ebpf::cc::Parser>(proto_filename); proto_parser_ = make_unique<ebpf::cc::Parser>(proto_filename);
...@@ -57,8 +61,10 @@ int BLoader::parse(llvm::Module *mod, const string &filename, const string &prot ...@@ -57,8 +61,10 @@ 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_); ret = codegen_->visit(parser_->root_node_, **tables);
if (get<0>(ret) != 0 || get<1>(ret).size()) { if (get<0>(ret) != 0 || get<1>(ret).size()) {
fprintf(stderr, "Codegen error @line=%d: %s\n", get<0>(ret), get<1>(ret).c_str()); fprintf(stderr, "Codegen error @line=%d: %s\n", get<0>(ret), get<1>(ret).c_str());
return get<0>(ret); return get<0>(ret);
...@@ -67,9 +73,4 @@ int BLoader::parse(llvm::Module *mod, const string &filename, const string &prot ...@@ -67,9 +73,4 @@ int BLoader::parse(llvm::Module *mod, const string &filename, const string &prot
return 0; return 0;
} }
int BLoader::get_table_fd(const string &name) const {
if (!codegen_) return -1;
return codegen_->get_table_fd(name);
}
} // namespace ebpf } // namespace ebpf
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#pragma once #pragma once
#include <map>
#include <memory>
#include <string> #include <string>
namespace llvm { namespace llvm {
...@@ -24,6 +26,8 @@ class Module; ...@@ -24,6 +26,8 @@ class Module;
namespace ebpf { namespace ebpf {
class TableDesc;
namespace cc { namespace cc {
class Parser; class Parser;
class CodegenLLVM; class CodegenLLVM;
...@@ -33,8 +37,8 @@ class BLoader { ...@@ -33,8 +37,8 @@ class BLoader {
public: public:
BLoader(); BLoader();
~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,
int get_table_fd(const std::string &name) const; std::unique_ptr<std::vector<TableDesc>> *tables);
private: private:
std::unique_ptr<cc::Parser> parser_; std::unique_ptr<cc::Parser> parser_;
std::unique_ptr<cc::Parser> proto_parser_; std::unique_ptr<cc::Parser> proto_parser_;
......
...@@ -51,6 +51,13 @@ bool BMapDeclVisitor::VisitFieldDecl(FieldDecl *D) { ...@@ -51,6 +51,13 @@ bool BMapDeclVisitor::VisitFieldDecl(FieldDecl *D) {
result_ += "\","; result_ += "\",";
return true; return true;
} }
bool BMapDeclVisitor::TraverseRecordDecl(RecordDecl *D) {
// skip children, handled in Visit...
if (!WalkUpFromRecordDecl(D))
return false;
return true;
}
bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) { bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) {
result_ += "[\""; result_ += "[\"";
result_ += D->getName(); result_ += D->getName();
...@@ -65,7 +72,7 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) { ...@@ -65,7 +72,7 @@ bool BMapDeclVisitor::VisitRecordDecl(RecordDecl *D) {
if (!D->getDefinition()->field_empty()) if (!D->getDefinition()->field_empty())
result_.erase(result_.end() - 2); result_.erase(result_.end() - 2);
result_ += "]]"; result_ += "]]";
return false; return true;
} }
bool BMapDeclVisitor::VisitTagType(const TagType *T) { bool BMapDeclVisitor::VisitTagType(const TagType *T) {
return TraverseDecl(T->getDecl()->getDefinition()); return TraverseDecl(T->getDecl()->getDefinition());
...@@ -80,7 +87,7 @@ bool BMapDeclVisitor::VisitBuiltinType(const BuiltinType *T) { ...@@ -80,7 +87,7 @@ bool BMapDeclVisitor::VisitBuiltinType(const BuiltinType *T) {
return true; return true;
} }
BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, map<string, BPFTable> &tables) BTypeVisitor::BTypeVisitor(ASTContext &C, Rewriter &rewriter, vector<TableDesc> &tables)
: C(C), rewriter_(rewriter), out_(llvm::errs()), tables_(tables) { : C(C), rewriter_(rewriter), out_(llvm::errs()), tables_(tables) {
} }
...@@ -135,13 +142,15 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) { ...@@ -135,13 +142,15 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
string args = rewriter_.getRewrittenText(argRange); string args = rewriter_.getRewrittenText(argRange);
// find the table fd, which was opened at declaration time // find the table fd, which was opened at declaration time
auto table_it = tables_.find(Ref->getDecl()->getName()); auto table_it = tables_.begin();
for (; table_it != tables_.end(); ++table_it)
if (table_it->name == Ref->getDecl()->getName()) break;
if (table_it == tables_.end()) { if (table_it == tables_.end()) {
C.getDiagnostics().Report(Ref->getLocEnd(), diag::err_expected) C.getDiagnostics().Report(Ref->getLocEnd(), diag::err_expected)
<< "initialized handle for bpf_table"; << "initialized handle for bpf_table";
return false; return false;
} }
string fd = to_string(table_it->second.fd); string fd = to_string(table_it->fd);
string prefix, suffix; string prefix, suffix;
string map_update_policy = "BPF_ANY"; string map_update_policy = "BPF_ANY";
string txt; string txt;
...@@ -354,18 +363,23 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) { ...@@ -354,18 +363,23 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
return false; return false;
} }
const RecordDecl *RD = R->getDecl()->getDefinition(); const RecordDecl *RD = R->getDecl()->getDefinition();
BPFTable table;
TableDesc table;
table.name = Decl->getName();
unsigned i = 0; unsigned i = 0;
for (auto F : RD->fields()) { for (auto F : RD->fields()) {
size_t sz = C.getTypeSize(F->getType()) >> 3; size_t sz = C.getTypeSize(F->getType()) >> 3;
if (F->getName() == "key") { if (F->getName() == "key") {
table.key_size = sz; table.key_size = sz;
BMapDeclVisitor visitor(C, table.key_desc); BMapDeclVisitor visitor(C, table.key_desc);
visitor.TraverseType(F->getType()); if (!visitor.TraverseType(F->getType()))
return false;
} else if (F->getName() == "leaf") { } else if (F->getName() == "leaf") {
table.leaf_size = sz; table.leaf_size = sz;
BMapDeclVisitor visitor(C, table.leaf_desc); BMapDeclVisitor visitor(C, table.leaf_desc);
visitor.TraverseType(F->getType()); if (!visitor.TraverseType(F->getType()))
return false;
} else if (F->getName() == "data") { } else if (F->getName() == "data") {
table.max_entries = sz / table.leaf_size; table.max_entries = sz / table.leaf_size;
} }
...@@ -397,7 +411,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) { ...@@ -397,7 +411,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
<< "valid bpf fd"; << "valid bpf fd";
return false; return false;
} }
tables_[Decl->getName()] = std::move(table); tables_.push_back(std::move(table));
} else if (const PointerType *P = Decl->getType()->getAs<PointerType>()) { } else if (const PointerType *P = Decl->getType()->getAs<PointerType>()) {
// if var is a pointer to a packet type, clone the annotation into the var // if var is a pointer to a packet type, clone the annotation into the var
// decl so that the packet dext/dins rewriter can catch it // decl so that the packet dext/dins rewriter can catch it
...@@ -414,7 +428,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) { ...@@ -414,7 +428,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
return true; return true;
} }
BTypeConsumer::BTypeConsumer(ASTContext &C, Rewriter &rewriter, map<string, BPFTable> &tables) BTypeConsumer::BTypeConsumer(ASTContext &C, Rewriter &rewriter, vector<TableDesc> &tables)
: visitor_(C, rewriter, tables) { : visitor_(C, rewriter, tables) {
} }
...@@ -425,7 +439,7 @@ bool BTypeConsumer::HandleTopLevelDecl(DeclGroupRef D) { ...@@ -425,7 +439,7 @@ bool BTypeConsumer::HandleTopLevelDecl(DeclGroupRef D) {
} }
BFrontendAction::BFrontendAction(llvm::raw_ostream &os) BFrontendAction::BFrontendAction(llvm::raw_ostream &os)
: rewriter_(new Rewriter), os_(os), tables_(new map<string, BPFTable>) { : rewriter_(new Rewriter), os_(os), tables_(new vector<TableDesc>) {
} }
void BFrontendAction::EndSourceFileAction() { void BFrontendAction::EndSourceFileAction() {
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#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"
namespace clang { namespace clang {
class ASTConsumer; class ASTConsumer;
class ASTContext; class ASTContext;
...@@ -36,25 +38,16 @@ class StringRef; ...@@ -36,25 +38,16 @@ class StringRef;
namespace ebpf { namespace ebpf {
struct BPFTable {
int fd;
size_t key_size;
size_t leaf_size;
size_t max_entries;
std::string key_desc;
std::string leaf_desc;
};
// Helper visitor for constructing a string representation of a key/leaf decl // Helper visitor for constructing a string representation of a key/leaf decl
class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> { class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> {
public: public:
explicit BMapDeclVisitor(clang::ASTContext &C, std::string &result); explicit BMapDeclVisitor(clang::ASTContext &C, std::string &result);
bool TraverseRecordDecl(clang::RecordDecl *Decl);
bool VisitRecordDecl(clang::RecordDecl *Decl); bool VisitRecordDecl(clang::RecordDecl *Decl);
bool VisitFieldDecl(clang::FieldDecl *Decl); bool VisitFieldDecl(clang::FieldDecl *Decl);
bool VisitBuiltinType(const clang::BuiltinType *T); bool VisitBuiltinType(const clang::BuiltinType *T);
bool VisitTypedefType(const clang::TypedefType *T); bool VisitTypedefType(const clang::TypedefType *T);
bool VisitTagType(const clang::TagType *T); bool VisitTagType(const clang::TagType *T);
const std::string & str() const { return result_; }
private: private:
clang::ASTContext &C; clang::ASTContext &C;
std::string &result_; std::string &result_;
...@@ -67,7 +60,7 @@ class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> { ...@@ -67,7 +60,7 @@ class BMapDeclVisitor : public clang::RecursiveASTVisitor<BMapDeclVisitor> {
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, clang::Rewriter &rewriter,
std::map<std::string, BPFTable> &tables); std::vector<TableDesc> &tables);
bool TraverseCallExpr(clang::CallExpr *Call); bool TraverseCallExpr(clang::CallExpr *Call);
bool TraverseMemberExpr(clang::MemberExpr *E); bool TraverseMemberExpr(clang::MemberExpr *E);
bool VisitFunctionDecl(clang::FunctionDecl *D); bool VisitFunctionDecl(clang::FunctionDecl *D);
...@@ -82,7 +75,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> { ...@@ -82,7 +75,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
clang::ASTContext &C; clang::ASTContext &C;
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::map<std::string, BPFTable> &tables_; /// store the open FDs std::vector<TableDesc> &tables_; /// store the open FDs
std::vector<clang::ParmVarDecl *> fn_args_; std::vector<clang::ParmVarDecl *> fn_args_;
}; };
...@@ -90,7 +83,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> { ...@@ -90,7 +83,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
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, clang::Rewriter &rewriter,
std::map<std::string, BPFTable> &tables); std::vector<TableDesc> &tables);
bool HandleTopLevelDecl(clang::DeclGroupRef D) override; bool HandleTopLevelDecl(clang::DeclGroupRef D) override;
private: private:
BTypeVisitor visitor_; BTypeVisitor visitor_;
...@@ -113,11 +106,11 @@ class BFrontendAction : public clang::ASTFrontendAction { ...@@ -113,11 +106,11 @@ class BFrontendAction : public clang::ASTFrontendAction {
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 // take ownership of the table-to-fd mapping data structure
std::unique_ptr<std::map<std::string, BPFTable>> take_tables() { return move(tables_); } std::unique_ptr<std::vector<TableDesc>> take_tables() { return move(tables_); }
private: private:
std::unique_ptr<clang::Rewriter> rewriter_; std::unique_ptr<clang::Rewriter> rewriter_;
llvm::raw_ostream &os_; llvm::raw_ostream &os_;
std::unique_ptr<std::map<std::string, BPFTable>> tables_; std::unique_ptr<std::vector<TableDesc>> tables_;
}; };
} // namespace visitor } // namespace visitor
...@@ -64,8 +64,7 @@ ClangLoader::ClangLoader(llvm::LLVMContext *ctx) ...@@ -64,8 +64,7 @@ ClangLoader::ClangLoader(llvm::LLVMContext *ctx)
ClangLoader::~ClangLoader() {} ClangLoader::~ClangLoader() {}
int ClangLoader::parse(unique_ptr<llvm::Module> *mod, int ClangLoader::parse(unique_ptr<llvm::Module> *mod, unique_ptr<vector<TableDesc>> *tables,
unique_ptr<map<string, BPFTable>> *tables,
const string &file, bool in_memory) { const string &file, bool in_memory) {
using namespace clang; using namespace clang;
......
...@@ -27,7 +27,7 @@ class LLVMContext; ...@@ -27,7 +27,7 @@ class LLVMContext;
namespace ebpf { namespace ebpf {
class BPFTable; class TableDesc;
namespace cc { namespace cc {
class Parser; class Parser;
...@@ -38,8 +38,7 @@ class ClangLoader { ...@@ -38,8 +38,7 @@ class ClangLoader {
public: public:
explicit ClangLoader(llvm::LLVMContext *ctx); explicit ClangLoader(llvm::LLVMContext *ctx);
~ClangLoader(); ~ClangLoader();
int parse(std::unique_ptr<llvm::Module> *mod, int parse(std::unique_ptr<llvm::Module> *mod, std::unique_ptr<std::vector<TableDesc>> *tables,
std::unique_ptr<std::map<std::string, BPFTable>> *tables,
const std::string &file, bool in_memory); const std::string &file, bool in_memory);
private: private:
llvm::LLVMContext *ctx_; llvm::LLVMContext *ctx_;
......
/*
* Copyright (c) 2015 PLUMgrid, 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 <cstdint>
#include <string>
namespace llvm {
class Function;
}
namespace ebpf {
struct TableDesc {
std::string name;
int fd;
size_t key_size; // sizes are in bytes
size_t leaf_size;
size_t max_entries;
std::string key_desc;
std::string leaf_desc;
llvm::Function *key_reader;
llvm::Function *leaf_reader;
};
} // namespace ebpf
...@@ -45,6 +45,8 @@ lib.bpf_table_key_desc.restype = ct.c_char_p ...@@ -45,6 +45,8 @@ lib.bpf_table_key_desc.restype = ct.c_char_p
lib.bpf_table_key_desc.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_key_desc.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_table_leaf_desc.restype = ct.c_char_p lib.bpf_table_leaf_desc.restype = ct.c_char_p
lib.bpf_table_leaf_desc.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_leaf_desc.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_table_update.restype = ct.c_int
lib.bpf_table_update.argtypes = [ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.c_char_p]
# keep in sync with libbpf.h # keep in sync with libbpf.h
lib.bpf_get_next_key.restype = ct.c_int lib.bpf_get_next_key.restype = ct.c_int
...@@ -258,6 +260,12 @@ class BPF(object): ...@@ -258,6 +260,12 @@ class BPF(object):
leaftype = BPF._decode_table_type(json.loads(leaf_desc.decode())) leaftype = BPF._decode_table_type(json.loads(leaf_desc.decode()))
return BPF.Table(self, map_fd, keytype, leaftype) return BPF.Table(self, map_fd, keytype, leaftype)
def update_table(self, name, key, leaf):
res = lib.bpf_table_update(self.module, name.encode("ascii"), key.encode("ascii"),
leaf.encode("ascii"))
if res < 0:
raise Exception("update_table failed")
@staticmethod @staticmethod
def attach_raw_socket(fn, dev): def attach_raw_socket(fn, dev):
if not isinstance(fn, BPF.Function): if not isinstance(fn, BPF.Function):
......
...@@ -46,5 +46,24 @@ int count_foo(struct pt_regs *ctx, unsigned long a, unsigned long b) { ...@@ -46,5 +46,24 @@ int count_foo(struct pt_regs *ctx, unsigned long a, unsigned long b) {
b = BPF(text=text, debug=0) b = BPF(text=text, debug=0)
fn = b.load_func("count_foo", BPF.KPROBE) fn = b.load_func("count_foo", BPF.KPROBE)
def test_sscanf(self):
text = """
BPF_TABLE("hash", int, struct { u64 a; u64 b; u64 c:36; u64 d:28; struct { u32 a; u32 b; } s; }, stats, 10);
int foo(void *ctx) {
return 0;
}
"""
b = BPF(text=text, debug=0)
fn = b.load_func("foo", BPF.KPROBE)
b.update_table("stats", "2", "{ 2 3 0x1000000004 { 5 6 }}")
t = b.get_table("stats")
l = t[t.Key(2)]
self.assertEqual(l.a, 2)
self.assertEqual(l.b, 3)
self.assertEqual(l.c, 4)
self.assertEqual(l.d, 1)
self.assertEqual(l.s.a, 5)
self.assertEqual(l.s.b, 6)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
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