Commit 1713e33b authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'libbpf: deprecate legacy BPF map definitions'

Andrii Nakryiko says:

====================

Officially deprecate legacy BPF map definitions in libbpf. They've been slated
for deprecation for a while in favor of more powerful BTF-defined map
definitions and this patch set adds warnings and a way to enforce this in
libbpf through LIBBPF_STRICT_MAP_DEFINITIONS strict mode flag.

Selftests are fixed up and updated, BPF documentation is updated, bpftool's
strict mode usage is adjusted to avoid breaking users unnecessarily.

v1->v2:
  - replace missed bpf_map_def case in Documentation/bpf/btf.rst (Alexei).
====================
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 1058b6a7 96c85308
...@@ -565,18 +565,15 @@ A map can be created with ``btf_fd`` and specified key/value type id.:: ...@@ -565,18 +565,15 @@ A map can be created with ``btf_fd`` and specified key/value type id.::
In libbpf, the map can be defined with extra annotation like below: In libbpf, the map can be defined with extra annotation like below:
:: ::
struct bpf_map_def SEC("maps") btf_map = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __type(key, int);
.value_size = sizeof(struct ipv_counts), __type(value, struct ipv_counts);
.max_entries = 4, __uint(max_entries, 4);
}; } btf_map SEC(".maps");
BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts);
Here, the parameters for macro BPF_ANNOTATE_KV_PAIR are map name, key and During ELF parsing, libbpf is able to extract key/value type_id's and assign
value types for the map. During ELF parsing, libbpf is able to extract them to BPF_MAP_CREATE attributes automatically.
key/value type_id's and assign them to BPF_MAP_CREATE attributes
automatically.
.. _BPF_Prog_Load: .. _BPF_Prog_Load:
...@@ -824,13 +821,12 @@ structure has bitfields. For example, for the following map,:: ...@@ -824,13 +821,12 @@ structure has bitfields. For example, for the following map,::
___A b1:4; ___A b1:4;
enum A b2:4; enum A b2:4;
}; };
struct bpf_map_def SEC("maps") tmpmap = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(__u32), __type(key, int);
.value_size = sizeof(struct tmp_t), __type(value, struct tmp_t);
.max_entries = 1, __uint(max_entries, 1);
}; } tmpmap SEC(".maps");
BPF_ANNOTATE_KV_PAIR(tmpmap, int, struct tmp_t);
bpftool is able to pretty print like below: bpftool is able to pretty print like below:
:: ::
......
...@@ -478,7 +478,14 @@ int main(int argc, char **argv) ...@@ -478,7 +478,14 @@ int main(int argc, char **argv)
} }
if (!legacy_libbpf) { if (!legacy_libbpf) {
ret = libbpf_set_strict_mode(LIBBPF_STRICT_ALL); enum libbpf_strict_mode mode;
/* Allow legacy map definitions for skeleton generation.
* It will still be rejected if users use LIBBPF_STRICT_ALL
* mode for loading generated skeleton.
*/
mode = (__LIBBPF_STRICT_LAST - 1) & ~LIBBPF_STRICT_MAP_DEFINITIONS;
ret = libbpf_set_strict_mode(mode);
if (ret) if (ret)
p_err("failed to enable libbpf strict mode: %d", ret); p_err("failed to enable libbpf strict mode: %d", ret);
} }
......
...@@ -133,7 +133,7 @@ struct bpf_map_def { ...@@ -133,7 +133,7 @@ struct bpf_map_def {
unsigned int value_size; unsigned int value_size;
unsigned int max_entries; unsigned int max_entries;
unsigned int map_flags; unsigned int map_flags;
}; } __attribute__((deprecated("use BTF-defined maps in .maps section")));
enum libbpf_pin_type { enum libbpf_pin_type {
LIBBPF_PIN_NONE, LIBBPF_PIN_NONE,
......
...@@ -1937,6 +1937,11 @@ static int bpf_object__init_user_maps(struct bpf_object *obj, bool strict) ...@@ -1937,6 +1937,11 @@ static int bpf_object__init_user_maps(struct bpf_object *obj, bool strict)
if (obj->efile.maps_shndx < 0) if (obj->efile.maps_shndx < 0)
return 0; return 0;
if (libbpf_mode & LIBBPF_STRICT_MAP_DEFINITIONS) {
pr_warn("legacy map definitions in SEC(\"maps\") are not supported\n");
return -EOPNOTSUPP;
}
if (!symbols) if (!symbols)
return -EINVAL; return -EINVAL;
...@@ -1999,6 +2004,8 @@ static int bpf_object__init_user_maps(struct bpf_object *obj, bool strict) ...@@ -1999,6 +2004,8 @@ static int bpf_object__init_user_maps(struct bpf_object *obj, bool strict)
return -LIBBPF_ERRNO__FORMAT; return -LIBBPF_ERRNO__FORMAT;
} }
pr_warn("map '%s' (legacy): legacy map definitions are deprecated, use BTF-defined maps instead\n", map_name);
if (ELF64_ST_BIND(sym->st_info) == STB_LOCAL) { if (ELF64_ST_BIND(sym->st_info) == STB_LOCAL) {
pr_warn("map '%s' (legacy): static maps are not supported\n", map_name); pr_warn("map '%s' (legacy): static maps are not supported\n", map_name);
return -ENOTSUP; return -ENOTSUP;
...@@ -4190,6 +4197,7 @@ static int bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map) ...@@ -4190,6 +4197,7 @@ static int bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map)
return 0; return 0;
if (!bpf_map__is_internal(map)) { if (!bpf_map__is_internal(map)) {
pr_warn("Use of BPF_ANNOTATE_KV_PAIR is deprecated, use BTF-defined maps in .maps section instead\n");
ret = btf__get_map_kv_tids(obj->btf, map->name, def->key_size, ret = btf__get_map_kv_tids(obj->btf, map->name, def->key_size,
def->value_size, &key_type_id, def->value_size, &key_type_id,
&value_type_id); &value_type_id);
......
...@@ -73,6 +73,11 @@ enum libbpf_strict_mode { ...@@ -73,6 +73,11 @@ enum libbpf_strict_mode {
* operation. * operation.
*/ */
LIBBPF_STRICT_AUTO_RLIMIT_MEMLOCK = 0x10, LIBBPF_STRICT_AUTO_RLIMIT_MEMLOCK = 0x10,
/*
* Error out on any SEC("maps") map definition, which are deprecated
* in favor of BTF-defined map definitions in SEC(".maps").
*/
LIBBPF_STRICT_MAP_DEFINITIONS = 0x20,
__LIBBPF_STRICT_LAST, __LIBBPF_STRICT_LAST,
}; };
......
...@@ -21,7 +21,7 @@ endif ...@@ -21,7 +21,7 @@ endif
BPF_GCC ?= $(shell command -v bpf-gcc;) BPF_GCC ?= $(shell command -v bpf-gcc;)
SAN_CFLAGS ?= SAN_CFLAGS ?=
CFLAGS += -g -O0 -rdynamic -Wall $(GENFLAGS) $(SAN_CFLAGS) \ CFLAGS += -g -O0 -rdynamic -Wall -Werror $(GENFLAGS) $(SAN_CFLAGS) \
-I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \ -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
-I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT) -I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT)
LDFLAGS += $(SAN_CFLAGS) LDFLAGS += $(SAN_CFLAGS)
...@@ -292,7 +292,7 @@ IS_LITTLE_ENDIAN = $(shell $(CC) -dM -E - </dev/null | \ ...@@ -292,7 +292,7 @@ IS_LITTLE_ENDIAN = $(shell $(CC) -dM -E - </dev/null | \
MENDIAN=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian) MENDIAN=$(if $(IS_LITTLE_ENDIAN),-mlittle-endian,-mbig-endian)
CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG)) CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG))
BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \ BPF_CFLAGS = -g -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \
-I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \ -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \
-I$(abspath $(OUTPUT)/../usr/include) -I$(abspath $(OUTPUT)/../usr/include)
......
...@@ -4560,6 +4560,8 @@ static void do_test_file(unsigned int test_num) ...@@ -4560,6 +4560,8 @@ static void do_test_file(unsigned int test_num)
has_btf_ext = btf_ext != NULL; has_btf_ext = btf_ext != NULL;
btf_ext__free(btf_ext); btf_ext__free(btf_ext);
/* temporary disable LIBBPF_STRICT_MAP_DEFINITIONS to test legacy maps */
libbpf_set_strict_mode((__LIBBPF_STRICT_LAST - 1) & ~LIBBPF_STRICT_MAP_DEFINITIONS);
obj = bpf_object__open(test->file); obj = bpf_object__open(test->file);
err = libbpf_get_error(obj); err = libbpf_get_error(obj);
if (CHECK(err, "obj: %d", err)) if (CHECK(err, "obj: %d", err))
...@@ -4684,6 +4686,8 @@ static void do_test_file(unsigned int test_num) ...@@ -4684,6 +4686,8 @@ static void do_test_file(unsigned int test_num)
fprintf(stderr, "OK"); fprintf(stderr, "OK");
done: done:
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
btf__free(btf); btf__free(btf);
free(func_info); free(func_info);
bpf_object__close(obj); bpf_object__close(obj);
......
...@@ -7,12 +7,12 @@ ...@@ -7,12 +7,12 @@
#include <bpf/bpf_endian.h> #include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
struct bpf_map_def SEC("maps") sock_map = { struct {
.type = BPF_MAP_TYPE_SOCKMAP, __uint(type, BPF_MAP_TYPE_SOCKMAP);
.key_size = sizeof(int), __type(key, int);
.value_size = sizeof(int), __type(value, int);
.max_entries = 2, __uint(max_entries, 2);
}; } sock_map SEC(".maps");
SEC("freplace/cls_redirect") SEC("freplace/cls_redirect")
int freplace_cls_redirect_test(struct __sk_buff *skb) int freplace_cls_redirect_test(struct __sk_buff *skb)
......
...@@ -2,19 +2,19 @@ ...@@ -2,19 +2,19 @@
#include <linux/bpf.h> #include <linux/bpf.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
struct bpf_map_def SEC("maps") htab = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.key_size = sizeof(__u32), __type(key, __u32);
.value_size = sizeof(long), __type(value, long);
.max_entries = 2, __uint(max_entries, 2);
}; } htab SEC(".maps");
struct bpf_map_def SEC("maps") array = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(__u32), __type(key, __u32);
.value_size = sizeof(long), __type(value, long);
.max_entries = 2, __uint(max_entries, 2);
}; } array SEC(".maps");
/* Sample program which should always load for testing control paths. */ /* Sample program which should always load for testing control paths. */
SEC(".text") int func() SEC(".text") int func()
......
...@@ -9,12 +9,15 @@ struct ipv_counts { ...@@ -9,12 +9,15 @@ struct ipv_counts {
unsigned int v6; unsigned int v6;
}; };
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
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),
.value_size = sizeof(struct ipv_counts), .value_size = sizeof(struct ipv_counts),
.max_entries = 4, .max_entries = 4,
}; };
#pragma GCC diagnostic pop
BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts); BPF_ANNOTATE_KV_PAIR(btf_map, int, struct ipv_counts);
......
...@@ -9,6 +9,8 @@ struct ipv_counts { ...@@ -9,6 +9,8 @@ struct ipv_counts {
unsigned int v6; unsigned int v6;
}; };
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* just to validate we can handle maps in multiple sections */ /* just to validate we can handle maps in multiple sections */
struct bpf_map_def SEC("maps") btf_map_legacy = { struct bpf_map_def SEC("maps") btf_map_legacy = {
.type = BPF_MAP_TYPE_ARRAY, .type = BPF_MAP_TYPE_ARRAY,
...@@ -16,6 +18,7 @@ struct bpf_map_def SEC("maps") btf_map_legacy = { ...@@ -16,6 +18,7 @@ struct bpf_map_def SEC("maps") btf_map_legacy = {
.value_size = sizeof(long long), .value_size = sizeof(long long),
.max_entries = 4, .max_entries = 4,
}; };
#pragma GCC diagnostic pop
BPF_ANNOTATE_KV_PAIR(btf_map_legacy, int, struct ipv_counts); BPF_ANNOTATE_KV_PAIR(btf_map_legacy, int, struct ipv_counts);
......
...@@ -8,12 +8,12 @@ struct ipv_counts { ...@@ -8,12 +8,12 @@ struct ipv_counts {
unsigned int v6; unsigned int v6;
}; };
struct bpf_map_def SEC("maps") btf_map = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(int), __uint(key_size, sizeof(int));
.value_size = sizeof(struct ipv_counts), __uint(value_size, sizeof(struct ipv_counts));
.max_entries = 4, __uint(max_entries, 4);
}; } btf_map SEC(".maps");
__attribute__((noinline)) __attribute__((noinline))
int test_long_fname_2(void) int test_long_fname_2(void)
......
...@@ -10,12 +10,12 @@ ...@@ -10,12 +10,12 @@
#define NUM_CGROUP_LEVELS 4 #define NUM_CGROUP_LEVELS 4
struct bpf_map_def SEC("maps") cgroup_ids = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(__u32), __type(key, __u32);
.value_size = sizeof(__u64), __type(value, __u64);
.max_entries = NUM_CGROUP_LEVELS, __uint(max_entries, NUM_CGROUP_LEVELS);
}; } cgroup_ids SEC(".maps");
static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level) static __always_inline void log_nth_level(struct __sk_buff *skb, __u32 level)
{ {
......
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
#define THROTTLE_RATE_BPS (5 * 1000 * 1000) #define THROTTLE_RATE_BPS (5 * 1000 * 1000)
/* flow_key => last_tstamp timestamp used */ /* flow_key => last_tstamp timestamp used */
struct bpf_map_def SEC("maps") flow_map = { struct {
.type = BPF_MAP_TYPE_HASH, __uint(type, BPF_MAP_TYPE_HASH);
.key_size = sizeof(uint32_t), __type(key, uint32_t);
.value_size = sizeof(uint64_t), __type(value, uint64_t);
.max_entries = 1, __uint(max_entries, 1);
}; } flow_map SEC(".maps");
static inline int throttle_flow(struct __sk_buff *skb) static inline int throttle_flow(struct __sk_buff *skb)
{ {
......
...@@ -16,12 +16,12 @@ ...@@ -16,12 +16,12 @@
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h> #include <bpf/bpf_endian.h>
struct bpf_map_def SEC("maps") results = { struct {
.type = BPF_MAP_TYPE_ARRAY, __uint(type, BPF_MAP_TYPE_ARRAY);
.key_size = sizeof(__u32), __type(key, __u32);
.value_size = sizeof(__u32), __type(value, __u32);
.max_entries = 3, __uint(max_entries, 3);
}; } results SEC(".maps");
static __always_inline __s64 gen_syncookie(void *data_end, struct bpf_sock *sk, static __always_inline __s64 gen_syncookie(void *data_end, struct bpf_sock *sk,
void *iph, __u32 ip_size, void *iph, __u32 ip_size,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment