Skip to content

Commit

Permalink
Merge branch 'bpf-libbpf-int-btf-map'
Browse files Browse the repository at this point in the history
Andrii Nakryiko says:

====================
This patch set implements an update to how BTF-defined maps are specified. The
change is in how integer attributes, e.g., type, max_entries, map_flags, are
specified: now they are captured as part of map definition struct's BTF type
information (using array dimension), eliminating the need for compile-time
data initialization and keeping all the metadata in one place.

All existing selftests that were using BTF-defined maps are updated, along
with some other selftests, that were switched to new syntax.

v4->v5:
- revert sample_map_ret0.c, which is loaded with iproute2 (kernel test robot);
v3->v4:
- add acks;
- fix int -> uint type in commit message;
v2->v3:
- rename __int into __uint (Yonghong);
v1->v2:
- split bpf_helpers.h change from libbpf change (Song).
====================

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
  • Loading branch information
Daniel Borkmann committed Jul 5, 2019
2 parents c5f48c9 + 1639b17 commit e232cb6
Show file tree
Hide file tree
Showing 33 changed files with 559 additions and 760 deletions.
58 changes: 28 additions & 30 deletions tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1029,40 +1029,40 @@ static const struct btf_type *skip_mods_and_typedefs(const struct btf *btf,
}
}

static bool get_map_field_int(const char *map_name,
const struct btf *btf,
/*
* Fetch integer attribute of BTF map definition. Such attributes are
* represented using a pointer to an array, in which dimensionality of array
* encodes specified integer value. E.g., int (*type)[BPF_MAP_TYPE_ARRAY];
* encodes `type => BPF_MAP_TYPE_ARRAY` key/value pair completely using BTF
* type definition, while using only sizeof(void *) space in ELF data section.
*/
static bool get_map_field_int(const char *map_name, const struct btf *btf,
const struct btf_type *def,
const struct btf_member *m,
const void *data, __u32 *res) {
const struct btf_member *m, __u32 *res) {
const struct btf_type *t = skip_mods_and_typedefs(btf, m->type);
const char *name = btf__name_by_offset(btf, m->name_off);
__u32 int_info = *(const __u32 *)(const void *)(t + 1);
const struct btf_array *arr_info;
const struct btf_type *arr_t;

if (BTF_INFO_KIND(t->info) != BTF_KIND_INT) {
pr_warning("map '%s': attr '%s': expected INT, got %u.\n",
if (BTF_INFO_KIND(t->info) != BTF_KIND_PTR) {
pr_warning("map '%s': attr '%s': expected PTR, got %u.\n",
map_name, name, BTF_INFO_KIND(t->info));
return false;
}
if (t->size != 4 || BTF_INT_BITS(int_info) != 32 ||
BTF_INT_OFFSET(int_info)) {
pr_warning("map '%s': attr '%s': expected 32-bit non-bitfield integer, "
"got %u-byte (%d-bit) one with bit offset %d.\n",
map_name, name, t->size, BTF_INT_BITS(int_info),
BTF_INT_OFFSET(int_info));
return false;
}
if (BTF_INFO_KFLAG(def->info) && BTF_MEMBER_BITFIELD_SIZE(m->offset)) {
pr_warning("map '%s': attr '%s': bitfield is not supported.\n",
map_name, name);

arr_t = btf__type_by_id(btf, t->type);
if (!arr_t) {
pr_warning("map '%s': attr '%s': type [%u] not found.\n",
map_name, name, t->type);
return false;
}
if (m->offset % 32) {
pr_warning("map '%s': attr '%s': unaligned fields are not supported.\n",
map_name, name);
if (BTF_INFO_KIND(arr_t->info) != BTF_KIND_ARRAY) {
pr_warning("map '%s': attr '%s': expected ARRAY, got %u.\n",
map_name, name, BTF_INFO_KIND(arr_t->info));
return false;
}

*res = *(const __u32 *)(data + m->offset / 8);
arr_info = (const void *)(arr_t + 1);
*res = arr_info->nelems;
return true;
}

Expand All @@ -1075,7 +1075,6 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
const struct btf_var_secinfo *vi;
const struct btf_var *var_extra;
const struct btf_member *m;
const void *def_data;
const char *map_name;
struct bpf_map *map;
int vlen, i;
Expand Down Expand Up @@ -1132,7 +1131,6 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
pr_debug("map '%s': at sec_idx %d, offset %zu.\n",
map_name, map->sec_idx, map->sec_offset);

def_data = data->d_buf + vi->offset;
vlen = BTF_INFO_VLEN(def->info);
m = (const void *)(def + 1);
for (i = 0; i < vlen; i++, m++) {
Expand All @@ -1145,27 +1143,27 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
}
if (strcmp(name, "type") == 0) {
if (!get_map_field_int(map_name, obj->btf, def, m,
def_data, &map->def.type))
&map->def.type))
return -EINVAL;
pr_debug("map '%s': found type = %u.\n",
map_name, map->def.type);
} else if (strcmp(name, "max_entries") == 0) {
if (!get_map_field_int(map_name, obj->btf, def, m,
def_data, &map->def.max_entries))
&map->def.max_entries))
return -EINVAL;
pr_debug("map '%s': found max_entries = %u.\n",
map_name, map->def.max_entries);
} else if (strcmp(name, "map_flags") == 0) {
if (!get_map_field_int(map_name, obj->btf, def, m,
def_data, &map->def.map_flags))
&map->def.map_flags))
return -EINVAL;
pr_debug("map '%s': found map_flags = %u.\n",
map_name, map->def.map_flags);
} else if (strcmp(name, "key_size") == 0) {
__u32 sz;

if (!get_map_field_int(map_name, obj->btf, def, m,
def_data, &sz))
&sz))
return -EINVAL;
pr_debug("map '%s': found key_size = %u.\n",
map_name, sz);
Expand Down Expand Up @@ -1208,7 +1206,7 @@ static int bpf_object__init_user_btf_map(struct bpf_object *obj,
__u32 sz;

if (!get_map_field_int(map_name, obj->btf, def, m,
def_data, &sz))
&sz))
return -EINVAL;
pr_debug("map '%s': found value_size = %u.\n",
map_name, sz);
Expand Down
3 changes: 3 additions & 0 deletions tools/testing/selftests/bpf/bpf_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
*/
#define SEC(NAME) __attribute__((section(NAME), used))

