Commit bd62f6c9 authored by Brenden Blanco's avatar Brenden Blanco Committed by GitHub

Merge pull request #1104 from mauriciovasquezbernal/bpf_table_string

[RFC]: Extend table API with string support 
parents 9bcad326 8e688f83
......@@ -90,6 +90,13 @@ public:
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;
......
......@@ -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);
......
......@@ -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) {
......@@ -107,7 +151,7 @@ public:
};
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) {
......@@ -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) {}
......@@ -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) {}
......@@ -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) {
......
......@@ -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
......@@ -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_}));
}
......@@ -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) {
......@@ -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;
}
}
}
......@@ -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;
}
......@@ -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;
......@@ -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;
......@@ -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;
......@@ -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;
......
......@@ -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()
......@@ -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;
};
......
......@@ -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)
......
/*
* Copyright (c) 2017 Politecnico di Torino
*
* 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 "BPF.h"
#include "catch.hpp"
TEST_CASE("test bpf table", "[bpf_table]") {
const std::string BPF_PROGRAM = R"(
BPF_TABLE("hash", int, int, myhash, 128);
)";
ebpf::BPF *bpf(new ebpf::BPF);
ebpf::StatusTuple res(0);
res = bpf->init(BPF_PROGRAM);
REQUIRE(res.code() == 0);
ebpf::BPFTable t = bpf->get_table("myhash");
// update element
std::string value;
res = t.update_value("0x07", "0x42");
REQUIRE(res.code() == 0);
res = t.get_value("0x07", value);
REQUIRE(res.code() == 0);
REQUIRE(value == "0x42");
// update another element
res = t.update_value("0x11", "0x777");
REQUIRE(res.code() == 0);
res = t.get_value("0x11", value);
REQUIRE(res.code() == 0);
REQUIRE(value == "0x777");
// remove value
res = t.remove_value("0x11");
REQUIRE(res.code() == 0);
res = t.get_value("0x11", value);
REQUIRE(res.code() != 0);
// delete bpf_module, call to key/leaf printf/scanf must fail
delete bpf;
res = t.update_value("0x07", "0x42");
REQUIRE(res.code() != 0);
res = t.get_value("0x07", value);
REQUIRE(res.code() != 0);
res = t.remove_value("0x07");
REQUIRE(res.code() != 0);
}
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