Commit db7fab56 authored by Teng Qin's avatar Teng Qin

Add bpf_get_first_key helper

This commit adds bpf_get_first_key helper, which gets the first key of
the map. It automatically tries to use the new Kernel functionality and
falls back to old Kernel behavior. This helps us unify the logic to walk
a map across different APIs (Python, C++, etc.)
parent b84fb862
......@@ -133,6 +133,44 @@ int bpf_delete_elem(int fd, void *key)
return syscall(__NR_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
}
int bpf_get_first_key(int fd, void *key, size_t key_size)
{
union bpf_attr attr;
int i, res;
memset(&attr, 0, sizeof(attr));
attr.map_fd = fd;
attr.key = 0;
attr.next_key = ptr_to_u64(key);
// 4.12 and above kernel supports passing NULL to BPF_MAP_GET_NEXT_KEY
// to get first key of the map. For older kernels, the call will fail.
res = syscall(__NR_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
if (res < 0 && errno == EFAULT) {
// Fall back to try to find a non-existing key.
static unsigned char try_values[3] = {0, 0xff, 0x55};
attr.key = ptr_to_u64(key);
for (i = 0; i < 3; i++) {
memset(key, try_values[i], key_size);
// We want to check the existence of the key but we don't know the size
// of map's value. So we pass an invalid pointer for value, expect
// the call to fail and check if the error is ENOENT indicating the
// key doesn't exist. If we use NULL for the invalid pointer, it might
// trigger a page fault in kernel and affect performence. Hence we use
// ~0 which will fail and return fast.
// This should fail since we pass an invalid pointer for value.
if (bpf_lookup_elem(fd, key, ~0) >= 0)
return -1;
// This means the key doesn't exist.
if (errno == ENOENT)
return syscall(__NR_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
}
return -1;
} else {
return res;
}
}
int bpf_get_next_key(int fd, void *key, void *next_key)
{
union bpf_attr attr;
......
......@@ -34,6 +34,7 @@ int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags);
int bpf_lookup_elem(int fd, void *key, void *value);
int bpf_delete_elem(int fd, void *key);
int bpf_get_first_key(int fd, void *key, size_t key_size);
int bpf_get_next_key(int fd, void *key, void *next_key);
int bpf_prog_load(enum bpf_prog_type prog_type,
......
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