Skip to content

Commit

Permalink
allow accesing table using strings
Browse files Browse the repository at this point in the history
This commit exposes functions to convert between key and value from/to
strings, additionally it implements the BPFTable class that allows
accessing tables using strings.

Signed-off-by: Mauricio Vasquez B <[email protected]>
  • Loading branch information
mauriciovasquezbernal committed Apr 26, 2017
1 parent cee6056 commit 8e688f8
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 57 deletions.
7 changes: 7 additions & 0 deletions src/cc/BPF.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ class BPF {
int group_fd = -1);
StatusTuple detach_perf_event(uint32_t ev_type, uint32_t ev_config);

BPFTable get_table(const std::string& name) {
TableStorage::iterator it;
if (bpf_module_->table_storage().Find(Path({bpf_module_->id(), name}), it))
return BPFTable(it->second);
return BPFTable({});
}

template <class ValueType>
BPFArrayTable<ValueType> get_array_table(const std::string& name) {
TableStorage::iterator it;
Expand Down
55 changes: 55 additions & 0 deletions src/cc/BPFTable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,61 @@

namespace ebpf {

BPFTable::BPFTable(const TableDesc& desc) : BPFTableBase<void, void>(desc) {}

StatusTuple BPFTable::get_value(const std::string& key_str,
std::string& value_str) {
char key[desc.key_size];
char value[desc.leaf_size];

StatusTuple r(0);

r = string_to_key(key_str, key);
if (r.code() != 0)
return r;

if (!lookup(key, value))
return StatusTuple(-1, "error getting value");

return leaf_to_string(value, value_str);
}

StatusTuple BPFTable::update_value(const std::string& key_str,
const std::string& value_str) {
char key[desc.key_size];
char value[desc.leaf_size];

StatusTuple r(0);

r = string_to_key(key_str, key);
if (r.code() != 0)
return r;

r = string_to_leaf(value_str, value);
if (r.code() != 0)
return r;

if (!update(key, value))
return StatusTuple(-1, "error updating element");

return StatusTuple(0);
}

StatusTuple BPFTable::remove_value(const std::string& key_str) {
char key[desc.key_size];

StatusTuple r(0);

r = string_to_key(key_str, key);
if (r.code() != 0)
return r;

if (!remove(key))
return StatusTuple(-1, "error removing element");

return StatusTuple(0);
}

BPFStackTable::~BPFStackTable() {
for (auto it : pid_sym_)
bcc_free_symcache(it.second, it.first);
Expand Down
76 changes: 60 additions & 16 deletions src/cc/BPFTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,39 +36,83 @@ namespace ebpf {
template <class KeyType, class ValueType>
class BPFTableBase {
public:
size_t capacity() { return capacity_; }
size_t capacity() { return desc.max_entries; }

protected:
explicit BPFTableBase(const TableDesc& desc) {
fd_ = desc.fd;
capacity_ = desc.max_entries;
StatusTuple string_to_key(const std::string& key_str, KeyType* key) {
if (!desc.key_sscanf)
return StatusTuple(-1, "Key sscanf not available");
if (desc.key_sscanf(key_str.c_str(), key) != 0)
return StatusTuple(-1, "Error on key_sscanff: %s", std::strerror(errno));
return StatusTuple(0);
}

StatusTuple string_to_leaf(const std::string& value_str, ValueType* value) {
if (!desc.leaf_sscanf)
return StatusTuple(-1, "Leaf sscanf not available");
if (desc.leaf_sscanf(value_str.c_str(), value) != 0)
return StatusTuple(-1, "Error on leaf_sscanff: %s", std::strerror(errno));
return StatusTuple(0);
}

StatusTuple key_to_string(const KeyType* key, std::string& key_str) {
char buf[8 * desc.key_size];
if (!desc.key_snprintf)
return StatusTuple(-1, "Key snprintf not available");
if (desc.key_snprintf(buf, sizeof(buf), key) < 0)
return StatusTuple(-1, "Error on key_sprintf: %s", std::strerror(errno));

key_str.assign(buf);
return StatusTuple(0);
}

StatusTuple leaf_to_string(const ValueType* value, std::string& value_str) {
char buf[8 * desc.leaf_size];
if (!desc.leaf_snprintf)
return StatusTuple(-1, "Leaf snprintf not available");
if (desc.leaf_snprintf(buf, sizeof(buf), value) < 0)
return StatusTuple(-1, "Error on leaf_sprintf: %s", std::strerror(errno));

value_str.assign(buf);
return StatusTuple(0);
}

protected:
explicit BPFTableBase(const TableDesc& desc) : desc(desc) {}

bool lookup(KeyType* key, ValueType* value) {
return bpf_lookup_elem(fd_, static_cast<void*>(key),
return bpf_lookup_elem(desc.fd, static_cast<void*>(key),
static_cast<void*>(value)) >= 0;
}

bool next(KeyType* key, KeyType* next_key) {
return bpf_get_next_key(fd_, static_cast<void*>(key),
return bpf_get_next_key(desc.fd, static_cast<void*>(key),
static_cast<void*>(next_key)) >= 0;
}

bool update(KeyType* key, ValueType* value) {
return bpf_update_elem(fd_, static_cast<void*>(key),
return bpf_update_elem(desc.fd, static_cast<void*>(key),
static_cast<void*>(value), 0) >= 0;
}

bool remove(KeyType* key) {
return bpf_delete_elem(fd_, static_cast<void*>(key)) >= 0;
return bpf_delete_elem(desc.fd, static_cast<void*>(key)) >= 0;
}

int fd_;
size_t capacity_;
const TableDesc& desc;
};

class BPFTable : public BPFTableBase<void, void> {
public:
BPFTable(const TableDesc& desc);

StatusTuple get_value(const std::string& key_str, std::string& value);
StatusTuple update_value(const std::string& key_str,
const std::string& value_str);
StatusTuple remove_value(const std::string& key_str);
};

template <class ValueType>
class BPFArrayTable : protected BPFTableBase<int, ValueType> {
class BPFArrayTable : public BPFTableBase<int, ValueType> {
public:
BPFArrayTable(const TableDesc& desc)
: BPFTableBase<int, ValueType>(desc) {
Expand Down Expand Up @@ -107,7 +151,7 @@ class BPFArrayTable : protected BPFTableBase<int, ValueType> {
};

template <class KeyType, class ValueType>
class BPFHashTable : protected BPFTableBase<KeyType, ValueType> {
class BPFHashTable : public BPFTableBase<KeyType, ValueType> {
public:
explicit BPFHashTable(const TableDesc& desc)
: BPFTableBase<KeyType, ValueType>(desc) {
Expand Down Expand Up @@ -167,7 +211,7 @@ struct stacktrace_t {
intptr_t ip[BPF_MAX_STACK_DEPTH];
};

class BPFStackTable : protected BPFTableBase<int, stacktrace_t> {
class BPFStackTable : public BPFTableBase<int, stacktrace_t> {
public:
BPFStackTable(const TableDesc& desc)
: BPFTableBase<int, stacktrace_t>(desc) {}
Expand All @@ -180,7 +224,7 @@ class BPFStackTable : protected BPFTableBase<int, stacktrace_t> {
std::map<int, void*> pid_sym_;
};

class BPFPerfBuffer : protected BPFTableBase<int, int> {
class BPFPerfBuffer : public BPFTableBase<int, int> {
public:
BPFPerfBuffer(const TableDesc& desc)
: BPFTableBase<int, int>(desc), epfd_(-1) {}
Expand All @@ -202,7 +246,7 @@ class BPFPerfBuffer : protected BPFTableBase<int, int> {
std::unique_ptr<epoll_event[]> ep_events_;
};

class BPFProgTable : protected BPFTableBase<int, int> {
class BPFProgTable : public BPFTableBase<int, int> {
public:
BPFProgTable(const TableDesc& desc)
: BPFTableBase<int, int>(desc) {
Expand Down
86 changes: 49 additions & 37 deletions src/cc/bpf_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ using std::unique_ptr;
using std::vector;
using namespace llvm;

typedef int (* sscanf_fn) (const char *, void *);
typedef int (* snprintf_fn) (char *, size_t, const void *);

const string BPFModule::FN_PREFIX = BPF_FN_PREFIX;

// Snooping class to remember the sections as the JIT creates them
Expand Down Expand Up @@ -123,6 +120,14 @@ BPFModule::~BPFModule() {
engine_.reset();
rw_engine_.reset();
ctx_.reset();

for (auto &v : tables_) {
v->key_sscanf = nullptr;
v->leaf_sscanf = nullptr;
v->key_snprintf = nullptr;
v->leaf_snprintf = nullptr;
}

ts_->DeletePrefix(Path({id_}));
}

Expand Down Expand Up @@ -350,6 +355,15 @@ int BPFModule::annotate() {
// separate module to hold the reader functions
auto m = make_unique<Module>("sscanf", *ctx_);

struct llvmfnpointers {
llvm::Function *key_sscanf;
llvm::Function *leaf_sscanf;
llvm::Function *key_snprintf;
llvm::Function *leaf_snprintf;
};

std::map<TableDesc *, llvmfnpointers> ptrs_map;

size_t id = 0;
Path path({id_});
for (auto it = ts_->lower_bound(path), up = ts_->upper_bound(path); it != up; ++it) {
Expand All @@ -363,18 +377,26 @@ int BPFModule::annotate() {
if (st->getNumElements() < 2) continue;
Type *key_type = st->elements()[0];
Type *leaf_type = st->elements()[1];
table.key_sscanf = make_reader(&*m, key_type);
if (!table.key_sscanf)

llvmfnpointers fns;

fns.key_sscanf = make_reader(&*m, key_type);
if (!fns.key_sscanf)
errs() << "Failed to compile sscanf for " << *key_type << "\n";
table.leaf_sscanf = make_reader(&*m, leaf_type);
if (!table.leaf_sscanf)

fns.leaf_sscanf = make_reader(&*m, leaf_type);
if (!fns.leaf_sscanf)
errs() << "Failed to compile sscanf for " << *leaf_type << "\n";
table.key_snprintf = make_writer(&*m, key_type);
if (!table.key_snprintf)

fns.key_snprintf = make_writer(&*m, key_type);
if (!fns.key_snprintf)
errs() << "Failed to compile snprintf for " << *key_type << "\n";
table.leaf_snprintf = make_writer(&*m, leaf_type);
if (!table.leaf_snprintf)

fns.leaf_snprintf = make_writer(&*m, leaf_type);
if (!fns.leaf_snprintf)
errs() << "Failed to compile snprintf for " << *leaf_type << "\n";

ptrs_map[&it->second] = fns;
}
}
}
Expand All @@ -383,6 +405,18 @@ int BPFModule::annotate() {
if (rw_engine_)
rw_engine_->finalizeObject();

for (auto &it : ptrs_map) {
auto t = it.first;
auto ptr = it.second;
t->key_sscanf = (sscanf_fn)rw_engine_->getPointerToFunction(ptr.key_sscanf);
t->leaf_sscanf =
(sscanf_fn)rw_engine_->getPointerToFunction(ptr.leaf_sscanf);
t->key_snprintf =
(snprintf_fn)rw_engine_->getPointerToFunction(ptr.key_snprintf);
t->leaf_snprintf =
(snprintf_fn)rw_engine_->getPointerToFunction(ptr.leaf_snprintf);
}

return 0;
}

Expand Down Expand Up @@ -619,12 +653,7 @@ int BPFModule::table_key_printf(size_t id, char *buf, size_t buflen, const void
fprintf(stderr, "Key snprintf not available\n");
return -1;
}
snprintf_fn fn = (snprintf_fn)rw_engine_->getPointerToFunction(desc.key_snprintf);
if (!fn) {
fprintf(stderr, "Key snprintf not available in JIT Engine\n");
return -1;
}
int rc = (*fn)(buf, buflen, key);
int rc = desc.key_snprintf(buf, buflen, key);
if (rc < 0) {
perror("snprintf");
return -1;
Expand All @@ -644,12 +673,7 @@ int BPFModule::table_leaf_printf(size_t id, char *buf, size_t buflen, const void
fprintf(stderr, "Key snprintf not available\n");
return -1;
}
snprintf_fn fn = (snprintf_fn)rw_engine_->getPointerToFunction(desc.leaf_snprintf);
if (!fn) {
fprintf(stderr, "Leaf snprintf not available in JIT Engine\n");
return -1;
}
int rc = (*fn)(buf, buflen, leaf);
int rc = desc.leaf_snprintf(buf, buflen, leaf);
if (rc < 0) {
perror("snprintf");
return -1;
Expand All @@ -669,13 +693,7 @@ int BPFModule::table_key_scanf(size_t id, const char *key_str, void *key) {
fprintf(stderr, "Key sscanf not available\n");
return -1;
}

sscanf_fn fn = (sscanf_fn)rw_engine_->getPointerToFunction(desc.key_sscanf);
if (!fn) {
fprintf(stderr, "Key sscanf not available in JIT Engine\n");
return -1;
}
int rc = (*fn)(key_str, key);
int rc = desc.key_sscanf(key_str, key);
if (rc != 0) {
perror("sscanf");
return -1;
Expand All @@ -691,13 +709,7 @@ int BPFModule::table_leaf_scanf(size_t id, const char *leaf_str, void *leaf) {
fprintf(stderr, "Key sscanf not available\n");
return -1;
}

sscanf_fn fn = (sscanf_fn)rw_engine_->getPointerToFunction(desc.leaf_sscanf);
if (!fn) {
fprintf(stderr, "Leaf sscanf not available in JIT Engine\n");
return -1;
}
int rc = (*fn)(leaf_str, leaf);
int rc = desc.leaf_sscanf(leaf_str, leaf);
if (rc != 0) {
perror("sscanf");
return -1;
Expand Down
11 changes: 7 additions & 4 deletions src/cc/table_desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ class FileDesc {
int fd;
};

typedef int (*sscanf_fn)(const char *, void *);
typedef int (*snprintf_fn)(char *, size_t, const void *);

/// 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()
Expand Down Expand Up @@ -118,10 +121,10 @@ class TableDesc {
int flags;
std::string key_desc;
std::string leaf_desc;
llvm::Function *key_sscanf;
llvm::Function *leaf_sscanf;
llvm::Function *key_snprintf;
llvm::Function *leaf_snprintf;
sscanf_fn key_sscanf;
sscanf_fn leaf_sscanf;
snprintf_fn key_snprintf;
snprintf_fn leaf_snprintf;
bool is_shared;
bool is_extern;
};
Expand Down
1 change: 1 addition & 0 deletions tests/cc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_executable(test_libbcc
test_libbcc.cc
test_c_api.cc
test_array_table.cc
test_bpf_table.cc
test_hash_table.cc
test_usdt_args.cc
test_usdt_probes.cc)
Expand Down
Loading

0 comments on commit 8e688f8

Please sign in to comment.