4
votes

Is it possible to share ebpf maps between different program types. I need to share a map between a tc-bpf program and a cgroup bpf program. This should be possible if the map is pinned to file system that act as global namespace. But, I haven't got this working.

The map is created by tc-bpf program and pinned to global namespace. Since it is tc-bpf program, the map is of type struct bpf_elf_map. This bpf program is loaded via iproute2.

Now, I have a cgroup bpf program that should be accessing this map, but since it is loaded via a user.c (libbpf) or bpftool and not iproute, the map that is defined here cannot be ‘bpf_elf_map’, but it is struct bpf_map_def. So in the cgroup bpf program, the same map is defined as struct bpf_map_def and not struct bpf_elf_map.

Probably because of this the cgroup program gets a new map_id when I dump the maps (and does not share the intended map), ideally when the same map is shared across bpf programs, these bpf programs would be having the same map_id associated with their unique prog_ids.

1
I can access the map in userspace through various syscall utilities available, but the intent is to access the map from a different bpf program(_kern.c) of a different attach type.user1727270

1 Answers

4
votes

It is possible to share access to eBPF maps between programs of different types.

First, you can forget about those differences between struct bpf_elf_map and struct bpf_map_def. They are structs used in user space to build the objects to pass to the kernel. Iproute2 and libbpf may not use the same struct/attribute names, but they both end up passing the map metadata to the bpf() system call in the same format, or the kernel would not understand what map is to be created.

When they are loaded to the kernel, eBPF programs refer to a given map through file descriptors to this map. This means that the process calling the bpf() system call to load the program first has to retrieve file descriptors to the map to use. So the two following cases may happen:

  • User space application (ip, tc, bpftool...) parses the ELF object file and collects map-related metadata. It does not identify (and possibly did not even try to identify) any existing map that should be reused for the program. So it creates a new map with the bpf() syscall, which returns a file descriptor to this newly-created map. This file descriptor is used in the program instructions referring to map access (once the program is loaded in the kernel, those file descriptors will be replaced by the map address), and the program is then loaded with the bpf() syscall. This is what happens with your tc program, and in your case it seems, with your cgroup program which is creating a second map.

  • Or user application parses the ELF object file, and finds somehow that there is already an existing map that the program should use. For example, it finds a map of id 1337, or a pinned map under /sys/fs/bpf/. In that case it retrieves a file descriptor to that map (from the id with bpf() syscall, from a pinned path with open()). Then as in the first case, it uses this file descriptor to prepare and then load the program.

Libbpf provides a way to reuse a file descriptor for a given map to use with a program. See for example bpf_map__reuse_fd(). Bpftool uses it to support reusing existing maps, with the map argument for bpftool prog load (see man bpftool-prog). For example, load a program from foo.o and tell it to reuse map of id 27 for the first map found in the object file, then the map pinned at /sys/fs/bpf/foomap for the map named foomap in the object file:

# bpftool prog load foo.o /sys/fs/bpf/foo_prog \
        map idx 0 id 27 \
        map foomap stats pinned /sys/fs/bpf/foomap