Commit 3fc27b71 authored by Quentin Monnet's avatar Quentin Monnet Committed by David S. Miller

tools: bpftool: try to mount bpffs if required for pinning objects

One possible cause of failure for `bpftool {prog|map} pin * file FILE`
is the FILE not being in an eBPF virtual file system (bpffs). In this
case, make bpftool attempt to mount bpffs on the parent directory of the
FILE. Then, if this operation is successful, try again to pin the
object.

The code for mnt_bpffs() is a copy of function bpf_mnt_fs() from
iproute2 package (under lib/bpf.c, taken at commit 4b73d52f8a81), with
modifications regarding handling of error messages.
Signed-off-by: default avatarQuentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e233df01
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include <unistd.h> #include <unistd.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <sys/mount.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/vfs.h> #include <sys/vfs.h>
...@@ -59,6 +60,37 @@ static bool is_bpffs(char *path) ...@@ -59,6 +60,37 @@ static bool is_bpffs(char *path)
return (unsigned long)st_fs.f_type == BPF_FS_MAGIC; return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
} }
static int mnt_bpffs(const char *target, char *buff, size_t bufflen)
{
bool bind_done = false;
while (mount("", target, "none", MS_PRIVATE | MS_REC, NULL)) {
if (errno != EINVAL || bind_done) {
snprintf(buff, bufflen,
"mount --make-private %s failed: %s",
target, strerror(errno));
return -1;
}
if (mount(target, target, "none", MS_BIND, NULL)) {
snprintf(buff, bufflen,
"mount --bind %s %s failed: %s",
target, target, strerror(errno));
return -1;
}
bind_done = true;
}
if (mount("bpf", target, "bpf", 0, "mode=0700")) {
snprintf(buff, bufflen, "mount -t bpf bpf %s failed: %s",
target, strerror(errno));
return -1;
}
return 0;
}
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
{ {
enum bpf_obj_type type; enum bpf_obj_type type;
...@@ -89,8 +121,11 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) ...@@ -89,8 +121,11 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
{ {
char err_str[ERR_MAX_LEN];
unsigned int id; unsigned int id;
char *endptr; char *endptr;
char *file;
char *dir;
int err; int err;
int fd; int fd;
...@@ -117,16 +152,36 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) ...@@ -117,16 +152,36 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
} }
err = bpf_obj_pin(fd, *argv); err = bpf_obj_pin(fd, *argv);
close(fd); if (!err)
if (err) { goto out_close;
p_err("can't pin the object (%s): %s", *argv,
errno == EACCES && !is_bpffs(dirname(*argv)) ? file = malloc(strlen(*argv) + 1);
"directory not in bpf file system (bpffs)" : strcpy(file, *argv);
strerror(errno)); dir = dirname(file);
return -1;
if (errno != EPERM || is_bpffs(dir)) {
p_err("can't pin the object (%s): %s", *argv, strerror(errno));
goto out_free;
} }
return 0; /* Attempt to mount bpffs, then retry pinning. */
err = mnt_bpffs(dir, err_str, ERR_MAX_LEN);
if (!err) {
err = bpf_obj_pin(fd, *argv);
if (err)
p_err("can't pin the object (%s): %s", *argv,
strerror(errno));
} else {
err_str[ERR_MAX_LEN - 1] = '\0';
p_err("can't mount BPF file system to pin the object (%s): %s",
*argv, err_str);
}
out_free:
free(file);
out_close:
close(fd);
return err;
} }
const char *get_fd_type_name(enum bpf_obj_type type) const char *get_fd_type_name(enum bpf_obj_type type)
......
...@@ -51,6 +51,8 @@ ...@@ -51,6 +51,8 @@
#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
#define BAD_ARG() ({ p_err("what is '%s'?\n", *argv); -1; }) #define BAD_ARG() ({ p_err("what is '%s'?\n", *argv); -1; })
#define ERR_MAX_LEN 1024
#define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" #define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
#define HELP_SPEC_PROGRAM \ #define HELP_SPEC_PROGRAM \
......
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