diff mbox

[PATCHv2,perf/core,5/7] tools lib bpf: Add bpf_program__pin()

Message ID 20170123011128.26534-6-joe@ovn.org
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Joe Stringer Jan. 23, 2017, 1:11 a.m. UTC
Add a new API to pin a BPF program to the filesystem. The user can
specify the path full path within a BPF filesystem to pin the program.
Programs with multiple instances are pinned as 'foo', 'foo_1', 'foo_2',
and so on.

Signed-off-by: Joe Stringer <joe@ovn.org>
---
v2: Don't automount BPF filesystem
    Split program, map, object pinning into separate APIs and separate
    patches.
---
 tools/lib/bpf/libbpf.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h |  1 +
 2 files changed, 77 insertions(+)

Comments

Wangnan (F) Jan. 25, 2017, 1:04 a.m. UTC | #1
On 2017/1/23 9:11, Joe Stringer wrote:
> Add a new API to pin a BPF program to the filesystem. The user can
> specify the path full path within a BPF filesystem to pin the program.
> Programs with multiple instances are pinned as 'foo', 'foo_1', 'foo_2',
> and so on.
>
> Signed-off-by: Joe Stringer <joe@ovn.org>
> ---
> v2: Don't automount BPF filesystem
>      Split program, map, object pinning into separate APIs and separate
>      patches.
> ---
>   tools/lib/bpf/libbpf.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
>   tools/lib/bpf/libbpf.h |  1 +
>   2 files changed, 77 insertions(+)
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index e6cd62b1264b..eea5c74808f7 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -4,6 +4,7 @@
>    * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
>    * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
>    * Copyright (C) 2015 Huawei Inc.
> + * Copyright (C) 2017 Nicira, Inc.
>    *
>    * This program is free software; you can redistribute it and/or
>    * modify it under the terms of the GNU Lesser General Public
> @@ -22,6 +23,7 @@
>   #include <stdlib.h>
>   #include <stdio.h>
>   #include <stdarg.h>
> +#include <libgen.h>
>   #include <inttypes.h>
>   #include <string.h>
>   #include <unistd.h>
> @@ -31,7 +33,10 @@
>   #include <linux/err.h>
>   #include <linux/kernel.h>
>   #include <linux/bpf.h>
> +#include <linux/magic.h>
>   #include <linux/list.h>
> +#include <linux/limits.h>
> +#include <sys/vfs.h>
>   #include <libelf.h>
>   #include <gelf.h>
>   
> @@ -1237,6 +1242,77 @@ int bpf_object__load(struct bpf_object *obj)
>   	return err;
>   }
>   
> +static int check_path(const char *path)
> +{
> +	struct statfs st_fs;
> +	char *dname, *dir;
> +	int err = 0;
> +
> +	if (path == NULL)
> +		return -EINVAL;
> +
> +	dname = strdup(path);
> +	dir = dirname(dname);
> +	if (statfs(dir, &st_fs)) {
> +		pr_warning("failed to statfs %s: %s\n", dir, strerror(errno));
> +		err = -errno;
> +	}
> +	free(dname);
> +
> +	if (!err && st_fs.f_type != BPF_FS_MAGIC) {
> +		pr_warning("specified path %s is not on BPF FS\n", path);
> +		err = -EINVAL;
> +	}
> +
> +	return err;
> +}
> +
> +int bpf_program__pin(struct bpf_program *prog, const char *path)

In your next patch please let caller select one instance:

int bpf_program__pin(struct bpf_program *prog, int instance, const char 
*path)
(please choose a better name)

Then your can wrap it with another function to pin all instances, implement
naming schema (%s_%d) there.

Then implement naming schema in bpf_object__pin like:

%s/objectname_mapname
%s/objectname_progname_%d

and make a bpf_{map,program}__pin the raw pinning functions with no 
naming schema.

