I'd create a map to store just one element (a port number) and it should be read/written both from userspace and kernelspace. Which map type should I use? Which size for key and value is appropriate and how can I write/read from both sides?
_user.c
/* create array map with one element */
map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 1, 0);
...
/* update map */
ret = bpf_map_update_elem(map_fd, &key, &i, BPF_ANY);
_kern.c
How can I refer to map_fd and operate on the same map?
EDIT:
I could successfully create and interact with the map only in one way:
defining the map within _kern.c
file, as follow:
struct bpf_map_def SEC("maps") my_map = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(uint32_t),
.value_size = sizeof(uint32_t),
.max_entries = 1,
};
That definition allows to operate directly on the map using bpf helpers like bpf_map_lookup_elem
.
Instead within _user.c
after loading the _kern.o
ebpf program into the kernel through bpf_prog_load
I used
map_fd = bpf_object__find_map_fd_by_name(obj, "my_map");
to retrieve the file descriptor associated with the map (I was missing this point). Once you get the file descriptor to perform, for instance, a map update you can call
ret = bpf_map_update_elem(map_fd, &key, &value, BPF_ANY);
QUESTION: in this case I retrieve the fd from user space using libbpf, but if I create a map from _user.c
with bpf_create_map
then how can I retrieve the fd from ebpf program ?
If you know you have just one element, the easiest is probably to go for an array map. In that case, you can trivially access your map entry by its index in the array: 0
.
If you were to do that, the size of the key would be the size of a 4-byte integer (sizeof(uint32_t)
), which are always used for array indices. The size of the value would be the size you need to store your port number: very likely a sizeof(uint16_t)
.
Then you can read/write from your BPF program by calling the relevant BPF helper functions: bpf_map_lookup_elem()
or bpf_map_update_elem()
(see man page for details). They are usually defined in bpf_helpers.h
which is not usually installed on your system, you can find versions of it in bcc or kernel repo.
From user space, you would update the entry by using the bpf()
system call, with its relevant commands: BPF_MAP_LOOKUP_ELEM()
and BPF_MAP_UPDATE_ELEM()
(see man page). But you don't necessarily have to re-implement the calls yourself: if you write a program, you should probably have a look at libbpf that provides wrappers. If you want to update your map from the command line, this is easy to do with bpftool
(see man page), something like bpftool map <map_ref> update key 0 0 0 0 value 0x37 0x13
(update) or bpftool map <map_ref> lookup key 0 0 0 0
(lookup).