mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 23:32:14 +00:00
bpf: btf: Add BTF support to libbpf
If the ".BTF" elf section exists, libbpf will try to create a btf_fd (through BPF_BTF_LOAD). If that fails, it will still continue loading the bpf prog/map without the BTF. If the bpf_object has a BTF loaded, it will create a map with the btf_fd. libbpf will try to figure out the btf_key_id and btf_value_id of a map by finding the BTF type with name "<map_name>_key" and "<map_name>_value". If they cannot be found, it will continue without using the BTF. Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Alexei Starovoitov <ast@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
parent
3bd86a8409
commit
8a138aed4a
7 changed files with 627 additions and 32 deletions
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "libbpf.h"
|
||||
#include "bpf.h"
|
||||
#include "btf.h"
|
||||
|
||||
#ifndef EM_BPF
|
||||
#define EM_BPF 247
|
||||
|
@ -212,6 +213,8 @@ struct bpf_map {
|
|||
char *name;
|
||||
size_t offset;
|
||||
struct bpf_map_def def;
|
||||
uint32_t btf_key_id;
|
||||
uint32_t btf_value_id;
|
||||
void *priv;
|
||||
bpf_map_clear_priv_t clear_priv;
|
||||
};
|
||||
|
@ -256,6 +259,8 @@ struct bpf_object {
|
|||
*/
|
||||
struct list_head list;
|
||||
|
||||
struct btf *btf;
|
||||
|
||||
void *priv;
|
||||
bpf_object_clear_priv_t clear_priv;
|
||||
|
||||
|
@ -819,7 +824,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
|||
data->d_size);
|
||||
else if (strcmp(name, "maps") == 0)
|
||||
obj->efile.maps_shndx = idx;
|
||||
else if (sh.sh_type == SHT_SYMTAB) {
|
||||
else if (strcmp(name, BTF_ELF_SEC) == 0) {
|
||||
obj->btf = btf__new(data->d_buf, data->d_size,
|
||||
__pr_debug);
|
||||
if (IS_ERR(obj->btf)) {
|
||||
pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
|
||||
BTF_ELF_SEC, PTR_ERR(obj->btf));
|
||||
obj->btf = NULL;
|
||||
}
|
||||
} else if (sh.sh_type == SHT_SYMTAB) {
|
||||
if (obj->efile.symbols) {
|
||||
pr_warning("bpf: multiple SYMTAB in %s\n",
|
||||
obj->path);
|
||||
|
@ -996,33 +1009,126 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf)
|
||||
{
|
||||
struct bpf_map_def *def = &map->def;
|
||||
const size_t max_name = 256;
|
||||
int64_t key_size, value_size;
|
||||
int32_t key_id, value_id;
|
||||
char name[max_name];
|
||||
|
||||
/* Find key type by name from BTF */
|
||||
if (snprintf(name, max_name, "%s_key", map->name) == max_name) {
|
||||
pr_warning("map:%s length of BTF key_type:%s_key is too long\n",
|
||||
map->name, map->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_id = btf__find_by_name(btf, name);
|
||||
if (key_id < 0) {
|
||||
pr_debug("map:%s key_type:%s cannot be found in BTF\n",
|
||||
map->name, name);
|
||||
return key_id;
|
||||
}
|
||||
|
||||
key_size = btf__resolve_size(btf, key_id);
|
||||
if (key_size < 0) {
|
||||
pr_warning("map:%s key_type:%s cannot get the BTF type_size\n",
|
||||
map->name, name);
|
||||
return key_size;
|
||||
}
|
||||
|
||||
if (def->key_size != key_size) {
|
||||
pr_warning("map:%s key_type:%s has BTF type_size:%ld != key_size:%u\n",
|
||||
map->name, name, key_size, def->key_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Find value type from BTF */
|
||||
if (snprintf(name, max_name, "%s_value", map->name) == max_name) {
|
||||
pr_warning("map:%s length of BTF value_type:%s_value is too long\n",
|
||||
map->name, map->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
value_id = btf__find_by_name(btf, name);
|
||||
if (value_id < 0) {
|
||||
pr_debug("map:%s value_type:%s cannot be found in BTF\n",
|
||||
map->name, name);
|
||||
return value_id;
|
||||
}
|
||||
|
||||
value_size = btf__resolve_size(btf, value_id);
|
||||
if (value_size < 0) {
|
||||
pr_warning("map:%s value_type:%s cannot get the BTF type_size\n",
|
||||
map->name, name);
|
||||
return value_size;
|
||||
}
|
||||
|
||||
if (def->value_size != value_size) {
|
||||
pr_warning("map:%s value_type:%s has BTF type_size:%ld != value_size:%u\n",
|
||||
map->name, name, value_size, def->value_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map->btf_key_id = key_id;
|
||||
map->btf_value_id = value_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_object__create_maps(struct bpf_object *obj)
|
||||
{
|
||||
struct bpf_create_map_attr create_attr = {};
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++) {
|
||||
struct bpf_map_def *def = &obj->maps[i].def;
|
||||
int *pfd = &obj->maps[i].fd;
|
||||
struct bpf_map *map = &obj->maps[i];
|
||||
struct bpf_map_def *def = &map->def;
|
||||
int *pfd = &map->fd;
|
||||
|
||||
create_attr.name = map->name;
|
||||
create_attr.map_type = def->type;
|
||||
create_attr.map_flags = def->map_flags;
|
||||
create_attr.key_size = def->key_size;
|
||||
create_attr.value_size = def->value_size;
|
||||
create_attr.max_entries = def->max_entries;
|
||||
create_attr.btf_fd = 0;
|
||||
create_attr.btf_key_id = 0;
|
||||
create_attr.btf_value_id = 0;
|
||||
|
||||
if (obj->btf && !bpf_map_find_btf_info(map, obj->btf)) {
|
||||
create_attr.btf_fd = btf__fd(obj->btf);
|
||||
create_attr.btf_key_id = map->btf_key_id;
|
||||
create_attr.btf_value_id = map->btf_value_id;
|
||||
}
|
||||
|
||||
*pfd = bpf_create_map_xattr(&create_attr);
|
||||
if (*pfd < 0 && create_attr.btf_key_id) {
|
||||
pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n",
|
||||
map->name, strerror(errno), errno);
|
||||
create_attr.btf_fd = 0;
|
||||
create_attr.btf_key_id = 0;
|
||||
create_attr.btf_value_id = 0;
|
||||
map->btf_key_id = 0;
|
||||
map->btf_value_id = 0;
|
||||
*pfd = bpf_create_map_xattr(&create_attr);
|
||||
}
|
||||
|
||||
*pfd = bpf_create_map_name(def->type,
|
||||
obj->maps[i].name,
|
||||
def->key_size,
|
||||
def->value_size,
|
||||
def->max_entries,
|
||||
def->map_flags);
|
||||
if (*pfd < 0) {
|
||||
size_t j;
|
||||
int err = *pfd;
|
||||
|
||||
err = *pfd;
|
||||
pr_warning("failed to create map (name: '%s'): %s\n",
|
||||
obj->maps[i].name,
|
||||
map->name,
|
||||
strerror(errno));
|
||||
for (j = 0; j < i; j++)
|
||||
zclose(obj->maps[j].fd);
|
||||
return err;
|
||||
}
|
||||
pr_debug("create map %s: fd=%d\n", obj->maps[i].name, *pfd);
|
||||
pr_debug("create map %s: fd=%d\n", map->name, *pfd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1641,6 +1747,7 @@ void bpf_object__close(struct bpf_object *obj)
|
|||
|
||||
bpf_object__elf_finish(obj);
|
||||
bpf_object__unload(obj);
|
||||
btf__free(obj->btf);
|
||||
|
||||
for (i = 0; i < obj->nr_maps; i++) {
|
||||
zfree(&obj->maps[i].name);
|
||||
|
@ -1692,6 +1799,11 @@ unsigned int bpf_object__kversion(struct bpf_object *obj)
|
|||
return obj ? obj->kern_version : 0;
|
||||
}
|
||||
|
||||
int bpf_object__btf_fd(const struct bpf_object *obj)
|
||||
{
|
||||
return obj->btf ? btf__fd(obj->btf) : -1;
|
||||
}
|
||||
|
||||
int bpf_object__set_priv(struct bpf_object *obj, void *priv,
|
||||
bpf_object_clear_priv_t clear_priv)
|
||||
{
|
||||
|
@ -1937,6 +2049,16 @@ const char *bpf_map__name(struct bpf_map *map)
|
|||
return map ? map->name : NULL;
|
||||
}
|
||||
|
||||
uint32_t bpf_map__btf_key_id(const struct bpf_map *map)
|
||||
{
|
||||
return map ? map->btf_key_id : 0;
|
||||
}
|
||||
|
||||
uint32_t bpf_map__btf_value_id(const struct bpf_map *map)
|
||||
{
|
||||
return map ? map->btf_value_id : 0;
|
||||
}
|
||||
|
||||
int bpf_map__set_priv(struct bpf_map *map, void *priv,
|
||||
bpf_map_clear_priv_t clear_priv)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue