bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/6] BPF static linker: support static vars and maps
@ 2021-04-22  1:45 Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 1/6] selftests/bpf: document latest Clang fix expectations for linking tests Andrii Nakryiko
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Andrii Nakryiko @ 2021-04-22  1:45 UTC (permalink / raw)
  To: bpf, netdev, ast, daniel; +Cc: andrii, kernel-team

Deal with static variables and maps better to make them work with BPF skeleton
well. All static variables and maps are renamed in corresponding BTF
information so as to have an "<obj_name>.." prefix, which allows to
distinguish name-conflicting static entities between multiple linked files.

Also make libbpf support static maps properly. Previously static map reference
resulted in the most probably erroneous use of the very *first* defined map,
because it was the one with offset 0. Now static map references are resolved
properly and thus static maps are finally usable. BPF static linker already
supports static maps and no further changes are required, beyond variable
renaming.

Patch #1 adds missed documentation of the latest Clang dependency.

N.B. This patch set is based on top of patch set [0].

  [0] https://patchwork.kernel.org/project/netdevbpf/list/?series=468825

Andrii Nakryiko (6):
  selftests/bpf: document latest Clang fix expectations for linking
    tests
  libbpf: rename static variables during linking
  libbpf: support static map definitions
  bpftool: handle transformed static map names in BPF skeleton
  selftests/bpf: extend linked_vars selftests with static variables
  selftests/bpf: extend linked_maps selftests with static maps

 tools/bpf/bpftool/gen.c                       |  38 +++---
 tools/lib/bpf/libbpf.c                        |   7 +-
 tools/lib/bpf/libbpf.h                        |  12 +-
 tools/lib/bpf/linker.c                        | 121 +++++++++++++++++-
 tools/testing/selftests/bpf/README.rst        |   9 ++
 .../selftests/bpf/prog_tests/linked_maps.c    |  20 ++-
 .../selftests/bpf/prog_tests/linked_vars.c    |  12 +-
 .../selftests/bpf/prog_tests/skeleton.c       |   8 +-
 .../selftests/bpf/prog_tests/static_linked.c  |   8 +-
 .../selftests/bpf/progs/bpf_iter_test_kern4.c |   4 +-
 .../selftests/bpf/progs/linked_maps1.c        |  13 ++
 .../selftests/bpf/progs/linked_maps2.c        |  18 +++
 .../selftests/bpf/progs/linked_vars1.c        |   4 +-
 .../selftests/bpf/progs/linked_vars2.c        |   4 +-
 .../selftests/bpf/progs/test_check_mtu.c      |   4 +-
 .../selftests/bpf/progs/test_cls_redirect.c   |   4 +-
 .../bpf/progs/test_snprintf_single.c          |   2 +-
 .../selftests/bpf/progs/test_sockmap_listen.c |   4 +-
 .../selftests/bpf/progs/test_static_linked1.c |   6 +-
 .../selftests/bpf/progs/test_static_linked2.c |   4 +-
 20 files changed, 251 insertions(+), 51 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 1/6] selftests/bpf: document latest Clang fix expectations for linking tests
  2021-04-22  1:45 [PATCH bpf-next 0/6] BPF static linker: support static vars and maps Andrii Nakryiko
@ 2021-04-22  1:45 ` Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 2/6] libbpf: rename static variables during linking Andrii Nakryiko
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Andrii Nakryiko @ 2021-04-22  1:45 UTC (permalink / raw)
  To: bpf, netdev, ast, daniel; +Cc: andrii, kernel-team

Document which fixes are required to generate correct static linking
selftests.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/testing/selftests/bpf/README.rst | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/tools/testing/selftests/bpf/README.rst b/tools/testing/selftests/bpf/README.rst
index 65fe318d1e71..3353778c30f8 100644
--- a/tools/testing/selftests/bpf/README.rst
+++ b/tools/testing/selftests/bpf/README.rst
@@ -193,3 +193,12 @@ Without it, the error from compiling bpf selftests looks like:
   libbpf: failed to find BTF for extern 'tcp_slow_start' [25] section: -2
 
 __ https://reviews.llvm.org/D93563
+
+Clang dependencies for static linking tests
+===========================================
+
+linked_vars, linked_maps, and linked_funcs tests depend on `Clang fix`__ to
+generate valid BTF information for weak variables. Please make sure you use
+Clang that contains the fix.
+
+__ https://reviews.llvm.org/D100362
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 2/6] libbpf: rename static variables during linking
  2021-04-22  1:45 [PATCH bpf-next 0/6] BPF static linker: support static vars and maps Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 1/6] selftests/bpf: document latest Clang fix expectations for linking tests Andrii Nakryiko
@ 2021-04-22  1:45 ` Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 3/6] libbpf: support static map definitions Andrii Nakryiko
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Andrii Nakryiko @ 2021-04-22  1:45 UTC (permalink / raw)
  To: bpf, netdev, ast, daniel; +Cc: andrii, kernel-team

Prepend <obj_name>.. prefix to each static variable in BTF info during static
linking. This makes them uniquely named for the sake of BPF skeleton use,
allowing to read/write static BPF variables from user-space. This uniqueness
guarantee depends on each linked file name uniqueness, of course. Double dots
separator was chosen both to be different (but similar) to the separator that
Clang is currently using for static variables defined inside functions as well
as to generate a natural (in libbpf parlance, at least) obj__var naming pattern
in BPF skeleton. Static linker also checks for static variable to already
contain ".." separator and skips the rename to allow multi-pass linking and not
keep making variable name ever increasing, if derived object name is changing on
each pass (as is the case for selftests).

This patch also adds opts to bpf_linker__add_file() API, which currently
allows to override object name for a given file and could be extended with other
per-file options in the future. This is not a breaking change because
bpf_linker__add_file() isn't yet released officially.

This patch also includes fixes to few selftests that are already using static
variables. They have to go in in the same patch to not break selftest build.
Keep in mind, this static variable rename only happens during static linking.
For any existing user of BPF skeleton using static variables nothing changes,
because those use cases are using variable names generated by Clang. Only new
users utilizing static linker might need to adjust BPF skeleton use, which
currently will be always new use cases. So ther is no risk of breakage.

static_linked selftests is modified to also validate conflicting static variable
names are handled correctly both during static linking and in BPF skeleton.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/bpf/bpftool/gen.c                       |   2 +-
 tools/lib/bpf/libbpf.h                        |  12 +-
 tools/lib/bpf/linker.c                        | 121 +++++++++++++++++-
 .../selftests/bpf/prog_tests/skeleton.c       |   8 +-
 .../selftests/bpf/prog_tests/static_linked.c  |   8 +-
 .../selftests/bpf/progs/bpf_iter_test_kern4.c |   4 +-
 .../selftests/bpf/progs/test_check_mtu.c      |   4 +-
 .../selftests/bpf/progs/test_cls_redirect.c   |   4 +-
 .../bpf/progs/test_snprintf_single.c          |   2 +-
 .../selftests/bpf/progs/test_sockmap_listen.c |   4 +-
 .../selftests/bpf/progs/test_static_linked1.c |   6 +-
 .../selftests/bpf/progs/test_static_linked2.c |   4 +-
 12 files changed, 151 insertions(+), 28 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 440a2fcb6441..06fee4a2910a 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -638,7 +638,7 @@ static int do_object(int argc, char **argv)
 	while (argc) {
 		file = GET_ARG();
 
-		err = bpf_linker__add_file(linker, file);
+		err = bpf_linker__add_file(linker, file, NULL);
 		if (err) {
 			p_err("failed to link '%s': %s (%d)", file, strerror(err), err);
 			goto out;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index bec4e6a6e31d..67505030c8d1 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -768,10 +768,20 @@ struct bpf_linker_opts {
 };
 #define bpf_linker_opts__last_field sz
 
+struct bpf_linker_file_opts {
+	/* size of this struct, for forward/backward compatiblity */
+	size_t sz;
+	/* object name override, similar to the one in bpf_object_open_opts */
+	const char *object_name;
+};
+#define bpf_linker_file_opts__last_field sz
+
 struct bpf_linker;
 
 LIBBPF_API struct bpf_linker *bpf_linker__new(const char *filename, struct bpf_linker_opts *opts);
-LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker, const char *filename);
+LIBBPF_API int bpf_linker__add_file(struct bpf_linker *linker,
+				    const char *filename,
+				    const struct bpf_linker_file_opts *opts);
 LIBBPF_API int bpf_linker__finalize(struct bpf_linker *linker);
 LIBBPF_API void bpf_linker__free(struct bpf_linker *linker);
 
diff --git a/tools/lib/bpf/linker.c b/tools/lib/bpf/linker.c
index 84d444427b65..6700084a5bf4 100644
--- a/tools/lib/bpf/linker.c
+++ b/tools/lib/bpf/linker.c
@@ -4,6 +4,8 @@
  *
  * Copyright (c) 2021 Facebook
  */
+#define _GNU_SOURCE
+#include <ctype.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -47,6 +49,16 @@ struct src_sec {
 	int sec_type_id;
 };
 
+#define MAX_OBJ_NAME_LEN 64
+
+/* According to C standard, only first 63 characters of C identifiers are
+ * guaranteed to be significant. So for transformed static variables of the most
+ * verbose form ('<obj_name>..<func_name>.<var_name>') we need to reserve extra
+ * 64 (function name and dot) + 63 (variable name) + 2 (for .. separator)
+ * characters.
+ */
+#define MAX_VAR_NAME_LEN (MAX_OBJ_NAME_LEN + 2 + 63 + 1 + 63)
+
 struct src_obj {
 	const char *filename;
 	int fd;
@@ -67,6 +79,10 @@ struct src_obj {
 	int *sym_map;
 	/* mapping from the src BTF type IDs to dst ones */
 	int *btf_type_map;
+
+	/* BPF object name used for static variable prefixing */
+	char obj_name[MAX_OBJ_NAME_LEN];
+	size_t obj_name_len;
 };
 
 /* single .BTF.ext data section */
@@ -158,7 +174,9 @@ struct bpf_linker {
 
 static int init_output_elf(struct bpf_linker *linker, const char *file);
 
-static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, struct src_obj *obj);
+static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
+				const struct bpf_linker_file_opts *opts,
+				struct src_obj *obj);
 static int linker_sanity_check_elf(struct src_obj *obj);
 static int linker_sanity_check_elf_symtab(struct src_obj *obj, struct src_sec *sec);
 static int linker_sanity_check_elf_relos(struct src_obj *obj, struct src_sec *sec);
@@ -435,15 +453,19 @@ static int init_output_elf(struct bpf_linker *linker, const char *file)
 	return 0;
 }
 
-int bpf_linker__add_file(struct bpf_linker *linker, const char *filename)
+int bpf_linker__add_file(struct bpf_linker *linker, const char *filename,
+			 const struct bpf_linker_file_opts *opts)
 {
 	struct src_obj obj = {};
 	int err = 0;
 
+	if (!OPTS_VALID(opts, bpf_linker_file_opts))
+		return -EINVAL;
+
 	if (!linker->elf)
 		return -EINVAL;
 
-	err = err ?: linker_load_obj_file(linker, filename, &obj);
+	err = err ?: linker_load_obj_file(linker, filename, opts, &obj);
 	err = err ?: linker_append_sec_data(linker, &obj);
 	err = err ?: linker_append_elf_syms(linker, &obj);
 	err = err ?: linker_append_elf_relos(linker, &obj);
@@ -529,7 +551,49 @@ static struct src_sec *add_src_sec(struct src_obj *obj, const char *sec_name)
 	return sec;
 }
 
-static int linker_load_obj_file(struct bpf_linker *linker, const char *filename, struct src_obj *obj)
+static void sanitize_obj_name(char *name)
+{
+	int i;
+
+	for (i = 0; name[i]; i++) {
+		if (name[i] == '_')
+			continue;
+		if (i == 0 && isalpha(name[i]))
+			continue;
+		if (i > 0 && isalnum(name[i]))
+			continue;
+
+		name[i] = '_';
+	}
+}
+
+static bool str_has_suffix(const char *str, const char *suffix)
+{
+	size_t n1 = strlen(str), n2 = strlen(suffix);
+
+	if (n1 < n2)
+		return false;
+
+	return strcmp(str + n1 - n2, suffix) == 0;
+}
+
+static void get_obj_name(char *name, const char *file)
+{
+	/* Using basename() GNU version which doesn't modify arg. */
+	strncpy(name, basename(file), MAX_OBJ_NAME_LEN - 1);
+	name[MAX_OBJ_NAME_LEN - 1] = '\0';
+
+	if (str_has_suffix(name, ".o"))
+		name[strlen(name) - sizeof(".o") + 1] = '\0';
+	if (str_has_suffix(name, ".bpf.o"))
+		name[strlen(name) - sizeof(".bpf.o") + 1] = '\0';
+
+	sanitize_obj_name(name);
+}
+
+static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
+				const struct bpf_linker_file_opts *opts,
+				struct src_obj *obj)
 {
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 	const int host_endianness = ELFDATA2LSB;
@@ -549,6 +613,14 @@ static int linker_load_obj_file(struct bpf_linker *linker, const char *filename,
 
 	obj->filename = filename;
 
+	if (OPTS_GET(opts, object_name, NULL)) {
+		strncpy(obj->obj_name, opts->object_name, MAX_OBJ_NAME_LEN);
+		obj->obj_name[MAX_OBJ_NAME_LEN - 1] = '\0';
+	} else {
+		get_obj_name(obj->obj_name, filename);
+	}
+	obj->obj_name_len = strlen(obj->obj_name);
+
 	obj->fd = open(filename, O_RDONLY);
 	if (obj->fd < 0) {
 		err = -errno;
@@ -2255,6 +2327,47 @@ static int linker_append_btf(struct bpf_linker *linker, struct src_obj *obj)
 				obj->btf_type_map[i] = glob_sym->btf_id;
 				continue;
 			}
+		} else if (btf_is_var(t) && btf_var(t)->linkage == BTF_VAR_STATIC) {
+			/* Static variables are renamed to include
+			 * "<obj_name>.." prefix (note double dots), similarly
+			 * to how static variables inside functions are named
+			 * "<func_name>.<var_name>" by compiler. This allows to
+			 * have  unique identifiers for static variables across
+			 * all linked object files (assuming unique filenames,
+			 * of course), which BPF skeleton relies on.
+			 *
+			 * So worst case static variable inside the function
+			 * will have the form "<obj_name>..<func_name>.<var_name"
+			 * and will get sanitized by BPF skeleton generation
+			 * logic to a field with <obj_name>__<func_name>_<var_name>
+			 * name. Typical static variable will have a
+			 * <obj_name>__<var_name> name, implying arguably nice
+			 * per-file scoping.
+			 *
+			 * If static var name already contains '..', though,
+			 * don't rename it, because it was already renamed by
+			 * previous linker passes.
+			 */
+			name = btf__str_by_offset(obj->btf, t->name_off);
+			if (!strstr(name, "..")) {
+				char new_name[MAX_VAR_NAME_LEN];
+
+				memcpy(new_name, obj->obj_name, obj->obj_name_len);
+				new_name[obj->obj_name_len] = '.';
+				new_name[obj->obj_name_len + 1] = '.';
+				new_name[obj->obj_name_len + 2] = '\0';
+				/* -3 is for '..' separator and terminating '\0' */
+				strncat(new_name, name, MAX_VAR_NAME_LEN - obj->obj_name_len - 3);
+
+				id = btf__add_str(obj->btf, new_name);
+				if (id < 0)
+					return id;
+
+				/* btf__add_str() might invalidate t, so re-fetch */
+				t = btf__type_by_id(obj->btf, i);
+
+				((struct btf_type *)t)->name_off = id;
+			}
 		}
 
 		id = btf__add_type(linker->btf, obj->btf, t);
diff --git a/tools/testing/selftests/bpf/prog_tests/skeleton.c b/tools/testing/selftests/bpf/prog_tests/skeleton.c
index fe87b77af459..bbade99fa544 100644
--- a/tools/testing/selftests/bpf/prog_tests/skeleton.c
+++ b/tools/testing/selftests/bpf/prog_tests/skeleton.c
@@ -82,10 +82,10 @@ void test_skeleton(void)
 	CHECK(data->out2 != 2, "res2", "got %lld != exp %d\n", data->out2, 2);
 	CHECK(bss->out3 != 3, "res3", "got %d != exp %d\n", (int)bss->out3, 3);
 	CHECK(bss->out4 != 4, "res4", "got %lld != exp %d\n", bss->out4, 4);
-	CHECK(bss->handler_out5.a != 5, "res5", "got %d != exp %d\n",
-	      bss->handler_out5.a, 5);
-	CHECK(bss->handler_out5.b != 6, "res6", "got %lld != exp %d\n",
-	      bss->handler_out5.b, 6);
+	CHECK(bss->test_skeleton__handler_out5.a != 5, "res5", "got %d != exp %d\n",
+	      bss->test_skeleton__handler_out5.a, 5);
+	CHECK(bss->test_skeleton__handler_out5.b != 6, "res6", "got %lld != exp %d\n",
+	      bss->test_skeleton__handler_out5.b, 6);
 	CHECK(bss->out6 != 14, "res7", "got %d != exp %d\n", bss->out6, 14);
 
 	CHECK(bss->bpf_syscall != kcfg->CONFIG_BPF_SYSCALL, "ext1",
diff --git a/tools/testing/selftests/bpf/prog_tests/static_linked.c b/tools/testing/selftests/bpf/prog_tests/static_linked.c
index 46556976dccc..f16736eab900 100644
--- a/tools/testing/selftests/bpf/prog_tests/static_linked.c
+++ b/tools/testing/selftests/bpf/prog_tests/static_linked.c
@@ -14,12 +14,12 @@ void test_static_linked(void)
 		return;
 
 	skel->rodata->rovar1 = 1;
-	skel->bss->static_var1 = 2;
-	skel->bss->static_var11 = 3;
+	skel->bss->test_static_linked1__static_var = 2;
+	skel->bss->test_static_linked1__static_var1 = 3;
 
 	skel->rodata->rovar2 = 4;
-	skel->bss->static_var2 = 5;
-	skel->bss->static_var22 = 6;
+	skel->bss->test_static_linked2__static_var = 5;
+	skel->bss->test_static_linked2__static_var2 = 6;
 
 	err = test_static_linked__load(skel);
 	if (!ASSERT_OK(err, "skel_load"))
diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c b/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c
index ee49493dc125..43bf8ec8ae79 100644
--- a/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c
+++ b/tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c
@@ -9,8 +9,8 @@ __u32 map1_id = 0, map2_id = 0;
 __u32 map1_accessed = 0, map2_accessed = 0;
 __u64 map1_seqnum = 0, map2_seqnum1 = 0, map2_seqnum2 = 0;
 
-static volatile const __u32 print_len;
-static volatile const __u32 ret1;
+volatile const __u32 print_len = 0;
+volatile const __u32 ret1 = 0;
 
 SEC("iter/bpf_map")
 int dump_bpf_map(struct bpf_iter__bpf_map *ctx)
diff --git a/tools/testing/selftests/bpf/progs/test_check_mtu.c b/tools/testing/selftests/bpf/progs/test_check_mtu.c
index c4a9bae96e75..71184af57749 100644
--- a/tools/testing/selftests/bpf/progs/test_check_mtu.c
+++ b/tools/testing/selftests/bpf/progs/test_check_mtu.c
@@ -11,8 +11,8 @@
 char _license[] SEC("license") = "GPL";
 
 /* Userspace will update with MTU it can see on device */
-static volatile const int GLOBAL_USER_MTU;
-static volatile const __u32 GLOBAL_USER_IFINDEX;
+volatile const int GLOBAL_USER_MTU;
+volatile const __u32 GLOBAL_USER_IFINDEX;
 
 /* BPF-prog will update these with MTU values it can see */
 __u32 global_bpf_mtu_xdp = 0;
diff --git a/tools/testing/selftests/bpf/progs/test_cls_redirect.c b/tools/testing/selftests/bpf/progs/test_cls_redirect.c
index 3c1e042962e6..e2a5acc4785c 100644
--- a/tools/testing/selftests/bpf/progs/test_cls_redirect.c
+++ b/tools/testing/selftests/bpf/progs/test_cls_redirect.c
@@ -39,8 +39,8 @@ char _license[] SEC("license") = "Dual BSD/GPL";
 /**
  * Destination port and IP used for UDP encapsulation.
  */
-static volatile const __be16 ENCAPSULATION_PORT;
-static volatile const __be32 ENCAPSULATION_IP;
+volatile const __be16 ENCAPSULATION_PORT;
+volatile const __be32 ENCAPSULATION_IP;
 
 typedef struct {
 	uint64_t processed_packets_total;
diff --git a/tools/testing/selftests/bpf/progs/test_snprintf_single.c b/tools/testing/selftests/bpf/progs/test_snprintf_single.c
index 402adaf344f9..6b63ba86b409 100644
--- a/tools/testing/selftests/bpf/progs/test_snprintf_single.c
+++ b/tools/testing/selftests/bpf/progs/test_snprintf_single.c
@@ -5,7 +5,7 @@
 #include <bpf/bpf_helpers.h>
 
 /* The format string is filled from the userspace such that loading fails */
-static const char fmt[10];
+const char fmt[10] = {};
 
 SEC("raw_tp/sys_enter")
 int handler(const void *ctx)
diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c b/tools/testing/selftests/bpf/progs/test_sockmap_listen.c
index a39eba9f5201..a1cc58b10c7c 100644
--- a/tools/testing/selftests/bpf/progs/test_sockmap_listen.c
+++ b/tools/testing/selftests/bpf/progs/test_sockmap_listen.c
@@ -28,8 +28,8 @@ struct {
 	__type(value, unsigned int);
 } verdict_map SEC(".maps");
 
-static volatile bool test_sockmap; /* toggled by user-space */
-static volatile bool test_ingress; /* toggled by user-space */
+bool test_sockmap = false; /* toggled by user-space */
+bool test_ingress = false; /* toggled by user-space */
 
 SEC("sk_skb/stream_parser")
 int prog_stream_parser(struct __sk_buff *skb)
diff --git a/tools/testing/selftests/bpf/progs/test_static_linked1.c b/tools/testing/selftests/bpf/progs/test_static_linked1.c
index ea1a6c4c7172..7e15d05888e7 100644
--- a/tools/testing/selftests/bpf/progs/test_static_linked1.c
+++ b/tools/testing/selftests/bpf/progs/test_static_linked1.c
@@ -5,8 +5,8 @@
 #include <bpf/bpf_helpers.h>
 
 /* 8-byte aligned .bss */
-static volatile long static_var1;
-static volatile int static_var11;
+static volatile long static_var;
+static volatile int static_var1;
 int var1 = 0;
 /* 4-byte aligned .rodata */
 const volatile int rovar1;
@@ -21,7 +21,7 @@ static __noinline int subprog(int x)
 SEC("raw_tp/sys_enter")
 int handler1(const void *ctx)
 {
-	var1 = subprog(rovar1) + static_var1 + static_var11;
+	var1 = subprog(rovar1) + static_var + static_var1;
 
 	return 0;
 }
diff --git a/tools/testing/selftests/bpf/progs/test_static_linked2.c b/tools/testing/selftests/bpf/progs/test_static_linked2.c
index 54d8d1ab577c..0d37c05d508e 100644
--- a/tools/testing/selftests/bpf/progs/test_static_linked2.c
+++ b/tools/testing/selftests/bpf/progs/test_static_linked2.c
@@ -5,8 +5,8 @@
 #include <bpf/bpf_helpers.h>
 
 /* 4-byte aligned .bss */
+static volatile int static_var;
 static volatile int static_var2;
-static volatile int static_var22;
 int var2 = 0;
 /* 8-byte aligned .rodata */
 const volatile long rovar2;
@@ -21,7 +21,7 @@ static __noinline int subprog(int x)
 SEC("raw_tp/sys_enter")
 int handler2(const void *ctx)
 {
-	var2 = subprog(rovar2) + static_var2 + static_var22;
+	var2 = subprog(rovar2) + static_var + static_var2;
 
 	return 0;
 }
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 3/6] libbpf: support static map definitions
  2021-04-22  1:45 [PATCH bpf-next 0/6] BPF static linker: support static vars and maps Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 1/6] selftests/bpf: document latest Clang fix expectations for linking tests Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 2/6] libbpf: rename static variables during linking Andrii Nakryiko
@ 2021-04-22  1:45 ` Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 4/6] bpftool: handle transformed static map names in BPF skeleton Andrii Nakryiko
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Andrii Nakryiko @ 2021-04-22  1:45 UTC (permalink / raw)
  To: bpf, netdev, ast, daniel; +Cc: andrii, kernel-team

Change libbpf relocation logic to support references to static map
definitions. This allows to use static maps and, combined with static linking,
hide internal maps from other files, just like static variables. User-space
will still be able to look up and modify static maps.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/lib/bpf/libbpf.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 82b1946a0802..a7c3bcb8e5ea 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -3632,6 +3632,8 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
 
 	/* generic map reference relocation */
 	if (type == LIBBPF_MAP_UNSPEC) {
+		size_t map_offset = sym->st_value + insn->imm;
+
 		if (!bpf_object__shndx_is_maps(obj, shdr_idx)) {
 			pr_warn("prog '%s': bad map relo against '%s' in section '%s'\n",
 				prog->name, sym_name, sym_sec_name);
@@ -3641,7 +3643,7 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
 			map = &obj->maps[map_idx];
 			if (map->libbpf_type != type ||
 			    map->sec_idx != sym->st_shndx ||
-			    map->sec_offset != sym->st_value)
+			    map->sec_offset != map_offset)
 				continue;
 			pr_debug("prog '%s': found map %zd (%s, sec %d, off %zu) for insn #%u\n",
 				 prog->name, map_idx, map->name, map->sec_idx,
@@ -3656,7 +3658,8 @@ static int bpf_program__record_reloc(struct bpf_program *prog,
 		reloc_desc->type = RELO_LD64;
 		reloc_desc->insn_idx = insn_idx;
 		reloc_desc->map_idx = map_idx;
-		reloc_desc->sym_off = 0; /* sym->st_value determines map_idx */
+		/* sym->st_value + insn->imm determines map_idx */
+		reloc_desc->sym_off = 0;
 		return 0;
 	}
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 4/6] bpftool: handle transformed static map names in BPF skeleton
  2021-04-22  1:45 [PATCH bpf-next 0/6] BPF static linker: support static vars and maps Andrii Nakryiko
                   ` (2 preceding siblings ...)
  2021-04-22  1:45 ` [PATCH bpf-next 3/6] libbpf: support static map definitions Andrii Nakryiko
@ 2021-04-22  1:45 ` Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 5/6] selftests/bpf: extend linked_vars selftests with static variables Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 6/6] selftests/bpf: extend linked_maps selftests with static maps Andrii Nakryiko
  5 siblings, 0 replies; 7+ messages in thread
