Add a new API to pin a BPF object to the filesystem. The user can specify a subdirectory under the BPF filesystem to pin these programs.
For example, with the subdirectory 'foo', programs and maps are pinned: /sys/fs/bpf/foo/progs/PROG_NAME /sys/fs/bpf/foo/maps/MAP_NAME If the user has specified an alternative BPF filesystem mountpoint via /proc/mounts, that will be read and used instead. Signed-off-by: Joe Stringer <j...@ovn.org> --- tools/lib/bpf/libbpf.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.h | 1 + 2 files changed, 137 insertions(+) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 6b651c19870d..181dca0bdacb 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4,6 +4,7 @@ * Copyright (C) 2013-2015 Alexei Starovoitov <a...@kernel.org> * Copyright (C) 2015 Wang Nan <wangn...@huawei.com> * Copyright (C) 2015 Huawei Inc. + * Copyright (C) 2016 Nicira, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -31,7 +32,12 @@ #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/mount.h> +#include <sys/stat.h> +#include <sys/vfs.h> #include <libelf.h> #include <gelf.h> @@ -1231,6 +1237,136 @@ int bpf_object__load(struct bpf_object *obj) return err; } +#define stringize(x) #x + +static int mount_bpf(char *path) +{ + const char *mounts_fmt = "%*s %"stringize(PATH_MAX)"s %#"stringize(NAME_MAX)"s %*s\n"; + struct statfs st_fs; + char type[NAME_MAX]; + int err = 0; + FILE *fp; + + /* Populate 'path'. */ + fp = fopen("/proc/mounts", "r"); + if (fp) { + while (fscanf(fp, mounts_fmt, path, type) == 2) { + if (!strcmp(type, "bpf")) + break; + } + if (fclose(fp)) { + err = -errno; + pr_warning("failed to close /proc/mounts: %s\n", + strerror(errno)); + } + if (strcmp(type, "bpf")) { + err = -errno; + pr_debug("failed to find bpf mount\n"); + } + } else { + err = -errno; + pr_warning("cannot open /proc/mounts: %s\n", strerror(errno)); + } + if (err) { + pr_debug("using /sys/fs/bpf for BPF filesystem mountpoint\n"); + strcpy(path, "/sys/fs/bpf"); + } + + if (!statfs(path, &st_fs) && st_fs.f_type == BPF_FS_MAGIC) + return 0; + + if (mount("bpf", path, "bpf", 0, NULL)) { + pr_warning("failed to mount bpf: %s\n", strerror(errno)); + return -errno; + } + + return 0; +} + +static int make_dirs(const char *path, const char *subdir, char *buf, + size_t len) +{ + snprintf(buf, len, "%s/%s/", path, subdir); + if (mkdir(buf, 0700) && errno != EEXIST) { + pr_warning("failed to mkdir %s: %s\n", subdir, strerror(errno)); + return -errno; + } + + snprintf(buf, len, "%s/%s/maps/", path, subdir); + if (mkdir(buf, 0700) && errno != EEXIST) { + pr_warning("failed to mkdir map: %s\n", strerror(errno)); + return -errno; + } + + snprintf(buf, len, "%s/%s/progs/", path, subdir); + if (mkdir(buf, 0700) && errno != EEXIST) { + pr_warning("failed to mkdir prog: %s\n", strerror(errno)); + return -errno; + } + + return 0; +} + +int bpf_object__pin(struct bpf_object *obj, const char *subdir) +{ + const size_t len = 255; + char path[PATH_MAX]; + char buf[len]; + size_t i, j; + int err = 0; + + if (!obj) + return -ENOENT; + + if (!obj->loaded) { + pr_warning("object not yet loaded; load it first\n"); + return -ENOENT; + } + + err = mount_bpf(path); + if (err) + return err; + + err = make_dirs(path, subdir, buf, len); + if (err) + return err; + + for (i = 0; i < obj->nr_maps; i++) { + struct bpf_map *map = &obj->maps[i]; + + snprintf(buf, len, "%s/%s/maps/%s", path, subdir, + bpf_map__name(map)); + if (bpf_obj_pin(map->fd, buf)) { + err = -errno; + pr_warning("failed to pin map: %s\n", strerror(errno)); + goto out; + } + pr_debug("Loaded map '%s' at '%s'\n", bpf_map__name(map), buf); + } + + if (obj->programs && obj->nr_programs) { + for (i = 0; i < obj->nr_programs; i++) { + struct bpf_program *prog = &obj->programs[i]; + + for (j = 0; j < prog->instances.nr; j++) { + snprintf(buf, len, "%s/%s/progs/%s_%zu", path, + subdir, prog->section_name, j); + if (bpf_obj_pin(prog->instances.fds[j], buf)) { + err = -errno; + pr_warning("failed to pin prog: %s\n", + strerror(errno)); + goto out; + } + pr_debug("Loaded prog '%s' at '%s'\n", + prog->section_name, buf); + } + } + } + +out: + return err; +} + 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..920699a437be 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -65,6 +65,7 @@ struct bpf_object *bpf_object__open(const char *path); struct bpf_object *bpf_object__open_buffer(void *obj_buf, size_t obj_buf_sz, const char *name); +int bpf_object__pin(struct bpf_object *object, const char *subdir); void bpf_object__close(struct bpf_object *object); /* Load/unload object into/from kernel */ -- 2.11.0