Topics

Behavior of bpf_obj_get

Adam Drescher
 

I am seeing unexpected behavior from bpf_obj_get, although this is
likely due to my inexperience with BPF.

In a loader program, I create a pinned map at
"sys/fs/bpf/test/xdp_stats_map". In a separate statistics program, I
access the pinned map via file descriptor -- I got the file descriptor
from a call to bpf_obj_get and provided the pathname above.

In a polling loop, I call bpf_obj_get on the same pathname and compare
this value to the original. However, instead of getting the same file
descriptor, the file descriptor returned by bpf_obj_get increments by
1 each invocation (so it returns 4, 5, 6, 7, ...). I am not doing
anything externally to reload the map or change the file descriptor.
Why is this happening? Looking at samples/bpf/fds_example.c as example
usage of bpf_obj_get, I would expect to get the same file descriptor
back. Any ideas?

Relevant code (filename has already been populated elsewhere):

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
char filename[PATH_MAX];

static void stats_poll(int map_fd, __u32 map_type, int interval)
{
int fd;
while (1) {
fd = bpf_obj_get(filename);
printf("filename: %s\n", filename);
printf("bpf_obj_get: %d - map_fd: %d\n", fd, map_fd);
sleep(interval);
}
}

Relevant output:
- BPF map (bpf_map_type:6) id:42 name:xdp_stats_map key_size:4
value_size:16 max_entries:5
filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 4 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 5 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 6 - map_fd: 3

Yonghong Song
 

On Thu, May 30, 2019 at 8:40 AM Adam Drescher <adam.r.drescher@...> wrote:

I am seeing unexpected behavior from bpf_obj_get, although this is
likely due to my inexperience with BPF.

In a loader program, I create a pinned map at
"sys/fs/bpf/test/xdp_stats_map". In a separate statistics program, I
access the pinned map via file descriptor -- I got the file descriptor
from a call to bpf_obj_get and provided the pathname above.

In a polling loop, I call bpf_obj_get on the same pathname and compare
this value to the original. However, instead of getting the same file
descriptor, the file descriptor returned by bpf_obj_get increments by
1 each invocation (so it returns 4, 5, 6, 7, ...). I am not doing
anything externally to reload the map or change the file descriptor.
Why is this happening? Looking at samples/bpf/fds_example.c as example
usage of bpf_obj_get, I would expect to get the same file descriptor
back. Any ideas?
No, you won't get the same file descriptor although they pointing to
the same map.
- the original map fd holds a reference count in the kernel.
- bpf_obj_get returns a new fd and map reference count is increased
by 1 as well

You can close the original map fd and the fd returned by bpf_obj_get() would
still be valid, and vice verse.


Relevant code (filename has already been populated elsewhere):

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
char filename[PATH_MAX];

static void stats_poll(int map_fd, __u32 map_type, int interval)
{
int fd;
while (1) {
fd = bpf_obj_get(filename);
printf("filename: %s\n", filename);
printf("bpf_obj_get: %d - map_fd: %d\n", fd, map_fd);
sleep(interval);
}
}

Relevant output:
- BPF map (bpf_map_type:6) id:42 name:xdp_stats_map key_size:4
value_size:16 max_entries:5
filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 4 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 5 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 6 - map_fd: 3


Adam Drescher
 

Thank you for your answer, that makes sense.

This leads me to a follow up question: is there a standard way to see
if a pinned map has been reloaded, without closing and re-opening the
map file every time to check? From your answer, now I know we cannot
do this by monitoring a change in the map's file descriptor. We cannot
use the map ID from bpf_obj_get_info_by_fd, as the info still
corresponds to the old map. As far as I can tell, we don't have access
to the BPF object or program pointers in a standalone userspace
daemon.

On Thu, May 30, 2019 at 12:00 PM Y Song <ys114321@...> wrote:

On Thu, May 30, 2019 at 8:40 AM Adam Drescher <adam.r.drescher@...> wrote:

I am seeing unexpected behavior from bpf_obj_get, although this is
likely due to my inexperience with BPF.

In a loader program, I create a pinned map at
"sys/fs/bpf/test/xdp_stats_map". In a separate statistics program, I
access the pinned map via file descriptor -- I got the file descriptor
from a call to bpf_obj_get and provided the pathname above.

In a polling loop, I call bpf_obj_get on the same pathname and compare
this value to the original. However, instead of getting the same file
descriptor, the file descriptor returned by bpf_obj_get increments by
1 each invocation (so it returns 4, 5, 6, 7, ...). I am not doing
anything externally to reload the map or change the file descriptor.
Why is this happening? Looking at samples/bpf/fds_example.c as example
usage of bpf_obj_get, I would expect to get the same file descriptor
back. Any ideas?
No, you won't get the same file descriptor although they pointing to
the same map.
- the original map fd holds a reference count in the kernel.
- bpf_obj_get returns a new fd and map reference count is increased
by 1 as well

You can close the original map fd and the fd returned by bpf_obj_get() would
still be valid, and vice verse.


Relevant code (filename has already been populated elsewhere):

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
char filename[PATH_MAX];

static void stats_poll(int map_fd, __u32 map_type, int interval)
{
int fd;
while (1) {
fd = bpf_obj_get(filename);
printf("filename: %s\n", filename);
printf("bpf_obj_get: %d - map_fd: %d\n", fd, map_fd);
sleep(interval);
}
}

Relevant output:
- BPF map (bpf_map_type:6) id:42 name:xdp_stats_map key_size:4
value_size:16 max_entries:5
filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 4 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 5 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 6 - map_fd: 3


Yonghong Song
 

On Thu, May 30, 2019 at 11:26 AM Adam Drescher
<adam.r.drescher@...> wrote:

Thank you for your answer, that makes sense.

This leads me to a follow up question: is there a standard way to see
if a pinned map has been reloaded, without closing and re-opening the
map file every time to check? From your answer, now I know we cannot
If you take a reference count for the pinned map, the map cannot be
removed.
If you are talking about the content change of a pinned map, the applicaiton
has to check the map key/values to find it. Just like shared memory.

do this by monitoring a change in the map's file descriptor. We cannot
use the map ID from bpf_obj_get_info_by_fd, as the info still
corresponds to the old map. As far as I can tell, we don't have access
to the BPF object or program pointers in a standalone userspace
daemon.
You got a map fd, you should use map fd to do standard map lookup/insert/delete
operations.


On Thu, May 30, 2019 at 12:00 PM Y Song <ys114321@...> wrote:

On Thu, May 30, 2019 at 8:40 AM Adam Drescher <adam.r.drescher@...> wrote:

I am seeing unexpected behavior from bpf_obj_get, although this is
likely due to my inexperience with BPF.

In a loader program, I create a pinned map at
"sys/fs/bpf/test/xdp_stats_map". In a separate statistics program, I
access the pinned map via file descriptor -- I got the file descriptor
from a call to bpf_obj_get and provided the pathname above.

In a polling loop, I call bpf_obj_get on the same pathname and compare
this value to the original. However, instead of getting the same file
descriptor, the file descriptor returned by bpf_obj_get increments by
1 each invocation (so it returns 4, 5, 6, 7, ...). I am not doing
anything externally to reload the map or change the file descriptor.
Why is this happening? Looking at samples/bpf/fds_example.c as example
usage of bpf_obj_get, I would expect to get the same file descriptor
back. Any ideas?
No, you won't get the same file descriptor although they pointing to
the same map.
- the original map fd holds a reference count in the kernel.
- bpf_obj_get returns a new fd and map reference count is increased
by 1 as well

You can close the original map fd and the fd returned by bpf_obj_get() would
still be valid, and vice verse.


Relevant code (filename has already been populated elsewhere):

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
char filename[PATH_MAX];

static void stats_poll(int map_fd, __u32 map_type, int interval)
{
int fd;
while (1) {
fd = bpf_obj_get(filename);
printf("filename: %s\n", filename);
printf("bpf_obj_get: %d - map_fd: %d\n", fd, map_fd);
sleep(interval);
}
}

Relevant output:
- BPF map (bpf_map_type:6) id:42 name:xdp_stats_map key_size:4
value_size:16 max_entries:5
filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 4 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 5 - map_fd: 3

filename: /sys/fs/bpf/test/xdp_stats_map
bpf_obj_get: 6 - map_fd: 3