1

Let's suppose there are two programs (User program and Kernel program).

User program made bpf map by api bpf_create_map_name() and it returns fd. With this fd, I can access the map by syscalls (e.g., bpf_map_update(fd, ..)). But I can do this only in the user space programs because the fd is valid only to user program(=user process), then How can I access to this map in the bpf program (located in the kernel space)?

I was heard that I can pin the map in the fs via libbpf's bpf_obj_pin(fd, file path) and can get this map via libbpf's bpf_obj_get(file path) but the problem is bpf_obj_get is only available in the user space because this is system call.

I saw a similar discussion before (Accessing BPF maps from kernel space). but this was not clear to me. To access bpf map via bpf_map_lookup_elem(fd, ..) in the kernel space, I have to know map's fd in advance. But as I mentioned before, the map's fd is not valid in the kernel.

I am using libbpf not BCC.

2 Answers 2

2

You should probably look at libbpf's function bpf_map__reuse_fd(), which allows to reuse a file descriptor pointing to an existing map for a BPF program.

Here is an example using this function: we first retrieve a pointer to the map to replace in the struct bpf_object by calling bpf_object__find_map_by_name(), and then tell it to reuse the existing fd.

Sign up to request clarification or add additional context in comments.

12 Comments

But can I use that functions when I make bpf_program? I thought that functions can be used in the user space. I was finding adequate 'bpf helper function' which do such roles.
My goal is to find and use map which is made by another bpf program. The bpf programs locate in kernel space.
Sorry I'm afraid I don't understand your question. In your eBPF program, you always use the map the same way - it doesn't matter if the map exists or not. Then it's up to libbpf to make sure that your program uses the right map: Either by creating it before loading the program, or by reusing the fd of an existing, pinned map created before, if you use bpf_map__reuse_fd(). If you meant something else, please clarify your question.
Okay, let's suppose two example xdpsock_kern.c and xdp1_kern.c (github.com/torvalds/linux/tree/master/samples/bpf). These are all bpf program which will be attached to two different trace points. xdpsock (bpf program) has 'xsks_map' map and xdp1 (bpf program) has 'rxcnt' map. I want to access to 'rxcnt' map when xdpsock is executed. In short, I want to lookup rxcnt map in the xdpsock program. Thank you for your concern. btw, I thought I can use libbpf functions (e.g., bpf_map__reuse_fd) in the user space program (e.g., xdpsock_user.c and xdp1_user.c) not in the kernel space program.
Yes, bpf_map__reuse_fd() is user space only. But it's in user space that you tell your programs what maps to use. Your particular example wouldn't work, because the maps aren't the same (should be same type and size for both programs). Say the maps were identical in both *_kern.c files; in that case, you would keep both BPF source files just as is. And then in user space with libbpf: 1) Create a struct bpf_object for each prog, 2) load the first one, which will make libbpf create the map it needs, 3) retrieve fd and call bpf_map__reuse_fd() to set it for the 2nd prog, 4) load 2nd prog
|
2

The only way to dynamically add maps to an existing eBPF program is to use a map-in-map type like BPF_MAP_TYPE_ARRAY_OF_MAPS or BPF_MAP_TYPE_HASH_OF_MAPS. To use it we define a inner and outer map type. The userspace program/loader creates the outer map and loads the program with a reference to the outer map. After that we can modify this outer map from userspace to add one or more inner maps to it at any time. Please take a look at samples in the kernel: test_map_in_map_user.c and test_map_in_map_kern.c.

To explain further and to clarify some things:

  • eBPF programs don't create maps, the ELF files contain map definitions which are read by the userspace program/loader which then creates them. eBPF programs can't create maps as of this moment.
  • When the loader creates a map, the kernel returns a file descriptor. When a eBPF program is loaded into the kernel, the loader will dynamically rewrite the program and inject this file descriptor into it. The kernel verifies the program using the loaded map, after which the actual memory address of the map is placed in the program instead of the file descriptor so the generated machine code can access the map directly by memory address. This verification and conversion step is the reason programs can't dynamically "get" map references.
  • Map-in-map types do work dynamically. That is because the verifier validates the inner map definition when the program is loaded to make sure the code is valid. Then when the userspace updates the map-in-map, the actual memory address of the map is stored which can be accesses by the eBPF program. But even so, you need to know how the type/structure of the inner map before loading the first program.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.