Some BPF commands return ENOTSUPP (524) to user space: iterating local
storage maps, element operations on ringbuf maps, creating an LRU hash
map without preallocation, freezing a struct_ops map, or running a
program type that has no test_run. ENOTSUPP is kernel internal, so
strerror() only gives "Unknown error 524":

  # bpftool map getnext pinned /sys/fs/bpf/sk_storage
  Error: can't get next key: Unknown error 524

Add a small helper that knows ENOTSUPP and use it where bpftool prints
the error of map create, map element operations, map freeze and prog
run.

Suggested-by: Daniel Borkmann <[email protected]>
Assisted-by: LLM
Signed-off-by: Maxim Skokov <[email protected]>
---
 tools/bpf/bpftool/common.c | 11 +++++++++++
 tools/bpf/bpftool/main.h   |  1 +
 tools/bpf/bpftool/map.c    | 18 +++++++++---------
 tools/bpf/bpftool/prog.c   |  2 +-
 4 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index f9b87efa7c9a7..ca5fa2f0bf9b1 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -72,6 +72,17 @@ void p_info(const char *fmt, ...)
        va_end(ap);
 }
 
+/*
+ * Like strerror(), but also knows ENOTSUPP (524), which the kernel returns
+ * to user space from some BPF commands although it is not a userspace errno.
+ */
+const char *bpf_strerror(int err)
+{
+       if (err == 524 /* ENOTSUPP */)
+               return "Operation not supported";
+       return strerror(err);
+}
+
 static bool is_bpffs(const char *path)
 {
        struct statfs st_fs;
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 6851346a60305..b1eb4b5d991b8 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -98,6 +98,7 @@ extern const char *cert_path;
 
 void __printf(1, 2) p_err(const char *fmt, ...);
 void __printf(1, 2) p_info(const char *fmt, ...);
+const char *bpf_strerror(int err);
 
 bool is_prefix(const char *pfx, const char *str);
 int detect_common_prefix(const char *arg, ...);
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 20d59eab09a12..d809b075e734f 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -228,7 +228,7 @@ print_entry_error(struct bpf_map_info *map_info, void *key, 
int lookup_errno)
                print_hex_data_json(key, map_info->key_size);
                jsonw_name(json_wtr, "value");
                jsonw_start_object(json_wtr);   /* error */
-               jsonw_string_field(json_wtr, "error", strerror(lookup_errno));
+               jsonw_string_field(json_wtr, "error", 
bpf_strerror(lookup_errno));
                jsonw_end_object(json_wtr);     /* error */
                jsonw_end_object(json_wtr);     /* entry */
        } else {
@@ -241,7 +241,7 @@ print_entry_error(struct bpf_map_info *map_info, void *key, 
int lookup_errno)
                        msg = "<cannot read>";
 
                print_entry_error_msg(map_info, key,
-                                     msg ? : strerror(lookup_errno));
+                                     msg ? : bpf_strerror(lookup_errno));
        }
 }
 
@@ -1032,7 +1032,7 @@ static int do_update(int argc, char **argv)
 
        err = bpf_map_update_elem(fd, key, value, flags);
        if (err) {
-               p_err("update failed: %s", strerror(errno));
+               p_err("update failed: %s", bpf_strerror(errno));
                goto exit_free;
        }
 
@@ -1136,7 +1136,7 @@ static int do_lookup(int argc, char **argv)
                                printf("\n\nNot found\n");
                        }
                } else {
-                       p_err("lookup failed: %s", strerror(errno));
+                       p_err("lookup failed: %s", bpf_strerror(errno));
                }
 
                goto exit_free;
@@ -1188,7 +1188,7 @@ static int do_getnext(int argc, char **argv)
 
        err = bpf_map_get_next_key(fd, key, nextkey);
        if (err) {
-               p_err("can't get next key: %s", strerror(errno));
+               p_err("can't get next key: %s", bpf_strerror(errno));
                goto exit_free;
        }
 
@@ -1253,7 +1253,7 @@ static int do_delete(int argc, char **argv)
 
        err = bpf_map_delete_elem(fd, key);
        if (err)
-               p_err("delete failed: %s", strerror(errno));
+               p_err("delete failed: %s", bpf_strerror(errno));
 
 exit_free:
        free(key);
@@ -1381,7 +1381,7 @@ static int do_create(int argc, char **argv)
 
        fd = bpf_map_create(map_type, map_name, key_size, value_size, 
max_entries, &attr);
        if (fd < 0) {
-               p_err("map create failed: %s", strerror(errno));
+               p_err("map create failed: %s", bpf_strerror(errno));
                goto exit;
        }
 
@@ -1427,7 +1427,7 @@ static int do_pop_dequeue(int argc, char **argv)
                        else
                                printf("Error: empty map\n");
                } else {
-                       p_err("pop failed: %s", strerror(errno));
+                       p_err("pop failed: %s", bpf_strerror(errno));
                }
 
                goto exit_free;
@@ -1462,7 +1462,7 @@ static int do_freeze(int argc, char **argv)
        err = bpf_map_freeze(fd);
        close(fd);
        if (err) {
-               p_err("failed to freeze map: %s", strerror(errno));
+               p_err("failed to freeze map: %s", bpf_strerror(errno));
                return err;
        }
 
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index eb077236d2eaa..43599c79c93ac 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -1499,7 +1499,7 @@ static int do_run(int argc, char **argv)
 
        err = bpf_prog_test_run_opts(fd, &test_attr);
        if (err) {
-               p_err("failed to run program: %s", strerror(errno));
+               p_err("failed to run program: %s", bpf_strerror(errno));
                goto free_ctx_out;
        }
 
-- 
2.47.3


Reply via email to