Skip to content

Commit

Permalink
Fix map.clear() usage for array type maps
Browse files Browse the repository at this point in the history
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: Brenden Blanco <[email protected]>
  • Loading branch information
Brenden Blanco committed Aug 24, 2015
1 parent 136d85f commit 8e40c23
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 6 deletions.
12 changes: 12 additions & 0 deletions src/cc/bpf_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ int bpf_table_fd_id(void *program, size_t 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) {
auto mod = static_cast<ebpf::BPFModule *>(program);
if (!mod) return nullptr;
Expand Down
2 changes: 2 additions & 0 deletions src/cc/bpf_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ size_t bpf_num_tables(void *program);
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_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_key_desc(void *program, const char *table_name);
const char * bpf_table_key_desc_id(void *program, size_t id);
Expand Down
9 changes: 9 additions & 0 deletions src/cc/bpf_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,15 @@ int BPFModule::table_fd(size_t id) const {
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 {
if (id >= tables_->size()) return nullptr;
return (*tables_)[id].name.c_str();
Expand Down
2 changes: 2 additions & 0 deletions src/cc/bpf_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class BPFModule {
int table_fd(size_t id) const;
int table_fd(const std::string &name) 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(const std::string &name) const;
size_t table_key_size(size_t id) const;
Expand Down
6 changes: 6 additions & 0 deletions src/cc/frontends/b/codegen_llvm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1232,9 +1232,15 @@ StatusTuple CodegenLLVM::visit(Node* root, vector<TableDesc> &tables) {
//TRY2(print_parser());

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({
table.first->id_->name_,
table_fds_[table.first],
map_type,
table.first->key_type_->bit_width_ >> 3,
table.first->leaf_type_->bit_width_ >> 3,
table.first->size_,
Expand Down
1 change: 1 addition & 0 deletions src/cc/frontends/clang/b_frontend_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
return false;
}
}
table.type = map_type;
table.fd = bpf_create_map(map_type, table.key_size, table.leaf_size, table.max_entries);
if (table.fd < 0) {
C.getDiagnostics().Report(Decl->getLocStart(), diag::err_expected)
Expand Down
1 change: 1 addition & 0 deletions src/cc/table_desc.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace ebpf {
struct TableDesc {
std::string name;
int fd;
int type;
size_t key_size; // sizes are in bytes
size_t leaf_size;
size_t max_entries;
Expand Down
37 changes: 34 additions & 3 deletions src/python/bpf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
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.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.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_table_leaf_desc.restype = ct.c_char_p
Expand Down Expand Up @@ -103,6 +105,10 @@ class BPF(object):
SCHED_CLS = 3
SCHED_ACT = 4

HASH = 1
ARRAY = 2
PROG_ARRAY = 3

class Function(object):
def __init__(self, bpf, name, fd):
self.bpf = bpf
Expand All @@ -116,6 +122,7 @@ def __init__(self, bpf, map_id, map_fd, keytype, leaftype):
self.map_fd = map_fd
self.Key = keytype
self.Leaf = leaftype
self.ttype = lib.bpf_table_type_id(self.bpf.module, self.map_id)

def key_sprintf(self, key):
key_p = ct.pointer(key)
Expand Down Expand Up @@ -180,9 +187,33 @@ def __len__(self):

def __delitem__(self, key):
key_p = ct.pointer(key)
res = lib.bpf_delete_elem(self.map_fd, ct.cast(key_p, ct.c_void_p))
if res < 0:
raise KeyError
ttype = lib.bpf_table_type_id(self.bpf.module, self.map_id)
# Deleting from array type maps does not have an effect, so
# 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):
return BPF.Table.Iter(self, self.Key)
Expand Down
7 changes: 4 additions & 3 deletions tools/pidpersec
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/python
# vim: ts=8 noet sw=8
#
# pidpersec Count new processes (via fork).
# For Linux, uses BCC, eBPF. See .c file.
Expand Down Expand Up @@ -32,8 +33,8 @@ while (1):
try:
sleep(1)
except KeyboardInterrupt:
pass; exit()
exit()

print("%s: PIDs/sec: %d" % (strftime("%H:%M:%S"),
(b["stats"][S_COUNT].value - last)))
last = b["stats"][S_COUNT].value
(b["stats"][S_COUNT].value)))
b["stats"].clear()

0 comments on commit 8e40c23

Please sign in to comment.