Vector
Vector

Reputation: 77

what is the detailed process of bps API map helpers like "bpf_map_update_elem"?

In my understanding, when userspace use bpf_map_update_elem(int fd, void *key, void *value, __u64 flags),

first, userspace find the map through the fd;

second, userspace make a memory in user-space;

and ....

I know a little bit, but the specific process is still unclear.

So I wanna know what the detail is when userspace run API map helpers.

Upvotes: 2

Views: 929

Answers (1)

Qeole
Qeole

Reputation: 9114

Because you mention “user space”, I am unsure what you are talking about exactly. So let's start with some clarification.

BPF maps (or at least, most of the existing types, including hash maps and arrays) can be accessed in two ways:

  • From user space, by any application running on the system and having sufficient permission
  • From kernel space, from BPF programs

From user space, there is no “helper” function. Interaction with maps is entirely (*) done through the bpf() syscall (with the BPF_MAP_LOOKUP_ELEM, BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM commands passed to the syscall as its first argument). See the bpf(2) manual page for more details. This is what you use in a user space application that would load and manage BPF programs and maps, say bpftool for example.

From kernel space, i.e. from a BPF program, things work differently and access is done with one of the BPF “helpers” such as bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags). See the bpf-helpers(7) man page for details on existing helpers. You can find details on those helper calls in the Cilium guide, or obviously by reading kernel code (e.g. for array maps). They look like low-level C function calls, with BPF registers being used to pass the necessary arguments, and then it calls from the BPF program instructions into the helper that is compiled as part of the kernel binary.

So you mentioned bpf_map_update_elem() and user space. Although this is the name for the helper on the kernel side, I suspect you might be talking about the function with the same name which is offered by the libbpf library, to provide a wrapper around the bpf() system call. So what happens with this function is rather simple.

  • There is no need to find the map from the file descriptor in user space: Actually the opposite happens, the file descriptor is open from the map in user space (from its map id, or from its pinned path under the /sys/fs/bpf virtual file system for example). So the fd is passed to the bpf() system call and used by the kernel as a reference to the map.
  • I'm not sure what you mean but “userspace make a memory in user-space”. There is no need to allocate any memory here: The key and value should already have been filled at this point, and they are passed to the kernel through the bpf() syscall to tell what entry to update, and with what value. Same things for the flags.
  • Once bpf() has been called, what happens on the kernel side is rather straightforwards. Mostly, the kernel check permissions, validates the arguments (to make sure they are safe and consistent with the map), then it updates the actual data. For array maps, array_map_update_elem() (used with the BPF helper on kernel side too, see link above) is called eventually.

(*) Some interactions might actually be done without the bpf() system call, I believe that with “global data” stored in BPF maps, use applications mmap() to the kernel memory. But this goes beyond the scope of basic usage of arrays and maps.

Upvotes: 4

Related Questions