forked from mirrors/linux
		
	bpf: Introduce BPF_ANNOTATE_KV_PAIR
This patch introduces BPF_ANNOTATE_KV_PAIR to signal the
bpf loader about the btf key_type and value_type of a bpf map.
Please refer to the changes in test_btf_haskv.c for its usage.
Both iproute2 and libbpf loader will then have the same
convention to find out the map's btf_key_type_id and
btf_value_type_id from a map's name.
Fixes: 8a138aed4a ("bpf: btf: Add BTF support to libbpf")
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
			
			
This commit is contained in:
		
							parent
							
								
									5b891af7fc
								
							
						
					
					
						commit
						38d5d3b3d5
					
				
					 5 changed files with 57 additions and 45 deletions
				
			
		|  | @ -189,8 +189,7 @@ static int btf_parse_type_sec(struct btf *btf, btf_print_fn_t err_log) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static const struct btf_type *btf_type_by_id(const struct btf *btf, | const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id) | ||||||
| 					     __u32 type_id) |  | ||||||
| { | { | ||||||
| 	if (type_id > btf->nr_types) | 	if (type_id > btf->nr_types) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  | @ -233,7 +232,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) | ||||||
| 	__s64 size = -1; | 	__s64 size = -1; | ||||||
| 	int i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	t = btf_type_by_id(btf, type_id); | 	t = btf__type_by_id(btf, type_id); | ||||||
| 	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); | 	for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t); | ||||||
| 	     i++) { | 	     i++) { | ||||||
| 		size = btf_type_size(t); | 		size = btf_type_size(t); | ||||||
|  | @ -258,7 +257,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		t = btf_type_by_id(btf, type_id); | 		t = btf__type_by_id(btf, type_id); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (size < 0) | 	if (size < 0) | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #define BTF_ELF_SEC ".BTF" | #define BTF_ELF_SEC ".BTF" | ||||||
| 
 | 
 | ||||||
| struct btf; | struct btf; | ||||||
|  | struct btf_type; | ||||||
| 
 | 
 | ||||||
| typedef int (*btf_print_fn_t)(const char *, ...) | typedef int (*btf_print_fn_t)(const char *, ...) | ||||||
| 	__attribute__((format(printf, 1, 2))); | 	__attribute__((format(printf, 1, 2))); | ||||||
|  | @ -16,6 +17,7 @@ typedef int (*btf_print_fn_t)(const char *, ...) | ||||||
| void btf__free(struct btf *btf); | void btf__free(struct btf *btf); | ||||||
| struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); | struct btf *btf__new(__u8 *data, __u32 size, btf_print_fn_t err_log); | ||||||
| __s32 btf__find_by_name(const struct btf *btf, const char *type_name); | __s32 btf__find_by_name(const struct btf *btf, const char *type_name); | ||||||
|  | const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 id); | ||||||
| __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); | __s64 btf__resolve_size(const struct btf *btf, __u32 type_id); | ||||||
| int btf__fd(const struct btf *btf); | int btf__fd(const struct btf *btf); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -36,6 +36,7 @@ | ||||||
| #include <linux/err.h> | #include <linux/err.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| #include <linux/bpf.h> | #include <linux/bpf.h> | ||||||
|  | #include <linux/btf.h> | ||||||
| #include <linux/list.h> | #include <linux/list.h> | ||||||
| #include <linux/limits.h> | #include <linux/limits.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
|  | @ -1014,68 +1015,72 @@ bpf_program__collect_reloc(struct bpf_program *prog, GElf_Shdr *shdr, | ||||||
| 
 | 
 | ||||||
| static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) | static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf) | ||||||
| { | { | ||||||
|  | 	const struct btf_type *container_type; | ||||||
|  | 	const struct btf_member *key, *value; | ||||||
| 	struct bpf_map_def *def = &map->def; | 	struct bpf_map_def *def = &map->def; | ||||||
| 	const size_t max_name = 256; | 	const size_t max_name = 256; | ||||||
|  | 	char container_name[max_name]; | ||||||
| 	__s64 key_size, value_size; | 	__s64 key_size, value_size; | ||||||
| 	__s32 key_id, value_id; | 	__s32 container_id; | ||||||
| 	char name[max_name]; |  | ||||||
| 
 | 
 | ||||||
| 	/* Find key type by name from BTF */ | 	if (snprintf(container_name, max_name, "____btf_map_%s", map->name) == | ||||||
| 	if (snprintf(name, max_name, "%s_key", map->name) == max_name) { | 	    max_name) { | ||||||
| 		pr_warning("map:%s length of BTF key_type:%s_key is too long\n", | 		pr_warning("map:%s length of '____btf_map_%s' is too long\n", | ||||||
| 			   map->name, map->name); | 			   map->name, map->name); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	key_id = btf__find_by_name(btf, name); | 	container_id = btf__find_by_name(btf, container_name); | ||||||
| 	if (key_id < 0) { | 	if (container_id < 0) { | ||||||
| 		pr_debug("map:%s key_type:%s cannot be found in BTF\n", | 		pr_debug("map:%s container_name:%s cannot be found in BTF. Missing BPF_ANNOTATE_KV_PAIR?\n", | ||||||
| 			 map->name, name); | 			 map->name, container_name); | ||||||
| 		return key_id; | 		return container_id; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	key_size = btf__resolve_size(btf, key_id); | 	container_type = btf__type_by_id(btf, container_id); | ||||||
|  | 	if (!container_type) { | ||||||
|  | 		pr_warning("map:%s cannot find BTF type for container_id:%u\n", | ||||||
|  | 			   map->name, container_id); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (BTF_INFO_KIND(container_type->info) != BTF_KIND_STRUCT || | ||||||
|  | 	    BTF_INFO_VLEN(container_type->info) < 2) { | ||||||
|  | 		pr_warning("map:%s container_name:%s is an invalid container struct\n", | ||||||
|  | 			   map->name, container_name); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	key = (struct btf_member *)(container_type + 1); | ||||||
|  | 	value = key + 1; | ||||||
|  | 
 | ||||||
|  | 	key_size = btf__resolve_size(btf, key->type); | ||||||
| 	if (key_size < 0) { | 	if (key_size < 0) { | ||||||
| 		pr_warning("map:%s key_type:%s cannot get the BTF type_size\n", | 		pr_warning("map:%s invalid BTF key_type_size\n", | ||||||
| 			   map->name, name); | 			   map->name); | ||||||
| 		return key_size; | 		return key_size; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (def->key_size != key_size) { | 	if (def->key_size != key_size) { | ||||||
| 		pr_warning("map:%s key_type:%s has BTF type_size:%u != key_size:%u\n", | 		pr_warning("map:%s btf_key_type_size:%u != map_def_key_size:%u\n", | ||||||
| 			   map->name, name, (unsigned int)key_size, def->key_size); | 			   map->name, (__u32)key_size, def->key_size); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Find value type from BTF */ | 	value_size = btf__resolve_size(btf, value->type); | ||||||
| 	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) { | 	if (value_size < 0) { | ||||||
| 		pr_warning("map:%s value_type:%s cannot get the BTF type_size\n", | 		pr_warning("map:%s invalid BTF value_type_size\n", map->name); | ||||||
| 			   map->name, name); |  | ||||||
| 		return value_size; | 		return value_size; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (def->value_size != value_size) { | 	if (def->value_size != value_size) { | ||||||
| 		pr_warning("map:%s value_type:%s has BTF type_size:%u != value_size:%u\n", | 		pr_warning("map:%s btf_value_type_size:%u != map_def_value_size:%u\n", | ||||||
| 			   map->name, name, (unsigned int)value_size, def->value_size); | 			   map->name, (__u32)value_size, def->value_size); | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	map->btf_key_type_id = key_id; | 	map->btf_key_type_id = key->type; | ||||||
| 	map->btf_value_type_id = value_id; | 	map->btf_value_type_id = value->type; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -158,6 +158,15 @@ struct bpf_map_def { | ||||||
| 	unsigned int numa_node; | 	unsigned int numa_node; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val)		\ | ||||||
|  | 	struct ____btf_map_##name {				\ | ||||||
|  | 		type_key key;					\ | ||||||
|  | 		type_val value;					\ | ||||||
|  | 	};							\ | ||||||
|  | 	struct ____btf_map_##name				\ | ||||||
|  | 	__attribute__ ((section(".maps." #name), used))		\ | ||||||
|  | 		____btf_map_##name = { } | ||||||
|  | 
 | ||||||
| static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = | static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = | ||||||
| 	(void *) BPF_FUNC_skb_load_bytes; | 	(void *) BPF_FUNC_skb_load_bytes; | ||||||
| static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = | static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = | ||||||
|  |  | ||||||
|  | @ -10,11 +10,6 @@ struct ipv_counts { | ||||||
| 	unsigned int v6; | 	unsigned int v6; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef int btf_map_key; |  | ||||||
| typedef struct ipv_counts btf_map_value; |  | ||||||
| btf_map_key dumm_key; |  | ||||||
| btf_map_value dummy_value; |  | ||||||
| 
 |  | ||||||
| struct bpf_map_def SEC("maps") btf_map = { | struct bpf_map_def SEC("maps") btf_map = { | ||||||
| 	.type = BPF_MAP_TYPE_ARRAY, | 	.type = BPF_MAP_TYPE_ARRAY, | ||||||
| 	.key_size = sizeof(int), | 	.key_size = sizeof(int), | ||||||
|  | @ -22,6 +17,8 @@ struct bpf_map_def SEC("maps") btf_map = { | ||||||
| 	.max_entries = 4, | 	.max_entries = 4, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts); | ||||||
|  | 
 | ||||||
| struct dummy_tracepoint_args { | struct dummy_tracepoint_args { | ||||||
| 	unsigned long long pad; | 	unsigned long long pad; | ||||||
| 	struct sock *sock; | 	struct sock *sock; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Martin KaFai Lau
						Martin KaFai Lau