To use global variables in eBPF, libbpf internally creates BPF maps.
I found that global variables are copied into memory during the open phase, before creating the BPF maps.
static int
bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type,
const char *real_name, int sec_idx, void *data, size_t data_sz)
{
struct bpf_map *map;
map = bpf_object__add_map(obj);
mmap_sz = bpf_map_mmap_sz(map);
map->mmaped = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (data)
memcpy(map->mmaped, data, data_sz);
}
What is the reason for copying global variables into memory before map creation? Why aren't the BPF maps created directly without this memory copy step?
I did some more research, but I still couldn't find a definitive explanation.
This logic was introduced in commit eba9c5f498a1
upstream. The description explains why this was implemented:
Refactor global data map initialization to use anonymous
mmap()
-ed memory instead ofmalloc()
-ed one. This allows to do a transparent re-mmap()
-ing of already existing memory address to point to BPF map's memory afterbpf_object__load()
step (done in follow up patch). This choreographed setup allows to have a nice and unsurprising way to pre-initialize read-only (and r/w as well) maps by user and after BPF map creation keep working withmmap()
-ed contents of this map. All in a way that doesn't require user code to update any pointers: the illusion of working with memory contents is preserved before and after actual BPF map instantiation.