Commit dc3a2d25 authored by Toke Høiland-Jørgensen's avatar Toke Høiland-Jørgensen Committed by Alexei Starovoitov

libbpf: Print hint about ulimit when getting permission denied error

Probably the single most common error newcomers to XDP are stumped by is
the 'permission denied' error they get when trying to load their program
and 'ulimit -l' is set too low. For examples, see [0], [1].

Since the error code is UAPI, we can't change that. Instead, this patch
adds a few heuristics in libbpf and outputs an additional hint if they are
met: If an EPERM is returned on map create or program load, and geteuid()
shows we are root, and the current RLIMIT_MEMLOCK is not infinity, we
output a hint about raising 'ulimit -l' as an additional log line.

[0] https://marc.info/?l=xdp-newbies&m=157043612505624&w=2
[1] https://github.com/xdp-project/xdp-tutorial/issues/86Signed-off-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Acked-by: default avatarJesper Dangaard Brouer <brouer@redhat.com>
Acked-by: default avatarYonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20191216181204.724953-1-toke@redhat.com
parent d50ecc46
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/vfs.h> #include <sys/vfs.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <sys/resource.h>
#include <tools/libc_compat.h> #include <tools/libc_compat.h>
#include <libelf.h> #include <libelf.h>
#include <gelf.h> #include <gelf.h>
...@@ -100,6 +101,32 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...) ...@@ -100,6 +101,32 @@ void libbpf_print(enum libbpf_print_level level, const char *format, ...)
va_end(args); va_end(args);
} }
static void pr_perm_msg(int err)
{
struct rlimit limit;
char buf[100];
if (err != -EPERM || geteuid() != 0)
return;
err = getrlimit(RLIMIT_MEMLOCK, &limit);
if (err)
return;
if (limit.rlim_cur == RLIM_INFINITY)
return;
if (limit.rlim_cur < 1024)
snprintf(buf, sizeof(buf), "%lu bytes", limit.rlim_cur);
else if (limit.rlim_cur < 1024*1024)
snprintf(buf, sizeof(buf), "%.1f KiB", (double)limit.rlim_cur / 1024);
else
snprintf(buf, sizeof(buf), "%.1f MiB", (double)limit.rlim_cur / (1024*1024));
pr_warn("permission error while running as root; try raising 'ulimit -l'? current value: %s\n",
buf);
}
#define STRERR_BUFSIZE 128 #define STRERR_BUFSIZE 128
/* Copied from tools/perf/util/util.h */ /* Copied from tools/perf/util/util.h */
...@@ -2983,6 +3010,7 @@ bpf_object__create_maps(struct bpf_object *obj) ...@@ -2983,6 +3010,7 @@ bpf_object__create_maps(struct bpf_object *obj)
cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
pr_warn("failed to create map (name: '%s'): %s(%d)\n", pr_warn("failed to create map (name: '%s'): %s(%d)\n",
map->name, cp, err); map->name, cp, err);
pr_perm_msg(err);
for (j = 0; j < i; j++) for (j = 0; j < i; j++)
zclose(obj->maps[j].fd); zclose(obj->maps[j].fd);
return err; return err;
...@@ -4381,6 +4409,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, ...@@ -4381,6 +4409,7 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
ret = -errno; ret = -errno;
cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
pr_warn("load bpf program failed: %s\n", cp); pr_warn("load bpf program failed: %s\n", cp);
pr_perm_msg(ret);
if (log_buf && log_buf[0] != '\0') { if (log_buf && log_buf[0] != '\0') {
ret = -LIBBPF_ERRNO__VERIFY; ret = -LIBBPF_ERRNO__VERIFY;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment