Commit 8e40c235 authored by Brenden Blanco's avatar Brenden Blanco

Fix map.clear() usage for array type maps

Calling delete on an array type map entry does not have an effect.
Instead, the entry needs to be zeroed out, since the array slot always
exists. To avoid unnecessary calls to update(), only call update() when
the map type is array-like. The type was not exposed to python up until
now, so add it.
Signed-off-by: default avatarBrenden Blanco <bblanco@plumgrid.com>
parent 136d85ff
...@@ -122,6 +122,18 @@ int bpf_table_fd_id(void *program, size_t id) { ...@@ -122,6 +122,18 @@ int bpf_table_fd_id(void *program, size_t id) {
return mod->table_fd(id); return mod->table_fd(id);
} }
int bpf_table_type(void *program, const char *table_name) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return -1;
return mod->table_type(table_name);
}
int bpf_table_type_id(void *program, size_t id) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return -1;
return mod->table_type(id);
}
const char * bpf_table_name(void *program, size_t id) { const char * bpf_table_name(void *program, size_t id) {
auto mod = static_cast<ebpf::BPFModule *>(program); auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return nullptr; if (!mod) return nullptr;
......
...@@ -40,6 +40,8 @@ size_t bpf_num_tables(void *program); ...@@ -40,6 +40,8 @@ size_t bpf_num_tables(void *program);
size_t bpf_table_id(void *program, const char *table_name); size_t bpf_table_id(void *program, const char *table_name);
int bpf_table_fd(void *program, const char *table_name); int bpf_table_fd(void *program, const char *table_name);
int bpf_table_fd_id(void *program, size_t id); int bpf_table_fd_id(void *program, size_t id);
int bpf_table_type(void *program, const char *table_name);
int bpf_table_type_id(void *program, size_t id);
const char * bpf_table_name(void *program, size_t id); const char * bpf_table_name(void *program, size_t id);
const char * bpf_table_key_desc(void *program, const char *table_name); 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);
......
...@@ -488,6 +488,15 @@ int BPFModule::table_fd(size_t id) const { ...@@ -488,6 +488,15 @@ int BPFModule::table_fd(size_t id) const {
return (*tables_)[id].fd; return (*tables_)[id].fd;
} }
int BPFModule::table_type(const string &name) const {
return table_type(table_id(name));
}
int BPFModule::table_type(size_t id) const {
if (id >= tables_->size()) return -1;
return (*tables_)[id].type;
}
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 nullptr;
return (*tables_)[id].name.c_str(); return (*tables_)[id].name.c_str();
......
...@@ -68,6 +68,8 @@ class BPFModule { ...@@ -68,6 +68,8 @@ class BPFModule {
int table_fd(size_t id) const; int table_fd(size_t id) const;
int table_fd(const std::string &name) const; int table_fd(const std::string &name) const;
const char * table_name(size_t id) const; const char * table_name(size_t id) const;
int table_type(const std::string &name) const;
int table_type(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(size_t id) const;
......
...@@ -1232,9 +1232,15 @@ StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) { ...@@ -1232,9 +1232,15 @@ StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) {
//TRY2(print_parser()); //TRY2(print_parser());
for (auto table : tables_) { for (auto table : tables_) {
bpf_map_type map_type = BPF_MAP_TYPE_UNSPEC;
if (table.first->type_id()->name_ == "FIXED_MATCH")
map_type = BPF_MAP_TYPE_HASH;
else if (table.first->type_id()->name_ == "INDEXED")
map_type = BPF_MAP_TYPE_ARRAY;
tables.push_back({ tables.push_back({
table.first->id_->name_, table.first->id_->name_,
table_fds_[table.first], table_fds_[table.first],
map_type,
table.first->key_type_->bit_width_ >> 3, table.first->key_type_->bit_width_ >> 3,
table.first->leaf_type_->bit_width_ >> 3, table.first->leaf_type_->bit_width_ >> 3,
table.first->size_, table.first->size_,
......
...@@ -408,6 +408,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) { ...@@ -408,6 +408,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
return false; return false;
} }
} }
table.type = map_type;
table.fd = bpf_create_map(map_type, table.key_size, table.leaf_size, table.max_entries); table.fd = bpf_create_map(map_type, table.key_size, table.leaf_size, table.max_entries);
if (table.fd < 0) { if (table.fd < 0) {
C.getDiagnostics().Report(Decl->getLocStart(), diag::err_expected) C.getDiagnostics().Report(Decl->getLocStart(), diag::err_expected)
......
...@@ -26,6 +26,7 @@ namespace ebpf { ...@@ -26,6 +26,7 @@ namespace ebpf {
struct TableDesc { struct TableDesc {
std::string name; std::string name;
int fd; int fd;
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;
size_t max_entries; size_t max_entries;
......
...@@ -44,6 +44,8 @@ lib.bpf_table_id.restype = ct.c_ulonglong ...@@ -44,6 +44,8 @@ lib.bpf_table_id.restype = ct.c_ulonglong
lib.bpf_table_id.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_id.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_table_fd.restype = ct.c_int lib.bpf_table_fd.restype = ct.c_int
lib.bpf_table_fd.argtypes = [ct.c_void_p, ct.c_char_p] lib.bpf_table_fd.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_table_type_id.restype = ct.c_int
lib.bpf_table_type_id.argtypes = [ct.c_void_p, ct.c_ulonglong]
lib.bpf_table_key_desc.restype = ct.c_char_p 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
...@@ -103,6 +105,10 @@ class BPF(object): ...@@ -103,6 +105,10 @@ class BPF(object):
SCHED_CLS = 3 SCHED_CLS = 3
SCHED_ACT = 4 SCHED_ACT = 4
HASH = 1
ARRAY = 2
PROG_ARRAY = 3
class Function(object): class Function(object):
def __init__(self, bpf, name, fd): def __init__(self, bpf, name, fd):
self.bpf = bpf self.bpf = bpf
...@@ -116,6 +122,7 @@ class BPF(object): ...@@ -116,6 +122,7 @@ class BPF(object):
self.map_fd = map_fd self.map_fd = map_fd
self.Key = keytype self.Key = keytype
self.Leaf = leaftype self.Leaf = leaftype
self.ttype = lib.bpf_table_type_id(self.bpf.module, self.map_id)
def key_sprintf(self, key): def key_sprintf(self, key):
key_p = ct.pointer(key) key_p = ct.pointer(key)
...@@ -180,9 +187,33 @@ class BPF(object): ...@@ -180,9 +187,33 @@ class BPF(object):
def __delitem__(self, key): def __delitem__(self, key):
key_p = ct.pointer(key) key_p = ct.pointer(key)
res = lib.bpf_delete_elem(self.map_fd, ct.cast(key_p, ct.c_void_p)) ttype = lib.bpf_table_type_id(self.bpf.module, self.map_id)
if res < 0: # Deleting from array type maps does not have an effect, so
raise KeyError # zero out the entry instead.
if ttype in (BPF.ARRAY, BPF.PROG_ARRAY):
leaf = self.Leaf()
leaf_p = ct.pointer(leaf)
res = lib.bpf_update_elem(self.map_fd,
ct.cast(key_p, ct.c_void_p),
ct.cast(leaf_p, ct.c_void_p), 0)
if res < 0:
raise Exception("Could not clear item")
else:
res = lib.bpf_delete_elem(self.map_fd,
ct.cast(key_p, ct.c_void_p))
if res < 0:
raise KeyError
def clear(self):
if self.ttype in (BPF.ARRAY, BPF.PROG_ARRAY):
# Special case clear, since this class is currently behaving
# like a dict but popitem on an array causes an infinite loop.
# TODO: derive Table from array.array instead
for k in self.keys():
self.__delitem__(k)
else:
super(BPF.Table, self).clear()
def __iter__(self): def __iter__(self):
return BPF.Table.Iter(self, self.Key) return BPF.Table.Iter(self, self.Key)
......
#!/usr/bin/python #!/usr/bin/python
# vim: ts=8 noet sw=8
# #
# pidpersec Count new processes (via fork). # pidpersec Count new processes (via fork).
# For Linux, uses BCC, eBPF. See .c file. # For Linux, uses BCC, eBPF. See .c file.
...@@ -32,8 +33,8 @@ while (1): ...@@ -32,8 +33,8 @@ while (1):
try: try:
sleep(1) sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
pass; exit() exit()
print("%s: PIDs/sec: %d" % (strftime("%H:%M:%S"), print("%s: PIDs/sec: %d" % (strftime("%H:%M:%S"),
(b["stats"][S_COUNT].value - last))) (b["stats"][S_COUNT].value)))
last = b["stats"][S_COUNT].value b["stats"].clear()
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