Thank you.
Wangnan (F) Jan. 25, 2017, 1:06 a.m. UTC | #2
On 2017/1/25 9:04, Wangnan (F) wrote:
>
>
> On 2017/1/23 9:11, Joe Stringer wrote:
>> Add a new API to pin a BPF program to the filesystem. The user can
>> specify the path full path within a BPF filesystem to pin the program.
>> Programs with multiple instances are pinned as 'foo', 'foo_1', 'foo_2',
>> and so on.
>>
>> Signed-off-by: Joe Stringer <joe@ovn.org>
>> ---
>> v2: Don't automount BPF filesystem
>>      Split program, map, object pinning into separate APIs and separate
>>      patches.
>> ---

[SNIP]

>> +int bpf_program__pin(struct bpf_program *prog, const char *path)
>
> In your next patch please let caller select one instance:
>
> int bpf_program__pin(struct bpf_program *prog, int instance, const 
> char *path)
> (please choose a better name)
>
> Then your can wrap it with another function to pin all instances, 
> implement
> naming schema (%s_%d) there.
>
> Then implement naming schema in bpf_object__pin like:
>
> %s/objectname_mapname
> %s/objectname_progname_%d
>

Is it possible to use directory tree instead?

%s/object/mapname
%s/object/prog/instance

Thank you.
Joe Stringer Jan. 25, 2017, 1:16 a.m. UTC | #3
On 24 January 2017 at 17:06, Wangnan (F) <wangnan0@huawei.com> wrote:
>
>
> On 2017/1/25 9:04, Wangnan (F) wrote:
>>
>>
>>
>> On 2017/1/23 9:11, Joe Stringer wrote:
>>>
>>> Add a new API to pin a BPF program to the filesystem. The user can
>>> specify the path full path within a BPF filesystem to pin the program.
>>> Programs with multiple instances are pinned as 'foo', 'foo_1', 'foo_2',
>>> and so on.
>>>
>>> Signed-off-by: Joe Stringer <joe@ovn.org>
>>> ---
>>> v2: Don't automount BPF filesystem
>>>      Split program, map, object pinning into separate APIs and separate
>>>      patches.
>>> ---
>
>
> [SNIP]
>
>>> +int bpf_program__pin(struct bpf_program *prog, const char *path)
>>
>>
>> In your next patch please let caller select one instance:
>>
>> int bpf_program__pin(struct bpf_program *prog, int instance, const char
>> *path)
>> (please choose a better name)
>>
>> Then your can wrap it with another function to pin all instances,
>> implement
>> naming schema (%s_%d) there.
>>
>> Then implement naming schema in bpf_object__pin like:
>>
>> %s/objectname_mapname
>> %s/objectname_progname_%d
>>
>
> Is it possible to use directory tree instead?
>
> %s/object/mapname
> %s/object/prog/instance

I don't think objects have names, so let's assume an object with two
program instances named foo, and one map named bar.

A call of bpf_object__pin(obj, "/sys/fs/bpf/myobj") would mount with
the following files and directories:
/sys/fs/bpf/myobj/foo/1
/sys/fs/bpf/myobj/foo/2
/sys/fs/bpf/myobj/bar

Alternatively, if you want to control exactly where you want the
progs/maps to be pinned, you can call eg
bpf_program__pin_instance(prog, "/sys/fs/bpf/wherever", 0) and that
instance will be mounted to /sys/fs/bpf/wherever, or alternatively
bpf_program__pin(prog, "/sys/fs/bpf/foo"), and you will end up with
/sys/fs/bpf/foo/{0,1}.

