4
votes

This is follow-up to who creates map in BPF since my new question is not directly relevant that thread.

So, it seems to me that there has to be a single point where a BPF map is created, either it is a bpf program or a user program that loads bpf etc.

A BPF program has to know type of maps it is going to work with at compile-time, so we need:

struct bpf_map_def SEC("maps") my_map = {
...
};

So it means that a user program, for example bpftool, will initiate creation of maps found in bpf ELF sections, as was shown in who creates map in BPF thread.

On the other hand, user application will need to add/delete entries in the map. For this to happen, it has to know map's ID in order to obtain get map's fd with bpf_map_get_fd_by_id() from libbpf. After that we can enjoy bpf_map_update_elem() and similar APIs.

On the other hand, if we declared a map section in the BPF program and do have map API in use, the map(s) will be preserved in the kernel and will be allocated IDs.

So in this case, we are going to have two maps with two different IDs: one created as a result of bpf_prog_load() from bpftool, and the other from the user application's bpf_create_map() (assuming that the application continues running, e.g. update maps, and does not return to shell).

There must be a way to bypass this ambiguity?

1

1 Answers

5
votes

I am not completely sure I understand your question, let me try to rephrase this.

  • You load an eBPF program with bpftool, which creates all maps needed by the program. bpftool is a user space application, and ultimately creates maps with the bpf(BPF_MAP_CREATE, …) syscall.
  • You have another user space application foobar that interacts with these maps, possibly by using libbpf (that in turns ends up performing bpf(BPF_MAP_*, …) syscalls) to look up, update or delete elements from the maps.
  • As I understand it, this second application foobar also tries to create the maps. Hence you have a conflict between the maps created by bpftool and the one created by foobar.

If this is correct, the solution is “simple”: do not create the maps twice.

This means that you should either delete the calls to bpf_create_map() from your other application foobar, or load your programs with something else than bpftool. Usually, the workflow consists in having the maps described in the eBPF object file, and created by the same application that loads the program, just before loading—this is what bpftool does. Then the application has the file descriptor for the map and can work on it.

Alternatively, it is possible to pin the map under the BPF virtual file system (/sys/fs/bpf/) so that another application can retrieve the file descriptor, and also access this map. This is done with the syscall bpf(BPF_OBJ_GET, …) (not yet documented on the man page at this time, at least on my system).

If I am correct, using pinned maps can also allow one to reuse an already existing map when loading a new eBPF program. I believe tc from package iproute2 intends to do that if the map described exists and is pinned already (see file lib/bpf.c, but the code is not exactly easy to read). This would typically be performed at relocation time.

Maps IDs were added recently, and primarily for debug or introspection, but they may provide another way to retrieve the file descriptor to a map in your case, as you describe with bpf_map_get_fd_by_id(). Although you have to find a way to get the ID in the first place.

Hope this helps!