mirror of
https://github.com/netdata/libbpf.git
synced 2026-03-30 05:09:06 +08:00
bpf: sync with latest bpf-next tree (#5)
sync with latest bpf-next tree. the include/linux/filter.h is created as libbpf.c tries to use various insn define macros. Signed-off-by: Yonghong Song <yhs@fb.com>
This commit is contained in:
637
src/libbpf.c
637
src/libbpf.c
@@ -24,9 +24,11 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/btf.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/ring_buffer.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
@@ -113,6 +115,11 @@ void libbpf_set_print(libbpf_print_fn_t warn,
|
||||
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
|
||||
#endif
|
||||
|
||||
struct bpf_capabilities {
|
||||
/* v4.14: kernel support for program & map names. */
|
||||
__u32 name:1;
|
||||
};
|
||||
|
||||
/*
|
||||
* bpf_prog should be a better name but it has been used in
|
||||
* linux/filter.h.
|
||||
@@ -123,6 +130,10 @@ struct bpf_program {
|
||||
char *name;
|
||||
int prog_ifindex;
|
||||
char *section_name;
|
||||
/* section_name with / replaced by _; makes recursive pinning
|
||||
* in bpf_object__pin_programs easier
|
||||
*/
|
||||
char *pin_name;
|
||||
struct bpf_insn *insns;
|
||||
size_t insns_cnt, main_prog_cnt;
|
||||
enum bpf_prog_type type;
|
||||
@@ -151,6 +162,12 @@ struct bpf_program {
|
||||
bpf_program_clear_priv_t clear_priv;
|
||||
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
int btf_fd;
|
||||
void *func_info;
|
||||
__u32 func_info_rec_size;
|
||||
__u32 func_info_len;
|
||||
|
||||
struct bpf_capabilities *caps;
|
||||
};
|
||||
|
||||
struct bpf_map {
|
||||
@@ -158,6 +175,7 @@ struct bpf_map {
|
||||
char *name;
|
||||
size_t offset;
|
||||
int map_ifindex;
|
||||
int inner_map_fd;
|
||||
struct bpf_map_def def;
|
||||
__u32 btf_key_type_id;
|
||||
__u32 btf_value_type_id;
|
||||
@@ -207,10 +225,13 @@ struct bpf_object {
|
||||
struct list_head list;
|
||||
|
||||
struct btf *btf;
|
||||
struct btf_ext *btf_ext;
|
||||
|
||||
void *priv;
|
||||
bpf_object_clear_priv_t clear_priv;
|
||||
|
||||
struct bpf_capabilities caps;
|
||||
|
||||
char path[];
|
||||
};
|
||||
#define obj_elf_valid(o) ((o)->efile.elf)
|
||||
@@ -236,6 +257,9 @@ void bpf_program__unload(struct bpf_program *prog)
|
||||
|
||||
prog->instances.nr = -1;
|
||||
zfree(&prog->instances.fds);
|
||||
|
||||
zclose(prog->btf_fd);
|
||||
zfree(&prog->func_info);
|
||||
}
|
||||
|
||||
static void bpf_program__exit(struct bpf_program *prog)
|
||||
@@ -252,6 +276,7 @@ static void bpf_program__exit(struct bpf_program *prog)
|
||||
bpf_program__unload(prog);
|
||||
zfree(&prog->name);
|
||||
zfree(&prog->section_name);
|
||||
zfree(&prog->pin_name);
|
||||
zfree(&prog->insns);
|
||||
zfree(&prog->reloc_desc);
|
||||
|
||||
@@ -260,6 +285,17 @@ static void bpf_program__exit(struct bpf_program *prog)
|
||||
prog->idx = -1;
|
||||
}
|
||||
|
||||
static char *__bpf_program__pin_name(struct bpf_program *prog)
|
||||
{
|
||||
char *name, *p;
|
||||
|
||||
name = p = strdup(prog->section_name);
|
||||
while ((p = strchr(p, '/')))
|
||||
*p = '_';
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
||||
struct bpf_program *prog)
|
||||
@@ -278,6 +314,13 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
||||
goto errout;
|
||||
}
|
||||
|
||||
prog->pin_name = __bpf_program__pin_name(prog);
|
||||
if (!prog->pin_name) {
|
||||
pr_warning("failed to alloc pin name for prog under section(%d) %s\n",
|
||||
idx, section_name);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
prog->insns = malloc(size);
|
||||
if (!prog->insns) {
|
||||
pr_warning("failed to alloc insns for prog under section %s\n",
|
||||
@@ -290,7 +333,8 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
|
||||
prog->idx = idx;
|
||||
prog->instances.fds = NULL;
|
||||
prog->instances.nr = -1;
|
||||
prog->type = BPF_PROG_TYPE_KPROBE;
|
||||
prog->type = BPF_PROG_TYPE_UNSPEC;
|
||||
prog->btf_fd = -1;
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
@@ -309,6 +353,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
prog.caps = &obj->caps;
|
||||
progs = obj->programs;
|
||||
nr_progs = obj->nr_programs;
|
||||
|
||||
@@ -561,6 +606,14 @@ static int compare_bpf_map(const void *_a, const void *_b)
|
||||
return a->offset - b->offset;
|
||||
}
|
||||
|
||||
static bool bpf_map_type__is_map_in_map(enum bpf_map_type type)
|
||||
{
|
||||
if (type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
|
||||
type == BPF_MAP_TYPE_HASH_OF_MAPS)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__init_maps(struct bpf_object *obj, int flags)
|
||||
{
|
||||
@@ -624,13 +677,15 @@ bpf_object__init_maps(struct bpf_object *obj, int flags)
|
||||
}
|
||||
obj->nr_maps = nr_maps;
|
||||
|
||||
/*
|
||||
* fill all fd with -1 so won't close incorrect
|
||||
* fd (fd=0 is stdin) when failure (zclose won't close
|
||||
* negative fd)).
|
||||
*/
|
||||
for (i = 0; i < nr_maps; i++)
|
||||
for (i = 0; i < nr_maps; i++) {
|
||||
/*
|
||||
* fill all fd with -1 so won't close incorrect
|
||||
* fd (fd=0 is stdin) when failure (zclose won't close
|
||||
* negative fd)).
|
||||
*/
|
||||
obj->maps[i].fd = -1;
|
||||
obj->maps[i].inner_map_fd = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill obj->maps using data in "maps" section.
|
||||
@@ -783,6 +838,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
|
||||
BTF_ELF_SEC, PTR_ERR(obj->btf));
|
||||
obj->btf = NULL;
|
||||
}
|
||||
} else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
|
||||
obj->btf_ext = btf_ext__new(data->d_buf, data->d_size,
|
||||
__pr_debug);
|
||||
if (IS_ERR(obj->btf_ext)) {
|
||||
pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
|
||||
BTF_EXT_ELF_SEC,
|
||||
PTR_ERR(obj->btf_ext));
|
||||
obj->btf_ext = NULL;
|
||||
}
|
||||
} else if (sh.sh_type == SHT_SYMTAB) {
|
||||
if (obj->efile.symbols) {
|
||||
pr_warning("bpf: multiple SYMTAB in %s\n",
|
||||
@@ -1093,6 +1157,52 @@ err_free_new_name:
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__probe_name(struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_load_program_attr attr;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
struct bpf_insn insns[] = {
|
||||
BPF_MOV64_IMM(BPF_REG_0, 0),
|
||||
BPF_EXIT_INSN(),
|
||||
};
|
||||
int ret;
|
||||
|
||||
/* make sure basic loading works */
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
|
||||
attr.insns = insns;
|
||||
attr.insns_cnt = ARRAY_SIZE(insns);
|
||||
attr.license = "GPL";
|
||||
|
||||
ret = bpf_load_program_xattr(&attr, NULL, 0);
|
||||
if (ret < 0) {
|
||||
cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
|
||||
pr_warning("Error in %s():%s(%d). Couldn't load basic 'r0 = 0' BPF program.\n",
|
||||
__func__, cp, errno);
|
||||
return -errno;
|
||||
}
|
||||
close(ret);
|
||||
|
||||
/* now try the same program, but with the name */
|
||||
|
||||
attr.name = "test";
|
||||
ret = bpf_load_program_xattr(&attr, NULL, 0);
|
||||
if (ret >= 0) {
|
||||
obj->caps.name = 1;
|
||||
close(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__probe_caps(struct bpf_object *obj)
|
||||
{
|
||||
return bpf_object__probe_name(obj);
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__create_maps(struct bpf_object *obj)
|
||||
{
|
||||
@@ -1112,7 +1222,8 @@ bpf_object__create_maps(struct bpf_object *obj)
|
||||
continue;
|
||||
}
|
||||
|
||||
create_attr.name = map->name;
|
||||
if (obj->caps.name)
|
||||
create_attr.name = map->name;
|
||||
create_attr.map_ifindex = map->map_ifindex;
|
||||
create_attr.map_type = def->type;
|
||||
create_attr.map_flags = def->map_flags;
|
||||
@@ -1122,6 +1233,9 @@ bpf_object__create_maps(struct bpf_object *obj)
|
||||
create_attr.btf_fd = 0;
|
||||
create_attr.btf_key_type_id = 0;
|
||||
create_attr.btf_value_type_id = 0;
|
||||
if (bpf_map_type__is_map_in_map(def->type) &&
|
||||
map->inner_map_fd >= 0)
|
||||
create_attr.inner_map_fd = map->inner_map_fd;
|
||||
|
||||
if (obj->btf && !bpf_map_find_btf_info(map, obj->btf)) {
|
||||
create_attr.btf_fd = btf__fd(obj->btf);
|
||||
@@ -1166,6 +1280,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
||||
struct bpf_insn *insn, *new_insn;
|
||||
struct bpf_program *text;
|
||||
size_t new_cnt;
|
||||
int err;
|
||||
|
||||
if (relo->type != RELO_CALL)
|
||||
return -LIBBPF_ERRNO__RELOC;
|
||||
@@ -1188,6 +1303,20 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
|
||||
pr_warning("oom in prog realloc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (obj->btf && obj->btf_ext) {
|
||||
err = btf_ext__reloc(obj->btf, obj->btf_ext,
|
||||
text->section_name,
|
||||
prog->insns_cnt,
|
||||
&prog->func_info,
|
||||
&prog->func_info_len);
|
||||
if (err) {
|
||||
pr_warning("error in btf_ext__reloc for sec %s\n",
|
||||
text->section_name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(new_insn + prog->insns_cnt, text->insns,
|
||||
text->insns_cnt * sizeof(*insn));
|
||||
prog->insns = new_insn;
|
||||
@@ -1207,7 +1336,24 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
if (!prog || !prog->reloc_desc)
|
||||
if (!prog)
|
||||
return 0;
|
||||
|
||||
if (obj->btf && obj->btf_ext) {
|
||||
err = btf_ext__reloc_init(obj->btf, obj->btf_ext,
|
||||
prog->section_name,
|
||||
&prog->func_info,
|
||||
&prog->func_info_rec_size,
|
||||
&prog->func_info_len);
|
||||
if (err) {
|
||||
pr_warning("err in btf_ext__reloc_init for sec %s\n",
|
||||
prog->section_name);
|
||||
return err;
|
||||
}
|
||||
prog->btf_fd = btf__fd(obj->btf);
|
||||
}
|
||||
|
||||
if (!prog->reloc_desc)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < prog->nr_reloc; i++) {
|
||||
@@ -1295,9 +1441,9 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
|
||||
}
|
||||
|
||||
static int
|
||||
load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,
|
||||
const char *name, struct bpf_insn *insns, int insns_cnt,
|
||||
char *license, __u32 kern_version, int *pfd, int prog_ifindex)
|
||||
load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
|
||||
char *license, __u32 kern_version, int *pfd,
|
||||
__u32 func_info_cnt)
|
||||
{
|
||||
struct bpf_load_program_attr load_attr;
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
@@ -1305,14 +1451,19 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,
|
||||
int ret;
|
||||
|
||||
memset(&load_attr, 0, sizeof(struct bpf_load_program_attr));
|
||||
load_attr.prog_type = type;
|
||||
load_attr.expected_attach_type = expected_attach_type;
|
||||
load_attr.name = name;
|
||||
load_attr.prog_type = prog->type;
|
||||
load_attr.expected_attach_type = prog->expected_attach_type;
|
||||
if (prog->caps->name)
|
||||
load_attr.name = prog->name;
|
||||
load_attr.insns = insns;
|
||||
load_attr.insns_cnt = insns_cnt;
|
||||
load_attr.license = license;
|
||||
load_attr.kern_version = kern_version;
|
||||
load_attr.prog_ifindex = prog_ifindex;
|
||||
load_attr.prog_ifindex = prog->prog_ifindex;
|
||||
load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
|
||||
load_attr.func_info = prog->func_info;
|
||||
load_attr.func_info_rec_size = prog->func_info_rec_size;
|
||||
load_attr.func_info_cnt = func_info_cnt;
|
||||
|
||||
if (!load_attr.insns || !load_attr.insns_cnt)
|
||||
return -EINVAL;
|
||||
@@ -1370,8 +1521,14 @@ int
|
||||
bpf_program__load(struct bpf_program *prog,
|
||||
char *license, __u32 kern_version)
|
||||
{
|
||||
__u32 func_info_cnt;
|
||||
int err = 0, fd, i;
|
||||
|
||||
if (prog->func_info_len == 0)
|
||||
func_info_cnt = 0;
|
||||
else
|
||||
func_info_cnt = prog->func_info_len / prog->func_info_rec_size;
|
||||
|
||||
if (prog->instances.nr < 0 || !prog->instances.fds) {
|
||||
if (prog->preprocessor) {
|
||||
pr_warning("Internal error: can't load program '%s'\n",
|
||||
@@ -1393,10 +1550,9 @@ bpf_program__load(struct bpf_program *prog,
|
||||
pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
|
||||
prog->section_name, prog->instances.nr);
|
||||
}
|
||||
err = load_program(prog->type, prog->expected_attach_type,
|
||||
prog->name, prog->insns, prog->insns_cnt,
|
||||
err = load_program(prog, prog->insns, prog->insns_cnt,
|
||||
license, kern_version, &fd,
|
||||
prog->prog_ifindex);
|
||||
func_info_cnt);
|
||||
if (!err)
|
||||
prog->instances.fds[0] = fd;
|
||||
goto out;
|
||||
@@ -1424,11 +1580,10 @@ bpf_program__load(struct bpf_program *prog,
|
||||
continue;
|
||||
}
|
||||
|
||||
err = load_program(prog->type, prog->expected_attach_type,
|
||||
prog->name, result.new_insn_ptr,
|
||||
err = load_program(prog, result.new_insn_ptr,
|
||||
result.new_insn_cnt,
|
||||
license, kern_version, &fd,
|
||||
prog->prog_ifindex);
|
||||
func_info_cnt);
|
||||
|
||||
if (err) {
|
||||
pr_warning("Loading the %dth instance of program '%s' failed\n",
|
||||
@@ -1494,12 +1649,12 @@ static bool bpf_prog_type__needs_kver(enum bpf_prog_type type)
|
||||
case BPF_PROG_TYPE_LIRC_MODE2:
|
||||
case BPF_PROG_TYPE_SK_REUSEPORT:
|
||||
case BPF_PROG_TYPE_FLOW_DISSECTOR:
|
||||
return false;
|
||||
case BPF_PROG_TYPE_UNSPEC:
|
||||
case BPF_PROG_TYPE_KPROBE:
|
||||
case BPF_PROG_TYPE_TRACEPOINT:
|
||||
case BPF_PROG_TYPE_PERF_EVENT:
|
||||
case BPF_PROG_TYPE_RAW_TRACEPOINT:
|
||||
case BPF_PROG_TYPE_PERF_EVENT:
|
||||
return false;
|
||||
case BPF_PROG_TYPE_KPROBE:
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@@ -1626,6 +1781,7 @@ int bpf_object__load(struct bpf_object *obj)
|
||||
|
||||
obj->loaded = true;
|
||||
|
||||
CHECK_ERR(bpf_object__probe_caps(obj), err, out);
|
||||
CHECK_ERR(bpf_object__create_maps(obj), err, out);
|
||||
CHECK_ERR(bpf_object__relocate(obj), err, out);
|
||||
CHECK_ERR(bpf_object__load_progs(obj), err, out);
|
||||
@@ -1698,6 +1854,34 @@ int bpf_program__pin_instance(struct bpf_program *prog, const char *path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_program__unpin_instance(struct bpf_program *prog, const char *path,
|
||||
int instance)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (prog == NULL) {
|
||||
pr_warning("invalid program pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (instance < 0 || instance >= prog->instances.nr) {
|
||||
pr_warning("invalid prog instance %d of prog %s (max %d)\n",
|
||||
instance, prog->section_name, prog->instances.nr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = unlink(path);
|
||||
if (err != 0)
|
||||
return -errno;
|
||||
pr_debug("unpinned program '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int make_dir(const char *path)
|
||||
{
|
||||
char *cp, errmsg[STRERR_BUFSIZE];
|
||||
@@ -1732,10 +1916,78 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (prog->instances.nr == 1) {
|
||||
/* don't create subdirs when pinning single instance */
|
||||
return bpf_program__pin_instance(prog, path, 0);
|
||||
}
|
||||
|
||||
err = make_dir(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < prog->instances.nr; i++) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%d", path, i);
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin;
|
||||
}
|
||||
|
||||
err = bpf_program__pin_instance(prog, buf, i);
|
||||
if (err)
|
||||
goto err_unpin;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin:
|
||||
for (i = i - 1; i >= 0; i--) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%d", path, i);
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_program__unpin_instance(prog, buf, i);
|
||||
}
|
||||
|
||||
rmdir(path);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_program__unpin(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 (prog->instances.nr == 1) {
|
||||
/* don't create subdirs when pinning single instance */
|
||||
return bpf_program__unpin_instance(prog, path, 0);
|
||||
}
|
||||
|
||||
for (i = 0; i < prog->instances.nr; i++) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
@@ -1746,11 +1998,15 @@ int bpf_program__pin(struct bpf_program *prog, const char *path)
|
||||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_program__pin_instance(prog, buf, i);
|
||||
err = bpf_program__unpin_instance(prog, buf, i);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rmdir(path);
|
||||
if (err)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1775,12 +2031,33 @@ int bpf_map__pin(struct bpf_map *map, const char *path)
|
||||
}
|
||||
|
||||
pr_debug("pinned map '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
int bpf_map__unpin(struct bpf_map *map, const char *path)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = check_path(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (map == NULL) {
|
||||
pr_warning("invalid map pointer\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = unlink(path);
|
||||
if (err != 0)
|
||||
return -errno;
|
||||
pr_debug("unpinned map '%s'\n", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin_maps(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
@@ -1796,6 +2073,53 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bpf_map__for_each(map, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
bpf_map__name(map));
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin_maps;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin_maps;
|
||||
}
|
||||
|
||||
err = bpf_map__pin(map, buf);
|
||||
if (err)
|
||||
goto err_unpin_maps;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin_maps:
|
||||
while ((map = bpf_map__prev(map, obj))) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
bpf_map__name(map));
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_map__unpin(map, buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_object__unpin_maps(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_map *map;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
bpf_map__for_each(map, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
@@ -1807,23 +2131,90 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_map__pin(map, buf);
|
||||
err = bpf_map__unpin(map, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin_programs(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
if (!obj->loaded) {
|
||||
pr_warning("object not yet loaded; load it first\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
err = make_dir(path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->section_name);
|
||||
prog->pin_name);
|
||||
if (len < 0) {
|
||||
err = -EINVAL;
|
||||
goto err_unpin_programs;
|
||||
} else if (len >= PATH_MAX) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto err_unpin_programs;
|
||||
}
|
||||
|
||||
err = bpf_program__pin(prog, buf);
|
||||
if (err)
|
||||
goto err_unpin_programs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unpin_programs:
|
||||
while ((prog = bpf_program__prev(prog, obj))) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->pin_name);
|
||||
if (len < 0)
|
||||
continue;
|
||||
else if (len >= PATH_MAX)
|
||||
continue;
|
||||
|
||||
bpf_program__unpin(prog, buf);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bpf_object__unpin_programs(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
struct bpf_program *prog;
|
||||
int err;
|
||||
|
||||
if (!obj)
|
||||
return -ENOENT;
|
||||
|
||||
bpf_object__for_each_program(prog, obj) {
|
||||
char buf[PATH_MAX];
|
||||
int len;
|
||||
|
||||
len = snprintf(buf, PATH_MAX, "%s/%s", path,
|
||||
prog->pin_name);
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
else if (len >= PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = bpf_program__pin(prog, buf);
|
||||
err = bpf_program__unpin(prog, buf);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -1831,6 +2222,23 @@ int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpf_object__pin(struct bpf_object *obj, const char *path)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bpf_object__pin_maps(obj, path);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = bpf_object__pin_programs(obj, path);
|
||||
if (err) {
|
||||
bpf_object__unpin_maps(obj, path);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bpf_object__close(struct bpf_object *obj)
|
||||
{
|
||||
size_t i;
|
||||
@@ -1844,6 +2252,7 @@ void bpf_object__close(struct bpf_object *obj)
|
||||
bpf_object__elf_finish(obj);
|
||||
bpf_object__unload(obj);
|
||||
btf__free(obj->btf);
|
||||
btf_ext__free(obj->btf_ext);
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++) {
|
||||
zfree(&obj->maps[i].name);
|
||||
@@ -1917,23 +2326,26 @@ void *bpf_object__priv(struct bpf_object *obj)
|
||||
}
|
||||
|
||||
static struct bpf_program *
|
||||
__bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
|
||||
__bpf_program__iter(struct bpf_program *p, struct bpf_object *obj, bool forward)
|
||||
{
|
||||
size_t idx;
|
||||
size_t nr_programs = obj->nr_programs;
|
||||
ssize_t idx;
|
||||
|
||||
if (!obj->programs)
|
||||
if (!nr_programs)
|
||||
return NULL;
|
||||
/* First handler */
|
||||
if (prev == NULL)
|
||||
return &obj->programs[0];
|
||||
|
||||
if (prev->obj != obj) {
|
||||
if (!p)
|
||||
/* Iter from the beginning */
|
||||
return forward ? &obj->programs[0] :
|
||||
&obj->programs[nr_programs - 1];
|
||||
|
||||
if (p->obj != obj) {
|
||||
pr_warning("error: program handler doesn't match object\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = (prev - obj->programs) + 1;
|
||||
if (idx >= obj->nr_programs)
|
||||
idx = (p - obj->programs) + (forward ? 1 : -1);
|
||||
if (idx >= obj->nr_programs || idx < 0)
|
||||
return NULL;
|
||||
return &obj->programs[idx];
|
||||
}
|
||||
@@ -1944,7 +2356,19 @@ bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
|
||||
struct bpf_program *prog = prev;
|
||||
|
||||
do {
|
||||
prog = __bpf_program__next(prog, obj);
|
||||
prog = __bpf_program__iter(prog, obj, true);
|
||||
} while (prog && bpf_program__is_function_storage(prog, obj));
|
||||
|
||||
return prog;
|
||||
}
|
||||
|
||||
struct bpf_program *
|
||||
bpf_program__prev(struct bpf_program *next, struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_program *prog = next;
|
||||
|
||||
do {
|
||||
prog = __bpf_program__iter(prog, obj, false);
|
||||
} while (prog && bpf_program__is_function_storage(prog, obj));
|
||||
|
||||
return prog;
|
||||
@@ -2083,19 +2507,19 @@ void bpf_program__set_expected_attach_type(struct bpf_program *prog,
|
||||
prog->expected_attach_type = type;
|
||||
}
|
||||
|
||||
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, atype) \
|
||||
{ string, sizeof(string) - 1, ptype, eatype, atype }
|
||||
#define BPF_PROG_SEC_IMPL(string, ptype, eatype, is_attachable, atype) \
|
||||
{ string, sizeof(string) - 1, ptype, eatype, is_attachable, atype }
|
||||
|
||||
/* Programs that can NOT be attached. */
|
||||
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, -EINVAL)
|
||||
#define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_IMPL(string, ptype, 0, 0, 0)
|
||||
|
||||
/* Programs that can be attached. */
|
||||
#define BPF_APROG_SEC(string, ptype, atype) \
|
||||
BPF_PROG_SEC_IMPL(string, ptype, 0, atype)
|
||||
BPF_PROG_SEC_IMPL(string, ptype, 0, 1, atype)
|
||||
|
||||
/* Programs that must specify expected attach type at load time. */
|
||||
#define BPF_EAPROG_SEC(string, ptype, eatype) \
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, eatype)
|
||||
BPF_PROG_SEC_IMPL(string, ptype, eatype, 1, eatype)
|
||||
|
||||
/* Programs that can be attached but attach type can't be identified by section
|
||||
* name. Kept for backward compatibility.
|
||||
@@ -2107,6 +2531,7 @@ static const struct {
|
||||
size_t len;
|
||||
enum bpf_prog_type prog_type;
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
int is_attachable;
|
||||
enum bpf_attach_type attach_type;
|
||||
} section_names[] = {
|
||||
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
|
||||
@@ -2197,7 +2622,7 @@ int libbpf_attach_type_by_name(const char *name,
|
||||
for (i = 0; i < ARRAY_SIZE(section_names); i++) {
|
||||
if (strncmp(name, section_names[i].sec, section_names[i].len))
|
||||
continue;
|
||||
if (section_names[i].attach_type == -EINVAL)
|
||||
if (!section_names[i].is_attachable)
|
||||
return -EINVAL;
|
||||
*attach_type = section_names[i].attach_type;
|
||||
return 0;
|
||||
@@ -2270,10 +2695,24 @@ void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
|
||||
map->map_ifindex = ifindex;
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd)
|
||||
{
|
||||
size_t idx;
|
||||
if (!bpf_map_type__is_map_in_map(map->def.type)) {
|
||||
pr_warning("error: unsupported map type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (map->inner_map_fd != -1) {
|
||||
pr_warning("error: inner_map_fd already specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
map->inner_map_fd = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bpf_map *
|
||||
__bpf_map__iter(struct bpf_map *m, struct bpf_object *obj, int i)
|
||||
{
|
||||
ssize_t idx;
|
||||
struct bpf_map *s, *e;
|
||||
|
||||
if (!obj || !obj->maps)
|
||||
@@ -2282,21 +2721,39 @@ bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
s = obj->maps;
|
||||
e = obj->maps + obj->nr_maps;
|
||||
|
||||
if (prev == NULL)
|
||||
return s;
|
||||
|
||||
if ((prev < s) || (prev >= e)) {
|
||||
if ((m < s) || (m >= e)) {
|
||||
pr_warning("error in %s: map handler doesn't belong to object\n",
|
||||
__func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = (prev - obj->maps) + 1;
|
||||
if (idx >= obj->nr_maps)
|
||||
idx = (m - obj->maps) + i;
|
||||
if (idx >= obj->nr_maps || idx < 0)
|
||||
return NULL;
|
||||
return &obj->maps[idx];
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
|
||||
{
|
||||
if (prev == NULL)
|
||||
return obj->maps;
|
||||
|
||||
return __bpf_map__iter(prev, obj, 1);
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_map__prev(struct bpf_map *next, struct bpf_object *obj)
|
||||
{
|
||||
if (next == NULL) {
|
||||
if (!obj->nr_maps)
|
||||
return NULL;
|
||||
return obj->maps + obj->nr_maps - 1;
|
||||
}
|
||||
|
||||
return __bpf_map__iter(next, obj, -1);
|
||||
}
|
||||
|
||||
struct bpf_map *
|
||||
bpf_object__find_map_by_name(struct bpf_object *obj, const char *name)
|
||||
{
|
||||
@@ -2414,61 +2871,49 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
|
||||
}
|
||||
|
||||
enum bpf_perf_event_ret
|
||||
bpf_perf_event_read_simple(void *mem, unsigned long size,
|
||||
unsigned long page_size, void **buf, size_t *buf_len,
|
||||
bpf_perf_event_print_t fn, void *priv)
|
||||
bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
|
||||
void **copy_mem, size_t *copy_size,
|
||||
bpf_perf_event_print_t fn, void *private_data)
|
||||
{
|
||||
volatile struct perf_event_mmap_page *header = mem;
|
||||
struct perf_event_mmap_page *header = mmap_mem;
|
||||
__u64 data_head = ring_buffer_read_head(header);
|
||||
__u64 data_tail = header->data_tail;
|
||||
__u64 data_head = header->data_head;
|
||||
int ret = LIBBPF_PERF_EVENT_ERROR;
|
||||
void *base, *begin, *end;
|
||||
void *base = ((__u8 *)header) + page_size;
|
||||
int ret = LIBBPF_PERF_EVENT_CONT;
|
||||
struct perf_event_header *ehdr;
|
||||
size_t ehdr_size;
|
||||
|
||||
asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */
|
||||
if (data_head == data_tail)
|
||||
return LIBBPF_PERF_EVENT_CONT;
|
||||
while (data_head != data_tail) {
|
||||
ehdr = base + (data_tail & (mmap_size - 1));
|
||||
ehdr_size = ehdr->size;
|
||||
|
||||
base = ((char *)header) + page_size;
|
||||
if (((void *)ehdr) + ehdr_size > base + mmap_size) {
|
||||
void *copy_start = ehdr;
|
||||
size_t len_first = base + mmap_size - copy_start;
|
||||
size_t len_secnd = ehdr_size - len_first;
|
||||
|
||||
begin = base + data_tail % size;
|
||||
end = base + data_head % size;
|
||||
|
||||
while (begin != end) {
|
||||
struct perf_event_header *ehdr;
|
||||
|
||||
ehdr = begin;
|
||||
if (begin + ehdr->size > base + size) {
|
||||
long len = base + size - begin;
|
||||
|
||||
if (*buf_len < ehdr->size) {
|
||||
free(*buf);
|
||||
*buf = malloc(ehdr->size);
|
||||
if (!*buf) {
|
||||
if (*copy_size < ehdr_size) {
|
||||
free(*copy_mem);
|
||||
*copy_mem = malloc(ehdr_size);
|
||||
if (!*copy_mem) {
|
||||
*copy_size = 0;
|
||||
ret = LIBBPF_PERF_EVENT_ERROR;
|
||||
break;
|
||||
}
|
||||
*buf_len = ehdr->size;
|
||||
*copy_size = ehdr_size;
|
||||
}
|
||||
|
||||
memcpy(*buf, begin, len);
|
||||
memcpy(*buf + len, base, ehdr->size - len);
|
||||
ehdr = (void *)*buf;
|
||||
begin = base + ehdr->size - len;
|
||||
} else if (begin + ehdr->size == base + size) {
|
||||
begin = base;
|
||||
} else {
|
||||
begin += ehdr->size;
|
||||
memcpy(*copy_mem, copy_start, len_first);
|
||||
memcpy(*copy_mem + len_first, base, len_secnd);
|
||||
ehdr = *copy_mem;
|
||||
}
|
||||
|
||||
ret = fn(ehdr, priv);
|
||||
ret = fn(ehdr, private_data);
|
||||
data_tail += ehdr_size;
|
||||
if (ret != LIBBPF_PERF_EVENT_CONT)
|
||||
break;
|
||||
|
||||
data_tail += ehdr->size;
|
||||
}
|
||||
|
||||
__sync_synchronize(); /* smp_mb() */
|
||||
header->data_tail = data_tail;
|
||||
|
||||
ring_buffer_write_tail(header, data_tail);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user