From 8a138aed4a807ceb143882fb23a423d524dcdb35 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Wed, 18 Apr 2018 15:56:05 -0700 Subject: 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 "_key" and "_value". If they cannot be found, it will continue without using the BTF. Signed-off-by: Martin KaFai Lau Acked-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/lib/bpf/bpf.c | 92 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 75 insertions(+), 17 deletions(-) (limited to 'tools/lib/bpf/bpf.c') diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index acbb3f8b3bec..76b36cc16e7f 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -73,43 +73,76 @@ static inline int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, return syscall(__NR_bpf, cmd, attr, size); } -int bpf_create_map_node(enum bpf_map_type map_type, const char *name, - int key_size, int value_size, int max_entries, - __u32 map_flags, int node) +int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) { - __u32 name_len = name ? strlen(name) : 0; + __u32 name_len = create_attr->name ? strlen(create_attr->name) : 0; union bpf_attr attr; memset(&attr, '\0', sizeof(attr)); - attr.map_type = map_type; - attr.key_size = key_size; - attr.value_size = value_size; - attr.max_entries = max_entries; - attr.map_flags = map_flags; - memcpy(attr.map_name, name, min(name_len, BPF_OBJ_NAME_LEN - 1)); + attr.map_type = create_attr->map_type; + attr.key_size = create_attr->key_size; + attr.value_size = create_attr->value_size; + attr.max_entries = create_attr->max_entries; + attr.map_flags = create_attr->map_flags; + memcpy(attr.map_name, create_attr->name, + min(name_len, BPF_OBJ_NAME_LEN - 1)); + attr.numa_node = create_attr->numa_node; + attr.btf_fd = create_attr->btf_fd; + attr.btf_key_id = create_attr->btf_key_id; + attr.btf_value_id = create_attr->btf_value_id; + + return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); +} +int bpf_create_map_node(enum bpf_map_type map_type, const char *name, + int key_size, int value_size, int max_entries, + __u32 map_flags, int node) +{ + struct bpf_create_map_attr map_attr = {}; + + map_attr.name = name; + map_attr.map_type = map_type; + map_attr.map_flags = map_flags; + map_attr.key_size = key_size; + map_attr.value_size = value_size; + map_attr.max_entries = max_entries; if (node >= 0) { - attr.map_flags |= BPF_F_NUMA_NODE; - attr.numa_node = node; + map_attr.numa_node = node; + map_attr.map_flags |= BPF_F_NUMA_NODE; } - return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); + return bpf_create_map_xattr(&map_attr); } int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, __u32 map_flags) { - return bpf_create_map_node(map_type, NULL, key_size, value_size, - max_entries, map_flags, -1); + struct bpf_create_map_attr map_attr = {}; + + map_attr.map_type = map_type; + map_attr.map_flags = map_flags; + map_attr.key_size = key_size; + map_attr.value_size = value_size; + map_attr.max_entries = max_entries; + + return bpf_create_map_xattr(&map_attr); } 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) { - return bpf_create_map_node(map_type, name, key_size, value_size, - max_entries, map_flags, -1); + struct bpf_create_map_attr map_attr = {}; + + map_attr.name = name; + map_attr.map_type = map_type; + map_attr.map_flags = map_flags; + map_attr.key_size = key_size; + map_attr.value_size = value_size; + map_attr.max_entries = max_entries; + + return bpf_create_map_xattr(&map_attr); } int bpf_create_map_in_map_node(enum bpf_map_type map_type, const char *name, @@ -573,3 +606,28 @@ cleanup: close(sock); return ret; } + +int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, + bool do_log) +{ + union bpf_attr attr = {}; + int fd; + + attr.btf = ptr_to_u64(btf); + attr.btf_size = btf_size; + +retry: + if (do_log && log_buf && log_buf_size) { + attr.btf_log_level = 1; + attr.btf_log_size = log_buf_size; + attr.btf_log_buf = ptr_to_u64(log_buf); + } + + fd = sys_bpf(BPF_BTF_LOAD, &attr, sizeof(attr)); + if (fd == -1 && !do_log && log_buf && log_buf_size) { + do_log = true; + goto retry; + } + + return fd; +} -- cgit v1.2.3 From cd8b89280c1c843756a2c95ed50a1a6446b42b52 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 4 May 2018 14:49:55 -0700 Subject: bpf: btf: Tests for BPF_OBJ_GET_INFO_BY_FD and BPF_BTF_GET_FD_BY_ID This patch adds test for BPF_BTF_GET_FD_BY_ID and the new btf_id/btf_key_id/btf_value_id in the "struct bpf_map_info". It also modifies the existing BPF_OBJ_GET_INFO_BY_FD test to reflect the new "struct bpf_btf_info". Signed-off-by: Martin KaFai Lau Acked-by: Alexei Starovoitov Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/lib/bpf/bpf.c | 10 ++ tools/lib/bpf/bpf.h | 1 + tools/testing/selftests/bpf/test_btf.c | 289 +++++++++++++++++++++++++++++++-- 3 files changed, 287 insertions(+), 13 deletions(-) (limited to 'tools/lib/bpf/bpf.c') diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 76b36cc16e7f..a3a8fb2ac697 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -458,6 +458,16 @@ int bpf_map_get_fd_by_id(__u32 id) return sys_bpf(BPF_MAP_GET_FD_BY_ID, &attr, sizeof(attr)); } +int bpf_btf_get_fd_by_id(__u32 id) +{ + union bpf_attr attr; + + bzero(&attr, sizeof(attr)); + attr.btf_id = id; + + return sys_bpf(BPF_BTF_GET_FD_BY_ID, &attr, sizeof(attr)); +} + int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len) { union bpf_attr attr; diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 553b11ad52b3..fb3a146d92ff 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -98,6 +98,7 @@ int bpf_prog_get_next_id(__u32 start_id, __u32 *next_id); int bpf_map_get_next_id(__u32 start_id, __u32 *next_id); int bpf_prog_get_fd_by_id(__u32 id); int bpf_map_get_fd_by_id(__u32 id); +int bpf_btf_get_fd_by_id(__u32 id); int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len); int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, __u32 *attach_flags, __u32 *prog_ids, __u32 *prog_cnt); diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index b7880a20fad1..c8bceae7ec02 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -1047,9 +1047,13 @@ struct btf_get_info_test { const char *str_sec; __u32 raw_types[MAX_NR_RAW_TYPES]; __u32 str_sec_size; - int info_size_delta; + int btf_size_delta; + int (*special_test)(unsigned int test_num); }; +static int test_big_btf_info(unsigned int test_num); +static int test_btf_id(unsigned int test_num); + const struct btf_get_info_test get_info_tests[] = { { .descr = "== raw_btf_size+1", @@ -1060,7 +1064,7 @@ const struct btf_get_info_test get_info_tests[] = { }, .str_sec = "", .str_sec_size = sizeof(""), - .info_size_delta = 1, + .btf_size_delta = 1, }, { .descr = "== raw_btf_size-3", @@ -1071,20 +1075,274 @@ const struct btf_get_info_test get_info_tests[] = { }, .str_sec = "", .str_sec_size = sizeof(""), - .info_size_delta = -3, + .btf_size_delta = -3, +}, +{ + .descr = "Large bpf_btf_info", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .special_test = test_big_btf_info, +}, +{ + .descr = "BTF ID", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* unsigned int */ /* [2] */ + BTF_TYPE_INT_ENC(0, 0, 0, 32, 4), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .special_test = test_btf_id, }, }; +static inline __u64 ptr_to_u64(const void *ptr) +{ + return (__u64)(unsigned long)ptr; +} + +static int test_big_btf_info(unsigned int test_num) +{ + const struct btf_get_info_test *test = &get_info_tests[test_num - 1]; + uint8_t *raw_btf = NULL, *user_btf = NULL; + unsigned int raw_btf_size; + struct { + struct bpf_btf_info info; + uint64_t garbage; + } info_garbage; + struct bpf_btf_info *info; + int btf_fd = -1, err; + uint32_t info_len; + + raw_btf = btf_raw_create(&hdr_tmpl, + test->raw_types, + test->str_sec, + test->str_sec_size, + &raw_btf_size); + + if (!raw_btf) + return -1; + + *btf_log_buf = '\0'; + + user_btf = malloc(raw_btf_size); + if (CHECK(!user_btf, "!user_btf")) { + err = -1; + goto done; + } + + btf_fd = bpf_load_btf(raw_btf, raw_btf_size, + btf_log_buf, BTF_LOG_BUF_SIZE, + args.always_log); + if (CHECK(btf_fd == -1, "errno:%d", errno)) { + err = -1; + goto done; + } + + /* + * GET_INFO should error out if the userspace info + * has non zero tailing bytes. + */ + info = &info_garbage.info; + memset(info, 0, sizeof(*info)); + info_garbage.garbage = 0xdeadbeef; + info_len = sizeof(info_garbage); + info->btf = ptr_to_u64(user_btf); + info->btf_size = raw_btf_size; + + err = bpf_obj_get_info_by_fd(btf_fd, info, &info_len); + if (CHECK(!err, "!err")) { + err = -1; + goto done; + } + + /* + * GET_INFO should succeed even info_len is larger than + * the kernel supported as long as tailing bytes are zero. + * The kernel supported info len should also be returned + * to userspace. + */ + info_garbage.garbage = 0; + err = bpf_obj_get_info_by_fd(btf_fd, info, &info_len); + if (CHECK(err || info_len != sizeof(*info), + "err:%d errno:%d info_len:%u sizeof(*info):%lu", + err, errno, info_len, sizeof(*info))) { + err = -1; + goto done; + } + + fprintf(stderr, "OK"); + +done: + if (*btf_log_buf && (err || args.always_log)) + fprintf(stderr, "\n%s", btf_log_buf); + + free(raw_btf); + free(user_btf); + + if (btf_fd != -1) + close(btf_fd); + + return err; +} + +static int test_btf_id(unsigned int test_num) +{ + const struct btf_get_info_test *test = &get_info_tests[test_num - 1]; + struct bpf_create_map_attr create_attr = {}; + uint8_t *raw_btf = NULL, *user_btf[2] = {}; + int btf_fd[2] = {-1, -1}, map_fd = -1; + struct bpf_map_info map_info = {}; + struct bpf_btf_info info[2] = {}; + unsigned int raw_btf_size; + uint32_t info_len; + int err, i, ret; + + raw_btf = btf_raw_create(&hdr_tmpl, + test->raw_types, + test->str_sec, + test->str_sec_size, + &raw_btf_size); + + if (!raw_btf) + return -1; + + *btf_log_buf = '\0'; + + for (i = 0; i < 2; i++) { + user_btf[i] = malloc(raw_btf_size); + if (CHECK(!user_btf[i], "!user_btf[%d]", i)) { + err = -1; + goto done; + } + info[i].btf = ptr_to_u64(user_btf[i]); + info[i].btf_size = raw_btf_size; + } + + btf_fd[0] = bpf_load_btf(raw_btf, raw_btf_size, + btf_log_buf, BTF_LOG_BUF_SIZE, + args.always_log); + if (CHECK(btf_fd[0] == -1, "errno:%d", errno)) { + err = -1; + goto done; + } + + /* Test BPF_OBJ_GET_INFO_BY_ID on btf_id */ + info_len = sizeof(info[0]); + err = bpf_obj_get_info_by_fd(btf_fd[0], &info[0], &info_len); + if (CHECK(err, "errno:%d", errno)) { + err = -1; + goto done; + } + + btf_fd[1] = bpf_btf_get_fd_by_id(info[0].id); + if (CHECK(btf_fd[1] == -1, "errno:%d", errno)) { + err = -1; + goto done; + } + + ret = 0; + err = bpf_obj_get_info_by_fd(btf_fd[1], &info[1], &info_len); + if (CHECK(err || info[0].id != info[1].id || + info[0].btf_size != info[1].btf_size || + (ret = memcmp(user_btf[0], user_btf[1], info[0].btf_size)), + "err:%d errno:%d id0:%u id1:%u btf_size0:%u btf_size1:%u memcmp:%d", + err, errno, info[0].id, info[1].id, + info[0].btf_size, info[1].btf_size, ret)) { + err = -1; + goto done; + } + + /* Test btf members in struct bpf_map_info */ + create_attr.name = "test_btf_id"; + create_attr.map_type = BPF_MAP_TYPE_ARRAY; + create_attr.key_size = sizeof(int); + create_attr.value_size = sizeof(unsigned int); + create_attr.max_entries = 4; + create_attr.btf_fd = btf_fd[0]; + create_attr.btf_key_id = 1; + create_attr.btf_value_id = 2; + + map_fd = bpf_create_map_xattr(&create_attr); + if (CHECK(map_fd == -1, "errno:%d", errno)) { + err = -1; + goto done; + } + + info_len = sizeof(map_info); + err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len); + if (CHECK(err || map_info.btf_id != info[0].id || + map_info.btf_key_id != 1 || map_info.btf_value_id != 2, + "err:%d errno:%d info.id:%u btf_id:%u btf_key_id:%u btf_value_id:%u", + err, errno, info[0].id, map_info.btf_id, map_info.btf_key_id, + map_info.btf_value_id)) { + err = -1; + goto done; + } + + for (i = 0; i < 2; i++) { + close(btf_fd[i]); + btf_fd[i] = -1; + } + + /* Test BTF ID is removed from the kernel */ + btf_fd[0] = bpf_btf_get_fd_by_id(map_info.btf_id); + if (CHECK(btf_fd[0] == -1, "errno:%d", errno)) { + err = -1; + goto done; + } + close(btf_fd[0]); + btf_fd[0] = -1; + + /* The map holds the last ref to BTF and its btf_id */ + close(map_fd); + map_fd = -1; + btf_fd[0] = bpf_btf_get_fd_by_id(map_info.btf_id); + if (CHECK(btf_fd[0] != -1, "BTF lingers")) { + err = -1; + goto done; + } + + fprintf(stderr, "OK"); + +done: + if (*btf_log_buf && (err || args.always_log)) + fprintf(stderr, "\n%s", btf_log_buf); + + free(raw_btf); + if (map_fd != -1) + close(map_fd); + for (i = 0; i < 2; i++) { + free(user_btf[i]); + if (btf_fd[i] != -1) + close(btf_fd[i]); + } + + return err; +} + static int do_test_get_info(unsigned int test_num) { const struct btf_get_info_test *test = &get_info_tests[test_num - 1]; unsigned int raw_btf_size, user_btf_size, expected_nbytes; uint8_t *raw_btf = NULL, *user_btf = NULL; - int btf_fd = -1, err; + struct bpf_btf_info info = {}; + int btf_fd = -1, err, ret; + uint32_t info_len; - fprintf(stderr, "BTF GET_INFO_BY_ID test[%u] (%s): ", + fprintf(stderr, "BTF GET_INFO test[%u] (%s): ", test_num, test->descr); + if (test->special_test) + return test->special_test(test_num); + raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, test->str_sec, @@ -1110,19 +1368,24 @@ static int do_test_get_info(unsigned int test_num) goto done; } - user_btf_size = (int)raw_btf_size + test->info_size_delta; + user_btf_size = (int)raw_btf_size + test->btf_size_delta; expected_nbytes = min(raw_btf_size, user_btf_size); if (raw_btf_size > expected_nbytes) memset(user_btf + expected_nbytes, 0xff, raw_btf_size - expected_nbytes); - err = bpf_obj_get_info_by_fd(btf_fd, user_btf, &user_btf_size); - if (CHECK(err || user_btf_size != raw_btf_size || - memcmp(raw_btf, user_btf, expected_nbytes), - "err:%d(errno:%d) raw_btf_size:%u user_btf_size:%u expected_nbytes:%u memcmp:%d", - err, errno, - raw_btf_size, user_btf_size, expected_nbytes, - memcmp(raw_btf, user_btf, expected_nbytes))) { + info_len = sizeof(info); + info.btf = ptr_to_u64(user_btf); + info.btf_size = user_btf_size; + + ret = 0; + err = bpf_obj_get_info_by_fd(btf_fd, &info, &info_len); + if (CHECK(err || !info.id || info_len != sizeof(info) || + info.btf_size != raw_btf_size || + (ret = memcmp(raw_btf, user_btf, expected_nbytes)), + "err:%d errno:%d info.id:%u info_len:%u sizeof(info):%lu raw_btf_size:%u info.btf_size:%u expected_nbytes:%u memcmp:%d", + err, errno, info.id, info_len, sizeof(info), + raw_btf_size, info.btf_size, expected_nbytes, ret)) { err = -1; goto done; } -- cgit v1.2.3 From f0307a7ed17fa8925321a4f58f5ca56eeedd4fa3 Mon Sep 17 00:00:00 2001 From: David Beckett Date: Wed, 16 May 2018 14:02:49 -0700 Subject: libbpf: add ifindex to enable offload support BPF programs currently can only be offloaded using iproute2. This patch will allow programs to be offloaded using libbpf calls. Signed-off-by: David Beckett Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- tools/lib/bpf/bpf.c | 2 ++ tools/lib/bpf/bpf.h | 2 ++ tools/lib/bpf/libbpf.c | 18 +++++++++++++++--- tools/lib/bpf/libbpf.h | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) (limited to 'tools/lib/bpf/bpf.c') diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index a3a8fb2ac697..6a8a00097fd8 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -91,6 +91,7 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) attr.btf_fd = create_attr->btf_fd; attr.btf_key_id = create_attr->btf_key_id; attr.btf_value_id = create_attr->btf_value_id; + attr.map_ifindex = create_attr->map_ifindex; return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } @@ -201,6 +202,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, attr.log_size = 0; attr.log_level = 0; attr.kern_version = load_attr->kern_version; + attr.prog_ifindex = load_attr->prog_ifindex; memcpy(attr.prog_name, load_attr->name, min(name_len, BPF_OBJ_NAME_LEN - 1)); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index fb3a146d92ff..15bff7728cf1 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -38,6 +38,7 @@ struct bpf_create_map_attr { __u32 btf_fd; __u32 btf_key_id; __u32 btf_value_id; + __u32 map_ifindex; }; int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr); @@ -64,6 +65,7 @@ struct bpf_load_program_attr { size_t insns_cnt; const char *license; __u32 kern_version; + __u32 prog_ifindex; }; /* Recommend log buffer size */ diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index df54c4c9e48a..3dbe217bf23e 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -178,6 +178,7 @@ struct bpf_program { /* Index in elf obj file, for relocation use. */ int idx; char *name; + int prog_ifindex; char *section_name; struct bpf_insn *insns; size_t insns_cnt, main_prog_cnt; @@ -213,6 +214,7 @@ struct bpf_map { int fd; char *name; size_t offset; + int map_ifindex; struct bpf_map_def def; uint32_t btf_key_id; uint32_t btf_value_id; @@ -1091,6 +1093,7 @@ bpf_object__create_maps(struct bpf_object *obj) int *pfd = &map->fd; 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; create_attr.key_size = def->key_size; @@ -1273,7 +1276,7 @@ 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) + char *license, u32 kern_version, int *pfd, int prog_ifindex) { struct bpf_load_program_attr load_attr; char *log_buf; @@ -1287,6 +1290,7 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, load_attr.insns_cnt = insns_cnt; load_attr.license = license; load_attr.kern_version = kern_version; + load_attr.prog_ifindex = prog_ifindex; if (!load_attr.insns || !load_attr.insns_cnt) return -EINVAL; @@ -1368,7 +1372,8 @@ bpf_program__load(struct bpf_program *prog, } err = load_program(prog->type, prog->expected_attach_type, prog->name, prog->insns, prog->insns_cnt, - license, kern_version, &fd); + license, kern_version, &fd, + prog->prog_ifindex); if (!err) prog->instances.fds[0] = fd; goto out; @@ -1399,7 +1404,8 @@ bpf_program__load(struct bpf_program *prog, err = load_program(prog->type, prog->expected_attach_type, prog->name, result.new_insn_ptr, result.new_insn_cnt, - license, kern_version, &fd); + license, kern_version, &fd, + prog->prog_ifindex); if (err) { pr_warning("Loading the %dth instance of program '%s' failed\n", @@ -2188,6 +2194,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, enum bpf_attach_type expected_attach_type; enum bpf_prog_type prog_type; struct bpf_object *obj; + struct bpf_map *map; int section_idx; int err; @@ -2207,6 +2214,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, * section name. */ prog_type = attr->prog_type; + prog->prog_ifindex = attr->ifindex; expected_attach_type = attr->expected_attach_type; if (prog_type == BPF_PROG_TYPE_UNSPEC) { section_idx = bpf_program__identify_section(prog); @@ -2227,6 +2235,10 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, first_prog = prog; } + bpf_map__for_each(map, obj) { + map->map_ifindex = attr->ifindex; + } + if (!first_prog) { pr_warning("object file doesn't contain bpf program\n"); bpf_object__close(obj); diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 4574b9563278..cd3fd8d782c7 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -259,6 +259,7 @@ struct bpf_prog_load_attr { const char *file; enum bpf_prog_type prog_type; enum bpf_attach_type expected_attach_type; + int ifindex; }; int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr, -- cgit v1.2.3 From 61746dbe1aa27c9e23293621665b8442dfed7698 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Tue, 22 May 2018 15:04:24 -0700 Subject: bpf: btf: Add tests for the btf uapi changes This patch does the followings: 1. Modify libbpf and test_btf to reflect the uapi changes in btf 2. Add test for the btf_header changes 3. Add tests for array->index_type 4. Add err_str check to the tests 5. Fix a 4 bytes hole in "struct test #1" by swapping "m" and "n" Signed-off-by: Martin KaFai Lau Signed-off-by: Daniel Borkmann --- tools/lib/bpf/bpf.c | 4 +- tools/lib/bpf/bpf.h | 4 +- tools/lib/bpf/btf.c | 5 +- tools/lib/bpf/libbpf.c | 34 +-- tools/lib/bpf/libbpf.h | 4 +- tools/testing/selftests/bpf/test_btf.c | 521 +++++++++++++++++++++++++++------ 6 files changed, 456 insertions(+), 116 deletions(-) (limited to 'tools/lib/bpf/bpf.c') diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 6a8a00097fd8..442b4cdfeb71 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -89,8 +89,8 @@ int bpf_create_map_xattr(const struct bpf_create_map_attr *create_attr) min(name_len, BPF_OBJ_NAME_LEN - 1)); attr.numa_node = create_attr->numa_node; attr.btf_fd = create_attr->btf_fd; - attr.btf_key_id = create_attr->btf_key_id; - attr.btf_value_id = create_attr->btf_value_id; + attr.btf_key_type_id = create_attr->btf_key_type_id; + attr.btf_value_type_id = create_attr->btf_value_type_id; attr.map_ifindex = create_attr->map_ifindex; return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 15bff7728cf1..d12344f66d4e 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -36,8 +36,8 @@ struct bpf_create_map_attr { __u32 max_entries; __u32 numa_node; __u32 btf_fd; - __u32 btf_key_id; - __u32 btf_value_id; + __u32 btf_key_type_id; + __u32 btf_value_type_id; __u32 map_ifindex; }; diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c index 2bac710e3194..8c54a4b6f187 100644 --- a/tools/lib/bpf/btf.c +++ b/tools/lib/bpf/btf.c @@ -35,9 +35,8 @@ struct btf { static const char *btf_name_by_offset(const struct btf *btf, uint32_t offset) { - if (!BTF_STR_TBL_ELF_ID(offset) && - BTF_STR_OFFSET(offset) < btf->hdr->str_len) - return &btf->strings[BTF_STR_OFFSET(offset)]; + if (offset < btf->hdr->str_len) + return &btf->strings[offset]; else return NULL; } diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 3dbe217bf23e..8f1707dbfcfa 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -216,8 +216,8 @@ struct bpf_map { size_t offset; int map_ifindex; struct bpf_map_def def; - uint32_t btf_key_id; - uint32_t btf_value_id; + uint32_t btf_key_type_id; + uint32_t btf_value_type_id; void *priv; bpf_map_clear_priv_t clear_priv; }; @@ -1074,8 +1074,8 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) return -EINVAL; } - map->btf_key_id = key_id; - map->btf_value_id = value_id; + map->btf_key_type_id = key_id; + map->btf_value_type_id = value_id; return 0; } @@ -1100,24 +1100,24 @@ bpf_object__create_maps(struct bpf_object *obj) 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; + create_attr.btf_key_type_id = 0; + create_attr.btf_value_type_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; + create_attr.btf_key_type_id = map->btf_key_type_id; + create_attr.btf_value_type_id = map->btf_value_type_id; } *pfd = bpf_create_map_xattr(&create_attr); - if (*pfd < 0 && create_attr.btf_key_id) { + if (*pfd < 0 && create_attr.btf_key_type_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; + create_attr.btf_key_type_id = 0; + create_attr.btf_value_type_id = 0; + map->btf_key_type_id = 0; + map->btf_value_type_id = 0; *pfd = bpf_create_map_xattr(&create_attr); } @@ -2085,14 +2085,14 @@ 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) +uint32_t bpf_map__btf_key_type_id(const struct bpf_map *map) { - return map ? map->btf_key_id : 0; + return map ? map->btf_key_type_id : 0; } -uint32_t bpf_map__btf_value_id(const struct bpf_map *map) +uint32_t bpf_map__btf_value_type_id(const struct bpf_map *map) { - return map ? map->btf_value_id : 0; + return map ? map->btf_value_type_id : 0; } int bpf_map__set_priv(struct bpf_map *map, void *priv, diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index cd3fd8d782c7..09976531aa74 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -244,8 +244,8 @@ bpf_map__next(struct bpf_map *map, struct bpf_object *obj); int bpf_map__fd(struct bpf_map *map); const struct bpf_map_def *bpf_map__def(struct bpf_map *map); const char *bpf_map__name(struct bpf_map *map); -uint32_t bpf_map__btf_key_id(const struct bpf_map *map); -uint32_t bpf_map__btf_value_id(const struct bpf_map *map); +uint32_t bpf_map__btf_key_type_id(const struct bpf_map *map); +uint32_t bpf_map__btf_value_type_id(const struct bpf_map *map); typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *); int bpf_map__set_priv(struct bpf_map *map, void *priv, diff --git a/tools/testing/selftests/bpf/test_btf.c b/tools/testing/selftests/bpf/test_btf.c index c8bceae7ec02..35064df688c1 100644 --- a/tools/testing/selftests/bpf/test_btf.c +++ b/tools/testing/selftests/bpf/test_btf.c @@ -113,22 +113,25 @@ static char btf_log_buf[BTF_LOG_BUF_SIZE]; static struct btf_header hdr_tmpl = { .magic = BTF_MAGIC, .version = BTF_VERSION, + .hdr_len = sizeof(struct btf_header), }; struct btf_raw_test { const char *descr; const char *str_sec; const char *map_name; + const char *err_str; __u32 raw_types[MAX_NR_RAW_TYPES]; __u32 str_sec_size; enum bpf_map_type map_type; __u32 key_size; __u32 value_size; - __u32 key_id; - __u32 value_id; + __u32 key_type_id; + __u32 value_type_id; __u32 max_entries; bool btf_load_err; bool map_create_err; + int hdr_len_delta; int type_off_delta; int str_off_delta; int str_len_delta; @@ -141,8 +144,8 @@ static struct btf_raw_test raw_tests[] = { * }; * * struct A { - * int m; - * unsigned long long n; + * unsigned long long m; + * int n; * char o; * [3 bytes hole] * int p[8]; @@ -163,8 +166,8 @@ static struct btf_raw_test raw_tests[] = { BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */ /* struct A { */ /* [5] */ BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 6), 180), - BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */ - BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* unsigned long long n;*/ + BTF_MEMBER_ENC(NAME_TBD, 2, 0), /* unsigned long long m;*/ + BTF_MEMBER_ENC(NAME_TBD, 1, 64),/* int n; */ BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */ BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */ BTF_MEMBER_ENC(NAME_TBD, 6, 384),/* int q[4][8] */ @@ -172,6 +175,7 @@ static struct btf_raw_test raw_tests[] = { /* } */ /* int[4][8] */ BTF_TYPE_ARRAY_ENC(4, 1, 4), /* [6] */ + /* enum E */ /* [7] */ BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 2), sizeof(int)), BTF_ENUM_ENC(NAME_TBD, 0), BTF_ENUM_ENC(NAME_TBD, 1), @@ -183,8 +187,8 @@ static struct btf_raw_test raw_tests[] = { .map_name = "struct_test1_map", .key_size = sizeof(int), .value_size = 180, - .key_id = 1, - .value_id = 5, + .key_type_id = 1, + .value_type_id = 5, .max_entries = 4, }, @@ -238,8 +242,8 @@ static struct btf_raw_test raw_tests[] = { .map_name = "struct_test2_map", .key_size = sizeof(int), .value_size = 68, - .key_id = 1, - .value_id = 3, + .key_type_id = 1, + .value_type_id = 3, .max_entries = 4, }, @@ -258,7 +262,7 @@ static struct btf_raw_test raw_tests[] = { /* struct A { */ /* [2] */ BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), sizeof(int) * 2 - 1), BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */ - BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* int n; */ + BTF_MEMBER_ENC(NAME_TBD, 1, 32),/* int n; */ /* } */ BTF_END_RAW, }, @@ -268,10 +272,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "size_check1_map", .key_size = sizeof(int), .value_size = 1, - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Member exceeds struct_size", }, /* Test member exeeds the size of struct @@ -301,11 +306,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "size_check2_map", .key_size = sizeof(int), .value_size = 1, - .key_id = 1, - .value_id = 3, + .key_type_id = 1, + .value_type_id = 3, .max_entries = 4, .btf_load_err = true, - + .err_str = "Member exceeds struct_size", }, /* Test member exeeds the size of struct @@ -335,10 +340,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "size_check3_map", .key_size = sizeof(int), .value_size = 1, - .key_id = 1, - .value_id = 3, + .key_type_id = 1, + .value_type_id = 3, .max_entries = 4, .btf_load_err = true, + .err_str = "Member exceeds struct_size", }, /* Test member exceeds the size of struct @@ -376,10 +382,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "size_check4_map", .key_size = sizeof(int), .value_size = 1, - .key_id = 1, - .value_id = 3, + .key_type_id = 1, + .value_type_id = 3, .max_entries = 4, .btf_load_err = true, + .err_str = "Member exceeds struct_size", }, /* typedef const void * const_void_ptr; @@ -411,8 +418,8 @@ static struct btf_raw_test raw_tests[] = { .map_name = "void_test1_map", .key_size = sizeof(int), .value_size = sizeof(void *), - .key_id = 1, - .value_id = 4, + .key_type_id = 1, + .value_type_id = 4, .max_entries = 4, }, @@ -440,10 +447,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "void_test2_map", .key_size = sizeof(int), .value_size = sizeof(void *), - .key_id = 1, - .value_id = 3, + .key_type_id = 1, + .value_type_id = 3, .max_entries = 4, .btf_load_err = true, + .err_str = "Invalid member", }, /* typedef const void * const_void_ptr; @@ -458,9 +466,9 @@ static struct btf_raw_test raw_tests[] = { BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0), /* const void* */ /* [3] */ BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2), - /* typedef const void * const_void_ptr */ + /* typedef const void * const_void_ptr */ /* [4] */ BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3), - /* const_void_ptr[4] */ /* [4] */ + /* const_void_ptr[4] */ /* [5] */ BTF_TYPE_ARRAY_ENC(3, 1, 4), BTF_END_RAW, }, @@ -470,8 +478,8 @@ static struct btf_raw_test raw_tests[] = { .map_name = "void_test3_map", .key_size = sizeof(int), .value_size = sizeof(void *) * 4, - .key_id = 1, - .value_id = 4, + .key_type_id = 1, + .value_type_id = 4, .max_entries = 4, }, @@ -493,10 +501,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "void_test4_map", .key_size = sizeof(int), .value_size = sizeof(void *) * 4, - .key_id = 1, - .value_id = 3, + .key_type_id = 1, + .value_type_id = 3, .max_entries = 4, .btf_load_err = true, + .err_str = "Invalid elem", }, /* Array_A <------------------+ @@ -523,10 +532,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test1_map", .key_size = sizeof(int), .value_size = sizeof(sizeof(int) * 8), - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, /* typedef is _before_ the BTF type of Array_A and Array_B @@ -551,7 +561,6 @@ static struct btf_raw_test raw_tests[] = { BTF_TYPE_ARRAY_ENC(2, 1, 8), /* [3] */ /* Array_B */ BTF_TYPE_ARRAY_ENC(3, 1, 8), /* [4] */ - BTF_END_RAW, }, .str_sec = "\0int_array\0", @@ -560,10 +569,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test2_map", .key_size = sizeof(int), .value_size = sizeof(sizeof(int) * 8), - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, /* Array_A <------------------+ @@ -582,7 +592,6 @@ static struct btf_raw_test raw_tests[] = { BTF_TYPE_ARRAY_ENC(3, 1, 8), /* Array_B */ /* [3] */ BTF_TYPE_ARRAY_ENC(2, 1, 8), - BTF_END_RAW, }, .str_sec = "", @@ -591,10 +600,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test3_map", .key_size = sizeof(int), .value_size = sizeof(sizeof(int) * 8), - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, /* typedef is _between_ the BTF type of Array_A and Array_B @@ -627,10 +637,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test4_map", .key_size = sizeof(int), .value_size = sizeof(sizeof(int) * 8), - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, /* typedef struct B Struct_B @@ -668,10 +679,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test5_map", .key_size = sizeof(int), .value_size = 8, - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, /* struct A { @@ -697,10 +709,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test6_map", .key_size = sizeof(int), .value_size = 8, - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, { @@ -724,10 +737,11 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test7_map", .key_size = sizeof(int), .value_size = sizeof(void *), - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, { @@ -759,34 +773,73 @@ static struct btf_raw_test raw_tests[] = { .map_name = "loop_test8_map", .key_size = sizeof(int), .value_size = sizeof(void *), - .key_id = 1, - .value_id = 2, + .key_type_id = 1, + .value_type_id = 2, .max_entries = 4, .btf_load_err = true, + .err_str = "Loop detected", }, { - .descr = "type_off == str_off", + .descr = "string section does not end with null", .raw_types = { /* int */ /* [1] */ BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), BTF_END_RAW, }, .str_sec = "\0int", + .str_sec_size = sizeof("\0int") - 1, + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "hdr_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid string section", +}, + +{ + .descr = "empty string section", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = 0, + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "hdr_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid string section", +}, + +{ + .descr = "empty type section", + .raw_types = { + BTF_END_RAW, + }, + .str_sec = "\0int", .str_sec_size = sizeof("\0int"), .map_type = BPF_MAP_TYPE_ARRAY, .map_name = "hdr_test_map", .key_size = sizeof(int), .value_size = sizeof(int), - .key_id = 1, - .value_id = 1, + .key_type_id = 1, + .value_type_id = 1, .max_entries = 4, .btf_load_err = true, - .type_off_delta = sizeof(struct btf_type) + sizeof(int) + sizeof("\0int"), + .err_str = "No type found", }, { - .descr = "Unaligned type_off", + .descr = "btf_header test. Longer hdr_len", .raw_types = { /* int */ /* [1] */ BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), @@ -798,15 +851,16 @@ static struct btf_raw_test raw_tests[] = { .map_name = "hdr_test_map", .key_size = sizeof(int), .value_size = sizeof(int), - .key_id = 1, - .value_id = 1, + .key_type_id = 1, + .value_type_id = 1, .max_entries = 4, .btf_load_err = true, - .type_off_delta = 1, + .hdr_len_delta = 4, + .err_str = "Unsupported btf_header", }, { - .descr = "str_off beyonds btf size", + .descr = "btf_header test. Gap between hdr and type", .raw_types = { /* int */ /* [1] */ BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), @@ -818,15 +872,16 @@ static struct btf_raw_test raw_tests[] = { .map_name = "hdr_test_map", .key_size = sizeof(int), .value_size = sizeof(int), - .key_id = 1, - .value_id = 1, + .key_type_id = 1, + .value_type_id = 1, .max_entries = 4, .btf_load_err = true, - .str_off_delta = sizeof("\0int") + 1, + .type_off_delta = 4, + .err_str = "Unsupported section found", }, { - .descr = "str_len beyonds btf size", + .descr = "btf_header test. Gap between type and str", .raw_types = { /* int */ /* [1] */ BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), @@ -838,15 +893,16 @@ static struct btf_raw_test raw_tests[] = { .map_name = "hdr_test_map", .key_size = sizeof(int), .value_size = sizeof(int), - .key_id = 1, - .value_id = 1, + .key_type_id = 1, + .value_type_id = 1, .max_entries = 4, .btf_load_err = true, - .str_len_delta = 1, + .str_off_delta = 4, + .err_str = "Unsupported section found", }, { - .descr = "String section does not end with null", + .descr = "btf_header test. Overlap between type and str", .raw_types = { /* int */ /* [1] */ BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), @@ -858,15 +914,16 @@ static struct btf_raw_test raw_tests[] = { .map_name = "hdr_test_map", .key_size = sizeof(int), .value_size = sizeof(int), - .key_id = 1, - .value_id = 1, + .key_type_id = 1, + .value_type_id = 1, .max_entries = 4, .btf_load_err = true, - .str_len_delta = -1, + .str_off_delta = -4, + .err_str = "Section overlap found", }, { - .descr = "Empty string section", + .descr = "btf_header test. Larger BTF size", .raw_types = { /* int */ /* [1] */ BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), @@ -878,11 +935,288 @@ static struct btf_raw_test raw_tests[] = { .map_name = "hdr_test_map", .key_size = sizeof(int), .value_size = sizeof(int), - .key_id = 1, - .value_id = 1, + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .str_len_delta = -4, + .err_str = "Unsupported section found", +}, + +{ + .descr = "btf_header test. Smaller BTF size", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), + BTF_END_RAW, + }, + .str_sec = "\0int", + .str_sec_size = sizeof("\0int"), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "hdr_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .str_len_delta = 4, + .err_str = "Total section length too long", +}, + +{ + .descr = "array test. index_type/elem_type \"int\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* int[16] */ /* [2] */ + BTF_TYPE_ARRAY_ENC(1, 1, 16), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "array test. index_type/elem_type \"const int\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* int[16] */ /* [2] */ + BTF_TYPE_ARRAY_ENC(3, 3, 16), + /* CONST type_id=1 */ /* [3] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 1), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "array test. index_type \"const int:31\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* int:31 */ /* [2] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 31, 4), + /* int[16] */ /* [3] */ + BTF_TYPE_ARRAY_ENC(1, 4, 16), + /* CONST type_id=2 */ /* [4] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 2), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid index", +}, + +{ + .descr = "array test. elem_type \"const int:31\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* int:31 */ /* [2] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 31, 4), + /* int[16] */ /* [3] */ + BTF_TYPE_ARRAY_ENC(4, 1, 16), + /* CONST type_id=2 */ /* [4] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 2), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid array of int", +}, + +{ + .descr = "array test. index_type \"void\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* int[16] */ /* [2] */ + BTF_TYPE_ARRAY_ENC(1, 0, 16), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid index", +}, + +{ + .descr = "array test. index_type \"const void\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* int[16] */ /* [2] */ + BTF_TYPE_ARRAY_ENC(1, 3, 16), + /* CONST type_id=0 (void) */ /* [3] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid index", +}, + +{ + .descr = "array test. elem_type \"const void\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* int[16] */ /* [2] */ + BTF_TYPE_ARRAY_ENC(3, 1, 16), + /* CONST type_id=0 (void) */ /* [3] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid elem", +}, + +{ + .descr = "array test. elem_type \"const void *\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* const void *[16] */ /* [2] */ + BTF_TYPE_ARRAY_ENC(3, 1, 16), + /* CONST type_id=4 */ /* [3] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 4), + /* void* */ /* [4] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, +}, + +{ + .descr = "array test. index_type \"const void *\"", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + /* const void *[16] */ /* [2] */ + BTF_TYPE_ARRAY_ENC(3, 3, 16), + /* CONST type_id=4 */ /* [3] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 4), + /* void* */ /* [4] */ + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, .max_entries = 4, .btf_load_err = true, - .str_len_delta = 0 - (int)sizeof("\0int"), + .err_str = "Invalid index", +}, + +{ + .descr = "int test. invalid int_data", + .raw_types = { + BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), 4), + 0x10000000, + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid int_data", +}, + +{ + .descr = "invalid BTF_INFO", + .raw_types = { + /* int */ /* [1] */ + BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), + BTF_TYPE_ENC(0, 0x10000000, 4), + BTF_END_RAW, + }, + .str_sec = "", + .str_sec_size = sizeof(""), + .map_type = BPF_MAP_TYPE_ARRAY, + .map_name = "array_test_map", + .key_size = sizeof(int), + .value_size = sizeof(int), + .key_type_id = 1, + .value_type_id = 1, + .max_entries = 4, + .btf_load_err = true, + .err_str = "Invalid btf_info", }, }; /* struct btf_raw_test raw_tests[] */ @@ -951,6 +1285,7 @@ static void *btf_raw_create(const struct btf_header *hdr, memcpy(raw_btf + offset, str, str_sec_size); ret_hdr = (struct btf_header *)raw_btf; + ret_hdr->type_len = type_sec_size; ret_hdr->str_off = type_sec_size; ret_hdr->str_len = str_sec_size; @@ -981,6 +1316,7 @@ static int do_test_raw(unsigned int test_num) hdr = raw_btf; + hdr->hdr_len = (int)hdr->hdr_len + test->hdr_len_delta; hdr->type_off = (int)hdr->type_off + test->type_off_delta; hdr->str_off = (int)hdr->str_off + test->str_off_delta; hdr->str_len = (int)hdr->str_len + test->str_len_delta; @@ -992,8 +1328,13 @@ static int do_test_raw(unsigned int test_num) free(raw_btf); err = ((btf_fd == -1) != test->btf_load_err); - CHECK(err, "btf_fd:%d test->btf_load_err:%u", - btf_fd, test->btf_load_err); + if (CHECK(err, "btf_fd:%d test->btf_load_err:%u", + btf_fd, test->btf_load_err) || + CHECK(test->err_str && !strstr(btf_log_buf, test->err_str), + "expected err_str:%s", test->err_str)) { + err = -1; + goto done; + } if (err || btf_fd == -1) goto done; @@ -1004,8 +1345,8 @@ static int do_test_raw(unsigned int test_num) create_attr.value_size = test->value_size; create_attr.max_entries = test->max_entries; create_attr.btf_fd = btf_fd; - create_attr.btf_key_id = test->key_id; - create_attr.btf_value_id = test->value_id; + create_attr.btf_key_type_id = test->key_type_id; + create_attr.btf_value_type_id = test->value_type_id; map_fd = bpf_create_map_xattr(&create_attr); @@ -1267,8 +1608,8 @@ static int test_btf_id(unsigned int test_num) create_attr.value_size = sizeof(unsigned int); create_attr.max_entries = 4; create_attr.btf_fd = btf_fd[0]; - create_attr.btf_key_id = 1; - create_attr.btf_value_id = 2; + create_attr.btf_key_type_id = 1; + create_attr.btf_value_type_id = 2; map_fd = bpf_create_map_xattr(&create_attr); if (CHECK(map_fd == -1, "errno:%d", errno)) { @@ -1279,10 +1620,10 @@ static int test_btf_id(unsigned int test_num) info_len = sizeof(map_info); err = bpf_obj_get_info_by_fd(map_fd, &map_info, &info_len); if (CHECK(err || map_info.btf_id != info[0].id || - map_info.btf_key_id != 1 || map_info.btf_value_id != 2, - "err:%d errno:%d info.id:%u btf_id:%u btf_key_id:%u btf_value_id:%u", - err, errno, info[0].id, map_info.btf_id, map_info.btf_key_id, - map_info.btf_value_id)) { + map_info.btf_key_type_id != 1 || map_info.btf_value_type_id != 2, + "err:%d errno:%d info.id:%u btf_id:%u btf_key_type_id:%u btf_value_type_id:%u", + err, errno, info[0].id, map_info.btf_id, map_info.btf_key_type_id, + map_info.btf_value_type_id)) { err = -1; goto done; } @@ -1542,10 +1883,10 @@ static int do_test_file(unsigned int test_num) goto done; } - err = (bpf_map__btf_key_id(map) == 0 || bpf_map__btf_value_id(map) == 0) + err = (bpf_map__btf_key_type_id(map) == 0 || bpf_map__btf_value_type_id(map) == 0) != test->btf_kv_notfound; - if (CHECK(err, "btf_key_id:%u btf_value_id:%u test->btf_kv_notfound:%u", - bpf_map__btf_key_id(map), bpf_map__btf_value_id(map), + if (CHECK(err, "btf_key_type_id:%u btf_value_type_id:%u test->btf_kv_notfound:%u", + bpf_map__btf_key_type_id(map), bpf_map__btf_value_type_id(map), test->btf_kv_notfound)) goto done; @@ -1615,7 +1956,7 @@ static struct btf_raw_test pprint_test = { /* 28 bits */ /* [7] */ BTF_TYPE_INT_ENC(0, 0, 0, 28, 4), /* uint8_t[8] */ /* [8] */ - BTF_TYPE_ARRAY_ENC(9, 3, 8), + BTF_TYPE_ARRAY_ENC(9, 1, 8), /* typedef unsigned char uint8_t */ /* [9] */ BTF_TYPEDEF_ENC(NAME_TBD, 1), /* typedef unsigned short uint16_t */ /* [10] */ @@ -1654,8 +1995,8 @@ static struct btf_raw_test pprint_test = { .map_name = "pprint_test", .key_size = sizeof(unsigned int), .value_size = sizeof(struct pprint_mapv), - .key_id = 3, /* unsigned int */ - .value_id = 16, /* struct pprint_mapv */ + .key_type_id = 3, /* unsigned int */ + .value_type_id = 16, /* struct pprint_mapv */ .max_entries = 128 * 1024, }; @@ -1712,8 +2053,8 @@ static int test_pprint(void) create_attr.value_size = test->value_size; create_attr.max_entries = test->max_entries; create_attr.btf_fd = btf_fd; - create_attr.btf_key_id = test->key_id; - create_attr.btf_value_id = test->value_id; + create_attr.btf_key_type_id = test->key_type_id; + create_attr.btf_value_type_id = test->value_type_id; map_fd = bpf_create_map_xattr(&create_attr); if (CHECK(map_fd == -1, "errno:%d", errno)) { -- cgit v1.2.3 From 30687ad94e57b53dd66950ab570203dfd1f9db34 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 24 May 2018 11:21:10 -0700 Subject: tools/bpf: sync kernel header bpf.h and add bpf_task_fd_query in libbpf Sync kernel header bpf.h to tools/include/uapi/linux/bpf.h and implement bpf_task_fd_query() in libbpf. The test programs in samples/bpf and tools/testing/selftests/bpf, and later bpftool will use this libbpf function to query kernel. Acked-by: Martin KaFai Lau Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/include/uapi/linux/bpf.h | 26 ++++++++++++++++++++++++++ tools/lib/bpf/bpf.c | 23 +++++++++++++++++++++++ tools/lib/bpf/bpf.h | 3 +++ 3 files changed, 52 insertions(+) (limited to 'tools/lib/bpf/bpf.c') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e95fec90c2c1..9b8c6e310e9a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -97,6 +97,7 @@ enum bpf_cmd { BPF_RAW_TRACEPOINT_OPEN, BPF_BTF_LOAD, BPF_BTF_GET_FD_BY_ID, + BPF_TASK_FD_QUERY, }; enum bpf_map_type { @@ -380,6 +381,22 @@ union bpf_attr { __u32 btf_log_size; __u32 btf_log_level; }; + + struct { + __u32 pid; /* input: pid */ + __u32 fd; /* input: fd */ + __u32 flags; /* input: flags */ + __u32 buf_len; /* input/output: buf len */ + __aligned_u64 buf; /* input/output: + * tp_name for tracepoint + * symbol for kprobe + * filename for uprobe + */ + __u32 prog_id; /* output: prod_id */ + __u32 fd_type; /* output: BPF_FD_TYPE_* */ + __u64 probe_offset; /* output: probe_offset */ + __u64 probe_addr; /* output: probe_addr */ + } task_fd_query; } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF @@ -2557,4 +2574,13 @@ struct bpf_fib_lookup { __u8 dmac[6]; /* ETH_ALEN */ }; +enum bpf_task_fd_type { + BPF_FD_TYPE_RAW_TRACEPOINT, /* tp name */ + BPF_FD_TYPE_TRACEPOINT, /* tp name */ + BPF_FD_TYPE_KPROBE, /* (symbol + offset) or addr */ + BPF_FD_TYPE_KRETPROBE, /* (symbol + offset) or addr */ + BPF_FD_TYPE_UPROBE, /* filename + offset */ + BPF_FD_TYPE_URETPROBE, /* filename + offset */ +}; + #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 442b4cdfeb71..9ddc89dae962 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -643,3 +643,26 @@ retry: return fd; } + +int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, + __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, + __u64 *probe_addr) +{ + union bpf_attr attr = {}; + int err; + + attr.task_fd_query.pid = pid; + attr.task_fd_query.fd = fd; + attr.task_fd_query.flags = flags; + attr.task_fd_query.buf = ptr_to_u64(buf); + attr.task_fd_query.buf_len = *buf_len; + + err = sys_bpf(BPF_TASK_FD_QUERY, &attr, sizeof(attr)); + *buf_len = attr.task_fd_query.buf_len; + *prog_id = attr.task_fd_query.prog_id; + *fd_type = attr.task_fd_query.fd_type; + *probe_offset = attr.task_fd_query.probe_offset; + *probe_addr = attr.task_fd_query.probe_addr; + + return err; +} diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index d12344f66d4e..0639a30a457d 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -107,4 +107,7 @@ int bpf_prog_query(int target_fd, enum bpf_attach_type type, __u32 query_flags, int bpf_raw_tracepoint_open(const char *name, int prog_fd); int bpf_load_btf(void *btf, __u32 btf_size, char *log_buf, __u32 log_buf_size, bool do_log); +int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, __u32 *buf_len, + __u32 *prog_id, __u32 *fd_type, __u64 *probe_offset, + __u64 *probe_addr); #endif -- cgit v1.2.3