From: Andrii Nakryiko @ 2021-04-22  1:45 UTC (permalink / raw)
  To: bpf, netdev, ast, daniel; +Cc: andrii, kernel-team

Static maps will be renamed according to the same rules as global variables
(<obj_name>..<map_name>) during static linking. This breaks current BPF
skeleton logic that uses normal non-internal maps' names as is. Instead, do
the same map identifier sanitization as is done for global variables, turning
static maps into <obj_name>__<map_name> fields in BPF skeleton. Their original
names with '..' separator are preserved by libbpf and submitted as is into the
kernel. As well as they can be looked up using their unsanitized name with
using bpf_object__find_map_by_name() API.

There are no breaking changes concerns, similarly to static variable renames,
because this renaming happens only during static linking. Plus static maps
never really worked and thus were never used in practice.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/bpf/bpftool/gen.c | 36 ++++++++++++++++++++++--------------
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 06fee4a2910a..72cfe738b0a2 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -23,6 +23,7 @@
 #include "main.h"
 
 #define MAX_OBJ_NAME_LEN 64
+#define MAX_MAP_NAME_LEN (2 * MAX_OBJ_NAME_LEN + 1)
 
 static void sanitize_identifier(char *name)
 {
@@ -67,23 +68,29 @@ static void get_header_guard(char *guard, const char *obj_name)
 		guard[i] = toupper(guard[i]);
 }
 
-static const char *get_map_ident(const struct bpf_map *map)
+static const char *get_map_ident(char *name, const struct bpf_map *map)
 {
-	const char *name = bpf_map__name(map);
+	const char *orig_name = bpf_map__name(map);
 
-	if (!bpf_map__is_internal(map))
+	if (!bpf_map__is_internal(map)) {
+		strncpy(name, orig_name, MAX_MAP_NAME_LEN);
+		name[MAX_MAP_NAME_LEN - 1] = '\0';
+		sanitize_identifier(name);
 		return name;
+	}
 
-	if (str_has_suffix(name, ".data"))
-		return "data";
-	else if (str_has_suffix(name, ".rodata"))
-		return "rodata";
-	else if (str_has_suffix(name, ".bss"))
-		return "bss";
-	else if (str_has_suffix(name, ".kconfig"))
-		return "kconfig";
+	if (str_has_suffix(orig_name, ".data"))
+		strcpy(name, "data");
+	else if (str_has_suffix(orig_name, ".rodata"))
+		strcpy(name, "rodata");
+	else if (str_has_suffix(orig_name, ".bss"))
+		strcpy(name, "bss");
+	else if (str_has_suffix(orig_name, ".kconfig"))
+		strcpy(name, "kconfig");
 	else
 		return NULL;
+
+	return name;
 }
 
 static void codegen_btf_dump_printf(void *ctx, const char *fmt, va_list args)
@@ -273,6 +280,7 @@ static void codegen(const char *template, ...)
 static int do_skeleton(int argc, char **argv)
 {
 	char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
+	char map_ident[MAX_MAP_NAME_LEN];
 	size_t i, map_cnt = 0, prog_cnt = 0, file_sz, mmap_sz;
 	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
 	char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;
@@ -348,7 +356,7 @@ static int do_skeleton(int argc, char **argv)
 	}
 
 	bpf_object__for_each_map(map, obj) {
-		ident = get_map_ident(map);
+		ident = get_map_ident(map_ident, map);
 		if (!ident) {
 			p_err("ignoring unrecognized internal map '%s'...",
 			      bpf_map__name(map));
@@ -382,7 +390,7 @@ static int do_skeleton(int argc, char **argv)
 	if (map_cnt) {
 		printf("\tstruct {\n");
 		bpf_object__for_each_map(map, obj) {
-			ident = get_map_ident(map);
+			ident = get_map_ident(map_ident, map);
 			if (!ident)
 				continue;
 			printf("\t\tstruct bpf_map *%s;\n", ident);
@@ -524,7 +532,7 @@ static int do_skeleton(int argc, char **argv)
 		);
 		i = 0;
 		bpf_object__for_each_map(map, obj) {
-			ident = get_map_ident(map);
+			ident = get_map_ident(map_ident, map);
 
 			if (!ident)
 				continue;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 5/6] selftests/bpf: extend linked_vars selftests with static variables
  2021-04-22  1:45 [PATCH bpf-next 0/6] BPF static linker: support static vars and maps Andrii Nakryiko
                   ` (3 preceding siblings ...)
  2021-04-22  1:45 ` [PATCH bpf-next 4/6] bpftool: handle transformed static map names in BPF skeleton Andrii Nakryiko
@ 2021-04-22  1:45 ` Andrii Nakryiko
  2021-04-22  1:45 ` [PATCH bpf-next 6/6] selftests/bpf: extend linked_maps selftests with static maps Andrii Nakryiko
  5 siblings, 0 replies; 7+ messages in thread
From: Andrii Nakryiko @ 2021-04-22  1:45 UTC (permalink / raw)
  To: bpf, netdev, ast, daniel; +Cc: andrii, kernel-team

Now that BPF static linker supports static variable renames and thus
non-unique static variables in BPF skeleton, add tests validating static
variables are resolved properly during multi-file static linking.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/testing/selftests/bpf/prog_tests/linked_vars.c | 12 ++++++++----
 tools/testing/selftests/bpf/progs/linked_vars1.c     |  4 +++-
 tools/testing/selftests/bpf/progs/linked_vars2.c     |  4 +++-
 3 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/linked_vars.c b/tools/testing/selftests/bpf/prog_tests/linked_vars.c
index f3d6ba31ef99..73f3fea41230 100644
--- a/tools/testing/selftests/bpf/prog_tests/linked_vars.c
+++ b/tools/testing/selftests/bpf/prog_tests/linked_vars.c
@@ -14,8 +14,12 @@ void test_linked_vars(void)
 	if (!ASSERT_OK_PTR(skel, "skel_open"))
 		return;
 
+	skel->bss->linked_vars1__input_bss_static = 100;
 	skel->bss->input_bss1 = 1000;
+
+	skel->bss->linked_vars2__input_bss_static = 200;
 	skel->bss->input_bss2 = 2000;
+
 	skel->bss->input_bss_weak = 3000;
 
 	err = linked_vars__load(skel);
@@ -29,11 +33,11 @@ void test_linked_vars(void)
 	/* trigger */
 	syscall(SYS_getpgid);
 
-	ASSERT_EQ(skel->bss->output_bss1, 1000 + 2000 + 3000, "output_bss1");
-	ASSERT_EQ(skel->bss->output_bss2, 1000 + 2000 + 3000, "output_bss2");
+	ASSERT_EQ(skel->bss->output_bss1, 100 + 1000 + 2000 + 3000, "output_bss1");
+	ASSERT_EQ(skel->bss->output_bss2, 200 + 1000 + 2000 + 3000, "output_bss2");
 	/* 10 comes from "winner" input_data_weak in first obj file */
-	ASSERT_EQ(skel->bss->output_data1, 1 + 2 + 10, "output_bss1");
-	ASSERT_EQ(skel->bss->output_data2, 1 + 2 + 10, "output_bss2");
+	ASSERT_EQ(skel->bss->output_data1, 1 + 2 + 10, "output_data1");
+	ASSERT_EQ(skel->bss->output_data2, 1 + 2 + 10, "output_data2");
 	/* 10 comes from "winner" input_rodata_weak in first obj file */
 	ASSERT_EQ(skel->bss->output_rodata1, 11 + 22 + 100, "output_weak1");
 	ASSERT_EQ(skel->bss->output_rodata2, 11 + 22 + 100, "output_weak2");
diff --git a/tools/testing/selftests/bpf/progs/linked_vars1.c b/tools/testing/selftests/bpf/progs/linked_vars1.c
index bc96eff9b8c1..05c7a2739c88 100644
--- a/tools/testing/selftests/bpf/progs/linked_vars1.c
+++ b/tools/testing/selftests/bpf/progs/linked_vars1.c
@@ -10,6 +10,8 @@ extern int LINUX_KERNEL_VERSION __kconfig;
 extern bool CONFIG_BPF_SYSCALL __kconfig __weak;
 extern const void bpf_link_fops __ksym __weak;
 
+static volatile int input_bss_static = 0;
+
 int input_bss1 = 0;
 int input_data1 = 1;
 const volatile int input_rodata1 = 11;
@@ -32,7 +34,7 @@ long output_sink1 = 0;
 static __noinline int get_bss_res(void)
 {
 	/* just make sure all the relocations work against .text as well */
-	return input_bss1 + input_bss2 + input_bss_weak;
+	return input_bss_static + input_bss1 + input_bss2 + input_bss_weak;
 }
 
 SEC("raw_tp/sys_enter")
diff --git a/tools/testing/selftests/bpf/progs/linked_vars2.c b/tools/testing/selftests/bpf/progs/linked_vars2.c
index 946c0ce4f505..c390ac667150 100644
--- a/tools/testing/selftests/bpf/progs/linked_vars2.c
+++ b/tools/testing/selftests/bpf/progs/linked_vars2.c
@@ -10,6 +10,8 @@ extern int LINUX_KERNEL_VERSION __kconfig;
 extern bool CONFIG_BPF_SYSCALL __kconfig;
 extern const void __start_BTF __ksym;
 
+static volatile int input_bss_static = 0;
+
 int input_bss2 = 0;
 int input_data2 = 2;
 const volatile int input_rodata2 = 22;
@@ -38,7 +40,7 @@ static __noinline int get_data_res(void)
 SEC("raw_tp/sys_enter")
 int BPF_PROG(handler2)
 {
-	output_bss2 = input_bss1 + input_bss2 + input_bss_weak;
+	output_bss2 = input_bss_static + input_bss1 + input_bss2 + input_bss_weak;
 	output_data2 = get_data_res();
 	output_rodata2 = input_rodata1 + input_rodata2 + input_rodata_weak;
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 6/6] selftests/bpf: extend linked_maps selftests with static maps
  2021-04-22  1:45 [PATCH bpf-next 0/6] BPF static linker: support static vars and maps Andrii Nakryiko
                   ` (4 preceding siblings ...)
  2021-04-22  1:45 ` [PATCH bpf-next 5/6] selftests/bpf: extend linked_vars selftests with static variables Andrii Nakryiko
@ 2021-04-22  1:45 ` Andrii Nakryiko
  5 siblings, 0 replies; 7+ messages in thread
From: Andrii Nakryiko @ 2021-04-22  1:45 UTC (permalink / raw)
  To: bpf, netdev, ast, daniel; +Cc: andrii, kernel-team

Add static maps to linked_maps selftests, validating that static maps with the
same name can co-exists in separate files and local references to such maps
are resolved correctly within each individual file.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 .../selftests/bpf/prog_tests/linked_maps.c    | 20 ++++++++++++++++++-
 .../selftests/bpf/progs/linked_maps1.c        | 13 ++++++++++++
 .../selftests/bpf/progs/linked_maps2.c        | 18 +++++++++++++++++
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/linked_maps.c b/tools/testing/selftests/bpf/prog_tests/linked_maps.c
index 85dcaaaf2775..6f51dae65b44 100644
--- a/tools/testing/selftests/bpf/prog_tests/linked_maps.c
+++ b/tools/testing/selftests/bpf/prog_tests/linked_maps.c
@@ -7,13 +7,21 @@
 
 void test_linked_maps(void)
 {
-	int err;
+	int key1 = 1, key2 = 2;
+	int val1 = 42, val2 = 24, val;
+	int err, map_fd1, map_fd2;
 	struct linked_maps *skel;
 
 	skel = linked_maps__open_and_load();
 	if (!ASSERT_OK_PTR(skel, "skel_open"))
 		return;
 
+	map_fd1 = bpf_map__fd(skel->maps.linked_maps1__map_static);
+	ASSERT_OK(bpf_map_update_elem(map_fd1, &key2, &val2, 0), "static_map1_update");
+
+	map_fd2 = bpf_map__fd(skel->maps.linked_maps2__map_static);
+	ASSERT_OK(bpf_map_update_elem(map_fd2, &key1, &val1, 0), "static_map2_update");
+
 	err = linked_maps__attach(skel);
 	if (!ASSERT_OK(err, "skel_attach"))
 		goto cleanup;
@@ -24,6 +32,16 @@ void test_linked_maps(void)
 	ASSERT_EQ(skel->bss->output_first1, 2000, "output_first1");
 	ASSERT_EQ(skel->bss->output_second1, 2, "output_second1");
 	ASSERT_EQ(skel->bss->output_weak1, 2, "output_weak1");
+	ASSERT_EQ(skel->bss->output_static1, val2, "output_static1");
+	ASSERT_OK(bpf_map_lookup_elem(map_fd1, &key1, &val), "static_map1_lookup");
+	ASSERT_EQ(val, 1, "static_map1_key1");
+
+	ASSERT_EQ(skel->bss->output_first2, 1000, "output_first2");
+	ASSERT_EQ(skel->bss->output_second2, 1, "output_second2");
+	ASSERT_EQ(skel->bss->output_weak2, 1, "output_weak2");
+	ASSERT_EQ(skel->bss->output_static2, val1, "output_static2");
+	ASSERT_OK(bpf_map_lookup_elem(map_fd2, &key2, &val), "static_map2_lookup");
+	ASSERT_EQ(val, 2, "static_map2_key2");
 
 cleanup:
 	linked_maps__destroy(skel);
diff --git a/tools/testing/selftests/bpf/progs/linked_maps1.c b/tools/testing/selftests/bpf/progs/linked_maps1.c
index 2f4bab565e64..5644949d63f8 100644
--- a/tools/testing/selftests/bpf/progs/linked_maps1.c
+++ b/tools/testing/selftests/bpf/progs/linked_maps1.c
@@ -37,9 +37,17 @@ struct {
 	__uint(max_entries, 16);
 } map_weak __weak SEC(".maps");
 
+static struct {
+	__uint(type, BPF_MAP_TYPE_HASH);
+	__type(key, int);
+	__type(value, int);
+	__uint(max_entries, 4);
+} map_static SEC(".maps");
+
 int output_first1 = 0;
 int output_second1 = 0;
 int output_weak1 = 0;
+int output_static1 = 0;
 
 SEC("raw_tp/sys_enter")
 int BPF_PROG(handler_enter1)
@@ -52,6 +60,7 @@ int BPF_PROG(handler_enter1)
 	bpf_map_update_elem(&map1, &key_struct, &val_struct, 0);
 	bpf_map_update_elem(&map2, &key, &val, 0);
 	bpf_map_update_elem(&map_weak, &key, &val, 0);
+	bpf_map_update_elem(&map_static, &key, &val, 0);
 
 	return 0;
 }
@@ -76,6 +85,10 @@ int BPF_PROG(handler_exit1)
 	if (val)
 		output_weak1 = *val;
 	
+	val = bpf_map_lookup_elem(&map_static, &key);
+	if (val)
+		output_static1 = *val;
+
 	return 0;
 }
 
diff --git a/tools/testing/selftests/bpf/progs/linked_maps2.c b/tools/testing/selftests/bpf/progs/linked_maps2.c
index 3f1490ea8f37..2b9e11ac0335 100644
--- a/tools/testing/selftests/bpf/progs/linked_maps2.c
+++ b/tools/testing/selftests/bpf/progs/linked_maps2.c
@@ -31,9 +31,22 @@ struct {
 	__uint(max_entries, 16);
 } map_weak __weak SEC(".maps");
 
+static struct {
+	/* different type */
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	/* key and value are kept int for convenience, they don't have to
+	 * match with map_static in linked_maps1
+	 */
+	__type(key, int);
+	__type(value, int);
+	/* different max_entries */
+	__uint(max_entries, 20);
+} map_static SEC(".maps");
+
 int output_first2 = 0;
 int output_second2 = 0;
 int output_weak2 = 0;
+int output_static2 = 0;
 
 SEC("raw_tp/sys_enter")
 int BPF_PROG(handler_enter2)
@@ -46,6 +59,7 @@ int BPF_PROG(handler_enter2)
 	bpf_map_update_elem(&map1, &key_struct, &val_struct, 0);
 	bpf_map_update_elem(&map2, &key, &val, 0);
 	bpf_map_update_elem(&map_weak, &key, &val, 0);
+	bpf_map_update_elem(&map_static, &key, &val, 0);
 
 	return 0;
 }
@@ -70,6 +84,10 @@ int BPF_PROG(handler_exit2)
 	if (val)
 		output_weak2 = *val;
 
+	val = bpf_map_lookup_elem(&map_static, &key);
+	if (val)
+		output_static2 = *val;
+
 	return 0;
 }
 
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-04-22  1:46 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-22  1:45 [PATCH bpf-next 0/6] BPF static linker: support static vars and maps Andrii Nakryiko
2021-04-22  1:45 ` [PATCH bpf-next 1/6] selftests/bpf: document latest Clang fix expectations for linking tests Andrii Nakryiko
2021-04-22  1:45 ` [PATCH bpf-next 2/6] libbpf: rename static variables during linking Andrii Nakryiko
2021-04-22  1:45 ` [PATCH bpf-next 3/6] libbpf: support static map definitions Andrii Nakryiko
2021-04-22  1:45 ` [PATCH bpf-next 4/6] bpftool: handle transformed static map names in BPF skeleton Andrii Nakryiko
2021-04-22  1:45 ` [PATCH bpf-next 5/6] selftests/bpf: extend linked_vars selftests with static variables Andrii Nakryiko
2021-04-22  1:45 ` [PATCH bpf-next 6/6] selftests/bpf: extend linked_maps selftests with static maps Andrii Nakryiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).