Netdev List
 help / color / mirror / Atom feed
From: Jakub Kicinski <jakub.kicinski@netronome.com>
To: netdev@vger.kernel.org
Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com,
	daniel@iogearbox.net,
	Quentin Monnet <quentin.monnet@netronome.com>,
	Jakub Kicinski <jakub.kicinski@netronome.com>
Subject: [PATCH net-next] tools: bpftool: try to mount bpffs if required for pinning objects
Date: Tue, 24 Oct 2017 20:11:28 -0700	[thread overview]
Message-ID: <20171025031128.13990-1-jakub.kicinski@netronome.com> (raw)

From: Quentin Monnet <quentin.monnet@netronome.com>

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: Quentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/bpf/bpftool/common.c | 71 ++++++++++++++++++++++++++++++++++++++++------
 tools/bpf/bpftool/main.h   |  2 ++
 2 files changed, 65 insertions(+), 8 deletions(-)

diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index b2533f1cae3e..f0288269dae8 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -42,6 +42,7 @@
 #include <unistd.h>
 #include <linux/limits.h>
 #include <linux/magic.h>
+#include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/vfs.h>
 
@@ -59,6 +60,37 @@ static bool is_bpffs(char *path)
 	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)
 {
 	enum bpf_obj_type 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))
 {
+	char err_str[ERR_MAX_LEN];
 	unsigned int id;
 	char *endptr;
+	char *file;
+	char *dir;
 	int err;
 	int fd;
 
@@ -117,16 +152,36 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
 	}
 
 	err = bpf_obj_pin(fd, *argv);
-	close(fd);
-	if (err) {
-		p_err("can't pin the object (%s): %s", *argv,
-		      errno == EACCES && !is_bpffs(dirname(*argv)) ?
-		    "directory not in bpf file system (bpffs)" :
-		    strerror(errno));
-		return -1;
+	if (!err)
+		goto out_close;
+
+	file = malloc(strlen(*argv) + 1);
+	strcpy(file, *argv);
+	dir = dirname(file);
+
+	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)
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 2f94bed03a8d..d315d01be645 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -51,6 +51,8 @@
 #define NEXT_ARGP()	({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
 #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 HELP_SPEC_PROGRAM						\
-- 
2.14.1

             reply	other threads:[~2017-10-25  3:11 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-25  3:11 Jakub Kicinski [this message]
2017-10-26  1:44 ` [PATCH net-next] tools: bpftool: try to mount bpffs if required for pinning objects Alexei Starovoitov
2017-10-26  8:53 ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20171025031128.13990-1-jakub.kicinski@netronome.com \
    --to=jakub.kicinski@netronome.com \
    --cc=alexei.starovoitov@gmail.com \
    --cc=daniel@iogearbox.net \
    --cc=netdev@vger.kernel.org \
    --cc=oss-drivers@netronome.com \
    --cc=quentin.monnet@netronome.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox