* [PATCH v2 bpf] libbpf: fix reuse of pinned map on older kernel
@ 2021-07-07 10:47 Martynas Pumputis
0 siblings, 0 replies; only message in thread
From: Martynas Pumputis @ 2021-07-07 10:47 UTC (permalink / raw)
To: bpf; +Cc: ast, daniel, andrii, m
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, probe the kernel for BPF_OBJ_GET_INFO_BY_FD support. If it
doesn't support, then fallback to derivation of the map properties via
/proc/$PID/fdinfo/$MAP_FD.
Signed-off-by: Martynas Pumputis <m@lambda.lt>
---
tools/lib/bpf/libbpf.c | 103 +++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 92 insertions(+), 11 deletions(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index ac882e1..f3daed3 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -193,6 +193,8 @@ enum kern_feature_id {
FEAT_MODULE_BTF,
/* BTF_KIND_FLOAT support */
FEAT_BTF_FLOAT,
+ /* BPF_OBJ_GET_INFO_BY_FD support */
+ FEAT_OBJ_GET_INFO_BY_FD,
__FEAT_CNT,
};
@@ -3920,14 +3922,54 @@ static int bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map)
return 0;
}
-int bpf_map__reuse_fd(struct bpf_map *map, int fd)
+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;
+}
+
+static int bpf_map__reuse_fd_safe(struct bpf_object *obj, struct bpf_map *map,
+ int fd)
{
struct bpf_map_info info = {};
__u32 len = sizeof(info);
int new_fd, err;
char *new_name;
- err = bpf_obj_get_info_by_fd(fd, &info, &len);
+ if (!obj || kernel_supports(obj, FEAT_OBJ_GET_INFO_BY_FD))
+ err = bpf_obj_get_info_by_fd(fd, &info, &len);
+ else
+ err = bpf_get_map_info_from_fdinfo(fd, &info);
if (err)
return libbpf_err(err);
@@ -3974,6 +4016,11 @@ err_free_new_name:
return libbpf_err(err);
}
+int bpf_map__reuse_fd(struct bpf_map *map, int fd)
+{
+ return bpf_map__reuse_fd_safe(NULL, map, fd);
+}
+
__u32 bpf_map__max_entries(const struct bpf_map *map)
{
return map->def.max_entries;
@@ -4320,6 +4367,27 @@ static int probe_module_btf(void)
return !err;
}
+static int probe_kern_bpf_get_info_by_fd(void)
+{
+ int fd, err;
+ __u32 len;
+ struct bpf_map_info info;
+ struct bpf_create_map_attr attr = {
+ .map_type = BPF_MAP_TYPE_ARRAY,
+ .key_size = sizeof(int),
+ .value_size = sizeof(int),
+ .max_entries = 1,
+ };
+
+ fd = bpf_create_map_xattr(&attr);
+ if (fd < 0)
+ return 0;
+
+ err = bpf_obj_get_info_by_fd(fd, &info, &len);
+ close(fd);
+ return !err;
+}
+
enum kern_feature_result {
FEAT_UNKNOWN = 0,
FEAT_SUPPORTED = 1,
@@ -4370,6 +4438,9 @@ static struct kern_feature_desc {
[FEAT_BTF_FLOAT] = {
"BTF_KIND_FLOAT support", probe_kern_btf_float,
},
+ [FEAT_OBJ_GET_INFO_BY_FD] = {
+ "BPF_OBJ_GET_INFO_BY_FD support", probe_kern_bpf_get_info_by_fd,
+ },
};
static bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id feat_id)
@@ -4398,7 +4469,8 @@ static bool kernel_supports(const struct bpf_object *obj, enum kern_feature_id f
return READ_ONCE(feat->res) == FEAT_SUPPORTED;
}
-static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
+static bool map_is_reuse_compat(struct bpf_object *obj,
+ const struct bpf_map *map, int map_fd)
{
struct bpf_map_info map_info = {};
char msg[STRERR_BUFSIZE];
@@ -4406,10 +4478,19 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
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)));
- return false;
+ if (kernel_supports(obj, FEAT_OBJ_GET_INFO_BY_FD)) {
+ 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)));
+ return false;
+ }
+ } else {
+ if (bpf_get_map_info_from_fdinfo(map_fd, &map_info)) {
+ pr_warn("failed to get map info for fdinfo: %s\n",
+ libbpf_strerror_r(errno, msg, sizeof(msg)));
+ return false;
+ }
}
return (map_info.type == map->def.type &&
@@ -4420,7 +4501,7 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
}
static int
-bpf_object__reuse_map(struct bpf_map *map)
+bpf_object__reuse_map(struct bpf_object *obj, struct bpf_map *map)
{
char *cp, errmsg[STRERR_BUFSIZE];
int err, pin_fd;
@@ -4440,14 +4521,14 @@ bpf_object__reuse_map(struct bpf_map *map)
return err;
}
- if (!map_is_reuse_compat(map, pin_fd)) {
+ if (!map_is_reuse_compat(obj, map, pin_fd)) {
pr_warn("couldn't reuse pinned map at '%s': parameter mismatch\n",
map->pin_path);
close(pin_fd);
return -EINVAL;
}
- err = bpf_map__reuse_fd(map, pin_fd);
+ err = bpf_map__reuse_fd_safe(obj, map, pin_fd);
if (err) {
close(pin_fd);
return err;
@@ -4643,7 +4724,7 @@ bpf_object__create_maps(struct bpf_object *obj)
map = &obj->maps[i];
if (map->pin_path) {
- err = bpf_object__reuse_map(map);
+ err = bpf_object__reuse_map(obj, map);
if (err) {
pr_warn("map '%s': error reusing pinned map\n",
map->name);
--
2.32.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2021-07-07 10:45 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-07-07 10:47 [PATCH v2 bpf] libbpf: fix reuse of pinned map on older kernel Martynas Pumputis
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.