bpf: libbpf: Provide basic API support to specify BPF obj name

This patch extends the libbpf to provide API support to
allow specifying BPF object name.

In tools/lib/bpf/libbpf, the C symbol of the function
and the map is used.  Regarding section name, all maps are
under the same section named "maps".  Hence, section name
is not a good choice for map's name.  To be consistent with
map, bpf_prog also follows and uses its function symbol as
the prog's name.

This patch adds logic to collect function's symbols in libbpf.
There is existing codes to collect the map's symbols and no change
is needed.

The bpf_load_program_name() and bpf_map_create_name() are
added to take the name argument.  For the other bpf_map_create_xxx()
variants, a name argument is directly added to them.

In samples/bpf, bpf_load.c in particular, the symbol is also
used as the map's name and the map symbols has already been
collected in the existing code.  For bpf_prog, bpf_load.c does
not collect the function symbol name.  We can consider to collect
them later if there is a need to continue supporting the bpf_load.c.

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Alexei Starovoitov <ast@fb.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Martin KaFai Lau 2017-09-27 14:37:54 -07:00 committed by David S. Miller
parent ad5b177bd7
commit 88cda1c9da
7 changed files with 157 additions and 47 deletions

View File

@ -221,6 +221,7 @@ static int load_maps(struct bpf_map_data *maps, int nr_maps,
int inner_map_fd = map_fd[maps[i].def.inner_map_idx]; int inner_map_fd = map_fd[maps[i].def.inner_map_idx];
map_fd[i] = bpf_create_map_in_map_node(maps[i].def.type, map_fd[i] = bpf_create_map_in_map_node(maps[i].def.type,
maps[i].name,
maps[i].def.key_size, maps[i].def.key_size,
inner_map_fd, inner_map_fd,
maps[i].def.max_entries, maps[i].def.max_entries,
@ -228,6 +229,7 @@ static int load_maps(struct bpf_map_data *maps, int nr_maps,
numa_node); numa_node);
} else { } else {
map_fd[i] = bpf_create_map_node(maps[i].def.type, map_fd[i] = bpf_create_map_node(maps[i].def.type,
maps[i].name,
maps[i].def.key_size, maps[i].def.key_size,
maps[i].def.value_size, maps[i].def.value_size,
maps[i].def.max_entries, maps[i].def.max_entries,

View File

@ -137,6 +137,7 @@ static void do_test_lru(enum test_type test, int cpu)
inner_lru_map_fds[cpu] = inner_lru_map_fds[cpu] =
bpf_create_map_node(BPF_MAP_TYPE_LRU_HASH, bpf_create_map_node(BPF_MAP_TYPE_LRU_HASH,
test_map_names[INNER_LRU_HASH_PREALLOC],
sizeof(uint32_t), sizeof(uint32_t),
sizeof(long), sizeof(long),
inner_lru_hash_size, 0, inner_lru_hash_size, 0,

View File

@ -175,6 +175,8 @@ enum bpf_attach_type {
/* Specify numa node during map creation */ /* Specify numa node during map creation */
#define BPF_F_NUMA_NODE (1U << 2) #define BPF_F_NUMA_NODE (1U << 2)
#define BPF_OBJ_NAME_LEN 16U
union bpf_attr { union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */ struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */ __u32 map_type; /* one of enum bpf_map_type */
@ -188,6 +190,7 @@ union bpf_attr {
__u32 numa_node; /* numa node (effective only if __u32 numa_node; /* numa node (effective only if
* BPF_F_NUMA_NODE is set). * BPF_F_NUMA_NODE is set).
*/ */
__u8 map_name[BPF_OBJ_NAME_LEN];
}; };
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
@ -210,6 +213,7 @@ union bpf_attr {
__aligned_u64 log_buf; /* user supplied buffer */ __aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */ __u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags; __u32 prog_flags;
__u8 prog_name[BPF_OBJ_NAME_LEN];
}; };
struct { /* anonymous struct used by BPF_OBJ_* commands */ struct { /* anonymous struct used by BPF_OBJ_* commands */
@ -812,6 +816,11 @@ struct bpf_prog_info {
__u32 xlated_prog_len; __u32 xlated_prog_len;
__aligned_u64 jited_prog_insns; __aligned_u64 jited_prog_insns;
__aligned_u64 xlated_prog_insns; __aligned_u64 xlated_prog_insns;
__u64 load_time; /* ns since boottime */
__u32 created_by_uid;
__u32 nr_map_ids;
__aligned_u64 map_ids;
__u8 name[BPF_OBJ_NAME_LEN];
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
struct bpf_map_info { struct bpf_map_info {
@ -821,6 +830,7 @@ struct bpf_map_info {
__u32 value_size; __u32 value_size;
__u32 max_entries; __u32 max_entries;
__u32 map_flags; __u32 map_flags;
__u8 name[BPF_OBJ_NAME_LEN];
} __attribute__((aligned(8))); } __attribute__((aligned(8)));
/* User bpf_sock_ops struct to access socket values and specify request ops /* User bpf_sock_ops struct to access socket values and specify request ops

View File

@ -46,6 +46,8 @@
# endif # endif
#endif #endif
#define min(x, y) ((x) < (y) ? (x) : (y))
static inline __u64 ptr_to_u64(const void *ptr) static inline __u64 ptr_to_u64(const void *ptr)
{ {
return (__u64) (unsigned long) ptr; return (__u64) (unsigned long) ptr;
@ -57,10 +59,11 @@ static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr,
return syscall(__NR_bpf, cmd, attr, size); return syscall(__NR_bpf, cmd, attr, size);
} }
int bpf_create_map_node(enum bpf_map_type map_type, int key_size, int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
int value_size, int max_entries, __u32 map_flags, int key_size, int value_size, int max_entries,
int node) __u32 map_flags, int node)
{ {
__u32 name_len = name ? strlen(name) : 0;
union bpf_attr attr; union bpf_attr attr;
memset(&attr, '\0', sizeof(attr)); memset(&attr, '\0', sizeof(attr));
@ -70,6 +73,8 @@ int bpf_create_map_node(enum bpf_map_type map_type, int key_size,
attr.value_size = value_size; attr.value_size = value_size;
attr.max_entries = max_entries; attr.max_entries = max_entries;
attr.map_flags = map_flags; attr.map_flags = map_flags;
memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1));
if (node >= 0) { if (node >= 0) {
attr.map_flags |= BPF_F_NUMA_NODE; attr.map_flags |= BPF_F_NUMA_NODE;
attr.numa_node = node; attr.numa_node = node;
@ -81,14 +86,23 @@ int bpf_create_map_node(enum bpf_map_type map_type, int key_size,
int bpf_create_map(enum bpf_map_type map_type, int key_size, int bpf_create_map(enum bpf_map_type map_type, int key_size,
int value_size, int max_entries, __u32 map_flags) int value_size, int max_entries, __u32 map_flags)
{ {
return bpf_create_map_node(map_type, key_size, value_size, return bpf_create_map_node(map_type, NULL, key_size, value_size,
max_entries, map_flags, -1); max_entries, map_flags, -1);
} }
int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, int bpf_create_map_name(enum bpf_map_type map_type, const char *name,
int inner_map_fd, int max_entries, int key_size, int value_size, int max_entries,
__u32 map_flags)
{
return bpf_create_map_node(map_type, name, key_size, value_size,
max_entries, map_flags, -1);
}
int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name,
int key_size, int inner_map_fd, int max_entries,
__u32 map_flags, int node) __u32 map_flags, int node)
{ {
__u32 name_len = name ? strlen(name) : 0;
union bpf_attr attr; union bpf_attr attr;
memset(&attr, '\0', sizeof(attr)); memset(&attr, '\0', sizeof(attr));
@ -99,6 +113,8 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size,
attr.inner_map_fd = inner_map_fd; attr.inner_map_fd = inner_map_fd;
attr.max_entries = max_entries; attr.max_entries = max_entries;
attr.map_flags = map_flags; attr.map_flags = map_flags;
memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1));
if (node >= 0) { if (node >= 0) {
attr.map_flags |= BPF_F_NUMA_NODE; attr.map_flags |= BPF_F_NUMA_NODE;
attr.numa_node = node; attr.numa_node = node;
@ -107,19 +123,24 @@ int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size,
return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
} }
int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
int inner_map_fd, int max_entries, __u32 map_flags) int key_size, int inner_map_fd, int max_entries,
__u32 map_flags)
{ {
return bpf_create_map_in_map_node(map_type, key_size, inner_map_fd, return bpf_create_map_in_map_node(map_type, name, key_size,
max_entries, map_flags, -1); inner_map_fd, max_entries, map_flags,
-1);
} }
int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, int bpf_load_program_name(enum bpf_prog_type type, const char *name,
size_t insns_cnt, const char *license, const struct bpf_insn *insns,
__u32 kern_version, char *log_buf, size_t log_buf_sz) size_t insns_cnt, const char *license,
__u32 kern_version, char *log_buf,
size_t log_buf_sz)
{ {
int fd; int fd;
union bpf_attr attr; union bpf_attr attr;
__u32 name_len = name ? strlen(name) : 0;
bzero(&attr, sizeof(attr)); bzero(&attr, sizeof(attr));
attr.prog_type = type; attr.prog_type = type;
@ -130,6 +151,7 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
attr.log_size = 0; attr.log_size = 0;
attr.log_level = 0; attr.log_level = 0;
attr.kern_version = kern_version; attr.kern_version = kern_version;
memcpy(attr.prog_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1));
fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
if (fd >= 0 || !log_buf || !log_buf_sz) if (fd >= 0 || !log_buf || !log_buf_sz)
@ -143,6 +165,15 @@ int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
} }
int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
size_t insns_cnt, const char *license,
__u32 kern_version, char *log_buf,
size_t log_buf_sz)
{
return bpf_load_program_name(type, NULL, insns, insns_cnt, license,
kern_version, log_buf, log_buf_sz);
}
int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns, int bpf_verify_program(enum bpf_prog_type type, const struct bpf_insn *insns,
size_t insns_cnt, int strict_alignment, size_t insns_cnt, int strict_alignment,
const char *license, __u32 kern_version, const char *license, __u32 kern_version,

View File

@ -24,19 +24,28 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <stddef.h> #include <stddef.h>
int bpf_create_map_node(enum bpf_map_type map_type, int key_size, int bpf_create_map_node(enum bpf_map_type map_type, const char *name,
int value_size, int max_entries, __u32 map_flags, int key_size, int value_size, int max_entries,
int node); __u32 map_flags, int node);
int bpf_create_map_name(enum bpf_map_type map_type, const char *name,
int key_size, int value_size, int max_entries,
__u32 map_flags);
int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
int max_entries, __u32 map_flags); int max_entries, __u32 map_flags);
int bpf_create_map_in_map_node(enum bpf_map_type map_type, int key_size, int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name,
int inner_map_fd, int max_entries, int key_size, int inner_map_fd, int max_entries,
__u32 map_flags, int node); __u32 map_flags, int node);
int bpf_create_map_in_map(enum bpf_map_type map_type, int key_size, int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
int inner_map_fd, int max_entries, __u32 map_flags); int key_size, int inner_map_fd, int max_entries,
__u32 map_flags);
/* Recommend log buffer size */ /* Recommend log buffer size */
#define BPF_LOG_BUF_SIZE 65536 #define BPF_LOG_BUF_SIZE 65536
int bpf_load_program_name(enum bpf_prog_type type, const char *name,
const struct bpf_insn *insns,
size_t insns_cnt, const char *license,
__u32 kern_version, char *log_buf,
size_t log_buf_sz);
int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
size_t insns_cnt, const char *license, size_t insns_cnt, const char *license,
__u32 kern_version, char *log_buf, __u32 kern_version, char *log_buf,

View File

@ -171,6 +171,7 @@ int libbpf_strerror(int err, char *buf, size_t size)
struct bpf_program { struct bpf_program {
/* Index in elf obj file, for relocation use. */ /* Index in elf obj file, for relocation use. */
int idx; int idx;
char *name;
char *section_name; char *section_name;
struct bpf_insn *insns; struct bpf_insn *insns;
size_t insns_cnt; size_t insns_cnt;
@ -283,6 +284,7 @@ static void bpf_program__exit(struct bpf_program *prog)
prog->clear_priv = NULL; prog->clear_priv = NULL;
bpf_program__unload(prog); bpf_program__unload(prog);
zfree(&prog->name);
zfree(&prog->section_name); zfree(&prog->section_name);
zfree(&prog->insns); zfree(&prog->insns);
zfree(&prog->reloc_desc); zfree(&prog->reloc_desc);
@ -293,26 +295,27 @@ static void bpf_program__exit(struct bpf_program *prog)
} }
static int static int
bpf_program__init(void *data, size_t size, char *name, int idx, bpf_program__init(void *data, size_t size, char *section_name, int idx,
struct bpf_program *prog) struct bpf_program *prog)
{ {
if (size < sizeof(struct bpf_insn)) { if (size < sizeof(struct bpf_insn)) {
pr_warning("corrupted section '%s'\n", name); pr_warning("corrupted section '%s'\n", section_name);
return -EINVAL; return -EINVAL;
} }
bzero(prog, sizeof(*prog)); bzero(prog, sizeof(*prog));
prog->section_name = strdup(name); prog->section_name = strdup(section_name);
if (!prog->section_name) { if (!prog->section_name) {
pr_warning("failed to alloc name for prog %s\n", pr_warning("failed to alloc name for prog under section %s\n",
name); section_name);
goto errout; goto errout;
} }
prog->insns = malloc(size); prog->insns = malloc(size);
if (!prog->insns) { if (!prog->insns) {
pr_warning("failed to alloc insns for %s\n", name); pr_warning("failed to alloc insns for prog under section %s\n",
section_name);
goto errout; goto errout;
} }
prog->insns_cnt = size / sizeof(struct bpf_insn); prog->insns_cnt = size / sizeof(struct bpf_insn);
@ -331,12 +334,12 @@ errout:
static int static int
bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
char *name, int idx) char *section_name, int idx)
{ {
struct bpf_program prog, *progs; struct bpf_program prog, *progs;
int nr_progs, err; int nr_progs, err;
err = bpf_program__init(data, size, name, idx, &prog); err = bpf_program__init(data, size, section_name, idx, &prog);
if (err) if (err)
return err; return err;
@ -350,8 +353,8 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
* is still valid, so don't need special treat for * is still valid, so don't need special treat for
* bpf_close_object(). * bpf_close_object().
*/ */
pr_warning("failed to alloc a new program '%s'\n", pr_warning("failed to alloc a new program under section '%s'\n",
name); section_name);
bpf_program__exit(&prog); bpf_program__exit(&prog);
return -ENOMEM; return -ENOMEM;
} }
@ -364,6 +367,54 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
return 0; return 0;
} }
static int
bpf_object__init_prog_names(struct bpf_object *obj)
{
Elf_Data *symbols = obj->efile.symbols;
struct bpf_program *prog;
size_t pi, si;
for (pi = 0; pi < obj->nr_programs; pi++) {
char *name = NULL;
prog = &obj->programs[pi];
for (si = 0; si < symbols->d_size / sizeof(GElf_Sym) && !name;
si++) {
GElf_Sym sym;
if (!gelf_getsym(symbols, si, &sym))
continue;
if (sym.st_shndx != prog->idx)
continue;
name = elf_strptr(obj->efile.elf,
obj->efile.strtabidx,
sym.st_name);
if (!name) {
pr_warning("failed to get sym name string for prog %s\n",
prog->section_name);
return -LIBBPF_ERRNO__LIBELF;
}
}
if (!name) {
pr_warning("failed to find sym for prog %s\n",
prog->section_name);
return -EINVAL;
}
prog->name = strdup(name);
if (!prog->name) {
pr_warning("failed to allocate memory for prog sym %s\n",
name);
return -ENOMEM;
}
}
return 0;
}
static struct bpf_object *bpf_object__new(const char *path, static struct bpf_object *bpf_object__new(const char *path,
void *obj_buf, void *obj_buf,
size_t obj_buf_sz) size_t obj_buf_sz)
@ -766,8 +817,12 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
pr_warning("Corrupted ELF file: index of strtab invalid\n"); pr_warning("Corrupted ELF file: index of strtab invalid\n");
return LIBBPF_ERRNO__FORMAT; return LIBBPF_ERRNO__FORMAT;
} }
if (obj->efile.maps_shndx >= 0) if (obj->efile.maps_shndx >= 0) {
err = bpf_object__init_maps(obj); err = bpf_object__init_maps(obj);
if (err)
goto out;
}
err = bpf_object__init_prog_names(obj);
out: out:
return err; return err;
} }
@ -870,11 +925,12 @@ bpf_object__create_maps(struct bpf_object *obj)
struct bpf_map_def *def = &obj->maps[i].def; struct bpf_map_def *def = &obj->maps[i].def;
int *pfd = &obj->maps[i].fd; int *pfd = &obj->maps[i].fd;
*pfd = bpf_create_map(def->type, *pfd = bpf_create_map_name(def->type,
def->key_size, obj->maps[i].name,
def->value_size, def->key_size,
def->max_entries, def->value_size,
0); def->max_entries,
0);
if (*pfd < 0) { if (*pfd < 0) {
size_t j; size_t j;
int err = *pfd; int err = *pfd;
@ -982,7 +1038,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
} }
static int static int
load_program(enum bpf_prog_type type, struct bpf_insn *insns, load_program(enum bpf_prog_type type, const char *name, struct bpf_insn *insns,
int insns_cnt, char *license, u32 kern_version, int *pfd) int insns_cnt, char *license, u32 kern_version, int *pfd)
{ {
int ret; int ret;
@ -995,8 +1051,8 @@ load_program(enum bpf_prog_type type, struct bpf_insn *insns,
if (!log_buf) if (!log_buf)
pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); pr_warning("Alloc log buffer for bpf loader error, continue without log\n");
ret = bpf_load_program(type, insns, insns_cnt, license, ret = bpf_load_program_name(type, name, insns, insns_cnt, license,
kern_version, log_buf, BPF_LOG_BUF_SIZE); kern_version, log_buf, BPF_LOG_BUF_SIZE);
if (ret >= 0) { if (ret >= 0) {
*pfd = ret; *pfd = ret;
@ -1021,9 +1077,9 @@ load_program(enum bpf_prog_type type, struct bpf_insn *insns,
if (type != BPF_PROG_TYPE_KPROBE) { if (type != BPF_PROG_TYPE_KPROBE) {
int fd; int fd;
fd = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, fd = bpf_load_program_name(BPF_PROG_TYPE_KPROBE, name,
insns_cnt, license, kern_version, insns, insns_cnt, license,
NULL, 0); kern_version, NULL, 0);
if (fd >= 0) { if (fd >= 0) {
close(fd); close(fd);
ret = -LIBBPF_ERRNO__PROGTYPE; ret = -LIBBPF_ERRNO__PROGTYPE;
@ -1067,8 +1123,8 @@ bpf_program__load(struct bpf_program *prog,
pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n", pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
prog->section_name, prog->instances.nr); prog->section_name, prog->instances.nr);
} }
err = load_program(prog->type, prog->insns, prog->insns_cnt, err = load_program(prog->type, prog->name, prog->insns,
license, kern_version, &fd); prog->insns_cnt, license, kern_version, &fd);
if (!err) if (!err)
prog->instances.fds[0] = fd; prog->instances.fds[0] = fd;
goto out; goto out;
@ -1096,7 +1152,8 @@ bpf_program__load(struct bpf_program *prog,
continue; continue;
} }
err = load_program(prog->type, result.new_insn_ptr, err = load_program(prog->type, prog->name,
result.new_insn_ptr,
result.new_insn_cnt, result.new_insn_cnt,
license, kern_version, &fd); license, kern_version, &fd);

View File

@ -6939,7 +6939,7 @@ static int create_map_in_map(void)
return inner_map_fd; return inner_map_fd;
} }
outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_ARRAY_OF_MAPS, NULL,
sizeof(int), inner_map_fd, 1, 0); sizeof(int), inner_map_fd, 1, 0);
if (outer_map_fd < 0) if (outer_map_fd < 0)
printf("Failed to create array of maps '%s'!\n", printf("Failed to create array of maps '%s'!\n",