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 <bblanco@plumgrid.com>
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;
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);
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();
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;
//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_,
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)
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;
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
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
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)
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)
#!/usr/bin/python
+# vim: ts=8 noet sw=8
#
# pidpersec Count new processes (via fork).
# For Linux, uses BCC, eBPF. See .c file.
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()