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:
yonghong-song
2018-11-26 14:32:21 -08:00
committed by GitHub
parent 319ff2f0f6
commit 556e0a0def
11 changed files with 1173 additions and 112 deletions

View File

@@ -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;
}