#define __uint(name, val) int (*name)[val]
#define __type(name, val) val *name

/* helper macro to print out debug messages */
#define bpf_printk(fmt, ...) \
({ \
Expand Down
28 changes: 10 additions & 18 deletions tools/testing/selftests/bpf/progs/bpf_flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,18 @@ struct frag_hdr {
};

struct {
__u32 type;
__u32 max_entries;
__u32 key_size;
__u32 value_size;
} jmp_table SEC(".maps") = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.max_entries = 8,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
};
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 8);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
} jmp_table SEC(".maps");

struct {
__u32 type;
__u32 max_entries;
__u32 *key;
struct bpf_flow_keys *value;
} last_dissection SEC(".maps") = {
.type = BPF_MAP_TYPE_ARRAY,
.max_entries = 1,
};
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, struct bpf_flow_keys);
} last_dissection SEC(".maps");

static __always_inline int export_flow_keys(struct bpf_flow_keys *keys,
int ret)
Expand Down
26 changes: 13 additions & 13 deletions tools/testing/selftests/bpf/progs/get_cgroup_id_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,19 @@
#include <linux/bpf.h>
#include "bpf_helpers.h"

struct bpf_map_def SEC("maps") cg_ids = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u64),
.max_entries = 1,
};

struct bpf_map_def SEC("maps") pidmap = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(__u32),
.max_entries = 1,
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, __u64);
} cg_ids SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, __u32);
} pidmap SEC(".maps");