This looks pretty reasonable to me.
Wangnan (F) Jan. 25, 2017, 2:18 a.m. UTC | #4
On 2017/1/25 9:16, Joe Stringer wrote:
> On 24 January 2017 at 17:06, Wangnan (F) <wangnan0@huawei.com> wrote:
>>
>> On 2017/1/25 9:04, Wangnan (F) wrote:
>>>
>>>
>>> On 2017/1/23 9:11, Joe Stringer wrote:
>>>> Add a new API to pin a BPF program to the filesystem. The user can
>>>> specify the path full path within a BPF filesystem to pin the program.
>>>> Programs with multiple instances are pinned as 'foo', 'foo_1', 'foo_2',
>>>> and so on.
>>>>
>>>> Signed-off-by: Joe Stringer <joe@ovn.org>
>>>> ---
>>>> v2: Don't automount BPF filesystem
>>>>       Split program, map, object pinning into separate APIs and separate
>>>>       patches.
>>>> ---
>>
>> [SNIP]
>>
>>>> +int bpf_program__pin(struct bpf_program *prog, const char *path)
>>>
>>> In your next patch please let caller select one instance:
>>>
>>> int bpf_program__pin(struct bpf_program *prog, int instance, const char
>>> *path)
>>> (please choose a better name)
>>>
>>> Then your can wrap it with another function to pin all instances,
>>> implement
>>> naming schema (%s_%d) there.
>>>
>>> Then implement naming schema in bpf_object__pin like:
>>>
>>> %s/objectname_mapname
>>> %s/objectname_progname_%d
>>>
>> Is it possible to use directory tree instead?
>>
>> %s/object/mapname
>> %s/object/prog/instance
> I don't think objects have names, so let's assume an object with two
> program instances named foo, and one map named bar.
>
> A call of bpf_object__pin(obj, "/sys/fs/bpf/myobj") would mount with
> the following files and directories:
> /sys/fs/bpf/myobj/foo/1
> /sys/fs/bpf/myobj/foo/2
> /sys/fs/bpf/myobj/bar
>
> Alternatively, if you want to control exactly where you want the
> progs/maps to be pinned, you can call eg
> bpf_program__pin_instance(prog, "/sys/fs/bpf/wherever", 0) and that
> instance will be mounted to /sys/fs/bpf/wherever, or alternatively
> bpf_program__pin(prog, "/sys/fs/bpf/foo"), and you will end up with
> /sys/fs/bpf/foo/{0,1}.
>
> This looks pretty reasonable to me.

It looks good to me.

Thank you.
Arnaldo Carvalho de Melo Jan. 26, 2017, 7:32 p.m. UTC | #5
Em Wed, Jan 25, 2017 at 10:18:22AM +0800, Wangnan (F) escreveu:
> On 2017/1/25 9:16, Joe Stringer wrote:
> > On 24 January 2017 at 17:06, Wangnan (F) <wangnan0@huawei.com> wrote:
> > > On 2017/1/25 9:04, Wangnan (F) wrote:
> > > Is it possible to use directory tree instead?

> > > %s/object/mapname
> > > %s/object/prog/instance
> > I don't think objects have names, so let's assume an object with two
> > program instances named foo, and one map named bar.

> > A call of bpf_object__pin(obj, "/sys/fs/bpf/myobj") would mount with
> > the following files and directories:
> > /sys/fs/bpf/myobj/foo/1
> > /sys/fs/bpf/myobj/foo/2
> > /sys/fs/bpf/myobj/bar

> > Alternatively, if you want to control exactly where you want the
> > progs/maps to be pinned, you can call eg
> > bpf_program__pin_instance(prog, "/sys/fs/bpf/wherever", 0) and that
> > instance will be mounted to /sys/fs/bpf/wherever, or alternatively
> > bpf_program__pin(prog, "/sys/fs/bpf/foo"), and you will end up with
> > /sys/fs/bpf/foo/{0,1}.

> > This looks pretty reasonable to me.

> It looks good to me.

Ok, please continue from perf/core, Ingo merged the first patch of this
patchset today,

- Arnaldo
Joe Stringer Jan. 26, 2017, 7:43 p.m. UTC | #6
On 26 January 2017 at 11:32, Arnaldo Carvalho de Melo <acme@kernel.org> wrote:
> Em Wed, Jan 25, 2017 at 10:18:22AM +0800, Wangnan (F) escreveu:
>> On 2017/1/25 9:16, Joe Stringer wrote:
>> > On 24 January 2017 at 17:06, Wangnan (F) <wangnan0@huawei.com> wrote:
>> > > On 2017/1/25 9:04, Wangnan (F) wrote:
>> > > Is it possible to use directory tree instead?
>
>> > > %s/object/mapname
>> > > %s/object/prog/instance
>> > I don't think objects have names, so let's assume an object with two
>> > program instances named foo, and one map named bar.
>
>> > A call of bpf_object__pin(obj, "/sys/fs/bpf/myobj") would mount with
>> > the following files and directories:
>> > /sys/fs/bpf/myobj/foo/1
>> > /sys/fs/bpf/myobj/foo/2
>> > /sys/fs/bpf/myobj/bar
>
>> > Alternatively, if you want to control exactly where you want the
>> > progs/maps to be pinned, you can call eg
>> > bpf_program__pin_instance(prog, "/sys/fs/bpf/wherever", 0) and that
>> > instance will be mounted to /sys/fs/bpf/wherever, or alternatively
>> > bpf_program__pin(prog, "/sys/fs/bpf/foo"), and you will end up with
>> > /sys/fs/bpf/foo/{0,1}.
>
>> > This looks pretty reasonable to me.
>
>> It looks good to me.
>
> Ok, please continue from perf/core, Ingo merged the first patch of this
> patchset today,

Ok thanks, I'll continue from there.
diff mbox

Patch

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index e6cd62b1264b..eea5c74808f7 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -4,6 +4,7 @@ 
  * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org>
  * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
  * Copyright (C) 2015 Huawei Inc.
+ * Copyright (C) 2017 Nicira, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,6 +23,7 @@ 
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <libgen.h>
 #include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
@@ -31,7 +33,10 @@ 
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/bpf.h>
+#include <linux/magic.h>
 #include <linux/list.h>
+#include <linux/limits.h>
+#include <sys/vfs.h>
 #include <libelf.h>
 #include <gelf.h>
 
@@ -1237,6 +1242,77 @@  int bpf_object__load(struct bpf_object *obj)
 	return err;
 }
 
+static int check_path(const char *path)
+{
+	struct statfs st_fs;
+	char *dname, *dir;
+	int err = 0;
+
+	if (path == NULL)
+		return -EINVAL;
+
+	dname = strdup(path);
+	dir = dirname(dname);
+	if (statfs(dir, &st_fs)) {
+		pr_warning("failed to statfs %s: %s\n", dir, strerror(errno));
+		err = -errno;
+	}
+	free(dname);
+
+	if (!err && st_fs.f_type != BPF_FS_MAGIC) {
+		pr_warning("specified path %s is not on BPF FS\n", path);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+int bpf_program__pin(struct bpf_program *prog, const char *path)
+{
+	int i, err;
+
+	err = check_path(path);
+	if (err)
+		return err;
+
+	if (prog == NULL) {
+		pr_warning("invalid program pointer\n");
+		return -EINVAL;
+	}
+
+	if (prog->instances.nr <= 0) {
+		pr_warning("no instances of prog %s to pin\n",
+			   prog->section_name);
+		return -EINVAL;
+	}
+
+	if (bpf_obj_pin(prog->instances.fds[0], path)) {
+		pr_warning("failed to pin program: %s\n", strerror(errno));
+		return -errno;
+	}
+	pr_debug("pinned program '%s'\n", path);
+
+	for (i = 1; i < prog->instances.nr; i++) {
+		char buf[PATH_MAX];
+		int len;
+
+		len = snprintf(buf, PATH_MAX, "%s_%d", path, i);
+		if (len < 0)
+			return -EINVAL;
+		else if (len > PATH_MAX)
+			return -ENAMETOOLONG;
+
+		if (bpf_obj_pin(prog->instances.fds[i], buf)) {
+			pr_warning("failed to pin program: %s\n",
+				   strerror(errno));
+			return -errno;
+		}
+		pr_debug("pinned program '%s'\n", buf);
+	}
+
+	return 0;
+}
+
 void bpf_object__close(struct bpf_object *obj)
 {
 	size_t i;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 4014d1ba5e3d..7973087c377b 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -106,6 +106,7 @@  void *bpf_program__priv(struct bpf_program *prog);
 const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
 
 int bpf_program__fd(struct bpf_program *prog);
+int bpf_program__pin(struct bpf_program *prog, const char *path);
 
 struct bpf_insn;