libbpf: fix reuse of pinned map on older kernel
PATCH v2 1/1 libbpf: fix reuse of pinned map on older kernel
When loading a BPF program with a pinned map, the loader checks whether the pinned map can be reused, i.e. their properties match. To derive such of the pinned map, the loader invokes BPF_OBJ_GET_INFO_BY_FD and then does the comparison.
Unfortunately, on < 4.12 kernels the BPF_OBJ_GET_INFO_BY_FD is not available, so loading the program fails with the following error:
libbpf: failed to get map info for map FD 5: Invalid argument
libbpf: couldn't reuse pinned map at
'/sys/fs/bpf/tc/globals/cilium_call_policy': parameter mismatch"
libbpf: map 'cilium_call_policy': error reusing pinned map
libbpf: map 'cilium_call_policy': failed to create:
Invalid argument(-22)
libbpf: failed to load object 'bpf_overlay.o'
To fix this, fallback to derivation of the map properties via /proc/$PID/fdinfo/$MAP_FD if BPF_OBJ_GET_INFO_BY_FD fails with EINVAL, which can be used as an indicator that the kernel doesn't support the latter.
--- tools/lib/bpf/libbpf.c | 48 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-)
tools/lib/bpf/libbpf.c +45 -3
@@ -3894,6 +3894,42 @@ static int bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map)return 0 ; } +static int bpf_get_map_info_from_fdinfo (int fd,struct bpf_map_info *info) +{ +char file[PATH_MAX ], buff[4096 ]; +FILE *fp; +__u32 val; +int err; + +snprintf (file,sizeof (file),"/proc/%d/fdinfo/%d" ,getpid (), fd); +memset (info,0 ,sizeof (*info)); + + fp =fopen (file,"r" ); +if (!fp) { + err = -errno; +pr_warn ("failed to open %s: %d. No procfs support?\n" , file, + err); +return err; + } + +while (fgets (buff,sizeof (buff), fp)) { +if (sscanf (buff,"map_type:\t%u" , &val) ==1 ) + info->type = val; +else if (sscanf (buff,"key_size:\t%u" , &val) ==1 ) + info->key_size = val; +else if (sscanf (buff,"value_size:\t%u" , &val) ==1 ) + info->value_size = val; +else if (sscanf (buff,"max_entries:\t%u" , &val) ==1 ) + info->max_entries = val; +else if (sscanf (buff,"map_flags:\t%i" , &val) ==1 ) + info->map_flags = val; + } + +fclose (fp); + +return 0 ; +} +int bpf_map__reuse_fd (struct bpf_map *map,int fd) {struct bpf_map_info info = {};
@@ -3902,6 +3938,8 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)char *new_name; err =bpf_obj_get_info_by_fd (fd, &info, &len); +if (err && errno ==EINVAL ) + err =bpf_get_map_info_from_fdinfo (fd, &info);if (err)return libbpf_err (err);
@@ -4381,12 +4419,16 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)struct bpf_map_info map_info = {};char msg[STRERR_BUFSIZE ];__u32 map_info_len; +int err; map_info_len =sizeof (map_info); -if (bpf_obj_get_info_by_fd (map_fd, &map_info, &map_info_len)) { -pr_warn ("failed to get map info for map FD %d: %s\n" , - map_fd,libbpf_strerror_r (errno, msg,sizeof (msg))); + err =bpf_obj_get_info_by_fd (map_fd, &map_info, &map_info_len); +if (err && errno ==EINVAL ) + err =bpf_get_map_info_from_fdinfo (map_fd, &map_info); +if (err) { +pr_warn ("failed to get map info for map FD %d: %s\n" , map_fd, +libbpf_strerror_r (errno, msg,sizeof (msg)));return false; }
Signature · 1 line
2.32.0
Quoted 17 lines · Martynas Pumputis
When loading a BPF program with a pinned map, the loader checks whether the pinned map can be reused, i.e. their properties match. To derive such of the pinned map, the loader invokes
BPF_OBJ_GET_INFO_BY_FDand then does the comparison.Unfortunately, on < 4.12 kernels the
BPF_OBJ_GET_INFO_BY_FDis not available, so loading the program fails with the following error:libbpf: failed to get map info for map FD 5: Invalid argument
libbpf: couldn't reuse pinned map at
'/sys/fs/bpf/tc/globals/cilium_call_policy': parameter mismatch"
libbpf: map 'cilium_call_policy': error reusing pinned map
libbpf: map 'cilium_call_policy': failed to create:
Invalid argument(-22)
libbpf: failed to load object 'bpf_overlay.o'
Quoted 7 lines
To fix this, fallback to derivation of the map properties via
/proc/$PID/fdinfo/$MAP_FDifBPF_OBJ_GET_INFO_BY_FDfails with EINVAL, which can be used as an indicator that the kernel doesn't support the latter.Signed-off-by Martynas Pumputis <[email protected]>---
LGTM.