SEC("tracepoint/syscalls/sys_enter_nanosleep")
int trace(void *ctx)
Expand Down
20 changes: 8 additions & 12 deletions tools/testing/selftests/bpf/progs/netcnt_prog.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,16 @@
#define NS_PER_SEC 1000000000

struct {
__u32 type;
struct bpf_cgroup_storage_key *key;
struct percpu_net_cnt *value;
} percpu_netcnt SEC(".maps") = {
.type = BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
};
__uint(type, BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE);
__type(key, struct bpf_cgroup_storage_key);
__type(value, struct percpu_net_cnt);
} percpu_netcnt SEC(".maps");

struct {
__u32 type;
struct bpf_cgroup_storage_key *key;
struct net_cnt *value;
} netcnt SEC(".maps") = {
.type = BPF_MAP_TYPE_CGROUP_STORAGE,
};
__uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
__type(key, struct bpf_cgroup_storage_key);
__type(value, struct net_cnt);
} netcnt SEC(".maps");

SEC("cgroup/skb")
int bpf_nextcnt(struct __sk_buff *skb)
Expand Down
90 changes: 41 additions & 49 deletions tools/testing/selftests/bpf/progs/pyperf.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,6 @@ typedef struct {
} Event;


struct bpf_elf_map {
__u32 type;
__u32 size_key;
__u32 size_value;
__u32 max_elem;
__u32 flags;
};

typedef int pid_t;

typedef struct {
Expand Down Expand Up @@ -118,47 +110,47 @@ static __always_inline bool get_frame_data(void *frame_ptr, PidData *pidData,
return true;
}

struct bpf_elf_map SEC("maps") pidmap = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(int),
.size_value = sizeof(PidData),
.max_elem = 1,
};

struct bpf_elf_map SEC("maps") eventmap = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(int),
.size_value = sizeof(Event),
.max_elem = 1,
};

struct bpf_elf_map SEC("maps") symbolmap = {
.type = BPF_MAP_TYPE_HASH,
.size_key = sizeof(Symbol),
.size_value = sizeof(int),
.max_elem = 1,
};

struct bpf_elf_map SEC("maps") statsmap = {
.type = BPF_MAP_TYPE_ARRAY,
.size_key = sizeof(Stats),
.size_value = sizeof(int),
.max_elem = 1,
};

struct bpf_elf_map SEC("maps") perfmap = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.size_key = sizeof(int),
.size_value = sizeof(int),
.max_elem = 32,
};

struct bpf_elf_map SEC("maps") stackmap = {
.type = BPF_MAP_TYPE_STACK_TRACE,
.size_key = sizeof(int),
.size_value = sizeof(long long) * 127,
.max_elem = 1000,
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1);
__type(key, int);
__type(value, PidData);
} pidmap SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1);
__type(key, int);
__type(value, Event);
} eventmap SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1);
__type(key, Symbol);
__type(value, int);
} symbolmap SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, int);
__type(value, Stats);
} statsmap SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(max_entries, 32);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
} perfmap SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
__uint(max_entries, 1000);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(long long) * 127);
} stackmap SEC(".maps");

static __always_inline int __on_event(struct pt_regs *ctx)
{
Expand Down
13 changes: 5 additions & 8 deletions tools/testing/selftests/bpf/progs/socket_cookie_prog.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@ struct socket_cookie {
};

struct {
__u32 type;
__u32 map_flags;
int *key;
struct socket_cookie *value;
} socket_cookies SEC(".maps") = {
.type = BPF_MAP_TYPE_SK_STORAGE,
.map_flags = BPF_F_NO_PREALLOC,
};
__uint(type, BPF_MAP_TYPE_SK_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, int);
__type(value, struct socket_cookie);
} socket_cookies SEC(".maps");

SEC("cgroup/connect6")
int set_cookie(struct bpf_sock_addr *ctx)
Expand Down
Loading

0 comments on commit e232cb6

Please sign in to comment.