From 03bd4773d898783fe3bc321287e4838e515fea92 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 30 Sep 2019 15:25:03 -0700 Subject: libbpf: Bump current version to v0.0.6 New release cycle started, let's bump to v0.0.6 proactively. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20190930222503.519782-1-andriin@fb.com --- tools/lib/bpf/libbpf.map | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index d04c7cb623ed..8d10ca03d78d 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -190,3 +190,6 @@ LIBBPF_0.0.5 { global: bpf_btf_get_next_id; } LIBBPF_0.0.4; + +LIBBPF_0.0.6 { +} LIBBPF_0.0.5; -- cgit v1.2.3 From fb27dcd2909d32e2219b54636ea212dbde45f985 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Wed, 2 Oct 2019 15:04:03 +0300 Subject: selftests/bpf: Add static to enable_all_controllers() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add static to enable_all_controllers() to get rid from annoying warning during samples/bpf build: samples/bpf/../../tools/testing/selftests/bpf/cgroup_helpers.c:44:5: warning: no previous prototype for ‘enable_all_controllers’ [-Wmissing-prototypes] int enable_all_controllers(char *cgroup_path) Signed-off-by: Ivan Khoronzhuk Signed-off-by: Daniel Borkmann Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191002120404.26962-2-ivan.khoronzhuk@linaro.org --- tools/testing/selftests/bpf/cgroup_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index e95c33e333a4..4d74f3c4619b 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -41,7 +41,7 @@ * * If successful, 0 is returned. */ -int enable_all_controllers(char *cgroup_path) +static int enable_all_controllers(char *cgroup_path) { char path[PATH_MAX + 1]; char buf[PATH_MAX]; -- cgit v1.2.3 From c588146378962786ddeec817f7736a53298a7b01 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Wed, 2 Oct 2019 15:04:04 +0300 Subject: selftests/bpf: Correct path to include msg + path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "path" buf is supposed to contain path + printf msg up to 24 bytes. It will be cut anyway, but compiler generates truncation warns like: " samples/bpf/../../tools/testing/selftests/bpf/cgroup_helpers.c: In function ‘setup_cgroup_environment’: samples/bpf/../../tools/testing/selftests/bpf/cgroup_helpers.c:52:34: warning: ‘/cgroup.controllers’ directive output may be truncated writing 19 bytes into a region of size between 1 and 4097 [-Wformat-truncation=] snprintf(path, sizeof(path), "%s/cgroup.controllers", cgroup_path); ^~~~~~~~~~~~~~~~~~~ samples/bpf/../../tools/testing/selftests/bpf/cgroup_helpers.c:52:2: note: ‘snprintf’ output between 20 and 4116 bytes into a destination of size 4097 snprintf(path, sizeof(path), "%s/cgroup.controllers", cgroup_path); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ samples/bpf/../../tools/testing/selftests/bpf/cgroup_helpers.c:72:34: warning: ‘/cgroup.subtree_control’ directive output may be truncated writing 23 bytes into a region of size between 1 and 4097 [-Wformat-truncation=] snprintf(path, sizeof(path), "%s/cgroup.subtree_control", ^~~~~~~~~~~~~~~~~~~~~~~ cgroup_path); samples/bpf/../../tools/testing/selftests/bpf/cgroup_helpers.c:72:2: note: ‘snprintf’ output between 24 and 4120 bytes into a destination of size 4097 snprintf(path, sizeof(path), "%s/cgroup.subtree_control", cgroup_path); " In order to avoid warns, lets decrease buf size for cgroup workdir on 24 bytes with assumption to include also "/cgroup.subtree_control" to the address. The cut will never happen anyway. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Daniel Borkmann Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191002120404.26962-3-ivan.khoronzhuk@linaro.org --- tools/testing/selftests/bpf/cgroup_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/cgroup_helpers.c b/tools/testing/selftests/bpf/cgroup_helpers.c index 4d74f3c4619b..0fb910df5387 100644 --- a/tools/testing/selftests/bpf/cgroup_helpers.c +++ b/tools/testing/selftests/bpf/cgroup_helpers.c @@ -98,7 +98,7 @@ static int enable_all_controllers(char *cgroup_path) */ int setup_cgroup_environment(void) { - char cgroup_workdir[PATH_MAX + 1]; + char cgroup_workdir[PATH_MAX - 24]; format_cgroup_path(cgroup_workdir, ""); -- cgit v1.2.3 From 38f51c07054ff4796e473dba3bff2e648378002c Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 3 Oct 2019 01:45:11 +0200 Subject: bpf, x86: Small optimization in comparing against imm0 Replace 'cmp reg, 0' with 'test reg, reg' for comparisons against zero. Saves 1 byte of instruction encoding per occurrence. The flag results of test 'reg, reg' are identical to 'cmp reg, 0' in all cases except for AF which we don't use/care about. In terms of macro-fusibility in combination with a subsequent conditional jump instruction, both have the same properties for the jumps used in the JIT translation. For example, same JITed Cilium program can shrink a bit from e.g. 12,455 to 12,317 bytes as tests with 0 are used quite frequently. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Acked-by: Song Liu Acked-by: John Fastabend --- arch/x86/net/bpf_jit_comp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 991549a1c5f3..3ad2ba1ad855 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -909,6 +909,16 @@ xadd: if (is_imm8(insn->off)) case BPF_JMP32 | BPF_JSLT | BPF_K: case BPF_JMP32 | BPF_JSGE | BPF_K: case BPF_JMP32 | BPF_JSLE | BPF_K: + /* test dst_reg, dst_reg to save one extra byte */ + if (imm32 == 0) { + if (BPF_CLASS(insn->code) == BPF_JMP) + EMIT1(add_2mod(0x48, dst_reg, dst_reg)); + else if (is_ereg(dst_reg)) + EMIT1(add_2mod(0x40, dst_reg, dst_reg)); + EMIT2(0x85, add_2reg(0xC0, dst_reg, dst_reg)); + goto emit_cond_jmp; + } + /* cmp dst_reg, imm8/32 */ if (BPF_CLASS(insn->code) == BPF_JMP) EMIT1(add_1mod(0x48, dst_reg)); -- cgit v1.2.3 From 4bbbf164f1a5e970543dcdb7a396fc1cf477725b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 3 Oct 2019 01:45:12 +0200 Subject: bpf: Add loop test case with 32 bit reg comparison against 0 Add a loop test with 32 bit register against 0 immediate: # ./test_verifier 631 #631/p taken loop with back jump to 1st insn, 2 OK Disassembly: [...] 1b: test %edi,%edi 1d: jne 0x0000000000000014 [...] Pretty much similar to prior "taken loop with back jump to 1st insn" test case just as jmp32 variant. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Acked-by: Song Liu --- tools/testing/selftests/bpf/verifier/loops1.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/testing/selftests/bpf/verifier/loops1.c b/tools/testing/selftests/bpf/verifier/loops1.c index 1fc4e61e9f9f..1af37187dc12 100644 --- a/tools/testing/selftests/bpf/verifier/loops1.c +++ b/tools/testing/selftests/bpf/verifier/loops1.c @@ -187,3 +187,20 @@ .prog_type = BPF_PROG_TYPE_XDP, .retval = 55, }, +{ + "taken loop with back jump to 1st insn, 2", + .insns = { + BPF_MOV64_IMM(BPF_REG_1, 10), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 1, 0, 1), + BPF_EXIT_INSN(), + BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_1), + BPF_ALU64_IMM(BPF_SUB, BPF_REG_1, 1), + BPF_JMP32_IMM(BPF_JNE, BPF_REG_1, 0, -3), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_XDP, + .retval = 55, +}, -- cgit v1.2.3 From a53ba15d81995868651dd28a85d8045aef3d4e20 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 3 Oct 2019 21:02:11 -0700 Subject: libbpf: Fix BTF-defined map's __type macro handling of arrays Due to a quirky C syntax of declaring pointers to array or function prototype, existing __type() macro doesn't work with map key/value types that are array or function prototype. One has to create a typedef first and use it to specify key/value type for a BPF map. By using typeof(), pointer to type is now handled uniformly for all kinds of types. Convert one of self-tests as a demonstration. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191004040211.2434033-1-andriin@fb.com --- tools/testing/selftests/bpf/bpf_helpers.h | 2 +- tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 54a50699bbfd..9f77cbaac01c 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -3,7 +3,7 @@ #define __BPF_HELPERS__ #define __uint(name, val) int (*name)[val] -#define __type(name, val) val *name +#define __type(name, val) typeof(val) *name /* helper macro to print out debug messages */ #define bpf_printk(fmt, ...) \ diff --git a/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c index f8ffa3f3d44b..6cc4479ac9df 100644 --- a/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c +++ b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c @@ -47,12 +47,11 @@ struct { * issue and avoid complicated C programming massaging. * This is an acceptable workaround since there is one entry here. */ -typedef __u64 raw_stack_trace_t[2 * MAX_STACK_RAWTP]; struct { __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); __uint(max_entries, 1); __type(key, __u32); - __type(value, raw_stack_trace_t); + __type(value, __u64[2 * MAX_STACK_RAWTP]); } rawdata_map SEC(".maps"); SEC("raw_tracepoint/sys_enter") -- cgit v1.2.3 From 5e61f27070292d4ad3af51dc68eebab6c1df69d3 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 4 Oct 2019 15:40:34 -0700 Subject: libbpf: stop enforcing kern_version, populate it for users Kernel version enforcement for kprobes/kretprobes was removed from 5.0 kernel in 6c4fc209fcf9 ("bpf: remove useless version check for prog load"). Since then, BPF programs were specifying SEC("version") just to please libbpf. We should stop enforcing this in libbpf, if even kernel doesn't care. Furthermore, libbpf now will pre-populate current kernel version of the host system, in case we are still running on old kernel. This patch also removes __bpf_object__open_xattr from libbpf.h, as nothing in libbpf is relying on having it in that header. That function was never exported as LIBBPF_API and even name suggests its internal version. So this should be safe to remove, as it doesn't break ABI. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.c | 100 +++++---------------- tools/lib/bpf/libbpf.h | 2 - .../selftests/bpf/progs/test_attach_probe.c | 1 - .../selftests/bpf/progs/test_get_stack_rawtp.c | 1 - .../testing/selftests/bpf/progs/test_perf_buffer.c | 1 - .../selftests/bpf/progs/test_stacktrace_map.c | 1 - 6 files changed, 23 insertions(+), 83 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index e0276520171b..024334b29b54 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -255,7 +256,7 @@ struct bpf_object { */ struct { int fd; - void *obj_buf; + const void *obj_buf; size_t obj_buf_sz; Elf *elf; GElf_Ehdr ehdr; @@ -491,8 +492,19 @@ bpf_object__init_prog_names(struct bpf_object *obj) return 0; } +static __u32 get_kernel_version(void) +{ + __u32 major, minor, patch; + struct utsname info; + + uname(&info); + if (sscanf(info.release, "%u.%u.%u", &major, &minor, &patch) != 3) + return 0; + return KERNEL_VERSION(major, minor, patch); +} + static struct bpf_object *bpf_object__new(const char *path, - void *obj_buf, + const void *obj_buf, size_t obj_buf_sz) { struct bpf_object *obj; @@ -526,6 +538,7 @@ static struct bpf_object *bpf_object__new(const char *path, obj->efile.rodata_shndx = -1; obj->efile.bss_shndx = -1; + obj->kern_version = get_kernel_version(); obj->loaded = false; INIT_LIST_HEAD(&obj->list); @@ -569,7 +582,7 @@ static int bpf_object__elf_init(struct bpf_object *obj) * obj_buf should have been validated by * bpf_object__open_buffer(). */ - obj->efile.elf = elf_memory(obj->efile.obj_buf, + obj->efile.elf = elf_memory((char *)obj->efile.obj_buf, obj->efile.obj_buf_sz); } else { obj->efile.fd = open(obj->path, O_RDONLY); @@ -636,21 +649,6 @@ bpf_object__init_license(struct bpf_object *obj, void *data, size_t size) return 0; } -static int -bpf_object__init_kversion(struct bpf_object *obj, void *data, size_t size) -{ - __u32 kver; - - if (size != sizeof(kver)) { - pr_warning("invalid kver section in %s\n", obj->path); - return -LIBBPF_ERRNO__FORMAT; - } - memcpy(&kver, data, sizeof(kver)); - obj->kern_version = kver; - pr_debug("kernel version of %s is %x\n", obj->path, obj->kern_version); - return 0; -} - static int compare_bpf_map(const void *_a, const void *_b) { const struct bpf_map *a = _a; @@ -1568,11 +1566,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) if (err) return err; } else if (strcmp(name, "version") == 0) { - err = bpf_object__init_kversion(obj, - data->d_buf, - data->d_size); - if (err) - return err; + /* skip, we don't need it anymore */ } else if (strcmp(name, "maps") == 0) { obj->efile.maps_shndx = idx; } else if (strcmp(name, MAPS_ELF_SEC) == 0) { @@ -3551,54 +3545,9 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level) return 0; } -static bool bpf_prog_type__needs_kver(enum bpf_prog_type type) -{ - switch (type) { - case BPF_PROG_TYPE_SOCKET_FILTER: - case BPF_PROG_TYPE_SCHED_CLS: - case BPF_PROG_TYPE_SCHED_ACT: - case BPF_PROG_TYPE_XDP: - case BPF_PROG_TYPE_CGROUP_SKB: - case BPF_PROG_TYPE_CGROUP_SOCK: - case BPF_PROG_TYPE_LWT_IN: - case BPF_PROG_TYPE_LWT_OUT: - case BPF_PROG_TYPE_LWT_XMIT: - case BPF_PROG_TYPE_LWT_SEG6LOCAL: - case BPF_PROG_TYPE_SOCK_OPS: - case BPF_PROG_TYPE_SK_SKB: - case BPF_PROG_TYPE_CGROUP_DEVICE: - case BPF_PROG_TYPE_SK_MSG: - case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: - case BPF_PROG_TYPE_LIRC_MODE2: - case BPF_PROG_TYPE_SK_REUSEPORT: - case BPF_PROG_TYPE_FLOW_DISSECTOR: - case BPF_PROG_TYPE_UNSPEC: - case BPF_PROG_TYPE_TRACEPOINT: - case BPF_PROG_TYPE_RAW_TRACEPOINT: - case BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE: - case BPF_PROG_TYPE_PERF_EVENT: - case BPF_PROG_TYPE_CGROUP_SYSCTL: - case BPF_PROG_TYPE_CGROUP_SOCKOPT: - return false; - case BPF_PROG_TYPE_KPROBE: - default: - return true; - } -} - -static int bpf_object__validate(struct bpf_object *obj, bool needs_kver) -{ - if (needs_kver && obj->kern_version == 0) { - pr_warning("%s doesn't provide kernel version\n", - obj->path); - return -LIBBPF_ERRNO__KVERSION; - } - return 0; -} - static struct bpf_object * -__bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, - bool needs_kver, int flags) +__bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, + int flags) { struct bpf_object *obj; int err; @@ -3617,7 +3566,6 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz, CHECK_ERR(bpf_object__probe_caps(obj), err, out); CHECK_ERR(bpf_object__elf_collect(obj, flags), err, out); CHECK_ERR(bpf_object__collect_reloc(obj), err, out); - CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out); bpf_object__elf_finish(obj); return obj; @@ -3626,8 +3574,8 @@ out: return ERR_PTR(err); } -struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, - int flags) +static struct bpf_object * +__bpf_object__open_xattr(struct bpf_object_open_attr *attr, int flags) { /* param validation */ if (!attr->file) @@ -3635,9 +3583,7 @@ struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, pr_debug("loading %s\n", attr->file); - return __bpf_object__open(attr->file, NULL, 0, - bpf_prog_type__needs_kver(attr->prog_type), - flags); + return __bpf_object__open(attr->file, NULL, 0, flags); } struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) @@ -3673,7 +3619,7 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf, } pr_debug("loading object '%s' from buffer\n", name); - return __bpf_object__open(name, obj_buf, obj_buf_sz, true, true); + return __bpf_object__open(name, obj_buf, obj_buf_sz, true); } int bpf_object__unload(struct bpf_object *obj) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index e8f70977d137..2905dffd70b2 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -70,8 +70,6 @@ struct bpf_object_open_attr { LIBBPF_API struct bpf_object *bpf_object__open(const char *path); LIBBPF_API struct bpf_object * bpf_object__open_xattr(struct bpf_object_open_attr *attr); -struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr, - int flags); LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, size_t obj_buf_sz, const char *name); diff --git a/tools/testing/selftests/bpf/progs/test_attach_probe.c b/tools/testing/selftests/bpf/progs/test_attach_probe.c index 63a8dfef893b..534621e38906 100644 --- a/tools/testing/selftests/bpf/progs/test_attach_probe.c +++ b/tools/testing/selftests/bpf/progs/test_attach_probe.c @@ -49,4 +49,3 @@ int handle_uprobe_return(struct pt_regs *ctx) } char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; diff --git a/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c index 6cc4479ac9df..6a4a8f57f174 100644 --- a/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c +++ b/tools/testing/selftests/bpf/progs/test_get_stack_rawtp.c @@ -99,4 +99,3 @@ int bpf_prog1(void *ctx) } char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/progs/test_perf_buffer.c b/tools/testing/selftests/bpf/progs/test_perf_buffer.c index 876c27deb65a..07c09ca5546a 100644 --- a/tools/testing/selftests/bpf/progs/test_perf_buffer.c +++ b/tools/testing/selftests/bpf/progs/test_perf_buffer.c @@ -22,4 +22,3 @@ int handle_sys_nanosleep_entry(struct pt_regs *ctx) } char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; diff --git a/tools/testing/selftests/bpf/progs/test_stacktrace_map.c b/tools/testing/selftests/bpf/progs/test_stacktrace_map.c index fa0be3e10a10..3b7e1dca8829 100644 --- a/tools/testing/selftests/bpf/progs/test_stacktrace_map.c +++ b/tools/testing/selftests/bpf/progs/test_stacktrace_map.c @@ -74,4 +74,3 @@ int oncpu(struct sched_switch_args *ctx) } char _license[] SEC("license") = "GPL"; -__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ -- cgit v1.2.3 From 2ce8450ef5a381e5ffeb4682c0093a3ab5d07008 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 4 Oct 2019 15:40:35 -0700 Subject: libbpf: add bpf_object__open_{file, mem} w/ extensible opts Add new set of bpf_object__open APIs using new approach to optional parameters extensibility allowing simpler ABI compatibility approach. This patch demonstrates an approach to implementing libbpf APIs that makes it easy to extend existing APIs with extra optional parameters in such a way, that ABI compatibility is preserved without having to do symbol versioning and generating lots of boilerplate code to handle it. To facilitate succinct code for working with options, add OPTS_VALID, OPTS_HAS, and OPTS_GET macros that hide all the NULL, size, and zero checks. Additionally, newly added libbpf APIs are encouraged to follow similar pattern of having all mandatory parameters as formal function parameters and always have optional (NULL-able) xxx_opts struct, which should always have real struct size as a first field and the rest would be optional parameters added over time, which tune the behavior of existing API, if specified by user. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.c | 87 ++++++++++++++++++++++++++++++++--------- tools/lib/bpf/libbpf.h | 46 ++++++++++++++++++++-- tools/lib/bpf/libbpf.map | 3 ++ tools/lib/bpf/libbpf_internal.h | 32 +++++++++++++++ 4 files changed, 146 insertions(+), 22 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 024334b29b54..d471d33400ae 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -505,7 +505,8 @@ static __u32 get_kernel_version(void) static struct bpf_object *bpf_object__new(const char *path, const void *obj_buf, - size_t obj_buf_sz) + size_t obj_buf_sz, + const char *obj_name) { struct bpf_object *obj; char *end; @@ -517,11 +518,17 @@ static struct bpf_object *bpf_object__new(const char *path, } strcpy(obj->path, path); - /* Using basename() GNU version which doesn't modify arg. */ - strncpy(obj->name, basename((void *)path), sizeof(obj->name) - 1); - end = strchr(obj->name, '.'); - if (end) - *end = 0; + if (obj_name) { + strncpy(obj->name, obj_name, sizeof(obj->name) - 1); + obj->name[sizeof(obj->name) - 1] = 0; + } else { + /* Using basename() GNU version which doesn't modify arg. */ + strncpy(obj->name, basename((void *)path), + sizeof(obj->name) - 1); + end = strchr(obj->name, '.'); + if (end) + *end = 0; + } obj->efile.fd = -1; /* @@ -3547,7 +3554,7 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level) static struct bpf_object * __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, - int flags) + const char *obj_name, int flags) { struct bpf_object *obj; int err; @@ -3557,7 +3564,7 @@ __bpf_object__open(const char *path, const void *obj_buf, size_t obj_buf_sz, return ERR_PTR(-LIBBPF_ERRNO__LIBELF); } - obj = bpf_object__new(path, obj_buf, obj_buf_sz); + obj = bpf_object__new(path, obj_buf, obj_buf_sz, obj_name); if (IS_ERR(obj)) return obj; @@ -3583,7 +3590,7 @@ __bpf_object__open_xattr(struct bpf_object_open_attr *attr, int flags) pr_debug("loading %s\n", attr->file); - return __bpf_object__open(attr->file, NULL, 0, flags); + return __bpf_object__open(attr->file, NULL, 0, NULL, flags); } struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr) @@ -3601,25 +3608,67 @@ struct bpf_object *bpf_object__open(const char *path) return bpf_object__open_xattr(&attr); } -struct bpf_object *bpf_object__open_buffer(void *obj_buf, - size_t obj_buf_sz, - const char *name) +struct bpf_object * +bpf_object__open_file(const char *path, struct bpf_object_open_opts *opts) +{ + const char *obj_name; + bool relaxed_maps; + + if (!OPTS_VALID(opts, bpf_object_open_opts)) + return ERR_PTR(-EINVAL); + if (!path) + return ERR_PTR(-EINVAL); + + pr_debug("loading %s\n", path); + + obj_name = OPTS_GET(opts, object_name, path); + relaxed_maps = OPTS_GET(opts, relaxed_maps, false); + return __bpf_object__open(path, NULL, 0, obj_name, + relaxed_maps ? MAPS_RELAX_COMPAT : 0); +} + +struct bpf_object * +bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz, + struct bpf_object_open_opts *opts) { char tmp_name[64]; + const char *obj_name; + bool relaxed_maps; - /* param validation */ - if (!obj_buf || obj_buf_sz <= 0) - return NULL; + if (!OPTS_VALID(opts, bpf_object_open_opts)) + return ERR_PTR(-EINVAL); + if (!obj_buf || obj_buf_sz == 0) + return ERR_PTR(-EINVAL); - if (!name) { + obj_name = OPTS_GET(opts, object_name, NULL); + if (!obj_name) { snprintf(tmp_name, sizeof(tmp_name), "%lx-%lx", (unsigned long)obj_buf, (unsigned long)obj_buf_sz); - name = tmp_name; + obj_name = tmp_name; } - pr_debug("loading object '%s' from buffer\n", name); + pr_debug("loading object '%s' from buffer\n", obj_name); + + relaxed_maps = OPTS_GET(opts, relaxed_maps, false); + return __bpf_object__open(obj_name, obj_buf, obj_buf_sz, obj_name, + relaxed_maps ? MAPS_RELAX_COMPAT : 0); +} + +struct bpf_object * +bpf_object__open_buffer(const void *obj_buf, size_t obj_buf_sz, + const char *name) +{ + LIBBPF_OPTS(bpf_object_open_opts, opts, + .object_name = name, + /* wrong default, but backwards-compatible */ + .relaxed_maps = true, + ); + + /* returning NULL is wrong, but backwards-compatible */ + if (!obj_buf || obj_buf_sz == 0) + return NULL; - return __bpf_object__open(name, obj_buf, obj_buf_sz, true); + return bpf_object__open_mem(obj_buf, obj_buf_sz, &opts); } int bpf_object__unload(struct bpf_object *obj) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 2905dffd70b2..667e6853e51f 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -67,12 +67,52 @@ struct bpf_object_open_attr { enum bpf_prog_type prog_type; }; +/* Helper macro to declare and initialize libbpf options struct + * + * This dance with uninitialized declaration, followed by memset to zero, + * followed by assignment using compound literal syntax is done to preserve + * ability to use a nice struct field initialization syntax and **hopefully** + * have all the padding bytes initialized to zero. It's not guaranteed though, + * when copying literal, that compiler won't copy garbage in literal's padding + * bytes, but that's the best way I've found and it seems to work in practice. + */ +#define LIBBPF_OPTS(TYPE, NAME, ...) \ + struct TYPE NAME; \ + memset(&NAME, 0, sizeof(struct TYPE)); \ + NAME = (struct TYPE) { \ + .sz = sizeof(struct TYPE), \ + __VA_ARGS__ \ + } + +struct bpf_object_open_opts { + /* size of this struct, for forward/backward compatiblity */ + size_t sz; + /* object name override, if provided: + * - for object open from file, this will override setting object + * name from file path's base name; + * - for object open from memory buffer, this will specify an object + * name and will override default "-" name; + */ + const char *object_name; + /* parse map definitions non-strictly, allowing extra attributes/data */ + bool relaxed_maps; +}; +#define bpf_object_open_opts__last_field relaxed_maps + LIBBPF_API struct bpf_object *bpf_object__open(const char *path); LIBBPF_API struct bpf_object * +bpf_object__open_file(const char *path, struct bpf_object_open_opts *opts); +LIBBPF_API struct bpf_object * +bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz, + struct bpf_object_open_opts *opts); + +/* deprecated bpf_object__open variants */ +LIBBPF_API struct bpf_object * +bpf_object__open_buffer(const void *obj_buf, size_t obj_buf_sz, + const char *name); +LIBBPF_API struct bpf_object * bpf_object__open_xattr(struct bpf_object_open_attr *attr); -LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, - size_t obj_buf_sz, - const char *name); + int bpf_object__section_size(const struct bpf_object *obj, const char *name, __u32 *size); int bpf_object__variable_offset(const struct bpf_object *obj, const char *name, diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 8d10ca03d78d..4d241fd92dd4 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -192,4 +192,7 @@ LIBBPF_0.0.5 { } LIBBPF_0.0.4; LIBBPF_0.0.6 { + global: + bpf_object__open_file; + bpf_object__open_mem; } LIBBPF_0.0.5; diff --git a/tools/lib/bpf/libbpf_internal.h b/tools/lib/bpf/libbpf_internal.h index 2e83a34f8c79..f51444fc7eb7 100644 --- a/tools/lib/bpf/libbpf_internal.h +++ b/tools/lib/bpf/libbpf_internal.h @@ -47,6 +47,38 @@ do { \ #define pr_info(fmt, ...) __pr(LIBBPF_INFO, fmt, ##__VA_ARGS__) #define pr_debug(fmt, ...) __pr(LIBBPF_DEBUG, fmt, ##__VA_ARGS__) +static inline bool libbpf_validate_opts(const char *opts, + size_t opts_sz, size_t user_sz, + const char *type_name) +{ + if (user_sz < sizeof(size_t)) { + pr_warning("%s size (%zu) is too small\n", type_name, user_sz); + return false; + } + if (user_sz > opts_sz) { + size_t i; + + for (i = opts_sz; i < user_sz; i++) { + if (opts[i]) { + pr_warning("%s has non-zero extra bytes", + type_name); + return false; + } + } + } + return true; +} + +#define OPTS_VALID(opts, type) \ + (!(opts) || libbpf_validate_opts((const char *)opts, \ + offsetofend(struct type, \ + type##__last_field), \ + (opts)->sz, #type)) +#define OPTS_HAS(opts, field) \ + ((opts) && opts->sz >= offsetofend(typeof(*(opts)), field)) +#define OPTS_GET(opts, field, fallback_value) \ + (OPTS_HAS(opts, field) ? (opts)->field : fallback_value) + int libbpf__load_raw_btf(const char *raw_types, size_t types_len, const char *str_sec, size_t str_len); -- cgit v1.2.3 From c9e4c3010c8c98aa867fce386ee459a32c00a487 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 4 Oct 2019 15:40:36 -0700 Subject: libbpf: fix bpf_object__name() to actually return object name bpf_object__name() was returning file path, not name. Fix this. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov --- tools/lib/bpf/libbpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index d471d33400ae..a02cdedc4e3f 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -4231,7 +4231,7 @@ bpf_object__next(struct bpf_object *prev) const char *bpf_object__name(const struct bpf_object *obj) { - return obj ? obj->path : ERR_PTR(-EINVAL); + return obj ? obj->name : ERR_PTR(-EINVAL); } unsigned int bpf_object__kversion(const struct bpf_object *obj) -- cgit v1.2.3 From 928ca75e59d7cf10ad2c4b446c7b5d046e244027 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 4 Oct 2019 15:40:37 -0700 Subject: selftests/bpf: switch tests to new bpf_object__open_{file, mem}() APIs Verify new bpf_object__open_mem() and bpf_object__open_file() APIs work as expected by switching test_attach_probe test to use embedded BPF object and bpf_object__open_mem() and test_reference_tracking to bpf_object__open_file(). Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 2 +- .../selftests/bpf/prog_tests/attach_probe.c | 49 +++++++++++++++++++--- .../selftests/bpf/prog_tests/reference_tracking.c | 16 ++++++- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 6889c19a628c..294d7472dad7 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -160,7 +160,7 @@ $(OUTPUT)/test_queue_map.o: test_queue_stack_map.h $(OUTPUT)/test_stack_map.o: test_queue_stack_map.h $(OUTPUT)/flow_dissector_load.o: flow_dissector_load.h -$(OUTPUT)/test_progs.o: flow_dissector_load.h +$(OUTPUT)/test_progs.o: flow_dissector_load.h $(OUTPUT)/test_attach_probe.o BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) diff --git a/tools/testing/selftests/bpf/prog_tests/attach_probe.c b/tools/testing/selftests/bpf/prog_tests/attach_probe.c index 5ecc267d98b0..4f50d32c4abb 100644 --- a/tools/testing/selftests/bpf/prog_tests/attach_probe.c +++ b/tools/testing/selftests/bpf/prog_tests/attach_probe.c @@ -1,6 +1,24 @@ // SPDX-License-Identifier: GPL-2.0 #include +#define EMBED_FILE(NAME, PATH) \ +asm ( \ +" .pushsection \".rodata\", \"a\", @progbits \n" \ +" .global "#NAME"_data \n" \ +#NAME"_data: \n" \ +" .incbin \"" PATH "\" \n" \ +#NAME"_data_end: \n" \ +" .global "#NAME"_size \n" \ +" .type "#NAME"_size, @object \n" \ +" .size "#NAME"_size, 4 \n" \ +" .align 4, \n" \ +#NAME"_size: \n" \ +" .int "#NAME"_data_end - "#NAME"_data \n" \ +" .popsection \n" \ +); \ +extern char NAME##_data[]; \ +extern int NAME##_size; + ssize_t get_base_addr() { size_t start; char buf[256]; @@ -21,6 +39,8 @@ ssize_t get_base_addr() { return -EINVAL; } +EMBED_FILE(probe, "test_attach_probe.o"); + void test_attach_probe(void) { const char *kprobe_name = "kprobe/sys_nanosleep"; @@ -29,11 +49,15 @@ void test_attach_probe(void) const char *uretprobe_name = "uretprobe/trigger_func"; const int kprobe_idx = 0, kretprobe_idx = 1; const int uprobe_idx = 2, uretprobe_idx = 3; - const char *file = "./test_attach_probe.o"; + const char *obj_name = "attach_probe"; + LIBBPF_OPTS(bpf_object_open_opts, open_opts, + .object_name = obj_name, + .relaxed_maps = true, + ); struct bpf_program *kprobe_prog, *kretprobe_prog; struct bpf_program *uprobe_prog, *uretprobe_prog; struct bpf_object *obj; - int err, prog_fd, duration = 0, res; + int err, duration = 0, res; struct bpf_link *kprobe_link = NULL; struct bpf_link *kretprobe_link = NULL; struct bpf_link *uprobe_link = NULL; @@ -48,11 +72,16 @@ void test_attach_probe(void) return; uprobe_offset = (size_t)&get_base_addr - base_addr; - /* load programs */ - err = bpf_prog_load(file, BPF_PROG_TYPE_KPROBE, &obj, &prog_fd); - if (CHECK(err, "obj_load", "err %d errno %d\n", err, errno)) + /* open object */ + obj = bpf_object__open_mem(probe_data, probe_size, &open_opts); + if (CHECK(IS_ERR(obj), "obj_open_mem", "err %ld\n", PTR_ERR(obj))) return; + if (CHECK(strcmp(bpf_object__name(obj), obj_name), "obj_name", + "wrong obj name '%s', expected '%s'\n", + bpf_object__name(obj), obj_name)) + goto cleanup; + kprobe_prog = bpf_object__find_program_by_title(obj, kprobe_name); if (CHECK(!kprobe_prog, "find_probe", "prog '%s' not found\n", kprobe_name)) @@ -70,6 +99,16 @@ void test_attach_probe(void) "prog '%s' not found\n", uretprobe_name)) goto cleanup; + bpf_program__set_kprobe(kprobe_prog); + bpf_program__set_kprobe(kretprobe_prog); + bpf_program__set_kprobe(uprobe_prog); + bpf_program__set_kprobe(uretprobe_prog); + + /* create maps && load programs */ + err = bpf_object__load(obj); + if (CHECK(err, "obj_load", "err %d\n", err)) + goto cleanup; + /* load maps */ results_map_fd = bpf_find_map(__func__, obj, "results_map"); if (CHECK(results_map_fd < 0, "find_results_map", diff --git a/tools/testing/selftests/bpf/prog_tests/reference_tracking.c b/tools/testing/selftests/bpf/prog_tests/reference_tracking.c index 5c78e2b5a917..86cee820d4d3 100644 --- a/tools/testing/selftests/bpf/prog_tests/reference_tracking.c +++ b/tools/testing/selftests/bpf/prog_tests/reference_tracking.c @@ -3,16 +3,26 @@ void test_reference_tracking(void) { - const char *file = "./test_sk_lookup_kern.o"; + const char *file = "test_sk_lookup_kern.o"; + const char *obj_name = "ref_track"; + LIBBPF_OPTS(bpf_object_open_opts, open_opts, + .object_name = obj_name, + .relaxed_maps = true, + ); struct bpf_object *obj; struct bpf_program *prog; __u32 duration = 0; int err = 0; - obj = bpf_object__open(file); + obj = bpf_object__open_file(file, &open_opts); if (CHECK_FAIL(IS_ERR(obj))) return; + if (CHECK(strcmp(bpf_object__name(obj), obj_name), "obj_name", + "wrong obj name '%s', expected '%s'\n", + bpf_object__name(obj), obj_name)) + goto cleanup; + bpf_object__for_each_program(prog, obj) { const char *title; @@ -35,5 +45,7 @@ void test_reference_tracking(void) } CHECK(err, title, "\n"); } + +cleanup: bpf_object__close(obj); } -- cgit v1.2.3 From a9eb048d5615152dc4b8aedb7e704a4e59bc2205 Mon Sep 17 00:00:00 2001 From: Toke Høiland-Jørgensen Date: Fri, 4 Oct 2019 17:34:44 +0200 Subject: libbpf: Add cscope and tags targets to Makefile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using cscope and/or TAGS files for navigating the source code is useful. Add simple targets to the Makefile to generate the index files for both tools. Signed-off-by: Toke Høiland-Jørgensen Signed-off-by: Alexei Starovoitov Tested-by: Andrii Nakryiko Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191004153444.1711278-1-toke@redhat.com --- tools/lib/bpf/.gitignore | 3 +++ tools/lib/bpf/Makefile | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore index d9e9dec04605..12382b0c71c7 100644 --- a/tools/lib/bpf/.gitignore +++ b/tools/lib/bpf/.gitignore @@ -3,3 +3,6 @@ libbpf.pc FEATURE-DUMP.libbpf test_libbpf libbpf.so.* +TAGS +tags +cscope.* diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index c6f94cffe06e..10b77644a17c 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -133,6 +133,8 @@ LIB_TARGET := $(addprefix $(OUTPUT),$(LIB_TARGET)) LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) PC_FILE := $(addprefix $(OUTPUT),$(PC_FILE)) +TAGS_PROG := $(if $(shell which etags 2>/dev/null),etags,ctags) + GLOBAL_SYM_COUNT = $(shell readelf -s --wide $(BPF_IN) | \ cut -d "@" -f1 | sed 's/_v[0-9]_[0-9]_[0-9].*//' | \ awk '/GLOBAL/ && /DEFAULT/ && !/UND/ {print $$8}' | \ @@ -262,7 +264,7 @@ clean: -PHONY += force elfdep bpfdep +PHONY += force elfdep bpfdep cscope tags force: elfdep: @@ -271,6 +273,14 @@ elfdep: bpfdep: @if [ "$(feature-bpf)" != "1" ]; then echo "BPF API too old"; exit 1 ; fi +cscope: + ls *.c *.h > cscope.files + cscope -b -q -I $(srctree)/include -f cscope.out + +tags: + rm -f TAGS tags + ls *.c *.h | xargs $(TAGS_PROG) -a + # Declare the contents of the .PHONY variable as phony. We keep that # information in a variable so we can use it in if_changed and friends. .PHONY: $(PHONY) -- cgit v1.2.3 From 5f0e5412781b01708f622d00c0b3f77b9dca7367 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sun, 6 Oct 2019 20:07:36 -0700 Subject: uapi/bpf: fix helper docs Various small fixes to BPF helper documentation comments, enabling automatic header generation with a list of BPF helpers. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov --- include/uapi/linux/bpf.h | 32 ++++++++++++++++---------------- tools/include/uapi/linux/bpf.h | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 77c6be96d676..a65c3b0c6935 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -794,7 +794,7 @@ union bpf_attr { * A 64-bit integer containing the current GID and UID, and * created as such: *current_gid* **<< 32 \|** *current_uid*. * - * int bpf_get_current_comm(char *buf, u32 size_of_buf) + * int bpf_get_current_comm(void *buf, u32 size_of_buf) * Description * Copy the **comm** attribute of the current task into *buf* of * *size_of_buf*. The **comm** attribute contains the name of @@ -1023,7 +1023,7 @@ union bpf_attr { * The realm of the route for the packet associated to *skb*, or 0 * if none was found. * - * int bpf_perf_event_output(struct pt_regs *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) + * int bpf_perf_event_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) * Description * Write raw *data* blob into a special BPF perf event held by * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf @@ -1068,7 +1068,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len) + * int bpf_skb_load_bytes(const void *skb, u32 offset, void *to, u32 len) * Description * This helper was provided as an easy way to load data from a * packet. It can be used to load *len* bytes from *offset* from @@ -1085,7 +1085,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_get_stackid(struct pt_regs *ctx, struct bpf_map *map, u64 flags) + * int bpf_get_stackid(void *ctx, struct bpf_map *map, u64 flags) * Description * Walk a user or a kernel stack and return its id. To achieve * this, the helper needs *ctx*, which is a pointer to the context @@ -1154,7 +1154,7 @@ union bpf_attr { * The checksum result, or a negative error code in case of * failure. * - * int bpf_skb_get_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size) + * int bpf_skb_get_tunnel_opt(struct sk_buff *skb, void *opt, u32 size) * Description * Retrieve tunnel options metadata for the packet associated to * *skb*, and store the raw tunnel option data to the buffer *opt* @@ -1172,7 +1172,7 @@ union bpf_attr { * Return * The size of the option data retrieved. * - * int bpf_skb_set_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size) + * int bpf_skb_set_tunnel_opt(struct sk_buff *skb, void *opt, u32 size) * Description * Set tunnel options metadata for the packet associated to *skb* * to the option data contained in the raw buffer *opt* of *size*. @@ -1511,7 +1511,7 @@ union bpf_attr { * Return * 0 * - * int bpf_setsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen) + * int bpf_setsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, void *optval, int optlen) * Description * Emulate a call to **setsockopt()** on the socket associated to * *bpf_socket*, which must be a full socket. The *level* at @@ -1595,7 +1595,7 @@ union bpf_attr { * Return * **XDP_REDIRECT** on success, or **XDP_ABORTED** on error. * - * int bpf_sk_redirect_map(struct bpf_map *map, u32 key, u64 flags) + * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) * Description * Redirect the packet to the socket referenced by *map* (of type * **BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and @@ -1715,7 +1715,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_getsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen) + * int bpf_getsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, void *optval, int optlen) * Description * Emulate a call to **getsockopt()** on the socket associated to * *bpf_socket*, which must be a full socket. The *level* at @@ -1947,7 +1947,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_get_stack(struct pt_regs *regs, void *buf, u32 size, u64 flags) + * int bpf_get_stack(void *ctx, void *buf, u32 size, u64 flags) * Description * Return a user or a kernel stack in bpf program provided buffer. * To achieve this, the helper needs *ctx*, which is a pointer @@ -1980,7 +1980,7 @@ union bpf_attr { * A non-negative value equal to or less than *size* on success, * or a negative error in case of failure. * - * int bpf_skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header) + * int bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header) * Description * This helper is similar to **bpf_skb_load_bytes**\ () in that * it provides an easy way to load *len* bytes from *offset* @@ -2033,7 +2033,7 @@ union bpf_attr { * * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the * packet is not forwarded or needs assist from full stack * - * int bpf_sock_hash_update(struct bpf_sock_ops_kern *skops, struct bpf_map *map, void *key, u64 flags) + * int bpf_sock_hash_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags) * Description * Add an entry to, or update a sockhash *map* referencing sockets. * The *skops* is used as a new value for the entry associated to @@ -2392,7 +2392,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags) + * int bpf_msg_push_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags) * Description * For socket policies, insert *len* bytes into *msg* at offset * *start*. @@ -2408,9 +2408,9 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 pop, u64 flags) + * int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags) * Description - * Will remove *pop* bytes from a *msg* starting at byte *start*. + * Will remove *len* bytes from a *msg* starting at byte *start*. * This may result in **ENOMEM** errors under certain situations if * an allocation and copy are required due to a full ring buffer. * However, the helper will try to avoid doing the allocation @@ -2505,7 +2505,7 @@ union bpf_attr { * A **struct bpf_tcp_sock** pointer on success, or **NULL** in * case of failure. * - * int bpf_skb_ecn_set_ce(struct sk_buf *skb) + * int bpf_skb_ecn_set_ce(struct sk_buff *skb) * Description * Set ECN (Explicit Congestion Notification) field of IP header * to **CE** (Congestion Encountered) if current value is **ECT** diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 77c6be96d676..a65c3b0c6935 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -794,7 +794,7 @@ union bpf_attr { * A 64-bit integer containing the current GID and UID, and * created as such: *current_gid* **<< 32 \|** *current_uid*. * - * int bpf_get_current_comm(char *buf, u32 size_of_buf) + * int bpf_get_current_comm(void *buf, u32 size_of_buf) * Description * Copy the **comm** attribute of the current task into *buf* of * *size_of_buf*. The **comm** attribute contains the name of @@ -1023,7 +1023,7 @@ union bpf_attr { * The realm of the route for the packet associated to *skb*, or 0 * if none was found. * - * int bpf_perf_event_output(struct pt_regs *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) + * int bpf_perf_event_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) * Description * Write raw *data* blob into a special BPF perf event held by * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf @@ -1068,7 +1068,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len) + * int bpf_skb_load_bytes(const void *skb, u32 offset, void *to, u32 len) * Description * This helper was provided as an easy way to load data from a * packet. It can be used to load *len* bytes from *offset* from @@ -1085,7 +1085,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_get_stackid(struct pt_regs *ctx, struct bpf_map *map, u64 flags) + * int bpf_get_stackid(void *ctx, struct bpf_map *map, u64 flags) * Description * Walk a user or a kernel stack and return its id. To achieve * this, the helper needs *ctx*, which is a pointer to the context @@ -1154,7 +1154,7 @@ union bpf_attr { * The checksum result, or a negative error code in case of * failure. * - * int bpf_skb_get_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size) + * int bpf_skb_get_tunnel_opt(struct sk_buff *skb, void *opt, u32 size) * Description * Retrieve tunnel options metadata for the packet associated to * *skb*, and store the raw tunnel option data to the buffer *opt* @@ -1172,7 +1172,7 @@ union bpf_attr { * Return * The size of the option data retrieved. * - * int bpf_skb_set_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size) + * int bpf_skb_set_tunnel_opt(struct sk_buff *skb, void *opt, u32 size) * Description * Set tunnel options metadata for the packet associated to *skb* * to the option data contained in the raw buffer *opt* of *size*. @@ -1511,7 +1511,7 @@ union bpf_attr { * Return * 0 * - * int bpf_setsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen) + * int bpf_setsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, void *optval, int optlen) * Description * Emulate a call to **setsockopt()** on the socket associated to * *bpf_socket*, which must be a full socket. The *level* at @@ -1595,7 +1595,7 @@ union bpf_attr { * Return * **XDP_REDIRECT** on success, or **XDP_ABORTED** on error. * - * int bpf_sk_redirect_map(struct bpf_map *map, u32 key, u64 flags) + * int bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) * Description * Redirect the packet to the socket referenced by *map* (of type * **BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and @@ -1715,7 +1715,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_getsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen) + * int bpf_getsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, void *optval, int optlen) * Description * Emulate a call to **getsockopt()** on the socket associated to * *bpf_socket*, which must be a full socket. The *level* at @@ -1947,7 +1947,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_get_stack(struct pt_regs *regs, void *buf, u32 size, u64 flags) + * int bpf_get_stack(void *ctx, void *buf, u32 size, u64 flags) * Description * Return a user or a kernel stack in bpf program provided buffer. * To achieve this, the helper needs *ctx*, which is a pointer @@ -1980,7 +1980,7 @@ union bpf_attr { * A non-negative value equal to or less than *size* on success, * or a negative error in case of failure. * - * int bpf_skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header) + * int bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header) * Description * This helper is similar to **bpf_skb_load_bytes**\ () in that * it provides an easy way to load *len* bytes from *offset* @@ -2033,7 +2033,7 @@ union bpf_attr { * * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the * packet is not forwarded or needs assist from full stack * - * int bpf_sock_hash_update(struct bpf_sock_ops_kern *skops, struct bpf_map *map, void *key, u64 flags) + * int bpf_sock_hash_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags) * Description * Add an entry to, or update a sockhash *map* referencing sockets. * The *skops* is used as a new value for the entry associated to @@ -2392,7 +2392,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags) + * int bpf_msg_push_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags) * Description * For socket policies, insert *len* bytes into *msg* at offset * *start*. @@ -2408,9 +2408,9 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 pop, u64 flags) + * int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags) * Description - * Will remove *pop* bytes from a *msg* starting at byte *start*. + * Will remove *len* bytes from a *msg* starting at byte *start*. * This may result in **ENOMEM** errors under certain situations if * an allocation and copy are required due to a full ring buffer. * However, the helper will try to avoid doing the allocation @@ -2505,7 +2505,7 @@ union bpf_attr { * A **struct bpf_tcp_sock** pointer on success, or **NULL** in * case of failure. * - * int bpf_skb_ecn_set_ce(struct sk_buf *skb) + * int bpf_skb_ecn_set_ce(struct sk_buff *skb) * Description * Set ECN (Explicit Congestion Notification) field of IP header * to **CE** (Congestion Encountered) if current value is **ECT** -- cgit v1.2.3 From 7a387bed47f7e80e257d966cd64a3e92a63e26a1 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sun, 6 Oct 2019 20:07:37 -0700 Subject: scripts/bpf: teach bpf_helpers_doc.py to dump BPF helper definitions Enhance scripts/bpf_helpers_doc.py to emit C header with BPF helper definitions (to be included from libbpf's bpf_helpers.h). Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov --- scripts/bpf_helpers_doc.py | 155 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 154 insertions(+), 1 deletion(-) diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py index 894cc58c1a03..15d3d83d6297 100755 --- a/scripts/bpf_helpers_doc.py +++ b/scripts/bpf_helpers_doc.py @@ -391,6 +391,154 @@ SEE ALSO print('') +class PrinterHelpers(Printer): + """ + A printer for dumping collected information about helpers as C header to + be included from BPF program. + @helpers: array of Helper objects to print to standard output + """ + + type_fwds = [ + 'struct bpf_fib_lookup', + 'struct bpf_perf_event_data', + 'struct bpf_perf_event_value', + 'struct bpf_sock', + 'struct bpf_sock_addr', + 'struct bpf_sock_ops', + 'struct bpf_sock_tuple', + 'struct bpf_spin_lock', + 'struct bpf_sysctl', + 'struct bpf_tcp_sock', + 'struct bpf_tunnel_key', + 'struct bpf_xfrm_state', + 'struct pt_regs', + 'struct sk_reuseport_md', + 'struct sockaddr', + 'struct tcphdr', + + 'struct __sk_buff', + 'struct sk_msg_md', + 'struct xpd_md', + ] + known_types = { + '...', + 'void', + 'const void', + 'char', + 'const char', + 'int', + 'long', + 'unsigned long', + + '__be16', + '__be32', + '__wsum', + + 'struct bpf_fib_lookup', + 'struct bpf_perf_event_data', + 'struct bpf_perf_event_value', + 'struct bpf_sock', + 'struct bpf_sock_addr', + 'struct bpf_sock_ops', + 'struct bpf_sock_tuple', + 'struct bpf_spin_lock', + 'struct bpf_sysctl', + 'struct bpf_tcp_sock', + 'struct bpf_tunnel_key', + 'struct bpf_xfrm_state', + 'struct pt_regs', + 'struct sk_reuseport_md', + 'struct sockaddr', + 'struct tcphdr', + } + mapped_types = { + 'u8': '__u8', + 'u16': '__u16', + 'u32': '__u32', + 'u64': '__u64', + 's8': '__s8', + 's16': '__s16', + 's32': '__s32', + 's64': '__s64', + 'size_t': 'unsigned long', + 'struct bpf_map': 'void', + 'struct sk_buff': 'struct __sk_buff', + 'const struct sk_buff': 'const struct __sk_buff', + 'struct sk_msg_buff': 'struct sk_msg_md', + 'struct xdp_buff': 'struct xdp_md', + } + + def print_header(self): + header = '''\ +/* This is auto-generated file. See bpf_helpers_doc.py for details. */ + +/* Forward declarations of BPF structs */''' + + print(header) + for fwd in self.type_fwds: + print('%s;' % fwd) + print('') + + def print_footer(self): + footer = '' + print(footer) + + def map_type(self, t): + if t in self.known_types: + return t + if t in self.mapped_types: + return self.mapped_types[t] + print("") + print("Unrecognized type '%s', please add it to known types!" % t) + sys.exit(1) + + seen_helpers = set() + + def print_one(self, helper): + proto = helper.proto_break_down() + + if proto['name'] in self.seen_helpers: + return + self.seen_helpers.add(proto['name']) + + print('/*') + print(" * %s" % proto['name']) + print(" *") + if (helper.desc): + # Do not strip all newline characters: formatted code at the end of + # a section must be followed by a blank line. + for line in re.sub('\n$', '', helper.desc, count=1).split('\n'): + print(' *{}{}'.format(' \t' if line else '', line)) + + if (helper.ret): + print(' *') + print(' * Returns') + for line in helper.ret.rstrip().split('\n'): + print(' *{}{}'.format(' \t' if line else '', line)) + + print(' */') + print('static %s %s(*%s)(' % (self.map_type(proto['ret_type']), + proto['ret_star'], proto['name']), end='') + comma = '' + for i, a in enumerate(proto['args']): + t = a['type'] + n = a['name'] + if proto['name'] == 'bpf_get_socket_cookie' and i == 0: + t = 'void' + n = 'ctx' + one_arg = '{}{}'.format(comma, self.map_type(t)) + if n: + if a['star']: + one_arg += ' {}'.format(a['star']) + else: + one_arg += ' ' + one_arg += '{}'.format(n) + comma = ', ' + print(one_arg, end='') + + print(') = (void *) %d;' % len(self.seen_helpers)) + print('') + ############################################################################### # If script is launched from scripts/ from kernel tree and can access @@ -405,6 +553,8 @@ Parse eBPF header file and generate documentation for eBPF helper functions. The RST-formatted output produced can be turned into a manual page with the rst2man utility. """) +argParser.add_argument('--header', action='store_true', + help='generate C header file') if (os.path.isfile(bpfh)): argParser.add_argument('--filename', help='path to include/uapi/linux/bpf.h', default=bpfh) @@ -417,5 +567,8 @@ headerParser = HeaderParser(args.filename) headerParser.run() # Print formatted output to standard output. -printer = PrinterRST(headerParser.helpers) +if args.header: + printer = PrinterHelpers(headerParser.helpers) +else: + printer = PrinterRST(headerParser.helpers) printer.print_all() -- cgit v1.2.3 From 24f25763d6de229e8ada7616db76fd9ba83775e9 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Sun, 6 Oct 2019 20:07:38 -0700 Subject: libbpf: auto-generate list of BPF helper definitions Get rid of list of BPF helpers in bpf_helpers.h (irony...) and auto-generate it into bpf_helpers_defs.h, which is now included from bpf_helpers.h. Suggested-by: Alexei Starovoitov Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/.gitignore | 1 + tools/testing/selftests/bpf/Makefile | 8 +- tools/testing/selftests/bpf/bpf_helpers.h | 264 +----------------------------- 3 files changed, 9 insertions(+), 264 deletions(-) diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 7470327edcfe..50063f66539d 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -39,3 +39,4 @@ libbpf.so.* test_hashmap test_btf_dump xdping +/bpf_helper_defs.h diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 294d7472dad7..b59fb4e8afaf 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -90,6 +90,10 @@ include ../lib.mk TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read all: $(TEST_CUSTOM_PROGS) +bpf_helper_defs.h: $(APIDIR)/linux/bpf.h + $(BPFDIR)/../../../scripts/bpf_helpers_doc.py --header \ + --file $(APIDIR)/linux/bpf.h > bpf_helper_defs.h + $(OUTPUT)/urandom_read: $(OUTPUT)/%: %.c $(CC) -o $@ $< -Wl,--build-id @@ -123,7 +127,7 @@ $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c # force a rebuild of BPFOBJ when its dependencies are updated force: -$(BPFOBJ): force +$(BPFOBJ): force bpf_helper_defs.h $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/ PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) @@ -319,4 +323,4 @@ $(VERIFIER_TESTS_H): $(VERIFIER_TEST_FILES) | $(VERIFIER_TESTS_DIR) EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(ALU32_BUILD_DIR) $(BPF_GCC_BUILD_DIR) \ $(VERIFIER_TESTS_H) $(PROG_TESTS_H) $(MAP_TESTS_H) \ - feature + feature bpf_helper_defs.h diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 9f77cbaac01c..15152280db6f 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -2,6 +2,8 @@ #ifndef __BPF_HELPERS__ #define __BPF_HELPERS__ +#include "bpf_helper_defs.h" + #define __uint(name, val) int (*name)[val] #define __type(name, val) typeof(val) *name @@ -21,219 +23,6 @@ */ #define SEC(NAME) __attribute__((section(NAME), used)) -/* helper functions called from eBPF programs written in C */ -static void *(*bpf_map_lookup_elem)(void *map, const void *key) = - (void *) BPF_FUNC_map_lookup_elem; -static int (*bpf_map_update_elem)(void *map, const void *key, const void *value, - unsigned long long flags) = - (void *) BPF_FUNC_map_update_elem; -static int (*bpf_map_delete_elem)(void *map, const void *key) = - (void *) BPF_FUNC_map_delete_elem; -static int (*bpf_map_push_elem)(void *map, const void *value, - unsigned long long flags) = - (void *) BPF_FUNC_map_push_elem; -static int (*bpf_map_pop_elem)(void *map, void *value) = - (void *) BPF_FUNC_map_pop_elem; -static int (*bpf_map_peek_elem)(void *map, void *value) = - (void *) BPF_FUNC_map_peek_elem; -static int (*bpf_probe_read)(void *dst, int size, const void *unsafe_ptr) = - (void *) BPF_FUNC_probe_read; -static unsigned long long (*bpf_ktime_get_ns)(void) = - (void *) BPF_FUNC_ktime_get_ns; -static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = - (void *) BPF_FUNC_trace_printk; -static void (*bpf_tail_call)(void *ctx, void *map, int index) = - (void *) BPF_FUNC_tail_call; -static unsigned long long (*bpf_get_smp_processor_id)(void) = - (void *) BPF_FUNC_get_smp_processor_id; -static unsigned long long (*bpf_get_current_pid_tgid)(void) = - (void *) BPF_FUNC_get_current_pid_tgid; -static unsigned long long (*bpf_get_current_uid_gid)(void) = - (void *) BPF_FUNC_get_current_uid_gid; -static int (*bpf_get_current_comm)(void *buf, int buf_size) = - (void *) BPF_FUNC_get_current_comm; -static unsigned long long (*bpf_perf_event_read)(void *map, - unsigned long long flags) = - (void *) BPF_FUNC_perf_event_read; -static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) = - (void *) BPF_FUNC_clone_redirect; -static int (*bpf_redirect)(int ifindex, int flags) = - (void *) BPF_FUNC_redirect; -static int (*bpf_redirect_map)(void *map, int key, int flags) = - (void *) BPF_FUNC_redirect_map; -static int (*bpf_perf_event_output)(void *ctx, void *map, - unsigned long long flags, void *data, - int size) = - (void *) BPF_FUNC_perf_event_output; -static int (*bpf_get_stackid)(void *ctx, void *map, int flags) = - (void *) BPF_FUNC_get_stackid; -static int (*bpf_probe_write_user)(void *dst, const void *src, int size) = - (void *) BPF_FUNC_probe_write_user; -static int (*bpf_current_task_under_cgroup)(void *map, int index) = - (void *) BPF_FUNC_current_task_under_cgroup; -static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) = - (void *) BPF_FUNC_skb_get_tunnel_key; -static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) = - (void *) BPF_FUNC_skb_set_tunnel_key; -static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) = - (void *) BPF_FUNC_skb_get_tunnel_opt; -static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) = - (void *) BPF_FUNC_skb_set_tunnel_opt; -static unsigned long long (*bpf_get_prandom_u32)(void) = - (void *) BPF_FUNC_get_prandom_u32; -static int (*bpf_xdp_adjust_head)(void *ctx, int offset) = - (void *) BPF_FUNC_xdp_adjust_head; -static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) = - (void *) BPF_FUNC_xdp_adjust_meta; -static int (*bpf_get_socket_cookie)(void *ctx) = - (void *) BPF_FUNC_get_socket_cookie; -static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval, - int optlen) = - (void *) BPF_FUNC_setsockopt; -static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval, - int optlen) = - (void *) BPF_FUNC_getsockopt; -static int (*bpf_sock_ops_cb_flags_set)(void *ctx, int flags) = - (void *) BPF_FUNC_sock_ops_cb_flags_set; -static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) = - (void *) BPF_FUNC_sk_redirect_map; -static int (*bpf_sk_redirect_hash)(void *ctx, void *map, void *key, int flags) = - (void *) BPF_FUNC_sk_redirect_hash; -static int (*bpf_sock_map_update)(void *map, void *key, void *value, - unsigned long long flags) = - (void *) BPF_FUNC_sock_map_update; -static int (*bpf_sock_hash_update)(void *map, void *key, void *value, - unsigned long long flags) = - (void *) BPF_FUNC_sock_hash_update; -static int (*bpf_perf_event_read_value)(void *map, unsigned long long flags, - void *buf, unsigned int buf_size) = - (void *) BPF_FUNC_perf_event_read_value; -static int (*bpf_perf_prog_read_value)(void *ctx, void *buf, - unsigned int buf_size) = - (void *) BPF_FUNC_perf_prog_read_value; -static int (*bpf_override_return)(void *ctx, unsigned long rc) = - (void *) BPF_FUNC_override_return; -static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = - (void *) BPF_FUNC_msg_redirect_map; -static int (*bpf_msg_redirect_hash)(void *ctx, - void *map, void *key, int flags) = - (void *) BPF_FUNC_msg_redirect_hash; -static int (*bpf_msg_apply_bytes)(void *ctx, int len) = - (void *) BPF_FUNC_msg_apply_bytes; -static int (*bpf_msg_cork_bytes)(void *ctx, int len) = - (void *) BPF_FUNC_msg_cork_bytes; -static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = - (void *) BPF_FUNC_msg_pull_data; -static int (*bpf_msg_push_data)(void *ctx, int start, int end, int flags) = - (void *) BPF_FUNC_msg_push_data; -static int (*bpf_msg_pop_data)(void *ctx, int start, int cut, int flags) = - (void *) BPF_FUNC_msg_pop_data; -static int (*bpf_bind)(void *ctx, void *addr, int addr_len) = - (void *) BPF_FUNC_bind; -static int (*bpf_xdp_adjust_tail)(void *ctx, int offset) = - (void *) BPF_FUNC_xdp_adjust_tail; -static int (*bpf_skb_get_xfrm_state)(void *ctx, int index, void *state, - int size, int flags) = - (void *) BPF_FUNC_skb_get_xfrm_state; -static int (*bpf_sk_select_reuseport)(void *ctx, void *map, void *key, __u32 flags) = - (void *) BPF_FUNC_sk_select_reuseport; -static int (*bpf_get_stack)(void *ctx, void *buf, int size, int flags) = - (void *) BPF_FUNC_get_stack; -static int (*bpf_fib_lookup)(void *ctx, struct bpf_fib_lookup *params, - int plen, __u32 flags) = - (void *) BPF_FUNC_fib_lookup; -static int (*bpf_lwt_push_encap)(void *ctx, unsigned int type, void *hdr, - unsigned int len) = - (void *) BPF_FUNC_lwt_push_encap; -static int (*bpf_lwt_seg6_store_bytes)(void *ctx, unsigned int offset, - void *from, unsigned int len) = - (void *) BPF_FUNC_lwt_seg6_store_bytes; -static int (*bpf_lwt_seg6_action)(void *ctx, unsigned int action, void *param, - unsigned int param_len) = - (void *) BPF_FUNC_lwt_seg6_action; -static int (*bpf_lwt_seg6_adjust_srh)(void *ctx, unsigned int offset, - unsigned int len) = - (void *) BPF_FUNC_lwt_seg6_adjust_srh; -static int (*bpf_rc_repeat)(void *ctx) = - (void *) BPF_FUNC_rc_repeat; -static int (*bpf_rc_keydown)(void *ctx, unsigned int protocol, - unsigned long long scancode, unsigned int toggle) = - (void *) BPF_FUNC_rc_keydown; -static unsigned long long (*bpf_get_current_cgroup_id)(void) = - (void *) BPF_FUNC_get_current_cgroup_id; -static void *(*bpf_get_local_storage)(void *map, unsigned long long flags) = - (void *) BPF_FUNC_get_local_storage; -static unsigned long long (*bpf_skb_cgroup_id)(void *ctx) = - (void *) BPF_FUNC_skb_cgroup_id; -static unsigned long long (*bpf_skb_ancestor_cgroup_id)(void *ctx, int level) = - (void *) BPF_FUNC_skb_ancestor_cgroup_id; -static struct bpf_sock *(*bpf_sk_lookup_tcp)(void *ctx, - struct bpf_sock_tuple *tuple, - int size, unsigned long long netns_id, - unsigned long long flags) = - (void *) BPF_FUNC_sk_lookup_tcp; -static struct bpf_sock *(*bpf_skc_lookup_tcp)(void *ctx, - struct bpf_sock_tuple *tuple, - int size, unsigned long long netns_id, - unsigned long long flags) = - (void *) BPF_FUNC_skc_lookup_tcp; -static struct bpf_sock *(*bpf_sk_lookup_udp)(void *ctx, - struct bpf_sock_tuple *tuple, - int size, unsigned long long netns_id, - unsigned long long flags) = - (void *) BPF_FUNC_sk_lookup_udp; -static int (*bpf_sk_release)(struct bpf_sock *sk) = - (void *) BPF_FUNC_sk_release; -static int (*bpf_skb_vlan_push)(void *ctx, __be16 vlan_proto, __u16 vlan_tci) = - (void *) BPF_FUNC_skb_vlan_push; -static int (*bpf_skb_vlan_pop)(void *ctx) = - (void *) BPF_FUNC_skb_vlan_pop; -static int (*bpf_rc_pointer_rel)(void *ctx, int rel_x, int rel_y) = - (void *) BPF_FUNC_rc_pointer_rel; -static void (*bpf_spin_lock)(struct bpf_spin_lock *lock) = - (void *) BPF_FUNC_spin_lock; -static void (*bpf_spin_unlock)(struct bpf_spin_lock *lock) = - (void *) BPF_FUNC_spin_unlock; -static struct bpf_sock *(*bpf_sk_fullsock)(struct bpf_sock *sk) = - (void *) BPF_FUNC_sk_fullsock; -static struct bpf_tcp_sock *(*bpf_tcp_sock)(struct bpf_sock *sk) = - (void *) BPF_FUNC_tcp_sock; -static struct bpf_sock *(*bpf_get_listener_sock)(struct bpf_sock *sk) = - (void *) BPF_FUNC_get_listener_sock; -static int (*bpf_skb_ecn_set_ce)(void *ctx) = - (void *) BPF_FUNC_skb_ecn_set_ce; -static int (*bpf_tcp_check_syncookie)(struct bpf_sock *sk, - void *ip, int ip_len, void *tcp, int tcp_len) = - (void *) BPF_FUNC_tcp_check_syncookie; -static int (*bpf_sysctl_get_name)(void *ctx, char *buf, - unsigned long long buf_len, - unsigned long long flags) = - (void *) BPF_FUNC_sysctl_get_name; -static int (*bpf_sysctl_get_current_value)(void *ctx, char *buf, - unsigned long long buf_len) = - (void *) BPF_FUNC_sysctl_get_current_value; -static int (*bpf_sysctl_get_new_value)(void *ctx, char *buf, - unsigned long long buf_len) = - (void *) BPF_FUNC_sysctl_get_new_value; -static int (*bpf_sysctl_set_new_value)(void *ctx, const char *buf, - unsigned long long buf_len) = - (void *) BPF_FUNC_sysctl_set_new_value; -static int (*bpf_strtol)(const char *buf, unsigned long long buf_len, - unsigned long long flags, long *res) = - (void *) BPF_FUNC_strtol; -static int (*bpf_strtoul)(const char *buf, unsigned long long buf_len, - unsigned long long flags, unsigned long *res) = - (void *) BPF_FUNC_strtoul; -static void *(*bpf_sk_storage_get)(void *map, struct bpf_sock *sk, - void *value, __u64 flags) = - (void *) BPF_FUNC_sk_storage_get; -static int (*bpf_sk_storage_delete)(void *map, struct bpf_sock *sk) = - (void *)BPF_FUNC_sk_storage_delete; -static int (*bpf_send_signal)(unsigned sig) = (void *)BPF_FUNC_send_signal; -static long long (*bpf_tcp_gen_syncookie)(struct bpf_sock *sk, void *ip, - int ip_len, void *tcp, int tcp_len) = - (void *) BPF_FUNC_tcp_gen_syncookie; - /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions */ @@ -273,55 +62,6 @@ struct bpf_map_def { __attribute__ ((section(".maps." #name), used)) \ ____btf_map_##name = { } -static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) = - (void *) BPF_FUNC_skb_load_bytes; -static int (*bpf_skb_load_bytes_relative)(void *ctx, int off, void *to, int len, __u32 start_header) = - (void *) BPF_FUNC_skb_load_bytes_relative; -static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) = - (void *) BPF_FUNC_skb_store_bytes; -static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) = - (void *) BPF_FUNC_l3_csum_replace; -static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = - (void *) BPF_FUNC_l4_csum_replace; -static int (*bpf_csum_diff)(void *from, int from_size, void *to, int to_size, int seed) = - (void *) BPF_FUNC_csum_diff; -static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) = - (void *) BPF_FUNC_skb_under_cgroup; -static int (*bpf_skb_change_head)(void *, int len, int flags) = - (void *) BPF_FUNC_skb_change_head; -static int (*bpf_skb_pull_data)(void *, int len) = - (void *) BPF_FUNC_skb_pull_data; -static unsigned int (*bpf_get_cgroup_classid)(void *ctx) = - (void *) BPF_FUNC_get_cgroup_classid; -static unsigned int (*bpf_get_route_realm)(void *ctx) = - (void *) BPF_FUNC_get_route_realm; -static int (*bpf_skb_change_proto)(void *ctx, __be16 proto, __u64 flags) = - (void *) BPF_FUNC_skb_change_proto; -static int (*bpf_skb_change_type)(void *ctx, __u32 type) = - (void *) BPF_FUNC_skb_change_type; -static unsigned int (*bpf_get_hash_recalc)(void *ctx) = - (void *) BPF_FUNC_get_hash_recalc; -static unsigned long long (*bpf_get_current_task)(void) = - (void *) BPF_FUNC_get_current_task; -static int (*bpf_skb_change_tail)(void *ctx, __u32 len, __u64 flags) = - (void *) BPF_FUNC_skb_change_tail; -static long long (*bpf_csum_update)(void *ctx, __u32 csum) = - (void *) BPF_FUNC_csum_update; -static void (*bpf_set_hash_invalid)(void *ctx) = - (void *) BPF_FUNC_set_hash_invalid; -static int (*bpf_get_numa_node_id)(void) = - (void *) BPF_FUNC_get_numa_node_id; -static int (*bpf_probe_read_str)(void *ctx, __u32 size, - const void *unsafe_ptr) = - (void *) BPF_FUNC_probe_read_str; -static unsigned int (*bpf_get_socket_uid)(void *ctx) = - (void *) BPF_FUNC_get_socket_uid; -static unsigned int (*bpf_set_hash)(void *ctx, __u32 hash) = - (void *) BPF_FUNC_set_hash; -static int (*bpf_skb_adjust_room)(void *ctx, __s32 len_diff, __u32 mode, - unsigned long long flags) = - (void *) BPF_FUNC_skb_adjust_room; - /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ #if defined(__TARGET_ARCH_x86) #define bpf_target_x86 -- cgit v1.2.3 From dcb5f40054b1c64ed608a7eecdcf67044e189e30 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 7 Oct 2019 13:41:49 -0700 Subject: selftests/bpf: Fix dependency ordering for attach_probe test Current Makefile dependency chain is not strict enough and allows test_attach_probe.o to be built before test_progs's prog_test/attach_probe.o is built, which leads to assembler complaining about missing included binary. This patch is a minimal fix to fix this issue by enforcing that test_attach_probe.o (BPF object file) is built before prog_tests/attach_probe.c is attempted to be compiled. Fixes: 928ca75e59d7 ("selftests/bpf: switch tests to new bpf_object__open_{file, mem}() APIs") Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191007204149.1575990-1-andriin@fb.com --- tools/testing/selftests/bpf/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index b59fb4e8afaf..771a4e82128b 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -164,7 +164,7 @@ $(OUTPUT)/test_queue_map.o: test_queue_stack_map.h $(OUTPUT)/test_stack_map.o: test_queue_stack_map.h $(OUTPUT)/flow_dissector_load.o: flow_dissector_load.h -$(OUTPUT)/test_progs.o: flow_dissector_load.h $(OUTPUT)/test_attach_probe.o +$(OUTPUT)/test_progs.o: flow_dissector_load.h BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) @@ -275,7 +275,7 @@ PROG_TESTS_H := $(PROG_TESTS_DIR)/tests.h PROG_TESTS_FILES := $(wildcard prog_tests/*.c) test_progs.c: $(PROG_TESTS_H) $(OUTPUT)/test_progs: CFLAGS += $(TEST_PROGS_CFLAGS) -$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_FILES) | $(PROG_TESTS_H) +$(OUTPUT)/test_progs: test_progs.c $(PROG_TESTS_FILES) | $(OUTPUT)/test_attach_probe.o $(PROG_TESTS_H) $(PROG_TESTS_H): $(PROG_TESTS_FILES) | $(PROG_TESTS_DIR) $(shell ( cd prog_tests/; \ echo '/* Generated header, do not edit */'; \ -- cgit v1.2.3 From 32e3e58e4c5910bb0d6024d151c2f559bb7e973c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Mon, 7 Oct 2019 15:56:04 -0700 Subject: bpftool: Fix bpftool build by switching to bpf_object__open_file() As part of libbpf in 5e61f2707029 ("libbpf: stop enforcing kern_version, populate it for users") non-LIBBPF_API __bpf_object__open_xattr() API was removed from libbpf.h header. This broke bpftool, which relied on that function. This patch fixes the build by switching to newly added bpf_object__open_file() which provides the same capabilities, but is official and future-proof API. v1->v2: - fix prog_type shadowing (Stanislav). Fixes: 5e61f2707029 ("libbpf: stop enforcing kern_version, populate it for users") Reported-by: Stanislav Fomichev Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Reviewed-by: Stanislav Fomichev Link: https://lore.kernel.org/bpf/20191007225604.2006146-1-andriin@fb.com --- tools/bpf/bpftool/main.c | 4 ++-- tools/bpf/bpftool/main.h | 2 +- tools/bpf/bpftool/prog.c | 22 ++++++++++++---------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 93d008687020..4764581ff9ea 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -27,7 +27,7 @@ bool json_output; bool show_pinned; bool block_mount; bool verifier_logs; -int bpf_flags; +bool relaxed_maps; struct pinned_obj_table prog_table; struct pinned_obj_table map_table; @@ -396,7 +396,7 @@ int main(int argc, char **argv) show_pinned = true; break; case 'm': - bpf_flags = MAPS_RELAX_COMPAT; + relaxed_maps = true; break; case 'n': block_mount = true; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index af9ad56c303a..2899095f8254 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -94,7 +94,7 @@ extern bool json_output; extern bool show_pinned; extern bool block_mount; extern bool verifier_logs; -extern int bpf_flags; +extern bool relaxed_maps; extern struct pinned_obj_table prog_table; extern struct pinned_obj_table map_table; diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 43fdbbfe41bb..27da96a797ab 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -1092,9 +1092,7 @@ free_data_in: static int load_with_options(int argc, char **argv, bool first_prog_only) { struct bpf_object_load_attr load_attr = { 0 }; - struct bpf_object_open_attr open_attr = { - .prog_type = BPF_PROG_TYPE_UNSPEC, - }; + enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; enum bpf_attach_type expected_attach_type; struct map_replace *map_replace = NULL; struct bpf_program *prog = NULL, *pos; @@ -1105,11 +1103,16 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) const char *pinfile; unsigned int i, j; __u32 ifindex = 0; + const char *file; int idx, err; + LIBBPF_OPTS(bpf_object_open_opts, open_opts, + .relaxed_maps = relaxed_maps, + ); + if (!REQ_ARGS(2)) return -1; - open_attr.file = GET_ARG(); + file = GET_ARG(); pinfile = GET_ARG(); while (argc) { @@ -1118,7 +1121,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) NEXT_ARG(); - if (open_attr.prog_type != BPF_PROG_TYPE_UNSPEC) { + if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { p_err("program type already specified"); goto err_free_reuse_maps; } @@ -1135,8 +1138,7 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) strcat(type, *argv); strcat(type, "/"); - err = libbpf_prog_type_by_name(type, - &open_attr.prog_type, + err = libbpf_prog_type_by_name(type, &common_prog_type, &expected_attach_type); free(type); if (err < 0) @@ -1224,16 +1226,16 @@ static int load_with_options(int argc, char **argv, bool first_prog_only) set_max_rlimit(); - obj = __bpf_object__open_xattr(&open_attr, bpf_flags); + obj = bpf_object__open_file(file, &open_opts); if (IS_ERR_OR_NULL(obj)) { p_err("failed to open object file"); goto err_free_reuse_maps; } bpf_object__for_each_program(pos, obj) { - enum bpf_prog_type prog_type = open_attr.prog_type; + enum bpf_prog_type prog_type = common_prog_type; - if (open_attr.prog_type == BPF_PROG_TYPE_UNSPEC) { + if (prog_type == BPF_PROG_TYPE_UNSPEC) { const char *sec_name = bpf_program__title(pos, false); err = libbpf_prog_type_by_name(sec_name, &prog_type, -- cgit v1.2.3 From 4564a8bb57e4240c08ce2db5194bfa2e71f57730 Mon Sep 17 00:00:00 2001 From: Anton Ivanov Date: Mon, 7 Oct 2019 09:26:36 +0100 Subject: samples/bpf: Trivial - fix spelling mistake in usage Fix spelling mistake. Signed-off-by: Anton Ivanov Signed-off-by: Alexei Starovoitov Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191007082636.14686-1-anton.ivanov@cambridgegreys.com --- samples/bpf/xdpsock_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bpf/xdpsock_user.c b/samples/bpf/xdpsock_user.c index df011ac33402..405c4e091f8b 100644 --- a/samples/bpf/xdpsock_user.c +++ b/samples/bpf/xdpsock_user.c @@ -378,7 +378,7 @@ static void usage(const char *prog) " -q, --queue=n Use queue n (default 0)\n" " -p, --poll Use poll syscall\n" " -S, --xdp-skb=n Use XDP skb-mod\n" - " -N, --xdp-native=n Enfore XDP native mode\n" + " -N, --xdp-native=n Enforce XDP native mode\n" " -n, --interval=n Specify statistics update interval (default 1 sec).\n" " -z, --zero-copy Force zero-copy mode.\n" " -c, --copy Force copy mode.\n" -- cgit v1.2.3 From a11c397c43d5b27491aa2f36276713cf151a4735 Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 7 Oct 2019 09:21:02 -0700 Subject: bpf/flow_dissector: add mode to enforce global BPF flow dissector Always use init_net flow dissector BPF program if it's attached and fall back to the per-net namespace one. Also, deny installing new programs if there is already one attached to the root namespace. Users can still detach their BPF programs, but can't attach any new ones (-EEXIST). Cc: Petar Penkov Acked-by: Andrii Nakryiko Acked-by: Song Liu Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- Documentation/bpf/prog_flow_dissector.rst | 3 +++ net/core/flow_dissector.c | 38 +++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/Documentation/bpf/prog_flow_dissector.rst b/Documentation/bpf/prog_flow_dissector.rst index a78bf036cadd..4d86780ab0f1 100644 --- a/Documentation/bpf/prog_flow_dissector.rst +++ b/Documentation/bpf/prog_flow_dissector.rst @@ -142,3 +142,6 @@ BPF flow dissector doesn't support exporting all the metadata that in-kernel C-based implementation can export. Notable example is single VLAN (802.1Q) and double VLAN (802.1AD) tags. Please refer to the ``struct bpf_flow_keys`` for a set of information that's currently can be exported from the BPF context. + +When BPF flow dissector is attached to the root network namespace (machine-wide +policy), users can't override it in their child network namespaces. diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 7c09d87d3269..6b4b88d1599d 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -114,19 +114,46 @@ int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, { struct bpf_prog *attached; struct net *net; + int ret = 0; net = current->nsproxy->net_ns; mutex_lock(&flow_dissector_mutex); + + if (net == &init_net) { + /* BPF flow dissector in the root namespace overrides + * any per-net-namespace one. When attaching to root, + * make sure we don't have any BPF program attached + * to the non-root namespaces. + */ + struct net *ns; + + for_each_net(ns) { + if (rcu_access_pointer(ns->flow_dissector_prog)) { + ret = -EEXIST; + goto out; + } + } + } else { + /* Make sure root flow dissector is not attached + * when attaching to the non-root namespace. + */ + if (rcu_access_pointer(init_net.flow_dissector_prog)) { + ret = -EEXIST; + goto out; + } + } + attached = rcu_dereference_protected(net->flow_dissector_prog, lockdep_is_held(&flow_dissector_mutex)); if (attached) { /* Only one BPF program can be attached at a time */ - mutex_unlock(&flow_dissector_mutex); - return -EEXIST; + ret = -EEXIST; + goto out; } rcu_assign_pointer(net->flow_dissector_prog, prog); +out: mutex_unlock(&flow_dissector_mutex); - return 0; + return ret; } int skb_flow_dissector_bpf_prog_detach(const union bpf_attr *attr) @@ -910,7 +937,10 @@ bool __skb_flow_dissect(const struct net *net, WARN_ON_ONCE(!net); if (net) { rcu_read_lock(); - attached = rcu_dereference(net->flow_dissector_prog); + attached = rcu_dereference(init_net.flow_dissector_prog); + + if (!attached) + attached = rcu_dereference(net->flow_dissector_prog); if (attached) { struct bpf_flow_keys flow_keys; -- cgit v1.2.3 From 1d9626dc08bf0f5c6932b98e0f4dc5d6b305786f Mon Sep 17 00:00:00 2001 From: Stanislav Fomichev Date: Mon, 7 Oct 2019 09:21:03 -0700 Subject: selftests/bpf: add test for BPF flow dissector in the root namespace Make sure non-root namespaces get an error if root flow dissector is attached. Cc: Petar Penkov Acked-by: Song Liu Signed-off-by: Stanislav Fomichev Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_flow_dissector.sh | 48 +++++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/bpf/test_flow_dissector.sh b/tools/testing/selftests/bpf/test_flow_dissector.sh index d23d4da66b83..2c3a25d64faf 100755 --- a/tools/testing/selftests/bpf/test_flow_dissector.sh +++ b/tools/testing/selftests/bpf/test_flow_dissector.sh @@ -18,19 +18,55 @@ fi # this is the case and run it with in_netns.sh if it is being run in the root # namespace. if [[ -z $(ip netns identify $$) ]]; then + err=0 + if bpftool="$(which bpftool)"; then + echo "Testing global flow dissector..." + + $bpftool prog loadall ./bpf_flow.o /sys/fs/bpf/flow \ + type flow_dissector + + if ! unshare --net $bpftool prog attach pinned \ + /sys/fs/bpf/flow/flow_dissector flow_dissector; then + echo "Unexpected unsuccessful attach in namespace" >&2 + err=1 + fi + + $bpftool prog attach pinned /sys/fs/bpf/flow/flow_dissector \ + flow_dissector + + if unshare --net $bpftool prog attach pinned \ + /sys/fs/bpf/flow/flow_dissector flow_dissector; then + echo "Unexpected successful attach in namespace" >&2 + err=1 + fi + + if ! $bpftool prog detach pinned \ + /sys/fs/bpf/flow/flow_dissector flow_dissector; then + echo "Failed to detach flow dissector" >&2 + err=1 + fi + + rm -rf /sys/fs/bpf/flow + else + echo "Skipping root flow dissector test, bpftool not found" >&2 + fi + + # Run the rest of the tests in a net namespace. ../net/in_netns.sh "$0" "$@" - exit $? -fi + err=$(( $err + $? )) -# Determine selftest success via shell exit code -exit_handler() -{ - if (( $? == 0 )); then + if (( $err == 0 )); then echo "selftests: $TESTNAME [PASS]"; else echo "selftests: $TESTNAME [FAILED]"; fi + exit $err +fi + +# Determine selftest success via shell exit code +exit_handler() +{ set +e # Cleanup -- cgit v1.2.3 From 8fdf5b780a148c4a7490c211acad3c01b4dde6ac Mon Sep 17 00:00:00 2001 From: "Daniel T. Lee" Date: Tue, 8 Oct 2019 02:21:17 +0900 Subject: samples: bpf: Add max_pckt_size option at xdp_adjust_tail Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited to 600. To make this size flexible, static global variable 'max_pcktsz' is added. By updating new packet size from the user space, xdp_adjust_tail_kern.o will use this value as a new max packet size. This static global variable can be accesible from .data section with bpf_object__find_map* from user space, since it is considered as internal map (accessible with .bss/.data/.rodata suffix). If no '-P ' option is used, the size of maximum packet will be 600 as a default. For clarity, change the helper to fetch map from 'bpf_map__next' to 'bpf_object__find_map_fd_by_name'. Also, changed the way to test prog_fd, map_fd from '!= 0' to '< 0', since fd could be 0 when stdin is closed. Signed-off-by: Daniel T. Lee Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191007172117.3916-1-danieltimlee@gmail.com --- samples/bpf/xdp_adjust_tail_kern.c | 7 +++++-- samples/bpf/xdp_adjust_tail_user.c | 29 ++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/samples/bpf/xdp_adjust_tail_kern.c b/samples/bpf/xdp_adjust_tail_kern.c index 411fdb21f8bc..c616508befb9 100644 --- a/samples/bpf/xdp_adjust_tail_kern.c +++ b/samples/bpf/xdp_adjust_tail_kern.c @@ -25,6 +25,9 @@ #define ICMP_TOOBIG_SIZE 98 #define ICMP_TOOBIG_PAYLOAD_SIZE 92 +/* volatile to prevent compiler optimizations */ +static volatile __u32 max_pcktsz = MAX_PCKT_SIZE; + struct bpf_map_def SEC("maps") icmpcnt = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(__u32), @@ -92,7 +95,7 @@ static __always_inline int send_icmp4_too_big(struct xdp_md *xdp) orig_iph = data + off; icmp_hdr->type = ICMP_DEST_UNREACH; icmp_hdr->code = ICMP_FRAG_NEEDED; - icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr)); + icmp_hdr->un.frag.mtu = htons(max_pcktsz - sizeof(struct ethhdr)); icmp_hdr->checksum = 0; ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum); icmp_hdr->checksum = csum; @@ -121,7 +124,7 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp) int pckt_size = data_end - data; int offset; - if (pckt_size > MAX_PCKT_SIZE) { + if (pckt_size > max(max_pcktsz, ICMP_TOOBIG_SIZE)) { offset = pckt_size - ICMP_TOOBIG_SIZE; if (bpf_xdp_adjust_tail(xdp, 0 - offset)) return XDP_PASS; diff --git a/samples/bpf/xdp_adjust_tail_user.c b/samples/bpf/xdp_adjust_tail_user.c index a3596b617c4c..d86e9ad0356b 100644 --- a/samples/bpf/xdp_adjust_tail_user.c +++ b/samples/bpf/xdp_adjust_tail_user.c @@ -23,6 +23,7 @@ #include "libbpf.h" #define STATS_INTERVAL_S 2U +#define MAX_PCKT_SIZE 600 static int ifindex = -1; static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST; @@ -72,6 +73,7 @@ static void usage(const char *cmd) printf("Usage: %s [...]\n", cmd); printf(" -i Interface\n"); printf(" -T Default: 0 (forever)\n"); + printf(" -P Default: %u\n", MAX_PCKT_SIZE); printf(" -S use skb-mode\n"); printf(" -N enforce native mode\n"); printf(" -F force loading prog\n"); @@ -85,13 +87,14 @@ int main(int argc, char **argv) .prog_type = BPF_PROG_TYPE_XDP, }; unsigned char opt_flags[256] = {}; - const char *optstr = "i:T:SNFh"; + const char *optstr = "i:T:P:SNFh"; struct bpf_prog_info info = {}; __u32 info_len = sizeof(info); unsigned int kill_after_s = 0; int i, prog_fd, map_fd, opt; struct bpf_object *obj; - struct bpf_map *map; + __u32 max_pckt_size = 0; + __u32 key = 0; char filename[256]; int err; @@ -110,6 +113,9 @@ int main(int argc, char **argv) case 'T': kill_after_s = atoi(optarg); break; + case 'P': + max_pckt_size = atoi(optarg); + break; case 'S': xdp_flags |= XDP_FLAGS_SKB_MODE; break; @@ -150,15 +156,20 @@ int main(int argc, char **argv) if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd)) return 1; - map = bpf_map__next(NULL, obj); - if (!map) { - printf("finding a map in obj file failed\n"); - return 1; + /* static global var 'max_pcktsz' is accessible from .data section */ + if (max_pckt_size) { + map_fd = bpf_object__find_map_fd_by_name(obj, "xdp_adju.data"); + if (map_fd < 0) { + printf("finding a max_pcktsz map in obj file failed\n"); + return 1; + } + bpf_map_update_elem(map_fd, &key, &max_pckt_size, BPF_ANY); } - map_fd = bpf_map__fd(map); - if (!prog_fd) { - printf("load_bpf_file: %s\n", strerror(errno)); + /* fetch icmpcnt map */ + map_fd = bpf_object__find_map_fd_by_name(obj, "icmpcnt"); + if (map_fd < 0) { + printf("finding a icmpcnt map in obj file failed\n"); return 1; } -- cgit v1.2.3 From cf0e9718da214415195a28e5909bd297fb178583 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 10:59:36 -0700 Subject: selftests/bpf: Undo GCC-specific bpf_helpers.h changes Having GCC provide its own bpf-helper.h is not the right approach and is going to be changed. Undo bpf_helpers.h change before moving bpf_helpers.h into libbpf. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Song Liu Acked-by: Ilya Leoshkevich Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20191008175942.1769476-2-andriin@fb.com --- tools/testing/selftests/bpf/bpf_helpers.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 15152280db6f..ffd4d8c9a087 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -15,8 +15,6 @@ ##__VA_ARGS__); \ }) -#ifdef __clang__ - /* helper macro to place programs, maps, license in * different sections in elf_bpf file. Section names * are interpreted by elf_bpf loader @@ -47,12 +45,6 @@ struct bpf_map_def { unsigned int numa_node; }; -#else - -#include - -#endif - #define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \ struct ____btf_map_##name { \ type_key key; \ -- cgit v1.2.3 From 36b5d471135c3ef5f4922aa23f6566b6a07227f7 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 10:59:37 -0700 Subject: selftests/bpf: samples/bpf: Split off legacy stuff from bpf_helpers.h Split off few legacy things from bpf_helpers.h into separate bpf_legacy.h file: - load_{byte|half|word}; - remove extra inner_idx and numa_node fields from bpf_map_def and introduce bpf_map_def_legacy for use in samples; - move BPF_ANNOTATE_KV_PAIR into bpf_legacy.h. Adjust samples and selftests accordingly by either including bpf_legacy.h and using bpf_map_def_legacy, or switching to BTF-defined maps altogether. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191008175942.1769476-3-andriin@fb.com --- samples/bpf/hbm_kern.h | 27 +++++++-------- samples/bpf/map_perf_test_kern.c | 23 +++++++------ samples/bpf/parse_ldabs.c | 1 + samples/bpf/sockex1_kern.c | 1 + samples/bpf/sockex2_kern.c | 1 + samples/bpf/sockex3_kern.c | 1 + samples/bpf/tcbpf1_kern.c | 1 + samples/bpf/test_map_in_map_kern.c | 15 +++++---- tools/testing/selftests/bpf/bpf_helpers.h | 24 +------------ tools/testing/selftests/bpf/bpf_legacy.h | 39 ++++++++++++++++++++++ tools/testing/selftests/bpf/progs/sockopt_sk.c | 13 ++++---- tools/testing/selftests/bpf/progs/tcp_rtt.c | 13 ++++---- tools/testing/selftests/bpf/progs/test_btf_haskv.c | 1 + tools/testing/selftests/bpf/progs/test_btf_newkv.c | 1 + 14 files changed, 91 insertions(+), 70 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_legacy.h diff --git a/samples/bpf/hbm_kern.h b/samples/bpf/hbm_kern.h index aa207a2eebbd..4edaf47876ca 100644 --- a/samples/bpf/hbm_kern.h +++ b/samples/bpf/hbm_kern.h @@ -59,21 +59,18 @@ #define BYTES_PER_NS(delta, rate) ((((u64)(delta)) * (rate)) >> 20) #define BYTES_TO_NS(bytes, rate) div64_u64(((u64)(bytes)) << 20, (u64)(rate)) -struct bpf_map_def SEC("maps") queue_state = { - .type = BPF_MAP_TYPE_CGROUP_STORAGE, - .key_size = sizeof(struct bpf_cgroup_storage_key), - .value_size = sizeof(struct hbm_vqueue), -}; -BPF_ANNOTATE_KV_PAIR(queue_state, struct bpf_cgroup_storage_key, - struct hbm_vqueue); - -struct bpf_map_def SEC("maps") queue_stats = { - .type = BPF_MAP_TYPE_ARRAY, - .key_size = sizeof(u32), - .value_size = sizeof(struct hbm_queue_stats), - .max_entries = 1, -}; -BPF_ANNOTATE_KV_PAIR(queue_stats, int, struct hbm_queue_stats); +struct { + __uint(type, BPF_MAP_TYPE_CGROUP_STORAGE); + __type(key, struct bpf_cgroup_storage_key); + __type(value, struct hbm_vqueue); +} queue_state SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, u32); + __type(value, struct hvm_queue_stats); +} queue_stats SEC(".maps"); struct hbm_pkt_info { int cwnd; diff --git a/samples/bpf/map_perf_test_kern.c b/samples/bpf/map_perf_test_kern.c index 2b2ffb97018b..f47ee513cb7c 100644 --- a/samples/bpf/map_perf_test_kern.c +++ b/samples/bpf/map_perf_test_kern.c @@ -9,25 +9,26 @@ #include #include #include "bpf_helpers.h" +#include "bpf_legacy.h" #define MAX_ENTRIES 1000 #define MAX_NR_CPUS 1024 -struct bpf_map_def SEC("maps") hash_map = { +struct bpf_map_def_legacy SEC("maps") hash_map = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), .max_entries = MAX_ENTRIES, }; -struct bpf_map_def SEC("maps") lru_hash_map = { +struct bpf_map_def_legacy SEC("maps") lru_hash_map = { .type = BPF_MAP_TYPE_LRU_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), .max_entries = 10000, }; -struct bpf_map_def SEC("maps") nocommon_lru_hash_map = { +struct bpf_map_def_legacy SEC("maps") nocommon_lru_hash_map = { .type = BPF_MAP_TYPE_LRU_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), @@ -35,7 +36,7 @@ struct bpf_map_def SEC("maps") nocommon_lru_hash_map = { .map_flags = BPF_F_NO_COMMON_LRU, }; -struct bpf_map_def SEC("maps") inner_lru_hash_map = { +struct bpf_map_def_legacy SEC("maps") inner_lru_hash_map = { .type = BPF_MAP_TYPE_LRU_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), @@ -44,20 +45,20 @@ struct bpf_map_def SEC("maps") inner_lru_hash_map = { .numa_node = 0, }; -struct bpf_map_def SEC("maps") array_of_lru_hashs = { +struct bpf_map_def_legacy SEC("maps") array_of_lru_hashs = { .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, .key_size = sizeof(u32), .max_entries = MAX_NR_CPUS, }; -struct bpf_map_def SEC("maps") percpu_hash_map = { +struct bpf_map_def_legacy SEC("maps") percpu_hash_map = { .type = BPF_MAP_TYPE_PERCPU_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), .max_entries = MAX_ENTRIES, }; -struct bpf_map_def SEC("maps") hash_map_alloc = { +struct bpf_map_def_legacy SEC("maps") hash_map_alloc = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), @@ -65,7 +66,7 @@ struct bpf_map_def SEC("maps") hash_map_alloc = { .map_flags = BPF_F_NO_PREALLOC, }; -struct bpf_map_def SEC("maps") percpu_hash_map_alloc = { +struct bpf_map_def_legacy SEC("maps") percpu_hash_map_alloc = { .type = BPF_MAP_TYPE_PERCPU_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), @@ -73,7 +74,7 @@ struct bpf_map_def SEC("maps") percpu_hash_map_alloc = { .map_flags = BPF_F_NO_PREALLOC, }; -struct bpf_map_def SEC("maps") lpm_trie_map_alloc = { +struct bpf_map_def_legacy SEC("maps") lpm_trie_map_alloc = { .type = BPF_MAP_TYPE_LPM_TRIE, .key_size = 8, .value_size = sizeof(long), @@ -81,14 +82,14 @@ struct bpf_map_def SEC("maps") lpm_trie_map_alloc = { .map_flags = BPF_F_NO_PREALLOC, }; -struct bpf_map_def SEC("maps") array_map = { +struct bpf_map_def_legacy SEC("maps") array_map = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(u32), .value_size = sizeof(long), .max_entries = MAX_ENTRIES, }; -struct bpf_map_def SEC("maps") lru_hash_lookup_map = { +struct bpf_map_def_legacy SEC("maps") lru_hash_lookup_map = { .type = BPF_MAP_TYPE_LRU_HASH, .key_size = sizeof(u32), .value_size = sizeof(long), diff --git a/samples/bpf/parse_ldabs.c b/samples/bpf/parse_ldabs.c index 6db6b21fdc6d..ef5892377beb 100644 --- a/samples/bpf/parse_ldabs.c +++ b/samples/bpf/parse_ldabs.c @@ -12,6 +12,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_legacy.h" #define DEFAULT_PKTGEN_UDP_PORT 9 #define IP_MF 0x2000 diff --git a/samples/bpf/sockex1_kern.c b/samples/bpf/sockex1_kern.c index ed18e9a4909c..f96943f443ab 100644 --- a/samples/bpf/sockex1_kern.c +++ b/samples/bpf/sockex1_kern.c @@ -3,6 +3,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_legacy.h" struct bpf_map_def SEC("maps") my_map = { .type = BPF_MAP_TYPE_ARRAY, diff --git a/samples/bpf/sockex2_kern.c b/samples/bpf/sockex2_kern.c index f2f9dbc021b0..5566fa7d92fa 100644 --- a/samples/bpf/sockex2_kern.c +++ b/samples/bpf/sockex2_kern.c @@ -1,5 +1,6 @@ #include #include "bpf_helpers.h" +#include "bpf_legacy.h" #include #include #include diff --git a/samples/bpf/sockex3_kern.c b/samples/bpf/sockex3_kern.c index c527b57d3ec8..151dd842ecc0 100644 --- a/samples/bpf/sockex3_kern.c +++ b/samples/bpf/sockex3_kern.c @@ -6,6 +6,7 @@ */ #include #include "bpf_helpers.h" +#include "bpf_legacy.h" #include #include #include diff --git a/samples/bpf/tcbpf1_kern.c b/samples/bpf/tcbpf1_kern.c index 274c884c87fe..ff43341bdfce 100644 --- a/samples/bpf/tcbpf1_kern.c +++ b/samples/bpf/tcbpf1_kern.c @@ -8,6 +8,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_legacy.h" /* compiler workaround */ #define _htonl __builtin_bswap32 diff --git a/samples/bpf/test_map_in_map_kern.c b/samples/bpf/test_map_in_map_kern.c index 42c44d091dd1..8101bf3dc7f7 100644 --- a/samples/bpf/test_map_in_map_kern.c +++ b/samples/bpf/test_map_in_map_kern.c @@ -11,11 +11,12 @@ #include #include #include "bpf_helpers.h" +#include "bpf_legacy.h" #define MAX_NR_PORTS 65536 /* map #0 */ -struct bpf_map_def SEC("maps") port_a = { +struct bpf_map_def_legacy SEC("maps") port_a = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(u32), .value_size = sizeof(int), @@ -23,7 +24,7 @@ struct bpf_map_def SEC("maps") port_a = { }; /* map #1 */ -struct bpf_map_def SEC("maps") port_h = { +struct bpf_map_def_legacy SEC("maps") port_h = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(u32), .value_size = sizeof(int), @@ -31,7 +32,7 @@ struct bpf_map_def SEC("maps") port_h = { }; /* map #2 */ -struct bpf_map_def SEC("maps") reg_result_h = { +struct bpf_map_def_legacy SEC("maps") reg_result_h = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(u32), .value_size = sizeof(int), @@ -39,7 +40,7 @@ struct bpf_map_def SEC("maps") reg_result_h = { }; /* map #3 */ -struct bpf_map_def SEC("maps") inline_result_h = { +struct bpf_map_def_legacy SEC("maps") inline_result_h = { .type = BPF_MAP_TYPE_HASH, .key_size = sizeof(u32), .value_size = sizeof(int), @@ -47,7 +48,7 @@ struct bpf_map_def SEC("maps") inline_result_h = { }; /* map #4 */ /* Test case #0 */ -struct bpf_map_def SEC("maps") a_of_port_a = { +struct bpf_map_def_legacy SEC("maps") a_of_port_a = { .type = BPF_MAP_TYPE_ARRAY_OF_MAPS, .key_size = sizeof(u32), .inner_map_idx = 0, /* map_fd[0] is port_a */ @@ -55,7 +56,7 @@ struct bpf_map_def SEC("maps") a_of_port_a = { }; /* map #5 */ /* Test case #1 */ -struct bpf_map_def SEC("maps") h_of_port_a = { +struct bpf_map_def_legacy SEC("maps") h_of_port_a = { .type = BPF_MAP_TYPE_HASH_OF_MAPS, .key_size = sizeof(u32), .inner_map_idx = 0, /* map_fd[0] is port_a */ @@ -63,7 +64,7 @@ struct bpf_map_def SEC("maps") h_of_port_a = { }; /* map #6 */ /* Test case #2 */ -struct bpf_map_def SEC("maps") h_of_port_h = { +struct bpf_map_def_legacy SEC("maps") h_of_port_h = { .type = BPF_MAP_TYPE_HASH_OF_MAPS, .key_size = sizeof(u32), .inner_map_idx = 1, /* map_fd[1] is port_h */ diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index ffd4d8c9a087..c7cfc27063d4 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -21,19 +21,8 @@ */ #define SEC(NAME) __attribute__((section(NAME), used)) -/* llvm builtin functions that eBPF C program may use to - * emit BPF_LD_ABS and BPF_LD_IND instructions - */ -struct sk_buff; -unsigned long long load_byte(void *skb, - unsigned long long off) asm("llvm.bpf.load.byte"); -unsigned long long load_half(void *skb, - unsigned long long off) asm("llvm.bpf.load.half"); -unsigned long long load_word(void *skb, - unsigned long long off) asm("llvm.bpf.load.word"); - /* a helper structure used by eBPF C program - * to describe map attributes to elf_bpf loader + * to describe BPF map attributes to libbpf loader */ struct bpf_map_def { unsigned int type; @@ -41,19 +30,8 @@ struct bpf_map_def { unsigned int value_size; unsigned int max_entries; unsigned int map_flags; - unsigned int inner_map_idx; - 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 = { } - /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ #if defined(__TARGET_ARCH_x86) #define bpf_target_x86 diff --git a/tools/testing/selftests/bpf/bpf_legacy.h b/tools/testing/selftests/bpf/bpf_legacy.h new file mode 100644 index 000000000000..6f8988738bc1 --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_legacy.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BPF_LEGACY__ +#define __BPF_LEGACY__ + +/* + * legacy bpf_map_def with extra fields supported only by bpf_load(), do not + * use outside of samples/bpf + */ +struct bpf_map_def_legacy { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; + unsigned int map_flags; + unsigned int inner_map_idx; + 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 = { } + +/* llvm builtin functions that eBPF C program may use to + * emit BPF_LD_ABS and BPF_LD_IND instructions + */ +unsigned long long load_byte(void *skb, + unsigned long long off) asm("llvm.bpf.load.byte"); +unsigned long long load_half(void *skb, + unsigned long long off) asm("llvm.bpf.load.half"); +unsigned long long load_word(void *skb, + unsigned long long off) asm("llvm.bpf.load.word"); + +#endif + diff --git a/tools/testing/selftests/bpf/progs/sockopt_sk.c b/tools/testing/selftests/bpf/progs/sockopt_sk.c index 9a3d1c79e6fe..1bafbb944e37 100644 --- a/tools/testing/selftests/bpf/progs/sockopt_sk.c +++ b/tools/testing/selftests/bpf/progs/sockopt_sk.c @@ -14,13 +14,12 @@ struct sockopt_sk { __u8 val; }; -struct bpf_map_def SEC("maps") socket_storage_map = { - .type = BPF_MAP_TYPE_SK_STORAGE, - .key_size = sizeof(int), - .value_size = sizeof(struct sockopt_sk), - .map_flags = BPF_F_NO_PREALLOC, -}; -BPF_ANNOTATE_KV_PAIR(socket_storage_map, int, struct sockopt_sk); +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct sockopt_sk); +} socket_storage_map SEC(".maps"); SEC("cgroup/getsockopt") int _getsockopt(struct bpf_sockopt *ctx) diff --git a/tools/testing/selftests/bpf/progs/tcp_rtt.c b/tools/testing/selftests/bpf/progs/tcp_rtt.c index 233bdcb1659e..2cf813a06b83 100644 --- a/tools/testing/selftests/bpf/progs/tcp_rtt.c +++ b/tools/testing/selftests/bpf/progs/tcp_rtt.c @@ -13,13 +13,12 @@ struct tcp_rtt_storage { __u32 icsk_retransmits; }; -struct bpf_map_def SEC("maps") socket_storage_map = { - .type = BPF_MAP_TYPE_SK_STORAGE, - .key_size = sizeof(int), - .value_size = sizeof(struct tcp_rtt_storage), - .map_flags = BPF_F_NO_PREALLOC, -}; -BPF_ANNOTATE_KV_PAIR(socket_storage_map, int, struct tcp_rtt_storage); +struct { + __uint(type, BPF_MAP_TYPE_SK_STORAGE); + __uint(map_flags, BPF_F_NO_PREALLOC); + __type(key, int); + __type(value, struct tcp_rtt_storage); +} socket_storage_map SEC(".maps"); SEC("sockops") int _sockops(struct bpf_sock_ops *ctx) diff --git a/tools/testing/selftests/bpf/progs/test_btf_haskv.c b/tools/testing/selftests/bpf/progs/test_btf_haskv.c index e5c79fe0ffdb..763c51447c19 100644 --- a/tools/testing/selftests/bpf/progs/test_btf_haskv.c +++ b/tools/testing/selftests/bpf/progs/test_btf_haskv.c @@ -2,6 +2,7 @@ /* Copyright (c) 2018 Facebook */ #include #include "bpf_helpers.h" +#include "bpf_legacy.h" int _version SEC("version") = 1; diff --git a/tools/testing/selftests/bpf/progs/test_btf_newkv.c b/tools/testing/selftests/bpf/progs/test_btf_newkv.c index 5ee3622ddebb..96f9e8451029 100644 --- a/tools/testing/selftests/bpf/progs/test_btf_newkv.c +++ b/tools/testing/selftests/bpf/progs/test_btf_newkv.c @@ -2,6 +2,7 @@ /* Copyright (c) 2018 Facebook */ #include #include "bpf_helpers.h" +#include "bpf_legacy.h" int _version SEC("version") = 1; -- cgit v1.2.3 From 694731e8ea7f6bbcf0c57763ed4f24faa14bf056 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 10:59:38 -0700 Subject: selftests/bpf: Adjust CO-RE reloc tests for new bpf_core_read() macro To allow adding a variadic BPF_CORE_READ macro with slightly different syntax and semantics, define CORE_READ in CO-RE reloc tests, which is a thin wrapper around low-level bpf_core_read() macro, which in turn is just a wrapper around bpf_probe_read(). Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191008175942.1769476-4-andriin@fb.com --- tools/testing/selftests/bpf/bpf_helpers.h | 8 ++++---- .../selftests/bpf/progs/test_core_reloc_arrays.c | 10 ++++++---- .../selftests/bpf/progs/test_core_reloc_flavors.c | 8 +++++--- .../testing/selftests/bpf/progs/test_core_reloc_ints.c | 18 ++++++++++-------- .../selftests/bpf/progs/test_core_reloc_kernel.c | 6 ++++-- .../testing/selftests/bpf/progs/test_core_reloc_misc.c | 8 +++++--- .../testing/selftests/bpf/progs/test_core_reloc_mods.c | 18 ++++++++++-------- .../selftests/bpf/progs/test_core_reloc_nesting.c | 6 ++++-- .../selftests/bpf/progs/test_core_reloc_primitives.c | 12 +++++++----- .../selftests/bpf/progs/test_core_reloc_ptr_as_arr.c | 4 +++- 10 files changed, 58 insertions(+), 40 deletions(-) diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index c7cfc27063d4..4e6f97142cd8 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -223,7 +223,7 @@ struct pt_regs; #endif /* - * BPF_CORE_READ abstracts away bpf_probe_read() call and captures offset + * bpf_core_read() abstracts away bpf_probe_read() call and captures offset * relocation for source address using __builtin_preserve_access_index() * built-in, provided by Clang. * @@ -238,8 +238,8 @@ struct pt_regs; * actual field offset, based on target kernel BTF type that matches original * (local) BTF, used to record relocation. */ -#define BPF_CORE_READ(dst, src) \ - bpf_probe_read((dst), sizeof(*(src)), \ - __builtin_preserve_access_index(src)) +#define bpf_core_read(dst, sz, src) \ + bpf_probe_read(dst, sz, \ + (const void *)__builtin_preserve_access_index(src)) #endif diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c b/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c index bf67f0fdf743..8e3f6e6a90e7 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c @@ -31,6 +31,8 @@ struct core_reloc_arrays { struct core_reloc_arrays_substruct d[1][2]; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_arrays(void *ctx) { @@ -38,16 +40,16 @@ int test_core_arrays(void *ctx) struct core_reloc_arrays_output *out = (void *)&data.out; /* in->a[2] */ - if (BPF_CORE_READ(&out->a2, &in->a[2])) + if (CORE_READ(&out->a2, &in->a[2])) return 1; /* in->b[1][2][3] */ - if (BPF_CORE_READ(&out->b123, &in->b[1][2][3])) + if (CORE_READ(&out->b123, &in->b[1][2][3])) return 1; /* in->c[1].c */ - if (BPF_CORE_READ(&out->c1c, &in->c[1].c)) + if (CORE_READ(&out->c1c, &in->c[1].c)) return 1; /* in->d[0][0].d */ - if (BPF_CORE_READ(&out->d00d, &in->d[0][0].d)) + if (CORE_READ(&out->d00d, &in->d[0][0].d)) return 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c b/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c index 9fda73e87972..613474a18b45 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c @@ -39,6 +39,8 @@ struct core_reloc_flavors___weird { }; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_flavors(void *ctx) { @@ -48,13 +50,13 @@ int test_core_flavors(void *ctx) struct core_reloc_flavors *out = (void *)&data.out; /* read a using weird layout */ - if (BPF_CORE_READ(&out->a, &in_weird->a)) + if (CORE_READ(&out->a, &in_weird->a)) return 1; /* read b using reversed layout */ - if (BPF_CORE_READ(&out->b, &in_rev->b)) + if (CORE_READ(&out->b, &in_rev->b)) return 1; /* read c using original layout */ - if (BPF_CORE_READ(&out->c, &in_orig->c)) + if (CORE_READ(&out->c, &in_orig->c)) return 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c b/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c index d99233c8008a..7a88a3975455 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c @@ -23,20 +23,22 @@ struct core_reloc_ints { int64_t s64_field; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_ints(void *ctx) { struct core_reloc_ints *in = (void *)&data.in; struct core_reloc_ints *out = (void *)&data.out; - if (BPF_CORE_READ(&out->u8_field, &in->u8_field) || - BPF_CORE_READ(&out->s8_field, &in->s8_field) || - BPF_CORE_READ(&out->u16_field, &in->u16_field) || - BPF_CORE_READ(&out->s16_field, &in->s16_field) || - BPF_CORE_READ(&out->u32_field, &in->u32_field) || - BPF_CORE_READ(&out->s32_field, &in->s32_field) || - BPF_CORE_READ(&out->u64_field, &in->u64_field) || - BPF_CORE_READ(&out->s64_field, &in->s64_field)) + if (CORE_READ(&out->u8_field, &in->u8_field) || + CORE_READ(&out->s8_field, &in->s8_field) || + CORE_READ(&out->u16_field, &in->u16_field) || + CORE_READ(&out->s16_field, &in->s16_field) || + CORE_READ(&out->u32_field, &in->u32_field) || + CORE_READ(&out->s32_field, &in->s32_field) || + CORE_READ(&out->u64_field, &in->u64_field) || + CORE_READ(&out->s64_field, &in->s64_field)) return 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c index 37e02aa3f0c8..684a06cf41ea 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c @@ -17,6 +17,8 @@ struct task_struct { int tgid; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_kernel(void *ctx) { @@ -24,8 +26,8 @@ int test_core_kernel(void *ctx) uint64_t pid_tgid = bpf_get_current_pid_tgid(); int pid, tgid; - if (BPF_CORE_READ(&pid, &task->pid) || - BPF_CORE_READ(&tgid, &task->tgid)) + if (CORE_READ(&pid, &task->pid) || + CORE_READ(&tgid, &task->tgid)) return 1; /* validate pid + tgid matches */ diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c b/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c index c59984bd3e23..10bdb2050552 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c @@ -32,6 +32,8 @@ struct core_reloc_misc_extensible { int b; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_misc(void *ctx) { @@ -41,15 +43,15 @@ int test_core_misc(void *ctx) struct core_reloc_misc_output *out = (void *)&data.out; /* record two different relocations with the same accessor string */ - if (BPF_CORE_READ(&out->a, &in_a->a1) || /* accessor: 0:0 */ - BPF_CORE_READ(&out->b, &in_b->b1)) /* accessor: 0:0 */ + if (CORE_READ(&out->a, &in_a->a1) || /* accessor: 0:0 */ + CORE_READ(&out->b, &in_b->b1)) /* accessor: 0:0 */ return 1; /* Validate relocations capture array-only accesses for structs with * fixed header, but with potentially extendable tail. This will read * first 4 bytes of 2nd element of in_ext array of potentially * variably sized struct core_reloc_misc_extensible. */ - if (BPF_CORE_READ(&out->c, &in_ext[2])) /* accessor: 2 */ + if (CORE_READ(&out->c, &in_ext[2])) /* accessor: 2 */ return 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c b/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c index f98b942c062b..e930e7e88c5c 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c @@ -41,20 +41,22 @@ struct core_reloc_mods { core_reloc_mods_substruct_t h; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_mods(void *ctx) { struct core_reloc_mods *in = (void *)&data.in; struct core_reloc_mods_output *out = (void *)&data.out; - if (BPF_CORE_READ(&out->a, &in->a) || - BPF_CORE_READ(&out->b, &in->b) || - BPF_CORE_READ(&out->c, &in->c) || - BPF_CORE_READ(&out->d, &in->d) || - BPF_CORE_READ(&out->e, &in->e[2]) || - BPF_CORE_READ(&out->f, &in->f[1]) || - BPF_CORE_READ(&out->g, &in->g.x) || - BPF_CORE_READ(&out->h, &in->h.y)) + if (CORE_READ(&out->a, &in->a) || + CORE_READ(&out->b, &in->b) || + CORE_READ(&out->c, &in->c) || + CORE_READ(&out->d, &in->d) || + CORE_READ(&out->e, &in->e[2]) || + CORE_READ(&out->f, &in->f[1]) || + CORE_READ(&out->g, &in->g.x) || + CORE_READ(&out->h, &in->h.y)) return 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c b/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c index 3ca30cec2b39..b63007958290 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c @@ -30,15 +30,17 @@ struct core_reloc_nesting { } b; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_nesting(void *ctx) { struct core_reloc_nesting *in = (void *)&data.in; struct core_reloc_nesting *out = (void *)&data.out; - if (BPF_CORE_READ(&out->a.a.a, &in->a.a.a)) + if (CORE_READ(&out->a.a.a, &in->a.a.a)) return 1; - if (BPF_CORE_READ(&out->b.b.b, &in->b.b.b)) + if (CORE_READ(&out->b.b.b, &in->b.b.b)) return 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c b/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c index add52f23ab35..7654f59914bc 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c @@ -25,17 +25,19 @@ struct core_reloc_primitives { int (*f)(const char *); }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_primitives(void *ctx) { struct core_reloc_primitives *in = (void *)&data.in; struct core_reloc_primitives *out = (void *)&data.out; - if (BPF_CORE_READ(&out->a, &in->a) || - BPF_CORE_READ(&out->b, &in->b) || - BPF_CORE_READ(&out->c, &in->c) || - BPF_CORE_READ(&out->d, &in->d) || - BPF_CORE_READ(&out->f, &in->f)) + if (CORE_READ(&out->a, &in->a) || + CORE_READ(&out->b, &in->b) || + CORE_READ(&out->c, &in->c) || + CORE_READ(&out->d, &in->d) || + CORE_READ(&out->f, &in->f)) return 1; return 0; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c b/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c index 526b7ddc7ea1..709f7cba453f 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c @@ -16,13 +16,15 @@ struct core_reloc_ptr_as_arr { int a; }; +#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) + SEC("raw_tracepoint/sys_enter") int test_core_ptr_as_arr(void *ctx) { struct core_reloc_ptr_as_arr *in = (void *)&data.in; struct core_reloc_ptr_as_arr *out = (void *)&data.out; - if (BPF_CORE_READ(&out->a, &in[2].a)) + if (CORE_READ(&out->a, &in[2].a)) return 1; return 0; -- cgit v1.2.3 From 3ac4dbe3dd8943450e0366f8174fbfc286ea8f19 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 10:59:39 -0700 Subject: selftests/bpf: Split off tracing-only helpers into bpf_tracing.h Split-off PT_REGS-related helpers into bpf_tracing.h header. Adjust selftests and samples to include it where necessary. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191008175942.1769476-5-andriin@fb.com --- samples/bpf/map_perf_test_kern.c | 1 + samples/bpf/offwaketime_kern.c | 1 + samples/bpf/sampleip_kern.c | 1 + samples/bpf/spintest_kern.c | 1 + samples/bpf/test_map_in_map_kern.c | 1 + samples/bpf/test_overhead_kprobe_kern.c | 1 + samples/bpf/test_probe_write_user_kern.c | 1 + samples/bpf/trace_event_kern.c | 1 + samples/bpf/tracex1_kern.c | 1 + samples/bpf/tracex2_kern.c | 1 + samples/bpf/tracex3_kern.c | 1 + samples/bpf/tracex4_kern.c | 1 + samples/bpf/tracex5_kern.c | 1 + tools/testing/selftests/bpf/bpf_helpers.h | 190 ----------------------------- tools/testing/selftests/bpf/bpf_tracing.h | 195 ++++++++++++++++++++++++++++++ tools/testing/selftests/bpf/progs/loop1.c | 1 + tools/testing/selftests/bpf/progs/loop2.c | 1 + tools/testing/selftests/bpf/progs/loop3.c | 1 + 18 files changed, 211 insertions(+), 190 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_tracing.h diff --git a/samples/bpf/map_perf_test_kern.c b/samples/bpf/map_perf_test_kern.c index f47ee513cb7c..5c11aefbc489 100644 --- a/samples/bpf/map_perf_test_kern.c +++ b/samples/bpf/map_perf_test_kern.c @@ -10,6 +10,7 @@ #include #include "bpf_helpers.h" #include "bpf_legacy.h" +#include "bpf_tracing.h" #define MAX_ENTRIES 1000 #define MAX_NR_CPUS 1024 diff --git a/samples/bpf/offwaketime_kern.c b/samples/bpf/offwaketime_kern.c index e7d9a0a3d45b..9cb5207a692f 100644 --- a/samples/bpf/offwaketime_kern.c +++ b/samples/bpf/offwaketime_kern.c @@ -6,6 +6,7 @@ */ #include #include "bpf_helpers.h" +#include "bpf_tracing.h" #include #include #include diff --git a/samples/bpf/sampleip_kern.c b/samples/bpf/sampleip_kern.c index ceabf31079cf..4a190893894f 100644 --- a/samples/bpf/sampleip_kern.c +++ b/samples/bpf/sampleip_kern.c @@ -9,6 +9,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" #define MAX_IPS 8192 diff --git a/samples/bpf/spintest_kern.c b/samples/bpf/spintest_kern.c index ce0167d09cdc..6e9478aa2938 100644 --- a/samples/bpf/spintest_kern.c +++ b/samples/bpf/spintest_kern.c @@ -10,6 +10,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" struct bpf_map_def SEC("maps") my_map = { .type = BPF_MAP_TYPE_HASH, diff --git a/samples/bpf/test_map_in_map_kern.c b/samples/bpf/test_map_in_map_kern.c index 8101bf3dc7f7..4f80cbe74c72 100644 --- a/samples/bpf/test_map_in_map_kern.c +++ b/samples/bpf/test_map_in_map_kern.c @@ -12,6 +12,7 @@ #include #include "bpf_helpers.h" #include "bpf_legacy.h" +#include "bpf_tracing.h" #define MAX_NR_PORTS 65536 diff --git a/samples/bpf/test_overhead_kprobe_kern.c b/samples/bpf/test_overhead_kprobe_kern.c index 468a66a92ef9..8d2518e68db9 100644 --- a/samples/bpf/test_overhead_kprobe_kern.c +++ b/samples/bpf/test_overhead_kprobe_kern.c @@ -8,6 +8,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" #define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;}) diff --git a/samples/bpf/test_probe_write_user_kern.c b/samples/bpf/test_probe_write_user_kern.c index 3a677c807044..a543358218e6 100644 --- a/samples/bpf/test_probe_write_user_kern.c +++ b/samples/bpf/test_probe_write_user_kern.c @@ -9,6 +9,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" struct bpf_map_def SEC("maps") dnat_map = { .type = BPF_MAP_TYPE_HASH, diff --git a/samples/bpf/trace_event_kern.c b/samples/bpf/trace_event_kern.c index 7068fbdde951..8dc18d233a27 100644 --- a/samples/bpf/trace_event_kern.c +++ b/samples/bpf/trace_event_kern.c @@ -10,6 +10,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" struct key_t { char comm[TASK_COMM_LEN]; diff --git a/samples/bpf/tracex1_kern.c b/samples/bpf/tracex1_kern.c index 107da148820f..1a15f6605129 100644 --- a/samples/bpf/tracex1_kern.c +++ b/samples/bpf/tracex1_kern.c @@ -9,6 +9,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" #define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;}) diff --git a/samples/bpf/tracex2_kern.c b/samples/bpf/tracex2_kern.c index 5e11c20ce5ec..d70b3ea79ea7 100644 --- a/samples/bpf/tracex2_kern.c +++ b/samples/bpf/tracex2_kern.c @@ -9,6 +9,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" struct bpf_map_def SEC("maps") my_map = { .type = BPF_MAP_TYPE_HASH, diff --git a/samples/bpf/tracex3_kern.c b/samples/bpf/tracex3_kern.c index ea1d4c19c132..9af546bebfa9 100644 --- a/samples/bpf/tracex3_kern.c +++ b/samples/bpf/tracex3_kern.c @@ -9,6 +9,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" struct bpf_map_def SEC("maps") my_map = { .type = BPF_MAP_TYPE_HASH, diff --git a/samples/bpf/tracex4_kern.c b/samples/bpf/tracex4_kern.c index 6dd8e384de96..2a02cbe9d9a1 100644 --- a/samples/bpf/tracex4_kern.c +++ b/samples/bpf/tracex4_kern.c @@ -8,6 +8,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" struct pair { u64 val; diff --git a/samples/bpf/tracex5_kern.c b/samples/bpf/tracex5_kern.c index 35cb0eed3be5..b3557b21a8fe 100644 --- a/samples/bpf/tracex5_kern.c +++ b/samples/bpf/tracex5_kern.c @@ -11,6 +11,7 @@ #include #include "syscall_nrs.h" #include "bpf_helpers.h" +#include "bpf_tracing.h" #define PROG(F) SEC("kprobe/"__stringify(F)) int bpf_func_##F diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 4e6f97142cd8..6d059c0a7845 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -32,196 +32,6 @@ struct bpf_map_def { unsigned int map_flags; }; -/* Scan the ARCH passed in from ARCH env variable (see Makefile) */ -#if defined(__TARGET_ARCH_x86) - #define bpf_target_x86 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_s390) - #define bpf_target_s390 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_arm) - #define bpf_target_arm - #define bpf_target_defined -#elif defined(__TARGET_ARCH_arm64) - #define bpf_target_arm64 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_mips) - #define bpf_target_mips - #define bpf_target_defined -#elif defined(__TARGET_ARCH_powerpc) - #define bpf_target_powerpc - #define bpf_target_defined -#elif defined(__TARGET_ARCH_sparc) - #define bpf_target_sparc - #define bpf_target_defined -#else - #undef bpf_target_defined -#endif - -/* Fall back to what the compiler says */ -#ifndef bpf_target_defined -#if defined(__x86_64__) - #define bpf_target_x86 -#elif defined(__s390__) - #define bpf_target_s390 -#elif defined(__arm__) - #define bpf_target_arm -#elif defined(__aarch64__) - #define bpf_target_arm64 -#elif defined(__mips__) - #define bpf_target_mips -#elif defined(__powerpc__) - #define bpf_target_powerpc -#elif defined(__sparc__) - #define bpf_target_sparc -#endif -#endif - -#if defined(bpf_target_x86) - -#ifdef __KERNEL__ -#define PT_REGS_PARM1(x) ((x)->di) -#define PT_REGS_PARM2(x) ((x)->si) -#define PT_REGS_PARM3(x) ((x)->dx) -#define PT_REGS_PARM4(x) ((x)->cx) -#define PT_REGS_PARM5(x) ((x)->r8) -#define PT_REGS_RET(x) ((x)->sp) -#define PT_REGS_FP(x) ((x)->bp) -#define PT_REGS_RC(x) ((x)->ax) -#define PT_REGS_SP(x) ((x)->sp) -#define PT_REGS_IP(x) ((x)->ip) -#else -#ifdef __i386__ -/* i386 kernel is built with -mregparm=3 */ -#define PT_REGS_PARM1(x) ((x)->eax) -#define PT_REGS_PARM2(x) ((x)->edx) -#define PT_REGS_PARM3(x) ((x)->ecx) -#define PT_REGS_PARM4(x) 0 -#define PT_REGS_PARM5(x) 0 -#define PT_REGS_RET(x) ((x)->esp) -#define PT_REGS_FP(x) ((x)->ebp) -#define PT_REGS_RC(x) ((x)->eax) -#define PT_REGS_SP(x) ((x)->esp) -#define PT_REGS_IP(x) ((x)->eip) -#else -#define PT_REGS_PARM1(x) ((x)->rdi) -#define PT_REGS_PARM2(x) ((x)->rsi) -#define PT_REGS_PARM3(x) ((x)->rdx) -#define PT_REGS_PARM4(x) ((x)->rcx) -#define PT_REGS_PARM5(x) ((x)->r8) -#define PT_REGS_RET(x) ((x)->rsp) -#define PT_REGS_FP(x) ((x)->rbp) -#define PT_REGS_RC(x) ((x)->rax) -#define PT_REGS_SP(x) ((x)->rsp) -#define PT_REGS_IP(x) ((x)->rip) -#endif -#endif - -#elif defined(bpf_target_s390) - -/* s390 provides user_pt_regs instead of struct pt_regs to userspace */ -struct pt_regs; -#define PT_REGS_S390 const volatile user_pt_regs -#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2]) -#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3]) -#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4]) -#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5]) -#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6]) -#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14]) -/* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11]) -#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2]) -#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15]) -#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr) - -#elif defined(bpf_target_arm) - -#define PT_REGS_PARM1(x) ((x)->uregs[0]) -#define PT_REGS_PARM2(x) ((x)->uregs[1]) -#define PT_REGS_PARM3(x) ((x)->uregs[2]) -#define PT_REGS_PARM4(x) ((x)->uregs[3]) -#define PT_REGS_PARM5(x) ((x)->uregs[4]) -#define PT_REGS_RET(x) ((x)->uregs[14]) -#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_RC(x) ((x)->uregs[0]) -#define PT_REGS_SP(x) ((x)->uregs[13]) -#define PT_REGS_IP(x) ((x)->uregs[12]) - -#elif defined(bpf_target_arm64) - -/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */ -struct pt_regs; -#define PT_REGS_ARM64 const volatile struct user_pt_regs -#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0]) -#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1]) -#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2]) -#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3]) -#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4]) -#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30]) -/* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29]) -#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0]) -#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp) -#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc) - -#elif defined(bpf_target_mips) - -#define PT_REGS_PARM1(x) ((x)->regs[4]) -#define PT_REGS_PARM2(x) ((x)->regs[5]) -#define PT_REGS_PARM3(x) ((x)->regs[6]) -#define PT_REGS_PARM4(x) ((x)->regs[7]) -#define PT_REGS_PARM5(x) ((x)->regs[8]) -#define PT_REGS_RET(x) ((x)->regs[31]) -#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_RC(x) ((x)->regs[1]) -#define PT_REGS_SP(x) ((x)->regs[29]) -#define PT_REGS_IP(x) ((x)->cp0_epc) - -#elif defined(bpf_target_powerpc) - -#define PT_REGS_PARM1(x) ((x)->gpr[3]) -#define PT_REGS_PARM2(x) ((x)->gpr[4]) -#define PT_REGS_PARM3(x) ((x)->gpr[5]) -#define PT_REGS_PARM4(x) ((x)->gpr[6]) -#define PT_REGS_PARM5(x) ((x)->gpr[7]) -#define PT_REGS_RC(x) ((x)->gpr[3]) -#define PT_REGS_SP(x) ((x)->sp) -#define PT_REGS_IP(x) ((x)->nip) - -#elif defined(bpf_target_sparc) - -#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) -#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) -#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) -#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) -#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) -#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) -#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) -#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) - -/* Should this also be a bpf_target check for the sparc case? */ -#if defined(__arch64__) -#define PT_REGS_IP(x) ((x)->tpc) -#else -#define PT_REGS_IP(x) ((x)->pc) -#endif - -#endif - -#if defined(bpf_target_powerpc) -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) -#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP -#elif defined(bpf_target_sparc) -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) -#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP -#else -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ \ - bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) -#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) ({ \ - bpf_probe_read(&(ip), sizeof(ip), \ - (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) -#endif - /* * bpf_core_read() abstracts away bpf_probe_read() call and captures offset * relocation for source address using __builtin_preserve_access_index() diff --git a/tools/testing/selftests/bpf/bpf_tracing.h b/tools/testing/selftests/bpf/bpf_tracing.h new file mode 100644 index 000000000000..b0dafe8b4ebc --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_tracing.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BPF_TRACING_H__ +#define __BPF_TRACING_H__ + +/* Scan the ARCH passed in from ARCH env variable (see Makefile) */ +#if defined(__TARGET_ARCH_x86) + #define bpf_target_x86 + #define bpf_target_defined +#elif defined(__TARGET_ARCH_s390) + #define bpf_target_s390 + #define bpf_target_defined +#elif defined(__TARGET_ARCH_arm) + #define bpf_target_arm + #define bpf_target_defined +#elif defined(__TARGET_ARCH_arm64) + #define bpf_target_arm64 + #define bpf_target_defined +#elif defined(__TARGET_ARCH_mips) + #define bpf_target_mips + #define bpf_target_defined +#elif defined(__TARGET_ARCH_powerpc) + #define bpf_target_powerpc + #define bpf_target_defined +#elif defined(__TARGET_ARCH_sparc) + #define bpf_target_sparc + #define bpf_target_defined +#else + #undef bpf_target_defined +#endif + +/* Fall back to what the compiler says */ +#ifndef bpf_target_defined +#if defined(__x86_64__) + #define bpf_target_x86 +#elif defined(__s390__) + #define bpf_target_s390 +#elif defined(__arm__) + #define bpf_target_arm +#elif defined(__aarch64__) + #define bpf_target_arm64 +#elif defined(__mips__) + #define bpf_target_mips +#elif defined(__powerpc__) + #define bpf_target_powerpc +#elif defined(__sparc__) + #define bpf_target_sparc +#endif +#endif + +#if defined(bpf_target_x86) + +#ifdef __KERNEL__ +#define PT_REGS_PARM1(x) ((x)->di) +#define PT_REGS_PARM2(x) ((x)->si) +#define PT_REGS_PARM3(x) ((x)->dx) +#define PT_REGS_PARM4(x) ((x)->cx) +#define PT_REGS_PARM5(x) ((x)->r8) +#define PT_REGS_RET(x) ((x)->sp) +#define PT_REGS_FP(x) ((x)->bp) +#define PT_REGS_RC(x) ((x)->ax) +#define PT_REGS_SP(x) ((x)->sp) +#define PT_REGS_IP(x) ((x)->ip) +#else +#ifdef __i386__ +/* i386 kernel is built with -mregparm=3 */ +#define PT_REGS_PARM1(x) ((x)->eax) +#define PT_REGS_PARM2(x) ((x)->edx) +#define PT_REGS_PARM3(x) ((x)->ecx) +#define PT_REGS_PARM4(x) 0 +#define PT_REGS_PARM5(x) 0 +#define PT_REGS_RET(x) ((x)->esp) +#define PT_REGS_FP(x) ((x)->ebp) +#define PT_REGS_RC(x) ((x)->eax) +#define PT_REGS_SP(x) ((x)->esp) +#define PT_REGS_IP(x) ((x)->eip) +#else +#define PT_REGS_PARM1(x) ((x)->rdi) +#define PT_REGS_PARM2(x) ((x)->rsi) +#define PT_REGS_PARM3(x) ((x)->rdx) +#define PT_REGS_PARM4(x) ((x)->rcx) +#define PT_REGS_PARM5(x) ((x)->r8) +#define PT_REGS_RET(x) ((x)->rsp) +#define PT_REGS_FP(x) ((x)->rbp) +#define PT_REGS_RC(x) ((x)->rax) +#define PT_REGS_SP(x) ((x)->rsp) +#define PT_REGS_IP(x) ((x)->rip) +#endif +#endif + +#elif defined(bpf_target_s390) + +/* s390 provides user_pt_regs instead of struct pt_regs to userspace */ +struct pt_regs; +#define PT_REGS_S390 const volatile user_pt_regs +#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2]) +#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3]) +#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4]) +#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5]) +#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6]) +#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14]) +/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11]) +#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2]) +#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15]) +#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr) + +#elif defined(bpf_target_arm) + +#define PT_REGS_PARM1(x) ((x)->uregs[0]) +#define PT_REGS_PARM2(x) ((x)->uregs[1]) +#define PT_REGS_PARM3(x) ((x)->uregs[2]) +#define PT_REGS_PARM4(x) ((x)->uregs[3]) +#define PT_REGS_PARM5(x) ((x)->uregs[4]) +#define PT_REGS_RET(x) ((x)->uregs[14]) +#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->uregs[0]) +#define PT_REGS_SP(x) ((x)->uregs[13]) +#define PT_REGS_IP(x) ((x)->uregs[12]) + +#elif defined(bpf_target_arm64) + +/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */ +struct pt_regs; +#define PT_REGS_ARM64 const volatile struct user_pt_regs +#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0]) +#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1]) +#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2]) +#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3]) +#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4]) +#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30]) +/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29]) +#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0]) +#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp) +#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc) + +#elif defined(bpf_target_mips) + +#define PT_REGS_PARM1(x) ((x)->regs[4]) +#define PT_REGS_PARM2(x) ((x)->regs[5]) +#define PT_REGS_PARM3(x) ((x)->regs[6]) +#define PT_REGS_PARM4(x) ((x)->regs[7]) +#define PT_REGS_PARM5(x) ((x)->regs[8]) +#define PT_REGS_RET(x) ((x)->regs[31]) +#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->regs[1]) +#define PT_REGS_SP(x) ((x)->regs[29]) +#define PT_REGS_IP(x) ((x)->cp0_epc) + +#elif defined(bpf_target_powerpc) + +#define PT_REGS_PARM1(x) ((x)->gpr[3]) +#define PT_REGS_PARM2(x) ((x)->gpr[4]) +#define PT_REGS_PARM3(x) ((x)->gpr[5]) +#define PT_REGS_PARM4(x) ((x)->gpr[6]) +#define PT_REGS_PARM5(x) ((x)->gpr[7]) +#define PT_REGS_RC(x) ((x)->gpr[3]) +#define PT_REGS_SP(x) ((x)->sp) +#define PT_REGS_IP(x) ((x)->nip) + +#elif defined(bpf_target_sparc) + +#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) +#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) +#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) +#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) +#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) +#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) + +/* Should this also be a bpf_target check for the sparc case? */ +#if defined(__arch64__) +#define PT_REGS_IP(x) ((x)->tpc) +#else +#define PT_REGS_IP(x) ((x)->pc) +#endif + +#endif + +#if defined(bpf_target_powerpc) +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#elif defined(bpf_target_sparc) +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#else +#define BPF_KPROBE_READ_RET_IP(ip, ctx) \ + ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) +#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \ + ({ bpf_probe_read(&(ip), sizeof(ip), \ + (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) +#endif + +#endif diff --git a/tools/testing/selftests/bpf/progs/loop1.c b/tools/testing/selftests/bpf/progs/loop1.c index 7cdb7f878310..40ac722a9da5 100644 --- a/tools/testing/selftests/bpf/progs/loop1.c +++ b/tools/testing/selftests/bpf/progs/loop1.c @@ -7,6 +7,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/loop2.c b/tools/testing/selftests/bpf/progs/loop2.c index 9b2f808a2863..bb80f29aa7f7 100644 --- a/tools/testing/selftests/bpf/progs/loop2.c +++ b/tools/testing/selftests/bpf/progs/loop2.c @@ -7,6 +7,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/loop3.c b/tools/testing/selftests/bpf/progs/loop3.c index d727657d51e2..2b9165a7afe1 100644 --- a/tools/testing/selftests/bpf/progs/loop3.c +++ b/tools/testing/selftests/bpf/progs/loop3.c @@ -7,6 +7,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_tracing.h" char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From e01a75c159691714607b8a22daa2ba7be275dd01 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 10:59:40 -0700 Subject: libbpf: Move bpf_{helpers, helper_defs, endian, tracing}.h into libbpf Move bpf_helpers.h, bpf_tracing.h, and bpf_endian.h into libbpf. Move bpf_helper_defs.h generation into libbpf's Makefile. Ensure all those headers are installed along the other libbpf headers. Also, adjust selftests and samples include path to include libbpf now. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191008175942.1769476-6-andriin@fb.com --- samples/bpf/Makefile | 2 +- tools/lib/bpf/.gitignore | 1 + tools/lib/bpf/Makefile | 16 ++- tools/lib/bpf/bpf_endian.h | 72 +++++++++++ tools/lib/bpf/bpf_helpers.h | 55 +++++++++ tools/lib/bpf/bpf_tracing.h | 195 ++++++++++++++++++++++++++++++ tools/testing/selftests/bpf/.gitignore | 1 - tools/testing/selftests/bpf/Makefile | 10 +- tools/testing/selftests/bpf/bpf_endian.h | 72 ----------- tools/testing/selftests/bpf/bpf_helpers.h | 55 --------- tools/testing/selftests/bpf/bpf_tracing.h | 195 ------------------------------ 11 files changed, 339 insertions(+), 335 deletions(-) create mode 100644 tools/lib/bpf/bpf_endian.h create mode 100644 tools/lib/bpf/bpf_helpers.h create mode 100644 tools/lib/bpf/bpf_tracing.h delete mode 100644 tools/testing/selftests/bpf/bpf_endian.h delete mode 100644 tools/testing/selftests/bpf/bpf_helpers.h delete mode 100644 tools/testing/selftests/bpf/bpf_tracing.h diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 1d9be26b4edd..a11d7270583d 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -282,7 +282,7 @@ $(obj)/hbm_edt_kern.o: $(src)/hbm.h $(src)/hbm_kern.h $(obj)/%.o: $(src)/%.c @echo " CLANG-bpf " $@ $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) -I$(obj) \ - -I$(srctree)/tools/testing/selftests/bpf/ \ + -I$(srctree)/tools/testing/selftests/bpf/ -I$(srctree)/tools/lib/bpf/ \ -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ -D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \ -Wno-gnu-variable-sized-type-not-at-end \ diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore index 12382b0c71c7..35bf013e368c 100644 --- a/tools/lib/bpf/.gitignore +++ b/tools/lib/bpf/.gitignore @@ -6,3 +6,4 @@ libbpf.so.* TAGS tags cscope.* +/bpf_helper_defs.h diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 10b77644a17c..974453564f01 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -157,7 +157,7 @@ all: fixdep all_cmd: $(CMD_TARGETS) check -$(BPF_IN): force elfdep bpfdep +$(BPF_IN): force elfdep bpfdep bpf_helper_defs.h @(test -f ../../include/uapi/linux/bpf.h -a -f ../../../include/uapi/linux/bpf.h && ( \ (diff -B ../../include/uapi/linux/bpf.h ../../../include/uapi/linux/bpf.h >/dev/null) || \ echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf.h' differs from latest version at 'include/uapi/linux/bpf.h'" >&2 )) || true @@ -175,6 +175,10 @@ $(BPF_IN): force elfdep bpfdep echo "Warning: Kernel ABI header at 'tools/include/uapi/linux/if_xdp.h' differs from latest version at 'include/uapi/linux/if_xdp.h'" >&2 )) || true $(Q)$(MAKE) $(build)=libbpf +bpf_helper_defs.h: $(srctree)/include/uapi/linux/bpf.h + $(Q)$(srctree)/scripts/bpf_helpers_doc.py --header \ + --file $(srctree)/include/uapi/linux/bpf.h > bpf_helper_defs.h + $(OUTPUT)libbpf.so: $(OUTPUT)libbpf.so.$(LIBBPF_VERSION) $(OUTPUT)libbpf.so.$(LIBBPF_VERSION): $(BPF_IN) @@ -236,13 +240,17 @@ install_lib: all_cmd $(call do_install_mkdir,$(libdir_SQ)); \ cp -fpR $(LIB_FILE) $(DESTDIR)$(libdir_SQ) -install_headers: +install_headers: bpf_helper_defs.h $(call QUIET_INSTALL, headers) \ $(call do_install,bpf.h,$(prefix)/include/bpf,644); \ $(call do_install,libbpf.h,$(prefix)/include/bpf,644); \ $(call do_install,btf.h,$(prefix)/include/bpf,644); \ $(call do_install,libbpf_util.h,$(prefix)/include/bpf,644); \ - $(call do_install,xsk.h,$(prefix)/include/bpf,644); + $(call do_install,xsk.h,$(prefix)/include/bpf,644); \ + $(call do_install,bpf_helpers.h,$(prefix)/include/bpf,644); \ + $(call do_install,bpf_helper_defs.h,$(prefix)/include/bpf,644); \ + $(call do_install,bpf_tracing.h,$(prefix)/include/bpf,644); \ + $(call do_install,bpf_endian.h,$(prefix)/include/bpf,644); install_pkgconfig: $(PC_FILE) $(call QUIET_INSTALL, $(PC_FILE)) \ @@ -259,7 +267,7 @@ config-clean: clean: $(call QUIET_CLEAN, libbpf) $(RM) $(TARGETS) $(CXX_TEST_TARGET) \ *.o *~ *.a *.so *.so.$(LIBBPF_MAJOR_VERSION) .*.d .*.cmd \ - *.pc LIBBPF-CFLAGS + *.pc LIBBPF-CFLAGS bpf_helper_defs.h $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf diff --git a/tools/lib/bpf/bpf_endian.h b/tools/lib/bpf/bpf_endian.h new file mode 100644 index 000000000000..fbe28008450f --- /dev/null +++ b/tools/lib/bpf/bpf_endian.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BPF_ENDIAN__ +#define __BPF_ENDIAN__ + +#include +#include + +/* LLVM's BPF target selects the endianness of the CPU + * it compiles on, or the user specifies (bpfel/bpfeb), + * respectively. The used __BYTE_ORDER__ is defined by + * the compiler, we cannot rely on __BYTE_ORDER from + * libc headers, since it doesn't reflect the actual + * requested byte order. + * + * Note, LLVM's BPF target has different __builtin_bswapX() + * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE + * in bpfel and bpfeb case, which means below, that we map + * to cpu_to_be16(). We could use it unconditionally in BPF + * case, but better not rely on it, so that this header here + * can be used from application and BPF program side, which + * use different targets. + */ +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define __bpf_ntohs(x) __builtin_bswap16(x) +# define __bpf_htons(x) __builtin_bswap16(x) +# define __bpf_constant_ntohs(x) ___constant_swab16(x) +# define __bpf_constant_htons(x) ___constant_swab16(x) +# define __bpf_ntohl(x) __builtin_bswap32(x) +# define __bpf_htonl(x) __builtin_bswap32(x) +# define __bpf_constant_ntohl(x) ___constant_swab32(x) +# define __bpf_constant_htonl(x) ___constant_swab32(x) +# define __bpf_be64_to_cpu(x) __builtin_bswap64(x) +# define __bpf_cpu_to_be64(x) __builtin_bswap64(x) +# define __bpf_constant_be64_to_cpu(x) ___constant_swab64(x) +# define __bpf_constant_cpu_to_be64(x) ___constant_swab64(x) +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define __bpf_ntohs(x) (x) +# define __bpf_htons(x) (x) +# define __bpf_constant_ntohs(x) (x) +# define __bpf_constant_htons(x) (x) +# define __bpf_ntohl(x) (x) +# define __bpf_htonl(x) (x) +# define __bpf_constant_ntohl(x) (x) +# define __bpf_constant_htonl(x) (x) +# define __bpf_be64_to_cpu(x) (x) +# define __bpf_cpu_to_be64(x) (x) +# define __bpf_constant_be64_to_cpu(x) (x) +# define __bpf_constant_cpu_to_be64(x) (x) +#else +# error "Fix your compiler's __BYTE_ORDER__?!" +#endif + +#define bpf_htons(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_htons(x) : __bpf_htons(x)) +#define bpf_ntohs(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_ntohs(x) : __bpf_ntohs(x)) +#define bpf_htonl(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_htonl(x) : __bpf_htonl(x)) +#define bpf_ntohl(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_ntohl(x) : __bpf_ntohl(x)) +#define bpf_cpu_to_be64(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x)) +#define bpf_be64_to_cpu(x) \ + (__builtin_constant_p(x) ? \ + __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x)) + +#endif /* __BPF_ENDIAN__ */ diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h new file mode 100644 index 000000000000..6d059c0a7845 --- /dev/null +++ b/tools/lib/bpf/bpf_helpers.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BPF_HELPERS__ +#define __BPF_HELPERS__ + +#include "bpf_helper_defs.h" + +#define __uint(name, val) int (*name)[val] +#define __type(name, val) typeof(val) *name + +/* helper macro to print out debug messages */ +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +/* helper macro to place programs, maps, license in + * different sections in elf_bpf file. Section names + * are interpreted by elf_bpf loader + */ +#define SEC(NAME) __attribute__((section(NAME), used)) + +/* a helper structure used by eBPF C program + * to describe BPF map attributes to libbpf loader + */ +struct bpf_map_def { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; + unsigned int map_flags; +}; + +/* + * bpf_core_read() abstracts away bpf_probe_read() call and captures offset + * relocation for source address using __builtin_preserve_access_index() + * built-in, provided by Clang. + * + * __builtin_preserve_access_index() takes as an argument an expression of + * taking an address of a field within struct/union. It makes compiler emit + * a relocation, which records BTF type ID describing root struct/union and an + * accessor string which describes exact embedded field that was used to take + * an address. See detailed description of this relocation format and + * semantics in comments to struct bpf_offset_reloc in libbpf_internal.h. + * + * This relocation allows libbpf to adjust BPF instruction to use correct + * actual field offset, based on target kernel BTF type that matches original + * (local) BTF, used to record relocation. + */ +#define bpf_core_read(dst, sz, src) \ + bpf_probe_read(dst, sz, \ + (const void *)__builtin_preserve_access_index(src)) + +#endif diff --git a/tools/lib/bpf/bpf_tracing.h b/tools/lib/bpf/bpf_tracing.h new file mode 100644 index 000000000000..b0dafe8b4ebc --- /dev/null +++ b/tools/lib/bpf/bpf_tracing.h @@ -0,0 +1,195 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BPF_TRACING_H__ +#define __BPF_TRACING_H__ + +/* Scan the ARCH passed in from ARCH env variable (see Makefile) */ +#if defined(__TARGET_ARCH_x86) + #define bpf_target_x86 + #define bpf_target_defined +#elif defined(__TARGET_ARCH_s390) + #define bpf_target_s390 + #define bpf_target_defined +#elif defined(__TARGET_ARCH_arm) + #define bpf_target_arm + #define bpf_target_defined +#elif defined(__TARGET_ARCH_arm64) + #define bpf_target_arm64 + #define bpf_target_defined +#elif defined(__TARGET_ARCH_mips) + #define bpf_target_mips + #define bpf_target_defined +#elif defined(__TARGET_ARCH_powerpc) + #define bpf_target_powerpc + #define bpf_target_defined +#elif defined(__TARGET_ARCH_sparc) + #define bpf_target_sparc + #define bpf_target_defined +#else + #undef bpf_target_defined +#endif + +/* Fall back to what the compiler says */ +#ifndef bpf_target_defined +#if defined(__x86_64__) + #define bpf_target_x86 +#elif defined(__s390__) + #define bpf_target_s390 +#elif defined(__arm__) + #define bpf_target_arm +#elif defined(__aarch64__) + #define bpf_target_arm64 +#elif defined(__mips__) + #define bpf_target_mips +#elif defined(__powerpc__) + #define bpf_target_powerpc +#elif defined(__sparc__) + #define bpf_target_sparc +#endif +#endif + +#if defined(bpf_target_x86) + +#ifdef __KERNEL__ +#define PT_REGS_PARM1(x) ((x)->di) +#define PT_REGS_PARM2(x) ((x)->si) +#define PT_REGS_PARM3(x) ((x)->dx) +#define PT_REGS_PARM4(x) ((x)->cx) +#define PT_REGS_PARM5(x) ((x)->r8) +#define PT_REGS_RET(x) ((x)->sp) +#define PT_REGS_FP(x) ((x)->bp) +#define PT_REGS_RC(x) ((x)->ax) +#define PT_REGS_SP(x) ((x)->sp) +#define PT_REGS_IP(x) ((x)->ip) +#else +#ifdef __i386__ +/* i386 kernel is built with -mregparm=3 */ +#define PT_REGS_PARM1(x) ((x)->eax) +#define PT_REGS_PARM2(x) ((x)->edx) +#define PT_REGS_PARM3(x) ((x)->ecx) +#define PT_REGS_PARM4(x) 0 +#define PT_REGS_PARM5(x) 0 +#define PT_REGS_RET(x) ((x)->esp) +#define PT_REGS_FP(x) ((x)->ebp) +#define PT_REGS_RC(x) ((x)->eax) +#define PT_REGS_SP(x) ((x)->esp) +#define PT_REGS_IP(x) ((x)->eip) +#else +#define PT_REGS_PARM1(x) ((x)->rdi) +#define PT_REGS_PARM2(x) ((x)->rsi) +#define PT_REGS_PARM3(x) ((x)->rdx) +#define PT_REGS_PARM4(x) ((x)->rcx) +#define PT_REGS_PARM5(x) ((x)->r8) +#define PT_REGS_RET(x) ((x)->rsp) +#define PT_REGS_FP(x) ((x)->rbp) +#define PT_REGS_RC(x) ((x)->rax) +#define PT_REGS_SP(x) ((x)->rsp) +#define PT_REGS_IP(x) ((x)->rip) +#endif +#endif + +#elif defined(bpf_target_s390) + +/* s390 provides user_pt_regs instead of struct pt_regs to userspace */ +struct pt_regs; +#define PT_REGS_S390 const volatile user_pt_regs +#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2]) +#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3]) +#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4]) +#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5]) +#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6]) +#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14]) +/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11]) +#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2]) +#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15]) +#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr) + +#elif defined(bpf_target_arm) + +#define PT_REGS_PARM1(x) ((x)->uregs[0]) +#define PT_REGS_PARM2(x) ((x)->uregs[1]) +#define PT_REGS_PARM3(x) ((x)->uregs[2]) +#define PT_REGS_PARM4(x) ((x)->uregs[3]) +#define PT_REGS_PARM5(x) ((x)->uregs[4]) +#define PT_REGS_RET(x) ((x)->uregs[14]) +#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->uregs[0]) +#define PT_REGS_SP(x) ((x)->uregs[13]) +#define PT_REGS_IP(x) ((x)->uregs[12]) + +#elif defined(bpf_target_arm64) + +/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */ +struct pt_regs; +#define PT_REGS_ARM64 const volatile struct user_pt_regs +#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0]) +#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1]) +#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2]) +#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3]) +#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4]) +#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30]) +/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29]) +#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0]) +#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp) +#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc) + +#elif defined(bpf_target_mips) + +#define PT_REGS_PARM1(x) ((x)->regs[4]) +#define PT_REGS_PARM2(x) ((x)->regs[5]) +#define PT_REGS_PARM3(x) ((x)->regs[6]) +#define PT_REGS_PARM4(x) ((x)->regs[7]) +#define PT_REGS_PARM5(x) ((x)->regs[8]) +#define PT_REGS_RET(x) ((x)->regs[31]) +#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->regs[1]) +#define PT_REGS_SP(x) ((x)->regs[29]) +#define PT_REGS_IP(x) ((x)->cp0_epc) + +#elif defined(bpf_target_powerpc) + +#define PT_REGS_PARM1(x) ((x)->gpr[3]) +#define PT_REGS_PARM2(x) ((x)->gpr[4]) +#define PT_REGS_PARM3(x) ((x)->gpr[5]) +#define PT_REGS_PARM4(x) ((x)->gpr[6]) +#define PT_REGS_PARM5(x) ((x)->gpr[7]) +#define PT_REGS_RC(x) ((x)->gpr[3]) +#define PT_REGS_SP(x) ((x)->sp) +#define PT_REGS_IP(x) ((x)->nip) + +#elif defined(bpf_target_sparc) + +#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) +#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) +#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) +#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) +#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) +#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) + +/* Should this also be a bpf_target check for the sparc case? */ +#if defined(__arch64__) +#define PT_REGS_IP(x) ((x)->tpc) +#else +#define PT_REGS_IP(x) ((x)->pc) +#endif + +#endif + +#if defined(bpf_target_powerpc) +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#elif defined(bpf_target_sparc) +#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#else +#define BPF_KPROBE_READ_RET_IP(ip, ctx) \ + ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) +#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \ + ({ bpf_probe_read(&(ip), sizeof(ip), \ + (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) +#endif + +#endif diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore index 50063f66539d..7470327edcfe 100644 --- a/tools/testing/selftests/bpf/.gitignore +++ b/tools/testing/selftests/bpf/.gitignore @@ -39,4 +39,3 @@ libbpf.so.* test_hashmap test_btf_dump xdping -/bpf_helper_defs.h diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 771a4e82128b..90944b7a8274 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -90,10 +90,6 @@ include ../lib.mk TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read all: $(TEST_CUSTOM_PROGS) -bpf_helper_defs.h: $(APIDIR)/linux/bpf.h - $(BPFDIR)/../../../scripts/bpf_helpers_doc.py --header \ - --file $(APIDIR)/linux/bpf.h > bpf_helper_defs.h - $(OUTPUT)/urandom_read: $(OUTPUT)/%: %.c $(CC) -o $@ $< -Wl,--build-id @@ -127,7 +123,7 @@ $(OUTPUT)/test_cgroup_attach: cgroup_helpers.c # force a rebuild of BPFOBJ when its dependencies are updated force: -$(BPFOBJ): force bpf_helper_defs.h +$(BPFOBJ): force $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/ PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) @@ -152,7 +148,7 @@ $(shell $(1) -v -E - &1 \ endef CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG)) BPF_CFLAGS = -I. -I./include/uapi -I../../../include/uapi \ - -I$(OUTPUT)/../usr/include -D__TARGET_ARCH_$(SRCARCH) + -I$(BPFDIR) -I$(OUTPUT)/../usr/include -D__TARGET_ARCH_$(SRCARCH) CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \ -Wno-compare-distinct-pointer-types @@ -323,4 +319,4 @@ $(VERIFIER_TESTS_H): $(VERIFIER_TEST_FILES) | $(VERIFIER_TESTS_DIR) EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(ALU32_BUILD_DIR) $(BPF_GCC_BUILD_DIR) \ $(VERIFIER_TESTS_H) $(PROG_TESTS_H) $(MAP_TESTS_H) \ - feature bpf_helper_defs.h + feature diff --git a/tools/testing/selftests/bpf/bpf_endian.h b/tools/testing/selftests/bpf/bpf_endian.h deleted file mode 100644 index fbe28008450f..000000000000 --- a/tools/testing/selftests/bpf/bpf_endian.h +++ /dev/null @@ -1,72 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#ifndef __BPF_ENDIAN__ -#define __BPF_ENDIAN__ - -#include -#include - -/* LLVM's BPF target selects the endianness of the CPU - * it compiles on, or the user specifies (bpfel/bpfeb), - * respectively. The used __BYTE_ORDER__ is defined by - * the compiler, we cannot rely on __BYTE_ORDER from - * libc headers, since it doesn't reflect the actual - * requested byte order. - * - * Note, LLVM's BPF target has different __builtin_bswapX() - * semantics. It does map to BPF_ALU | BPF_END | BPF_TO_BE - * in bpfel and bpfeb case, which means below, that we map - * to cpu_to_be16(). We could use it unconditionally in BPF - * case, but better not rely on it, so that this header here - * can be used from application and BPF program side, which - * use different targets. - */ -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define __bpf_ntohs(x) __builtin_bswap16(x) -# define __bpf_htons(x) __builtin_bswap16(x) -# define __bpf_constant_ntohs(x) ___constant_swab16(x) -# define __bpf_constant_htons(x) ___constant_swab16(x) -# define __bpf_ntohl(x) __builtin_bswap32(x) -# define __bpf_htonl(x) __builtin_bswap32(x) -# define __bpf_constant_ntohl(x) ___constant_swab32(x) -# define __bpf_constant_htonl(x) ___constant_swab32(x) -# define __bpf_be64_to_cpu(x) __builtin_bswap64(x) -# define __bpf_cpu_to_be64(x) __builtin_bswap64(x) -# define __bpf_constant_be64_to_cpu(x) ___constant_swab64(x) -# define __bpf_constant_cpu_to_be64(x) ___constant_swab64(x) -#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define __bpf_ntohs(x) (x) -# define __bpf_htons(x) (x) -# define __bpf_constant_ntohs(x) (x) -# define __bpf_constant_htons(x) (x) -# define __bpf_ntohl(x) (x) -# define __bpf_htonl(x) (x) -# define __bpf_constant_ntohl(x) (x) -# define __bpf_constant_htonl(x) (x) -# define __bpf_be64_to_cpu(x) (x) -# define __bpf_cpu_to_be64(x) (x) -# define __bpf_constant_be64_to_cpu(x) (x) -# define __bpf_constant_cpu_to_be64(x) (x) -#else -# error "Fix your compiler's __BYTE_ORDER__?!" -#endif - -#define bpf_htons(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_htons(x) : __bpf_htons(x)) -#define bpf_ntohs(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_ntohs(x) : __bpf_ntohs(x)) -#define bpf_htonl(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_htonl(x) : __bpf_htonl(x)) -#define bpf_ntohl(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_ntohl(x) : __bpf_ntohl(x)) -#define bpf_cpu_to_be64(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_cpu_to_be64(x) : __bpf_cpu_to_be64(x)) -#define bpf_be64_to_cpu(x) \ - (__builtin_constant_p(x) ? \ - __bpf_constant_be64_to_cpu(x) : __bpf_be64_to_cpu(x)) - -#endif /* __BPF_ENDIAN__ */ diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h deleted file mode 100644 index 6d059c0a7845..000000000000 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#ifndef __BPF_HELPERS__ -#define __BPF_HELPERS__ - -#include "bpf_helper_defs.h" - -#define __uint(name, val) int (*name)[val] -#define __type(name, val) typeof(val) *name - -/* helper macro to print out debug messages */ -#define bpf_printk(fmt, ...) \ -({ \ - char ____fmt[] = fmt; \ - bpf_trace_printk(____fmt, sizeof(____fmt), \ - ##__VA_ARGS__); \ -}) - -/* helper macro to place programs, maps, license in - * different sections in elf_bpf file. Section names - * are interpreted by elf_bpf loader - */ -#define SEC(NAME) __attribute__((section(NAME), used)) - -/* a helper structure used by eBPF C program - * to describe BPF map attributes to libbpf loader - */ -struct bpf_map_def { - unsigned int type; - unsigned int key_size; - unsigned int value_size; - unsigned int max_entries; - unsigned int map_flags; -}; - -/* - * bpf_core_read() abstracts away bpf_probe_read() call and captures offset - * relocation for source address using __builtin_preserve_access_index() - * built-in, provided by Clang. - * - * __builtin_preserve_access_index() takes as an argument an expression of - * taking an address of a field within struct/union. It makes compiler emit - * a relocation, which records BTF type ID describing root struct/union and an - * accessor string which describes exact embedded field that was used to take - * an address. See detailed description of this relocation format and - * semantics in comments to struct bpf_offset_reloc in libbpf_internal.h. - * - * This relocation allows libbpf to adjust BPF instruction to use correct - * actual field offset, based on target kernel BTF type that matches original - * (local) BTF, used to record relocation. - */ -#define bpf_core_read(dst, sz, src) \ - bpf_probe_read(dst, sz, \ - (const void *)__builtin_preserve_access_index(src)) - -#endif diff --git a/tools/testing/selftests/bpf/bpf_tracing.h b/tools/testing/selftests/bpf/bpf_tracing.h deleted file mode 100644 index b0dafe8b4ebc..000000000000 --- a/tools/testing/selftests/bpf/bpf_tracing.h +++ /dev/null @@ -1,195 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#ifndef __BPF_TRACING_H__ -#define __BPF_TRACING_H__ - -/* Scan the ARCH passed in from ARCH env variable (see Makefile) */ -#if defined(__TARGET_ARCH_x86) - #define bpf_target_x86 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_s390) - #define bpf_target_s390 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_arm) - #define bpf_target_arm - #define bpf_target_defined -#elif defined(__TARGET_ARCH_arm64) - #define bpf_target_arm64 - #define bpf_target_defined -#elif defined(__TARGET_ARCH_mips) - #define bpf_target_mips - #define bpf_target_defined -#elif defined(__TARGET_ARCH_powerpc) - #define bpf_target_powerpc - #define bpf_target_defined -#elif defined(__TARGET_ARCH_sparc) - #define bpf_target_sparc - #define bpf_target_defined -#else - #undef bpf_target_defined -#endif - -/* Fall back to what the compiler says */ -#ifndef bpf_target_defined -#if defined(__x86_64__) - #define bpf_target_x86 -#elif defined(__s390__) - #define bpf_target_s390 -#elif defined(__arm__) - #define bpf_target_arm -#elif defined(__aarch64__) - #define bpf_target_arm64 -#elif defined(__mips__) - #define bpf_target_mips -#elif defined(__powerpc__) - #define bpf_target_powerpc -#elif defined(__sparc__) - #define bpf_target_sparc -#endif -#endif - -#if defined(bpf_target_x86) - -#ifdef __KERNEL__ -#define PT_REGS_PARM1(x) ((x)->di) -#define PT_REGS_PARM2(x) ((x)->si) -#define PT_REGS_PARM3(x) ((x)->dx) -#define PT_REGS_PARM4(x) ((x)->cx) -#define PT_REGS_PARM5(x) ((x)->r8) -#define PT_REGS_RET(x) ((x)->sp) -#define PT_REGS_FP(x) ((x)->bp) -#define PT_REGS_RC(x) ((x)->ax) -#define PT_REGS_SP(x) ((x)->sp) -#define PT_REGS_IP(x) ((x)->ip) -#else -#ifdef __i386__ -/* i386 kernel is built with -mregparm=3 */ -#define PT_REGS_PARM1(x) ((x)->eax) -#define PT_REGS_PARM2(x) ((x)->edx) -#define PT_REGS_PARM3(x) ((x)->ecx) -#define PT_REGS_PARM4(x) 0 -#define PT_REGS_PARM5(x) 0 -#define PT_REGS_RET(x) ((x)->esp) -#define PT_REGS_FP(x) ((x)->ebp) -#define PT_REGS_RC(x) ((x)->eax) -#define PT_REGS_SP(x) ((x)->esp) -#define PT_REGS_IP(x) ((x)->eip) -#else -#define PT_REGS_PARM1(x) ((x)->rdi) -#define PT_REGS_PARM2(x) ((x)->rsi) -#define PT_REGS_PARM3(x) ((x)->rdx) -#define PT_REGS_PARM4(x) ((x)->rcx) -#define PT_REGS_PARM5(x) ((x)->r8) -#define PT_REGS_RET(x) ((x)->rsp) -#define PT_REGS_FP(x) ((x)->rbp) -#define PT_REGS_RC(x) ((x)->rax) -#define PT_REGS_SP(x) ((x)->rsp) -#define PT_REGS_IP(x) ((x)->rip) -#endif -#endif - -#elif defined(bpf_target_s390) - -/* s390 provides user_pt_regs instead of struct pt_regs to userspace */ -struct pt_regs; -#define PT_REGS_S390 const volatile user_pt_regs -#define PT_REGS_PARM1(x) (((PT_REGS_S390 *)(x))->gprs[2]) -#define PT_REGS_PARM2(x) (((PT_REGS_S390 *)(x))->gprs[3]) -#define PT_REGS_PARM3(x) (((PT_REGS_S390 *)(x))->gprs[4]) -#define PT_REGS_PARM4(x) (((PT_REGS_S390 *)(x))->gprs[5]) -#define PT_REGS_PARM5(x) (((PT_REGS_S390 *)(x))->gprs[6]) -#define PT_REGS_RET(x) (((PT_REGS_S390 *)(x))->gprs[14]) -/* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_FP(x) (((PT_REGS_S390 *)(x))->gprs[11]) -#define PT_REGS_RC(x) (((PT_REGS_S390 *)(x))->gprs[2]) -#define PT_REGS_SP(x) (((PT_REGS_S390 *)(x))->gprs[15]) -#define PT_REGS_IP(x) (((PT_REGS_S390 *)(x))->psw.addr) - -#elif defined(bpf_target_arm) - -#define PT_REGS_PARM1(x) ((x)->uregs[0]) -#define PT_REGS_PARM2(x) ((x)->uregs[1]) -#define PT_REGS_PARM3(x) ((x)->uregs[2]) -#define PT_REGS_PARM4(x) ((x)->uregs[3]) -#define PT_REGS_PARM5(x) ((x)->uregs[4]) -#define PT_REGS_RET(x) ((x)->uregs[14]) -#define PT_REGS_FP(x) ((x)->uregs[11]) /* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_RC(x) ((x)->uregs[0]) -#define PT_REGS_SP(x) ((x)->uregs[13]) -#define PT_REGS_IP(x) ((x)->uregs[12]) - -#elif defined(bpf_target_arm64) - -/* arm64 provides struct user_pt_regs instead of struct pt_regs to userspace */ -struct pt_regs; -#define PT_REGS_ARM64 const volatile struct user_pt_regs -#define PT_REGS_PARM1(x) (((PT_REGS_ARM64 *)(x))->regs[0]) -#define PT_REGS_PARM2(x) (((PT_REGS_ARM64 *)(x))->regs[1]) -#define PT_REGS_PARM3(x) (((PT_REGS_ARM64 *)(x))->regs[2]) -#define PT_REGS_PARM4(x) (((PT_REGS_ARM64 *)(x))->regs[3]) -#define PT_REGS_PARM5(x) (((PT_REGS_ARM64 *)(x))->regs[4]) -#define PT_REGS_RET(x) (((PT_REGS_ARM64 *)(x))->regs[30]) -/* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_FP(x) (((PT_REGS_ARM64 *)(x))->regs[29]) -#define PT_REGS_RC(x) (((PT_REGS_ARM64 *)(x))->regs[0]) -#define PT_REGS_SP(x) (((PT_REGS_ARM64 *)(x))->sp) -#define PT_REGS_IP(x) (((PT_REGS_ARM64 *)(x))->pc) - -#elif defined(bpf_target_mips) - -#define PT_REGS_PARM1(x) ((x)->regs[4]) -#define PT_REGS_PARM2(x) ((x)->regs[5]) -#define PT_REGS_PARM3(x) ((x)->regs[6]) -#define PT_REGS_PARM4(x) ((x)->regs[7]) -#define PT_REGS_PARM5(x) ((x)->regs[8]) -#define PT_REGS_RET(x) ((x)->regs[31]) -#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */ -#define PT_REGS_RC(x) ((x)->regs[1]) -#define PT_REGS_SP(x) ((x)->regs[29]) -#define PT_REGS_IP(x) ((x)->cp0_epc) - -#elif defined(bpf_target_powerpc) - -#define PT_REGS_PARM1(x) ((x)->gpr[3]) -#define PT_REGS_PARM2(x) ((x)->gpr[4]) -#define PT_REGS_PARM3(x) ((x)->gpr[5]) -#define PT_REGS_PARM4(x) ((x)->gpr[6]) -#define PT_REGS_PARM5(x) ((x)->gpr[7]) -#define PT_REGS_RC(x) ((x)->gpr[3]) -#define PT_REGS_SP(x) ((x)->sp) -#define PT_REGS_IP(x) ((x)->nip) - -#elif defined(bpf_target_sparc) - -#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0]) -#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1]) -#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2]) -#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3]) -#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4]) -#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7]) -#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0]) -#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP]) - -/* Should this also be a bpf_target check for the sparc case? */ -#if defined(__arch64__) -#define PT_REGS_IP(x) ((x)->tpc) -#else -#define PT_REGS_IP(x) ((x)->pc) -#endif - -#endif - -#if defined(bpf_target_powerpc) -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = (ctx)->link; }) -#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP -#elif defined(bpf_target_sparc) -#define BPF_KPROBE_READ_RET_IP(ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) -#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP -#else -#define BPF_KPROBE_READ_RET_IP(ip, ctx) \ - ({ bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) -#define BPF_KRETPROBE_READ_RET_IP(ip, ctx) \ - ({ bpf_probe_read(&(ip), sizeof(ip), \ - (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) -#endif - -#endif -- cgit v1.2.3 From 7db3822ab99157e16c41caa5e7d788834d5a3c7c Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 10:59:41 -0700 Subject: libbpf: Add BPF_CORE_READ/BPF_CORE_READ_INTO helpers Add few macros simplifying BCC-like multi-level probe reads, while also emitting CO-RE relocations for each read. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191008175942.1769476-7-andriin@fb.com --- tools/lib/bpf/Makefile | 3 +- tools/lib/bpf/bpf_core_read.h | 167 +++++++++++++++++++++ tools/lib/bpf/bpf_helpers.h | 32 ++-- .../selftests/bpf/progs/test_core_reloc_arrays.c | 1 + .../selftests/bpf/progs/test_core_reloc_flavors.c | 1 + .../selftests/bpf/progs/test_core_reloc_ints.c | 1 + .../selftests/bpf/progs/test_core_reloc_kernel.c | 1 + .../selftests/bpf/progs/test_core_reloc_misc.c | 1 + .../selftests/bpf/progs/test_core_reloc_mods.c | 1 + .../selftests/bpf/progs/test_core_reloc_nesting.c | 1 + .../bpf/progs/test_core_reloc_primitives.c | 1 + .../bpf/progs/test_core_reloc_ptr_as_arr.c | 1 + 12 files changed, 187 insertions(+), 24 deletions(-) create mode 100644 tools/lib/bpf/bpf_core_read.h diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 974453564f01..1270955e4845 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -250,7 +250,8 @@ install_headers: bpf_helper_defs.h $(call do_install,bpf_helpers.h,$(prefix)/include/bpf,644); \ $(call do_install,bpf_helper_defs.h,$(prefix)/include/bpf,644); \ $(call do_install,bpf_tracing.h,$(prefix)/include/bpf,644); \ - $(call do_install,bpf_endian.h,$(prefix)/include/bpf,644); + $(call do_install,bpf_endian.h,$(prefix)/include/bpf,644); \ + $(call do_install,bpf_core_read.h,$(prefix)/include/bpf,644); install_pkgconfig: $(PC_FILE) $(call QUIET_INSTALL, $(PC_FILE)) \ diff --git a/tools/lib/bpf/bpf_core_read.h b/tools/lib/bpf/bpf_core_read.h new file mode 100644 index 000000000000..ae877e3ffb51 --- /dev/null +++ b/tools/lib/bpf/bpf_core_read.h @@ -0,0 +1,167 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __BPF_CORE_READ_H__ +#define __BPF_CORE_READ_H__ + +/* + * bpf_core_read() abstracts away bpf_probe_read() call and captures offset + * relocation for source address using __builtin_preserve_access_index() + * built-in, provided by Clang. + * + * __builtin_preserve_access_index() takes as an argument an expression of + * taking an address of a field within struct/union. It makes compiler emit + * a relocation, which records BTF type ID describing root struct/union and an + * accessor string which describes exact embedded field that was used to take + * an address. See detailed description of this relocation format and + * semantics in comments to struct bpf_offset_reloc in libbpf_internal.h. + * + * This relocation allows libbpf to adjust BPF instruction to use correct + * actual field offset, based on target kernel BTF type that matches original + * (local) BTF, used to record relocation. + */ +#define bpf_core_read(dst, sz, src) \ + bpf_probe_read(dst, sz, \ + (const void *)__builtin_preserve_access_index(src)) + +/* + * bpf_core_read_str() is a thin wrapper around bpf_probe_read_str() + * additionally emitting BPF CO-RE field relocation for specified source + * argument. + */ +#define bpf_core_read_str(dst, sz, src) \ + bpf_probe_read_str(dst, sz, \ + (const void *)__builtin_preserve_access_index(src)) + +#define ___concat(a, b) a ## b +#define ___apply(fn, n) ___concat(fn, n) +#define ___nth(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, __11, N, ...) N + +/* + * return number of provided arguments; used for switch-based variadic macro + * definitions (see ___last, ___arrow, etc below) + */ +#define ___narg(...) ___nth(_, ##__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) +/* + * return 0 if no arguments are passed, N - otherwise; used for + * recursively-defined macros to specify termination (0) case, and generic + * (N) case (e.g., ___read_ptrs, ___core_read) + */ +#define ___empty(...) ___nth(_, ##__VA_ARGS__, N, N, N, N, N, N, N, N, N, N, 0) + +#define ___last1(x) x +#define ___last2(a, x) x +#define ___last3(a, b, x) x +#define ___last4(a, b, c, x) x +#define ___last5(a, b, c, d, x) x +#define ___last6(a, b, c, d, e, x) x +#define ___last7(a, b, c, d, e, f, x) x +#define ___last8(a, b, c, d, e, f, g, x) x +#define ___last9(a, b, c, d, e, f, g, h, x) x +#define ___last10(a, b, c, d, e, f, g, h, i, x) x +#define ___last(...) ___apply(___last, ___narg(__VA_ARGS__))(__VA_ARGS__) + +#define ___nolast2(a, _) a +#define ___nolast3(a, b, _) a, b +#define ___nolast4(a, b, c, _) a, b, c +#define ___nolast5(a, b, c, d, _) a, b, c, d +#define ___nolast6(a, b, c, d, e, _) a, b, c, d, e +#define ___nolast7(a, b, c, d, e, f, _) a, b, c, d, e, f +#define ___nolast8(a, b, c, d, e, f, g, _) a, b, c, d, e, f, g +#define ___nolast9(a, b, c, d, e, f, g, h, _) a, b, c, d, e, f, g, h +#define ___nolast10(a, b, c, d, e, f, g, h, i, _) a, b, c, d, e, f, g, h, i +#define ___nolast(...) ___apply(___nolast, ___narg(__VA_ARGS__))(__VA_ARGS__) + +#define ___arrow1(a) a +#define ___arrow2(a, b) a->b +#define ___arrow3(a, b, c) a->b->c +#define ___arrow4(a, b, c, d) a->b->c->d +#define ___arrow5(a, b, c, d, e) a->b->c->d->e +#define ___arrow6(a, b, c, d, e, f) a->b->c->d->e->f +#define ___arrow7(a, b, c, d, e, f, g) a->b->c->d->e->f->g +#define ___arrow8(a, b, c, d, e, f, g, h) a->b->c->d->e->f->g->h +#define ___arrow9(a, b, c, d, e, f, g, h, i) a->b->c->d->e->f->g->h->i +#define ___arrow10(a, b, c, d, e, f, g, h, i, j) a->b->c->d->e->f->g->h->i->j +#define ___arrow(...) ___apply(___arrow, ___narg(__VA_ARGS__))(__VA_ARGS__) + +#define ___type(...) typeof(___arrow(__VA_ARGS__)) + +#define ___read(read_fn, dst, src_type, src, accessor) \ + read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor) + +/* "recursively" read a sequence of inner pointers using local __t var */ +#define ___rd_last(...) \ + ___read(bpf_core_read, &__t, \ + ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__)); +#define ___rd_p0(src) const void *__t = src; +#define ___rd_p1(...) ___rd_p0(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p2(...) ___rd_p1(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p3(...) ___rd_p2(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p4(...) ___rd_p3(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p5(...) ___rd_p4(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p6(...) ___rd_p5(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p7(...) ___rd_p6(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p8(...) ___rd_p7(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p9(...) ___rd_p8(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___read_ptrs(src, ...) \ + ___apply(___rd_p, ___narg(__VA_ARGS__))(src, __VA_ARGS__) + +#define ___core_read0(fn, dst, src, a) \ + ___read(fn, dst, ___type(src), src, a); +#define ___core_readN(fn, dst, src, ...) \ + ___read_ptrs(src, ___nolast(__VA_ARGS__)) \ + ___read(fn, dst, ___type(src, ___nolast(__VA_ARGS__)), __t, \ + ___last(__VA_ARGS__)); +#define ___core_read(fn, dst, src, a, ...) \ + ___apply(___core_read, ___empty(__VA_ARGS__))(fn, dst, \ + src, a, ##__VA_ARGS__) + +/* + * BPF_CORE_READ_INTO() is a more performance-conscious variant of + * BPF_CORE_READ(), in which final field is read into user-provided storage. + * See BPF_CORE_READ() below for more details on general usage. + */ +#define BPF_CORE_READ_INTO(dst, src, a, ...) \ + ({ \ + ___core_read(bpf_core_read, dst, src, a, ##__VA_ARGS__) \ + }) + +/* + * BPF_CORE_READ_STR_INTO() does same "pointer chasing" as + * BPF_CORE_READ() for intermediate pointers, but then executes (and returns + * corresponding error code) bpf_core_read_str() for final string read. + */ +#define BPF_CORE_READ_STR_INTO(dst, src, a, ...) \ + ({ \ + ___core_read(bpf_core_read_str, dst, src, a, ##__VA_ARGS__) \ + }) + +/* + * BPF_CORE_READ() is used to simplify BPF CO-RE relocatable read, especially + * when there are few pointer chasing steps. + * E.g., what in non-BPF world (or in BPF w/ BCC) would be something like: + * int x = s->a.b.c->d.e->f->g; + * can be succinctly achieved using BPF_CORE_READ as: + * int x = BPF_CORE_READ(s, a.b.c, d.e, f, g); + * + * BPF_CORE_READ will decompose above statement into 4 bpf_core_read (BPF + * CO-RE relocatable bpf_probe_read() wrapper) calls, logically equivalent to: + * 1. const void *__t = s->a.b.c; + * 2. __t = __t->d.e; + * 3. __t = __t->f; + * 4. return __t->g; + * + * Equivalence is logical, because there is a heavy type casting/preservation + * involved, as well as all the reads are happening through bpf_probe_read() + * calls using __builtin_preserve_access_index() to emit CO-RE relocations. + * + * N.B. Only up to 9 "field accessors" are supported, which should be more + * than enough for any practical purpose. + */ +#define BPF_CORE_READ(src, a, ...) \ + ({ \ + ___type(src, a, ##__VA_ARGS__) __r; \ + BPF_CORE_READ_INTO(&__r, src, a, ##__VA_ARGS__); \ + __r; \ + }) + +#endif + diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index 6d059c0a7845..2203595f38c3 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -7,7 +7,7 @@ #define __uint(name, val) int (*name)[val] #define __type(name, val) typeof(val) *name -/* helper macro to print out debug messages */ +/* Helper macro to print out debug messages */ #define bpf_printk(fmt, ...) \ ({ \ char ____fmt[] = fmt; \ @@ -15,13 +15,19 @@ ##__VA_ARGS__); \ }) -/* helper macro to place programs, maps, license in +/* + * Helper macro to place programs, maps, license in * different sections in elf_bpf file. Section names * are interpreted by elf_bpf loader */ #define SEC(NAME) __attribute__((section(NAME), used)) -/* a helper structure used by eBPF C program +#ifndef __always_inline +#define __always_inline __attribute__((always_inline)) +#endif + +/* + * Helper structure used by eBPF C program * to describe BPF map attributes to libbpf loader */ struct bpf_map_def { @@ -32,24 +38,4 @@ struct bpf_map_def { unsigned int map_flags; }; -/* - * bpf_core_read() abstracts away bpf_probe_read() call and captures offset - * relocation for source address using __builtin_preserve_access_index() - * built-in, provided by Clang. - * - * __builtin_preserve_access_index() takes as an argument an expression of - * taking an address of a field within struct/union. It makes compiler emit - * a relocation, which records BTF type ID describing root struct/union and an - * accessor string which describes exact embedded field that was used to take - * an address. See detailed description of this relocation format and - * semantics in comments to struct bpf_offset_reloc in libbpf_internal.h. - * - * This relocation allows libbpf to adjust BPF instruction to use correct - * actual field offset, based on target kernel BTF type that matches original - * (local) BTF, used to record relocation. - */ -#define bpf_core_read(dst, sz, src) \ - bpf_probe_read(dst, sz, \ - (const void *)__builtin_preserve_access_index(src)) - #endif diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c b/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c index 8e3f6e6a90e7..96b1f5f3b07a 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c b/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c index 613474a18b45..71fd7cebc9d7 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_flavors.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c b/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c index 7a88a3975455..ad5c3f59c9c6 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_ints.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c index 684a06cf41ea..14ce688463de 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c b/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c index 10bdb2050552..1a36b0856653 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_misc.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c b/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c index e930e7e88c5c..3199fafede2c 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_mods.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c b/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c index b63007958290..98238cb64fbd 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_nesting.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c b/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c index 7654f59914bc..4f3ecb9127bb 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_primitives.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c b/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c index 709f7cba453f..27f602f00419 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_ptr_as_arr.c @@ -4,6 +4,7 @@ #include #include #include "bpf_helpers.h" +#include "bpf_core_read.h" char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From ee2eb063d330dc8dbe71041a1dae3cea889fdcb5 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 10:59:42 -0700 Subject: selftests/bpf: Add BPF_CORE_READ and BPF_CORE_READ_STR_INTO macro tests Validate BPF_CORE_READ correctness and handling of up to 9 levels of nestedness using cyclic task->(group_leader->)*->tgid chains. Also add a test of maximum-dpeth BPF_CORE_READ_STR_INTO() macro. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Acked-by: Song Liu Link: https://lore.kernel.org/bpf/20191008175942.1769476-8-andriin@fb.com --- .../testing/selftests/bpf/prog_tests/core_reloc.c | 8 +++- .../testing/selftests/bpf/progs/core_reloc_types.h | 9 ++++ .../selftests/bpf/progs/test_core_reloc_kernel.c | 54 +++++++++++++++++++++- 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/bpf/prog_tests/core_reloc.c b/tools/testing/selftests/bpf/prog_tests/core_reloc.c index f3863f976a48..21a0dff66241 100644 --- a/tools/testing/selftests/bpf/prog_tests/core_reloc.c +++ b/tools/testing/selftests/bpf/prog_tests/core_reloc.c @@ -193,8 +193,12 @@ static struct core_reloc_test_case test_cases[] = { .btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */ .input = "", .input_len = 0, - .output = "\1", /* true */ - .output_len = 1, + .output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) { + .valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }, + .comm = "test_progs\0\0\0\0\0", + .comm_len = 11, + }, + .output_len = sizeof(struct core_reloc_kernel_output), }, /* validate BPF program can use multiple flavors to match against diff --git a/tools/testing/selftests/bpf/progs/core_reloc_types.h b/tools/testing/selftests/bpf/progs/core_reloc_types.h index f686a8138d90..9a6bdeb4894c 100644 --- a/tools/testing/selftests/bpf/progs/core_reloc_types.h +++ b/tools/testing/selftests/bpf/progs/core_reloc_types.h @@ -1,5 +1,14 @@ #include #include +/* + * KERNEL + */ + +struct core_reloc_kernel_output { + int valid[10]; + char comm[16]; + int comm_len; +}; /* * FLAVORS diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c index 14ce688463de..50f609618b65 100644 --- a/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c +++ b/tools/testing/selftests/bpf/progs/test_core_reloc_kernel.c @@ -13,9 +13,17 @@ static volatile struct data { char out[256]; } data; +struct core_reloc_kernel_output { + int valid[10]; + char comm[16]; + int comm_len; +}; + struct task_struct { int pid; int tgid; + char comm[16]; + struct task_struct *group_leader; }; #define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src) @@ -24,7 +32,9 @@ SEC("raw_tracepoint/sys_enter") int test_core_kernel(void *ctx) { struct task_struct *task = (void *)bpf_get_current_task(); + struct core_reloc_kernel_output *out = (void *)&data.out; uint64_t pid_tgid = bpf_get_current_pid_tgid(); + uint32_t real_tgid = (uint32_t)pid_tgid; int pid, tgid; if (CORE_READ(&pid, &task->pid) || @@ -32,7 +42,49 @@ int test_core_kernel(void *ctx) return 1; /* validate pid + tgid matches */ - data.out[0] = (((uint64_t)pid << 32) | tgid) == pid_tgid; + out->valid[0] = (((uint64_t)pid << 32) | tgid) == pid_tgid; + + /* test variadic BPF_CORE_READ macros */ + out->valid[1] = BPF_CORE_READ(task, + tgid) == real_tgid; + out->valid[2] = BPF_CORE_READ(task, + group_leader, + tgid) == real_tgid; + out->valid[3] = BPF_CORE_READ(task, + group_leader, group_leader, + tgid) == real_tgid; + out->valid[4] = BPF_CORE_READ(task, + group_leader, group_leader, group_leader, + tgid) == real_tgid; + out->valid[5] = BPF_CORE_READ(task, + group_leader, group_leader, group_leader, + group_leader, + tgid) == real_tgid; + out->valid[6] = BPF_CORE_READ(task, + group_leader, group_leader, group_leader, + group_leader, group_leader, + tgid) == real_tgid; + out->valid[7] = BPF_CORE_READ(task, + group_leader, group_leader, group_leader, + group_leader, group_leader, group_leader, + tgid) == real_tgid; + out->valid[8] = BPF_CORE_READ(task, + group_leader, group_leader, group_leader, + group_leader, group_leader, group_leader, + group_leader, + tgid) == real_tgid; + out->valid[9] = BPF_CORE_READ(task, + group_leader, group_leader, group_leader, + group_leader, group_leader, group_leader, + group_leader, group_leader, + tgid) == real_tgid; + + /* test BPF_CORE_READ_STR_INTO() returns correct code and contents */ + out->comm_len = BPF_CORE_READ_STR_INTO( + &out->comm, task, + group_leader, group_leader, group_leader, group_leader, + group_leader, group_leader, group_leader, group_leader, + comm); return 0; } -- cgit v1.2.3 From b4099769f3321a8d258a47a8b4b9d278dad28a73 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 16:10:06 -0700 Subject: libbpf: Fix struct end padding in btf_dump Fix a case where explicit padding at the end of a struct is necessary due to non-standart alignment requirements of fields (which BTF doesn't capture explicitly). Fixes: 351131b51c7a ("libbpf: add btf_dump API for BTF-to-C conversion") Reported-by: John Fastabend Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Tested-by: John Fastabend Link: https://lore.kernel.org/bpf/20191008231009.2991130-2-andriin@fb.com --- tools/lib/bpf/btf_dump.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index ede55fec3618..87f27e2664c5 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -876,7 +876,6 @@ static void btf_dump_emit_struct_def(struct btf_dump *d, __u16 vlen = btf_vlen(t); packed = is_struct ? btf_is_struct_packed(d->btf, id, t) : 0; - align = packed ? 1 : btf_align_of(d->btf, id); btf_dump_printf(d, "%s%s%s {", is_struct ? "struct" : "union", @@ -906,6 +905,13 @@ static void btf_dump_emit_struct_def(struct btf_dump *d, btf_dump_printf(d, ";"); } + /* pad at the end, if necessary */ + if (is_struct) { + align = packed ? 1 : btf_align_of(d->btf, id); + btf_dump_emit_bit_padding(d, off, t->size * 8, 0, align, + lvl + 1); + } + if (vlen) btf_dump_printf(d, "\n"); btf_dump_printf(d, "%s}", pfx(lvl)); -- cgit v1.2.3 From 6e05abc9abd5dc4dc9e6b98e01564f4a2659f0fe Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 16:10:07 -0700 Subject: selftests/bpf: Convert test_btf_dump into test_progs test Convert test_btf_dump into a part of test_progs, instead of a stand-alone test binary. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191008231009.2991130-3-andriin@fb.com --- tools/testing/selftests/bpf/Makefile | 2 +- tools/testing/selftests/bpf/prog_tests/btf_dump.c | 130 +++++++++++++++++++ tools/testing/selftests/bpf/test_btf_dump.c | 150 ---------------------- 3 files changed, 131 insertions(+), 151 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_dump.c delete mode 100644 tools/testing/selftests/bpf/test_btf_dump.c diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 90944b7a8274..40552fb441e5 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -29,7 +29,7 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test test_sock test_btf test_sockmap get_cgroup_id_user test_socket_cookie \ test_cgroup_storage test_select_reuseport test_section_names \ test_netcnt test_tcpnotify_user test_sock_fields test_sysctl test_hashmap \ - test_btf_dump test_cgroup_attach xdping + test_cgroup_attach xdping BPF_OBJ_FILES = $(patsubst %.c,%.o, $(notdir $(wildcard progs/*.c))) TEST_GEN_FILES = $(BPF_OBJ_FILES) diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dump.c b/tools/testing/selftests/bpf/prog_tests/btf_dump.c new file mode 100644 index 000000000000..7390d3061065 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/btf_dump.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +static int duration = 0; + +void btf_dump_printf(void *ctx, const char *fmt, va_list args) +{ + vfprintf(ctx, fmt, args); +} + +static struct btf_dump_test_case { + const char *name; + const char *file; + struct btf_dump_opts opts; +} btf_dump_test_cases[] = { + {"btf_dump: syntax", "btf_dump_test_case_syntax", {}}, + {"btf_dump: ordering", "btf_dump_test_case_ordering", {}}, + {"btf_dump: padding", "btf_dump_test_case_padding", {}}, + {"btf_dump: packing", "btf_dump_test_case_packing", {}}, + {"btf_dump: bitfields", "btf_dump_test_case_bitfields", {}}, + {"btf_dump: multidim", "btf_dump_test_case_multidim", {}}, + {"btf_dump: namespacing", "btf_dump_test_case_namespacing", {}}, +}; + +static int btf_dump_all_types(const struct btf *btf, + const struct btf_dump_opts *opts) +{ + size_t type_cnt = btf__get_nr_types(btf); + struct btf_dump *d; + int err = 0, id; + + d = btf_dump__new(btf, NULL, opts, btf_dump_printf); + if (IS_ERR(d)) + return PTR_ERR(d); + + for (id = 1; id <= type_cnt; id++) { + err = btf_dump__dump_type(d, id); + if (err) + goto done; + } + +done: + btf_dump__free(d); + return err; +} + +static int test_btf_dump_case(int n, struct btf_dump_test_case *t) +{ + char test_file[256], out_file[256], diff_cmd[1024]; + struct btf *btf = NULL; + int err = 0, fd = -1; + FILE *f = NULL; + + snprintf(test_file, sizeof(test_file), "%s.o", t->file); + + btf = btf__parse_elf(test_file, NULL); + if (CHECK(IS_ERR(btf), "btf_parse_elf", + "failed to load test BTF: %ld\n", PTR_ERR(btf))) { + err = -PTR_ERR(btf); + btf = NULL; + goto done; + } + + snprintf(out_file, sizeof(out_file), "/tmp/%s.output.XXXXXX", t->file); + fd = mkstemp(out_file); + if (CHECK(fd < 0, "create_tmp", "failed to create file: %d\n", fd)) { + err = fd; + goto done; + } + f = fdopen(fd, "w"); + if (CHECK(f == NULL, "open_tmp", "failed to open file: %s(%d)\n", + strerror(errno), errno)) { + close(fd); + goto done; + } + + t->opts.ctx = f; + err = btf_dump_all_types(btf, &t->opts); + fclose(f); + close(fd); + if (CHECK(err, "btf_dump", "failure during C dumping: %d\n", err)) { + goto done; + } + + snprintf(test_file, sizeof(test_file), "progs/%s.c", t->file); + if (access(test_file, R_OK) == -1) + /* + * When the test is run with O=, kselftest copies TEST_FILES + * without preserving the directory structure. + */ + snprintf(test_file, sizeof(test_file), "%s.c", t->file); + /* + * Diff test output and expected test output, contained between + * START-EXPECTED-OUTPUT and END-EXPECTED-OUTPUT lines in test case. + * For expected output lines, everything before '*' is stripped out. + * Also lines containing comment start and comment end markers are + * ignored. + */ + snprintf(diff_cmd, sizeof(diff_cmd), + "awk '/START-EXPECTED-OUTPUT/{out=1;next} " + "/END-EXPECTED-OUTPUT/{out=0} " + "/\\/\\*|\\*\\//{next} " /* ignore comment start/end lines */ + "out {sub(/^[ \\t]*\\*/, \"\"); print}' '%s' | diff -u - '%s'", + test_file, out_file); + err = system(diff_cmd); + if (CHECK(err, "diff", + "differing test output, output=%s, err=%d, diff cmd:\n%s\n", + out_file, err, diff_cmd)) + goto done; + + remove(out_file); + +done: + btf__free(btf); + return err; +} + +void test_btf_dump() { + int i; + + for (i = 0; i < ARRAY_SIZE(btf_dump_test_cases); i++) { + struct btf_dump_test_case *t = &btf_dump_test_cases[i]; + + if (!test__start_subtest(t->name)) + continue; + + test_btf_dump_case(i, &btf_dump_test_cases[i]); + } +} diff --git a/tools/testing/selftests/bpf/test_btf_dump.c b/tools/testing/selftests/bpf/test_btf_dump.c deleted file mode 100644 index 6e75dd3cb14f..000000000000 --- a/tools/testing/selftests/bpf/test_btf_dump.c +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define CHECK(condition, format...) ({ \ - int __ret = !!(condition); \ - if (__ret) { \ - fprintf(stderr, "%s:%d:FAIL ", __func__, __LINE__); \ - fprintf(stderr, format); \ - } \ - __ret; \ -}) - -void btf_dump_printf(void *ctx, const char *fmt, va_list args) -{ - vfprintf(ctx, fmt, args); -} - -struct btf_dump_test_case { - const char *name; - struct btf_dump_opts opts; -} btf_dump_test_cases[] = { - {.name = "btf_dump_test_case_syntax", .opts = {}}, - {.name = "btf_dump_test_case_ordering", .opts = {}}, - {.name = "btf_dump_test_case_padding", .opts = {}}, - {.name = "btf_dump_test_case_packing", .opts = {}}, - {.name = "btf_dump_test_case_bitfields", .opts = {}}, - {.name = "btf_dump_test_case_multidim", .opts = {}}, - {.name = "btf_dump_test_case_namespacing", .opts = {}}, -}; - -static int btf_dump_all_types(const struct btf *btf, - const struct btf_dump_opts *opts) -{ - size_t type_cnt = btf__get_nr_types(btf); - struct btf_dump *d; - int err = 0, id; - - d = btf_dump__new(btf, NULL, opts, btf_dump_printf); - if (IS_ERR(d)) - return PTR_ERR(d); - - for (id = 1; id <= type_cnt; id++) { - err = btf_dump__dump_type(d, id); - if (err) - goto done; - } - -done: - btf_dump__free(d); - return err; -} - -int test_btf_dump_case(int n, struct btf_dump_test_case *test_case) -{ - char test_file[256], out_file[256], diff_cmd[1024]; - struct btf *btf = NULL; - int err = 0, fd = -1; - FILE *f = NULL; - - fprintf(stderr, "Test case #%d (%s): ", n, test_case->name); - - snprintf(test_file, sizeof(test_file), "%s.o", test_case->name); - - btf = btf__parse_elf(test_file, NULL); - if (CHECK(IS_ERR(btf), - "failed to load test BTF: %ld\n", PTR_ERR(btf))) { - err = -PTR_ERR(btf); - btf = NULL; - goto done; - } - - snprintf(out_file, sizeof(out_file), - "/tmp/%s.output.XXXXXX", test_case->name); - fd = mkstemp(out_file); - if (CHECK(fd < 0, "failed to create temp output file: %d\n", fd)) { - err = fd; - goto done; - } - f = fdopen(fd, "w"); - if (CHECK(f == NULL, "failed to open temp output file: %s(%d)\n", - strerror(errno), errno)) { - close(fd); - goto done; - } - - test_case->opts.ctx = f; - err = btf_dump_all_types(btf, &test_case->opts); - fclose(f); - close(fd); - if (CHECK(err, "failure during C dumping: %d\n", err)) { - goto done; - } - - snprintf(test_file, sizeof(test_file), "progs/%s.c", test_case->name); - if (access(test_file, R_OK) == -1) - /* - * When the test is run with O=, kselftest copies TEST_FILES - * without preserving the directory structure. - */ - snprintf(test_file, sizeof(test_file), "%s.c", - test_case->name); - /* - * Diff test output and expected test output, contained between - * START-EXPECTED-OUTPUT and END-EXPECTED-OUTPUT lines in test case. - * For expected output lines, everything before '*' is stripped out. - * Also lines containing comment start and comment end markers are - * ignored. - */ - snprintf(diff_cmd, sizeof(diff_cmd), - "awk '/START-EXPECTED-OUTPUT/{out=1;next} " - "/END-EXPECTED-OUTPUT/{out=0} " - "/\\/\\*|\\*\\//{next} " /* ignore comment start/end lines */ - "out {sub(/^[ \\t]*\\*/, \"\"); print}' '%s' | diff -u - '%s'", - test_file, out_file); - err = system(diff_cmd); - if (CHECK(err, - "differing test output, output=%s, err=%d, diff cmd:\n%s\n", - out_file, err, diff_cmd)) - goto done; - - remove(out_file); - fprintf(stderr, "OK\n"); - -done: - btf__free(btf); - return err; -} - -int main() { - int test_case_cnt, i, err, failed = 0; - - test_case_cnt = sizeof(btf_dump_test_cases) / - sizeof(btf_dump_test_cases[0]); - - for (i = 0; i < test_case_cnt; i++) { - err = test_btf_dump_case(i, &btf_dump_test_cases[i]); - if (err) - failed++; - } - - fprintf(stderr, "%d tests succeeded, %d tests failed.\n", - test_case_cnt - failed, failed); - - return failed; -} -- cgit v1.2.3 From 76790c7c66ccc8695afc75e73f54c0ca86267ed2 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Tue, 8 Oct 2019 16:10:08 -0700 Subject: selftests/bpf: Fix btf_dump padding test case Existing padding test case for btf_dump has a good test that was supposed to test padding generation at the end of a struct, but its expected output was specified incorrectly. Fix this. Fixes: 2d2a3ad872f8 ("selftests/bpf: add btf_dump BTF-to-C conversion tests") Reported-by: John Fastabend Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191008231009.2991130-4-andriin@fb.com --- tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c index 3a62119c7498..35c512818a56 100644 --- a/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c +++ b/tools/testing/selftests/bpf/progs/btf_dump_test_case_padding.c @@ -62,6 +62,10 @@ struct padded_a_lot { * long: 64; * long: 64; * int b; + * long: 32; + * long: 64; + * long: 64; + * long: 64; *}; * */ @@ -95,7 +99,6 @@ struct zone_padding { struct zone { int a; short b; - short: 16; struct zone_padding __pad__; }; -- cgit v1.2.3 From 25bfef430e960e695403b5d9c8dcc11b9f5d62be Mon Sep 17 00:00:00 2001 From: Ilya Maximets Date: Wed, 9 Oct 2019 18:49:29 +0200 Subject: libbpf: Fix passing uninitialized bytes to setsockopt 'struct xdp_umem_reg' has 4 bytes of padding at the end that makes valgrind complain about passing uninitialized stack memory to the syscall: Syscall param socketcall.setsockopt() points to uninitialised byte(s) at 0x4E7AB7E: setsockopt (in /usr/lib64/libc-2.29.so) by 0x4BDE035: xsk_umem__create@@LIBBPF_0.0.4 (xsk.c:172) Uninitialised value was created by a stack allocation at 0x4BDDEBA: xsk_umem__create@@LIBBPF_0.0.4 (xsk.c:140) Padding bytes appeared after introducing of a new 'flags' field. memset() is required to clear them. Fixes: 10d30e301732 ("libbpf: add flags to umem config") Signed-off-by: Ilya Maximets Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191009164929.17242-1-i.maximets@ovn.org --- tools/lib/bpf/xsk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/lib/bpf/xsk.c b/tools/lib/bpf/xsk.c index 24fa313524fb..b0f532544c91 100644 --- a/tools/lib/bpf/xsk.c +++ b/tools/lib/bpf/xsk.c @@ -163,6 +163,7 @@ int xsk_umem__create_v0_0_4(struct xsk_umem **umem_ptr, void *umem_area, umem->umem_area = umem_area; xsk_set_umem_config(&umem->config, usr_config); + memset(&mr, 0, sizeof(mr)); mr.addr = (uintptr_t)umem_area; mr.len = size; mr.chunk_size = umem->config.frame_size; -- cgit v1.2.3 From e0b68fb186b251374adbd870f99b1ecea236e770 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 9 Oct 2019 21:25:34 -0700 Subject: scripts/bpf: Fix xdp_md forward declaration typo Fix typo in struct xpd_md, generated from bpf_helpers_doc.py, which is causing compilation warnings for programs using bpf_helpers.h Fixes: 7a387bed47f7 ("scripts/bpf: teach bpf_helpers_doc.py to dump BPF helper definitions") Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191010042534.290562-1-andriin@fb.com --- scripts/bpf_helpers_doc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bpf_helpers_doc.py b/scripts/bpf_helpers_doc.py index 15d3d83d6297..7df9ce598ff9 100755 --- a/scripts/bpf_helpers_doc.py +++ b/scripts/bpf_helpers_doc.py @@ -418,7 +418,7 @@ class PrinterHelpers(Printer): 'struct __sk_buff', 'struct sk_msg_md', - 'struct xpd_md', + 'struct xdp_md', ] known_types = { '...', -- cgit v1.2.3 From a23740ec43ba022dbfd139d0fe3eff193216272b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 9 Oct 2019 13:14:57 -0700 Subject: bpf: Track contents of read-only maps as scalars Maps that are read-only both from BPF program side and user space side have their contents constant, so verifier can track referenced values precisely and use that knowledge for dead code elimination, branch pruning, etc. This patch teaches BPF verifier how to do this. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20191009201458.2679171-2-andriin@fb.com --- kernel/bpf/verifier.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ffc3e53f5300..b818fed3208d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2739,6 +2739,41 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) reg->smax_value = reg->umax_value; } +static bool bpf_map_is_rdonly(const struct bpf_map *map) +{ + return (map->map_flags & BPF_F_RDONLY_PROG) && map->frozen; +} + +static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val) +{ + void *ptr; + u64 addr; + int err; + + err = map->ops->map_direct_value_addr(map, &addr, off); + if (err) + return err; + ptr = (void *)addr + off; + + switch (size) { + case sizeof(u8): + *val = (u64)*(u8 *)ptr; + break; + case sizeof(u16): + *val = (u64)*(u16 *)ptr; + break; + case sizeof(u32): + *val = (u64)*(u32 *)ptr; + break; + case sizeof(u64): + *val = *(u64 *)ptr; + break; + default: + return -EINVAL; + } + return 0; +} + /* check whether memory at (regno + off) is accessible for t = (read | write) * if t==write, value_regno is a register which value is stored into memory * if t==read, value_regno is a register which will receive the value from memory @@ -2776,9 +2811,27 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn if (err) return err; err = check_map_access(env, regno, off, size, false); - if (!err && t == BPF_READ && value_regno >= 0) - mark_reg_unknown(env, regs, value_regno); + if (!err && t == BPF_READ && value_regno >= 0) { + struct bpf_map *map = reg->map_ptr; + + /* if map is read-only, track its contents as scalars */ + if (tnum_is_const(reg->var_off) && + bpf_map_is_rdonly(map) && + map->ops->map_direct_value_addr) { + int map_off = off + reg->var_off.value; + u64 val = 0; + err = bpf_map_direct_read(map, map_off, size, + &val); + if (err) + return err; + + regs[value_regno].type = SCALAR_VALUE; + __mark_reg_known(®s[value_regno], val); + } else { + mark_reg_unknown(env, regs, value_regno); + } + } } else if (reg->type == PTR_TO_CTX) { enum bpf_reg_type reg_type = SCALAR_VALUE; -- cgit v1.2.3 From 666b2c10ee9d51f14d04c416a14b1cb6fd0846e4 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Wed, 9 Oct 2019 13:14:58 -0700 Subject: selftests/bpf: Add read-only map values propagation tests Add tests checking that verifier does proper constant propagation for read-only maps. If constant propagation didn't work, skipp_loop and part_loop BPF programs would be rejected due to BPF verifier otherwise not being able to prove they ever complete. With constant propagation, though, they are succesfully validated as properly terminating loops. Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20191009201458.2679171-3-andriin@fb.com --- .../testing/selftests/bpf/prog_tests/rdonly_maps.c | 99 ++++++++++++++++++++++ .../testing/selftests/bpf/progs/test_rdonly_maps.c | 83 ++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/rdonly_maps.c create mode 100644 tools/testing/selftests/bpf/progs/test_rdonly_maps.c diff --git a/tools/testing/selftests/bpf/prog_tests/rdonly_maps.c b/tools/testing/selftests/bpf/prog_tests/rdonly_maps.c new file mode 100644 index 000000000000..9bf9de0aaeea --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/rdonly_maps.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +struct bss { + unsigned did_run; + unsigned iters; + unsigned sum; +}; + +struct rdonly_map_subtest { + const char *subtest_name; + const char *prog_name; + unsigned exp_iters; + unsigned exp_sum; +}; + +void test_rdonly_maps(void) +{ + const char *prog_name_skip_loop = "raw_tracepoint/sys_enter:skip_loop"; + const char *prog_name_part_loop = "raw_tracepoint/sys_enter:part_loop"; + const char *prog_name_full_loop = "raw_tracepoint/sys_enter:full_loop"; + const char *file = "test_rdonly_maps.o"; + struct rdonly_map_subtest subtests[] = { + { "skip loop", prog_name_skip_loop, 0, 0 }, + { "part loop", prog_name_part_loop, 3, 2 + 3 + 4 }, + { "full loop", prog_name_full_loop, 4, 2 + 3 + 4 + 5 }, + }; + int i, err, zero = 0, duration = 0; + struct bpf_link *link = NULL; + struct bpf_program *prog; + struct bpf_map *bss_map; + struct bpf_object *obj; + struct bss bss; + + obj = bpf_object__open_file(file, NULL); + if (CHECK(IS_ERR(obj), "obj_open", "err %ld\n", PTR_ERR(obj))) + return; + + bpf_object__for_each_program(prog, obj) { + bpf_program__set_raw_tracepoint(prog); + } + + err = bpf_object__load(obj); + if (CHECK(err, "obj_load", "err %d errno %d\n", err, errno)) + goto cleanup; + + bss_map = bpf_object__find_map_by_name(obj, "test_rdo.bss"); + if (CHECK(!bss_map, "find_bss_map", "failed\n")) + goto cleanup; + + for (i = 0; i < ARRAY_SIZE(subtests); i++) { + const struct rdonly_map_subtest *t = &subtests[i]; + + if (!test__start_subtest(t->subtest_name)) + continue; + + prog = bpf_object__find_program_by_title(obj, t->prog_name); + if (CHECK(!prog, "find_prog", "prog '%s' not found\n", + t->prog_name)) + goto cleanup; + + memset(&bss, 0, sizeof(bss)); + err = bpf_map_update_elem(bpf_map__fd(bss_map), &zero, &bss, 0); + if (CHECK(err, "set_bss", "failed to set bss data: %d\n", err)) + goto cleanup; + + link = bpf_program__attach_raw_tracepoint(prog, "sys_enter"); + if (CHECK(IS_ERR(link), "attach_prog", "prog '%s', err %ld\n", + t->prog_name, PTR_ERR(link))) { + link = NULL; + goto cleanup; + } + + /* trigger probe */ + usleep(1); + + bpf_link__destroy(link); + link = NULL; + + err = bpf_map_lookup_elem(bpf_map__fd(bss_map), &zero, &bss); + if (CHECK(err, "get_bss", "failed to get bss data: %d\n", err)) + goto cleanup; + if (CHECK(bss.did_run == 0, "check_run", + "prog '%s' didn't run?\n", t->prog_name)) + goto cleanup; + if (CHECK(bss.iters != t->exp_iters, "check_iters", + "prog '%s' iters: %d, expected: %d\n", + t->prog_name, bss.iters, t->exp_iters)) + goto cleanup; + if (CHECK(bss.sum != t->exp_sum, "check_sum", + "prog '%s' sum: %d, expected: %d\n", + t->prog_name, bss.sum, t->exp_sum)) + goto cleanup; + } + +cleanup: + bpf_link__destroy(link); + bpf_object__close(obj); +} diff --git a/tools/testing/selftests/bpf/progs/test_rdonly_maps.c b/tools/testing/selftests/bpf/progs/test_rdonly_maps.c new file mode 100644 index 000000000000..52d94e8b214d --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_rdonly_maps.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Facebook + +#include +#include +#include "bpf_helpers.h" + +static volatile const struct { + unsigned a[4]; + /* + * if the struct's size is multiple of 16, compiler will put it into + * .rodata.cst16 section, which is not recognized by libbpf; work + * around this by ensuring we don't have 16-aligned struct + */ + char _y; +} rdonly_values = { .a = {2, 3, 4, 5} }; + +static volatile struct { + unsigned did_run; + unsigned iters; + unsigned sum; +} res; + +SEC("raw_tracepoint/sys_enter:skip_loop") +int skip_loop(struct pt_regs *ctx) +{ + /* prevent compiler to optimize everything out */ + unsigned * volatile p = (void *)&rdonly_values.a; + unsigned iters = 0, sum = 0; + + /* we should never enter this loop */ + while (*p & 1) { + iters++; + sum += *p; + p++; + } + res.did_run = 1; + res.iters = iters; + res.sum = sum; + return 0; +} + +SEC("raw_tracepoint/sys_enter:part_loop") +int part_loop(struct pt_regs *ctx) +{ + /* prevent compiler to optimize everything out */ + unsigned * volatile p = (void *)&rdonly_values.a; + unsigned iters = 0, sum = 0; + + /* validate verifier can derive loop termination */ + while (*p < 5) { + iters++; + sum += *p; + p++; + } + res.did_run = 1; + res.iters = iters; + res.sum = sum; + return 0; +} + +SEC("raw_tracepoint/sys_enter:full_loop") +int full_loop(struct pt_regs *ctx) +{ + /* prevent compiler to optimize everything out */ + unsigned * volatile p = (void *)&rdonly_values.a; + int i = sizeof(rdonly_values.a) / sizeof(rdonly_values.a[0]); + unsigned iters = 0, sum = 0; + + /* validate verifier can allow full loop as well */ + while (i > 0 ) { + iters++; + sum += *p; + p++; + i--; + } + res.did_run = 1; + res.iters = iters; + res.sum = sum; + return 0; +} + +char _license[] SEC("license") = "GPL"; -- cgit v1.2.3 From 84a081f60db63aaae3665118203506aa09a7f94f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 11 Oct 2019 11:11:40 -0700 Subject: bpf: Align struct bpf_prog_stats Do not risk spanning these small structures on two cache lines. Signed-off-by: Eric Dumazet Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20191011181140.2898-1-edumazet@google.com --- include/linux/bpf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 5b9d22338606..282e28bf41ec 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -363,7 +363,7 @@ struct bpf_prog_stats { u64 cnt; u64 nsecs; struct u64_stats_sync syncp; -}; +} __aligned(2 * sizeof(u64)); struct bpf_prog_aux { atomic_t refcnt; -- cgit v1.2.3 From 719b78a5674f15fef2e4a56484614657fd759978 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 11 Oct 2019 10:29:45 +0200 Subject: flow_dissector: Allow updating the flow dissector program atomically It is currently not possible to detach the flow dissector program and attach a new one in an atomic fashion, that is with a single syscall. Attempts to do so will be met with EEXIST error. This makes updates to flow dissector program hard. Traffic steering that relies on BPF-powered flow dissection gets disrupted while old program has been already detached but the new one has not been attached yet. There is also a window of opportunity to attach a flow dissector to a non-root namespace while updating the root flow dissector, thus blocking the update. Lastly, the behavior is inconsistent with cgroup BPF programs, which can be replaced with a single bpf(BPF_PROG_ATTACH, ...) syscall without any restrictions. Allow attaching a new flow dissector program when another one is already present with a restriction that it can't be the same program. Signed-off-by: Jakub Sitnicki Signed-off-by: Daniel Borkmann Reviewed-by: Stanislav Fomichev Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/20191011082946.22695-2-jakub@cloudflare.com --- net/core/flow_dissector.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 6b4b88d1599d..dbf502c18656 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -128,6 +128,8 @@ int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, struct net *ns; for_each_net(ns) { + if (ns == &init_net) + continue; if (rcu_access_pointer(ns->flow_dissector_prog)) { ret = -EEXIST; goto out; @@ -145,12 +147,14 @@ int skb_flow_dissector_bpf_prog_attach(const union bpf_attr *attr, attached = rcu_dereference_protected(net->flow_dissector_prog, lockdep_is_held(&flow_dissector_mutex)); - if (attached) { - /* Only one BPF program can be attached at a time */ - ret = -EEXIST; + if (attached == prog) { + /* The same program cannot be attached twice */ + ret = -EINVAL; goto out; } rcu_assign_pointer(net->flow_dissector_prog, prog); + if (attached) + bpf_prog_put(attached); out: mutex_unlock(&flow_dissector_mutex); return ret; -- cgit v1.2.3 From f97eea1756f383fefc147f4c76c54942944a3d95 Mon Sep 17 00:00:00 2001 From: Jakub Sitnicki Date: Fri, 11 Oct 2019 10:29:46 +0200 Subject: selftests/bpf: Check that flow dissector can be re-attached Make sure a new flow dissector program can be attached to replace the old one with a single syscall. Also check that attaching the same program twice is prohibited. Signed-off-by: Jakub Sitnicki Signed-off-by: Daniel Borkmann Reviewed-by: Stanislav Fomichev Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/20191011082946.22695-3-jakub@cloudflare.com --- .../bpf/prog_tests/flow_dissector_reattach.c | 127 +++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c new file mode 100644 index 000000000000..777faffc4639 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector_reattach.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test that the flow_dissector program can be updated with a single + * syscall by attaching a new program that replaces the existing one. + * + * Corner case - the same program cannot be attached twice. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include +#include + +#include "test_progs.h" + +static bool is_attached(int netns) +{ + __u32 cnt; + int err; + + err = bpf_prog_query(netns, BPF_FLOW_DISSECTOR, 0, NULL, NULL, &cnt); + if (CHECK_FAIL(err)) { + perror("bpf_prog_query"); + return true; /* fail-safe */ + } + + return cnt > 0; +} + +static int load_prog(void) +{ + struct bpf_insn prog[] = { + BPF_MOV64_IMM(BPF_REG_0, BPF_OK), + BPF_EXIT_INSN(), + }; + int fd; + + fd = bpf_load_program(BPF_PROG_TYPE_FLOW_DISSECTOR, prog, + ARRAY_SIZE(prog), "GPL", 0, NULL, 0); + if (CHECK_FAIL(fd < 0)) + perror("bpf_load_program"); + + return fd; +} + +static void do_flow_dissector_reattach(void) +{ + int prog_fd[2] = { -1, -1 }; + int err; + + prog_fd[0] = load_prog(); + if (prog_fd[0] < 0) + return; + + prog_fd[1] = load_prog(); + if (prog_fd[1] < 0) + goto out_close; + + err = bpf_prog_attach(prog_fd[0], 0, BPF_FLOW_DISSECTOR, 0); + if (CHECK_FAIL(err)) { + perror("bpf_prog_attach-0"); + goto out_close; + } + + /* Expect success when attaching a different program */ + err = bpf_prog_attach(prog_fd[1], 0, BPF_FLOW_DISSECTOR, 0); + if (CHECK_FAIL(err)) { + perror("bpf_prog_attach-1"); + goto out_detach; + } + + /* Expect failure when attaching the same program twice */ + err = bpf_prog_attach(prog_fd[1], 0, BPF_FLOW_DISSECTOR, 0); + if (CHECK_FAIL(!err || errno != EINVAL)) + perror("bpf_prog_attach-2"); + +out_detach: + err = bpf_prog_detach(0, BPF_FLOW_DISSECTOR); + if (CHECK_FAIL(err)) + perror("bpf_prog_detach"); + +out_close: + close(prog_fd[1]); + close(prog_fd[0]); +} + +void test_flow_dissector_reattach(void) +{ + int init_net, err; + + init_net = open("/proc/1/ns/net", O_RDONLY); + if (CHECK_FAIL(init_net < 0)) { + perror("open(/proc/1/ns/net)"); + return; + } + + err = setns(init_net, CLONE_NEWNET); + if (CHECK_FAIL(err)) { + perror("setns(/proc/1/ns/net)"); + goto out_close; + } + + if (is_attached(init_net)) { + test__skip(); + printf("Can't test with flow dissector attached to init_net\n"); + return; + } + + /* First run tests in root network namespace */ + do_flow_dissector_reattach(); + + /* Then repeat tests in a non-root namespace */ + err = unshare(CLONE_NEWNET); + if (CHECK_FAIL(err)) { + perror("unshare(CLONE_NEWNET)"); + goto out_close; + } + do_flow_dissector_reattach(); + +out_close: + close(init_net); +} -- cgit v1.2.3 From 2dedd7d2165565bafa89718eaadfc5d1a7865f66 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 11 Oct 2019 10:20:53 -0700 Subject: bpf: Fix cast to pointer from integer of different size warning Fix "warning: cast to pointer from integer of different size" when casting u64 addr to void *. Fixes: a23740ec43ba ("bpf: Track contents of read-only maps as scalars") Reported-by: kbuild test robot Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Martin KaFai Lau Link: https://lore.kernel.org/bpf/20191011172053.2980619-1-andriin@fb.com --- kernel/bpf/verifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b818fed3208d..d3446f018b9a 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2753,7 +2753,7 @@ static int bpf_map_direct_read(struct bpf_map *map, int off, int size, u64 *val) err = map->ops->map_direct_value_addr(map, &addr, off); if (err) return err; - ptr = (void *)addr + off; + ptr = (void *)(long)addr + off; switch (size) { case sizeof(u8): -- cgit v1.2.3 From baead859edbb3cd53b8e388c1f33641ce01d4c01 Mon Sep 17 00:00:00 2001 From: Anton Ivanov Date: Fri, 11 Oct 2019 09:43:03 +0100 Subject: xdp: Trivial, fix spelling in function description Fix typo 'boolian' into 'boolean'. Signed-off-by: Anton Ivanov Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20191011084303.28418-1-anton.ivanov@cambridgegreys.com --- net/core/xdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/xdp.c b/net/core/xdp.c index d7bf62ffbb5e..20781ad5f9c3 100644 --- a/net/core/xdp.c +++ b/net/core/xdp.c @@ -386,7 +386,7 @@ EXPORT_SYMBOL_GPL(xdp_rxq_info_reg_mem_model); /* XDP RX runs under NAPI protection, and in different delivery error * scenarios (e.g. queue full), it is possible to return the xdp_frame - * while still leveraging this protection. The @napi_direct boolian + * while still leveraging this protection. The @napi_direct boolean * is used for those calls sites. Thus, allowing for faster recycling * of xdp_frames/pages in those cases. */ -- cgit v1.2.3 From 409017847d2014db8ab1da49dd48182af88344b7 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 10 Oct 2019 19:38:47 -0700 Subject: libbpf: Generate more efficient BPF_CORE_READ code Existing BPF_CORE_READ() macro generates slightly suboptimal code. If there are intermediate pointers to be read, initial source pointer is going to be assigned into a temporary variable and then temporary variable is going to be uniformly used as a "source" pointer for all intermediate pointer reads. Schematically (ignoring all the type casts), BPF_CORE_READ(s, a, b, c) is expanded into: ({ const void *__t = src; bpf_probe_read(&__t, sizeof(*__t), &__t->a); bpf_probe_read(&__t, sizeof(*__t), &__t->b); typeof(s->a->b->c) __r; bpf_probe_read(&__r, sizeof(*__r), &__t->c); }) This initial `__t = src` makes calls more uniform, but causes slightly less optimal register usage sometimes when compiled with Clang. This can cascase into, e.g., more register spills. This patch fixes this issue by generating more optimal sequence: ({ const void *__t; bpf_probe_read(&__t, sizeof(*__t), &src->a); /* <-- src here */ bpf_probe_read(&__t, sizeof(*__t), &__t->b); typeof(s->a->b->c) __r; bpf_probe_read(&__r, sizeof(*__r), &__t->c); }) Fixes: 7db3822ab991 ("libbpf: Add BPF_CORE_READ/BPF_CORE_READ_INTO helpers") Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Link: https://lore.kernel.org/bpf/20191011023847.275936-1-andriin@fb.com --- tools/lib/bpf/bpf_core_read.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/bpf_core_read.h b/tools/lib/bpf/bpf_core_read.h index ae877e3ffb51..4daf04c25493 100644 --- a/tools/lib/bpf/bpf_core_read.h +++ b/tools/lib/bpf/bpf_core_read.h @@ -88,11 +88,11 @@ read_fn((void *)(dst), sizeof(*(dst)), &((src_type)(src))->accessor) /* "recursively" read a sequence of inner pointers using local __t var */ +#define ___rd_first(src, a) ___read(bpf_core_read, &__t, ___type(src), src, a); #define ___rd_last(...) \ ___read(bpf_core_read, &__t, \ ___type(___nolast(__VA_ARGS__)), __t, ___last(__VA_ARGS__)); -#define ___rd_p0(src) const void *__t = src; -#define ___rd_p1(...) ___rd_p0(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) +#define ___rd_p1(...) const void *__t; ___rd_first(__VA_ARGS__) #define ___rd_p2(...) ___rd_p1(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) #define ___rd_p3(...) ___rd_p2(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) #define ___rd_p4(...) ___rd_p3(___nolast(__VA_ARGS__)) ___rd_last(__VA_ARGS__) -- cgit v1.2.3 From e78dcbf414545b53218dab0fb5af5d6b61513eaf Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Thu, 10 Oct 2019 20:29:01 -0700 Subject: libbpf: Handle invalid typedef emitted by old GCC Old GCC versions are producing invalid typedef for __gnuc_va_list pointing to void. Special-case this and emit valid: typedef __builtin_va_list __gnuc_va_list; Reported-by: John Fastabend Signed-off-by: Andrii Nakryiko Signed-off-by: Daniel Borkmann Acked-by: Martin KaFai Lau Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20191011032901.452042-1-andriin@fb.com --- tools/lib/bpf/btf_dump.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/lib/bpf/btf_dump.c b/tools/lib/bpf/btf_dump.c index 87f27e2664c5..139812b46c7b 100644 --- a/tools/lib/bpf/btf_dump.c +++ b/tools/lib/bpf/btf_dump.c @@ -975,6 +975,17 @@ static void btf_dump_emit_typedef_def(struct btf_dump *d, __u32 id, { const char *name = btf_dump_ident_name(d, id); + /* + * Old GCC versions are emitting invalid typedef for __gnuc_va_list + * pointing to VOID. This generates warnings from btf_dump() and + * results in uncompilable header file, so we are fixing it up here + * with valid typedef into __builtin_va_list. + */ + if (t->type == 0 && strcmp(name, "__gnuc_va_list") == 0) { + btf_dump_printf(d, "typedef __builtin_va_list __gnuc_va_list"); + return; + } + btf_dump_printf(d, "typedef "); btf_dump_emit_type_decl(d, t->type, name, lvl); } -- cgit v1.2.3 From cdd5b2d1fc86f8dda383d4f0b4ac9b533539e76a Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:27:54 +0300 Subject: samples/bpf: Fix HDR_PROBE "echo" echo should be replaced with echo -e to handle '\n' correctly, but instead, replace it with printf as some systems can't handle echo -e. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-2-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index a11d7270583d..4f61725b1d86 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -201,7 +201,7 @@ endif # Don't evaluate probes and warnings if we need to run make recursively ifneq ($(src),) -HDR_PROBE := $(shell echo "\#include \n struct list_head { int a; }; int main() { return 0; }" | \ +HDR_PROBE := $(shell printf "\#include \n struct list_head { int a; }; int main() { return 0; }" | \ $(HOSTCC) $(KBUILD_HOSTCFLAGS) -x c - -o /dev/null 2>/dev/null && \ echo okay) -- cgit v1.2.3 From 39e0c3649f2ef5fc1beac4f6cc5f5f9ddb1885a9 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:27:55 +0300 Subject: samples/bpf: Fix cookie_uid_helper_example obj build Don't list userspace "cookie_uid_helper_example" object in list for bpf objects. 'always' target is used for listing bpf programs, but 'cookie_uid_helper_example.o' is a user space ELF file, and covered by rule `per_socket_stats_example`, so shouldn't be in 'always'. Let us remove `always += cookie_uid_helper_example.o`, which avoids breaking cross compilation due to mismatched includes. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-3-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 4f61725b1d86..045fa43842e6 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -145,7 +145,6 @@ always += sampleip_kern.o always += lwt_len_hist_kern.o always += xdp_tx_iptunnel_kern.o always += test_map_in_map_kern.o -always += cookie_uid_helper_example.o always += tcp_synrto_kern.o always += tcp_rwnd_kern.o always += tcp_bufs_kern.o -- cgit v1.2.3 From 518c13401e16eae1d83d6e459daf6e776a97eba9 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:27:56 +0300 Subject: samples/bpf: Use --target from cross-compile For cross compiling the target triple can be inherited from cross-compile prefix as it's done in CLANG_FLAGS from kernel makefile. So copy-paste this decision from kernel Makefile. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-4-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 045fa43842e6..9c8c9872004d 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -195,7 +195,7 @@ BTF_PAHOLE ?= pahole # Detect that we're cross compiling and use the cross compiler ifdef CROSS_COMPILE HOSTCC = $(CROSS_COMPILE)gcc -CLANG_ARCH_ARGS = -target $(ARCH) +CLANG_ARCH_ARGS = --target=$(notdir $(CROSS_COMPILE:%-=%)) endif # Don't evaluate probes and warnings if we need to run make recursively -- cgit v1.2.3 From 2a560df7c147abcced2ff8c3b5572e0b1b36ac3f Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:27:57 +0300 Subject: samples/bpf: Use own EXTRA_CFLAGS for clang commands It can overlap with CFLAGS used for libraries built with gcc if not now then in next patches. Correct it here for simplicity. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-5-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 9c8c9872004d..cf882e43648a 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -218,10 +218,10 @@ BTF_LLVM_PROBE := $(shell echo "int main() { return 0; }" | \ /bin/rm -f ./llvm_btf_verify.o) ifneq ($(BTF_LLVM_PROBE),) - EXTRA_CFLAGS += -g + BPF_EXTRA_CFLAGS += -g else ifneq ($(and $(BTF_LLC_PROBE),$(BTF_PAHOLE_PROBE),$(BTF_OBJCOPY_PROBE)),) - EXTRA_CFLAGS += -g + BPF_EXTRA_CFLAGS += -g LLC_FLAGS += -mattr=dwarfris DWARF2BTF = y endif @@ -280,8 +280,9 @@ $(obj)/hbm_edt_kern.o: $(src)/hbm.h $(src)/hbm_kern.h # useless for BPF samples. $(obj)/%.o: $(src)/%.c @echo " CLANG-bpf " $@ - $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) -I$(obj) \ - -I$(srctree)/tools/testing/selftests/bpf/ -I$(srctree)/tools/lib/bpf/ \ + $(Q)$(CLANG) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(BPF_EXTRA_CFLAGS) \ + -I$(obj) -I$(srctree)/tools/testing/selftests/bpf/ \ + -I$(srctree)/tools/lib/bpf/ \ -D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \ -D__TARGET_ARCH_$(SRCARCH) -Wno-compare-distinct-pointer-types \ -Wno-gnu-variable-sized-type-not-at-end \ -- cgit v1.2.3 From 0e865aedad571b93b2d8bb780f17befd5ee4b308 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:27:58 +0300 Subject: samples/bpf: Use __LINUX_ARM_ARCH__ selector for arm For arm, -D__LINUX_ARM_ARCH__=X is min version used as instruction set selector and is absolutely required while parsing some parts of headers. It's present in KBUILD_CFLAGS but not in autoconf.h, so let's retrieve it from and add to programs cflags. In another case errors like "SMP is not supported" for armv7 and bunch of other errors are issued resulting to incorrect final object. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011002808.28206-6-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index cf882e43648a..9b33e7395eac 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -185,6 +185,14 @@ HOSTLDLIBS_map_perf_test += -lrt HOSTLDLIBS_test_overhead += -lrt HOSTLDLIBS_xdpsock += -pthread +ifeq ($(ARCH), arm) +# Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux +# headers when arm instruction set identification is requested. +ARM_ARCH_SELECTOR := $(filter -D__LINUX_ARM_ARCH__%, $(KBUILD_CFLAGS)) +BPF_EXTRA_CFLAGS := $(ARM_ARCH_SELECTOR) +KBUILD_HOSTCFLAGS += $(ARM_ARCH_SELECTOR) +endif + # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang LLC ?= llc -- cgit v1.2.3 From 54b7fbd4484bdf8a13045abdf57a66185390f07f Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:27:59 +0300 Subject: samples/bpf: Drop unnecessarily inclusion for bpf_load Drop inclusion for bpf_load -I$(objtree)/usr/include as it is included for all objects anyway, with above line: KBUILD_HOSTCFLAGS += -I$(objtree)/usr/include Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-7-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 9b33e7395eac..bb2d976e824e 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -176,7 +176,7 @@ KBUILD_HOSTCFLAGS += -I$(srctree)/tools/testing/selftests/bpf/ KBUILD_HOSTCFLAGS += -I$(srctree)/tools/lib/ -I$(srctree)/tools/include KBUILD_HOSTCFLAGS += -I$(srctree)/tools/perf -HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable +HOSTCFLAGS_bpf_load.o += -Wno-unused-variable KBUILD_HOSTLDLIBS += $(LIBBPF) -lelf HOSTLDLIBS_tracex4 += -lrt -- cgit v1.2.3 From 752677e89fca11fd6e239df2fb9877b9e6b83ab2 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:00 +0300 Subject: samples/bpf: Add makefile.target for separate CC target build The Makefile.target is added only and will be used in sample/bpf/Makefile later in order to switch cross-compiling to CC from HOSTCC environment. The HOSTCC is supposed to build binaries and tools running on the host afterwards, in order to simplify build or so, like "fixdep" or else. In case of cross compiling "fixdep" is executed on host when the rest samples should run on target arch. In order to build binaries for target arch with CC and tools running on host with HOSTCC, lets add Makefile.target for simplicity, having definition and routines similar to ones, used in script/Makefile.host. This allows later add cross-compilation to samples/bpf with minimum changes. The tprog stands for target programs built with CC. Makefile.target contains only stuff needed for samples/bpf, potentially can be reused later and now needed only for unblocking tricky samples/bpf cross compilation. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011002808.28206-8-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile.target | 75 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 samples/bpf/Makefile.target diff --git a/samples/bpf/Makefile.target b/samples/bpf/Makefile.target new file mode 100644 index 000000000000..7621f55e2947 --- /dev/null +++ b/samples/bpf/Makefile.target @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0 +# ========================================================================== +# Building binaries on the host system +# Binaries are not used during the compilation of the kernel, and intended +# to be build for target board, target board can be host of course. Added to +# build binaries to run not on host system. +# +# Sample syntax +# tprogs-y := xsk_example +# Will compile xsk_example.c and create an executable named xsk_example +# +# tprogs-y := xdpsock +# xdpsock-objs := xdpsock_1.o xdpsock_2.o +# Will compile xdpsock_1.c and xdpsock_2.c, and then link the executable +# xdpsock, based on xdpsock_1.o and xdpsock_2.o +# +# Derived from scripts/Makefile.host +# +__tprogs := $(sort $(tprogs-y)) + +# C code +# Executables compiled from a single .c file +tprog-csingle := $(foreach m,$(__tprogs), \ + $(if $($(m)-objs),,$(m))) + +# C executables linked based on several .o files +tprog-cmulti := $(foreach m,$(__tprogs),\ + $(if $($(m)-objs),$(m))) + +# Object (.o) files compiled from .c files +tprog-cobjs := $(sort $(foreach m,$(__tprogs),$($(m)-objs))) + +tprog-csingle := $(addprefix $(obj)/,$(tprog-csingle)) +tprog-cmulti := $(addprefix $(obj)/,$(tprog-cmulti)) +tprog-cobjs := $(addprefix $(obj)/,$(tprog-cobjs)) + +##### +# Handle options to gcc. Support building with separate output directory + +_tprogc_flags = $(TPROGS_CFLAGS) \ + $(TPROGCFLAGS_$(basetarget).o) + +# $(objtree)/$(obj) for including generated headers from checkin source files +ifeq ($(KBUILD_EXTMOD),) +ifdef building_out_of_srctree +_tprogc_flags += -I $(objtree)/$(obj) +endif +endif + +tprogc_flags = -Wp,-MD,$(depfile) $(_tprogc_flags) + +# Create executable from a single .c file +# tprog-csingle -> Executable +quiet_cmd_tprog-csingle = CC $@ + cmd_tprog-csingle = $(CC) $(tprogc_flags) $(TPROGS_LDFLAGS) -o $@ $< \ + $(TPROGS_LDLIBS) $(TPROGLDLIBS_$(@F)) +$(tprog-csingle): $(obj)/%: $(src)/%.c FORCE + $(call if_changed_dep,tprog-csingle) + +# Link an executable based on list of .o files, all plain c +# tprog-cmulti -> executable +quiet_cmd_tprog-cmulti = LD $@ + cmd_tprog-cmulti = $(CC) $(tprogc_flags) $(TPROGS_LDFLAGS) -o $@ \ + $(addprefix $(obj)/,$($(@F)-objs)) \ + $(TPROGS_LDLIBS) $(TPROGLDLIBS_$(@F)) +$(tprog-cmulti): $(tprog-cobjs) FORCE + $(call if_changed,tprog-cmulti) +$(call multi_depend, $(tprog-cmulti), , -objs) + +# Create .o file from a single .c file +# tprog-cobjs -> .o +quiet_cmd_tprog-cobjs = CC $@ + cmd_tprog-cobjs = $(CC) $(tprogc_flags) -c -o $@ $< +$(tprog-cobjs): $(obj)/%.o: $(src)/%.c FORCE + $(call if_changed_dep,tprog-cobjs) -- cgit v1.2.3 From 1d97c6c2511f10e19f683a4431e8ee887c1daab6 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:01 +0300 Subject: samples/bpf: Base target programs rules on Makefile.target The main reason for that - HOSTCC and CC have different aims. HOSTCC is used to build programs running on host, that can cross-comple target programs with CC. It was tested for arm and arm64 cross compilation, based on linaro toolchain, but should work for others. So, in order to split cross compilation (CC) with host build (HOSTCC), lets base samples on Makefile.target. It allows to cross-compile samples/bpf programs with CC while auxialry tools running on host built with HOSTCC. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011002808.28206-9-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 135 ++++++++++++++++++++++++++------------------------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index bb2d976e824e..91bfb421c278 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -4,55 +4,53 @@ BPF_SAMPLES_PATH ?= $(abspath $(srctree)/$(src)) TOOLS_PATH := $(BPF_SAMPLES_PATH)/../../tools # List of programs to build -hostprogs-y := test_lru_dist -hostprogs-y += sock_example -hostprogs-y += fds_example -hostprogs-y += sockex1 -hostprogs-y += sockex2 -hostprogs-y += sockex3 -hostprogs-y += tracex1 -hostprogs-y += tracex2 -hostprogs-y += tracex3 -hostprogs-y += tracex4 -hostprogs-y += tracex5 -hostprogs-y += tracex6 -hostprogs-y += tracex7 -hostprogs-y += test_probe_write_user -hostprogs-y += trace_output -hostprogs-y += lathist -hostprogs-y += offwaketime -hostprogs-y += spintest -hostprogs-y += map_perf_test -hostprogs-y += test_overhead -hostprogs-y += test_cgrp2_array_pin -hostprogs-y += test_cgrp2_attach -hostprogs-y += test_cgrp2_sock -hostprogs-y += test_cgrp2_sock2 -hostprogs-y += xdp1 -hostprogs-y += xdp2 -hostprogs-y += xdp_router_ipv4 -hostprogs-y += test_current_task_under_cgroup -hostprogs-y += trace_event -hostprogs-y += sampleip -hostprogs-y += tc_l2_redirect -hostprogs-y += lwt_len_hist -hostprogs-y += xdp_tx_iptunnel -hostprogs-y += test_map_in_map -hostprogs-y += per_socket_stats_example -hostprogs-y += xdp_redirect -hostprogs-y += xdp_redirect_map -hostprogs-y += xdp_redirect_cpu -hostprogs-y += xdp_monitor -hostprogs-y += xdp_rxq_info -hostprogs-y += syscall_tp -hostprogs-y += cpustat -hostprogs-y += xdp_adjust_tail -hostprogs-y += xdpsock -hostprogs-y += xdp_fwd -hostprogs-y += task_fd_query -hostprogs-y += xdp_sample_pkts -hostprogs-y += ibumad -hostprogs-y += hbm +tprogs-y := test_lru_dist +tprogs-y += sock_example +tprogs-y += fds_example +tprogs-y += sockex1 +tprogs-y += sockex2 +tprogs-y += sockex3 +tprogs-y += tracex1 +tprogs-y += tracex2 +tprogs-y += tracex3 +tprogs-y += tracex4 +tprogs-y += tracex5 +tprogs-y += tracex6 +tprogs-y += tracex7 +tprogs-y += test_probe_write_user +tprogs-y += trace_output +tprogs-y += lathist +tprogs-y += offwaketime +tprogs-y += spintest +tprogs-y += map_perf_test +tprogs-y += test_overhead +tprogs-y += test_cgrp2_array_pin +tprogs-y += test_cgrp2_attach +tprogs-y += test_cgrp2_sock +tprogs-y += test_cgrp2_sock2 +tprogs-y += xdp1 +tprogs-y += xdp2 +tprogs-y += xdp_router_ipv4 +tprogs-y += test_current_task_under_cgroup +tprogs-y += trace_event +tprogs-y += sampleip +tprogs-y += tc_l2_redirect +tprogs-y += lwt_len_hist +tprogs-y += xdp_tx_iptunnel +tprogs-y += test_map_in_map +tprogs-y += xdp_redirect_map +tprogs-y += xdp_redirect_cpu +tprogs-y += xdp_monitor +tprogs-y += xdp_rxq_info +tprogs-y += syscall_tp +tprogs-y += cpustat +tprogs-y += xdp_adjust_tail +tprogs-y += xdpsock +tprogs-y += xdp_fwd +tprogs-y += task_fd_query +tprogs-y += xdp_sample_pkts +tprogs-y += ibumad +tprogs-y += hbm # Libbpf dependencies LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a @@ -111,7 +109,7 @@ ibumad-objs := bpf_load.o ibumad_user.o $(TRACE_HELPERS) hbm-objs := bpf_load.o hbm.o $(CGROUP_HELPERS) # Tell kbuild to always build the programs -always := $(hostprogs-y) +always := $(tprogs-y) always += sockex1_kern.o always += sockex2_kern.o always += sockex3_kern.o @@ -170,29 +168,32 @@ always += ibumad_kern.o always += hbm_out_kern.o always += hbm_edt_kern.o -KBUILD_HOSTCFLAGS += -I$(objtree)/usr/include -KBUILD_HOSTCFLAGS += -I$(srctree)/tools/lib/bpf/ -KBUILD_HOSTCFLAGS += -I$(srctree)/tools/testing/selftests/bpf/ -KBUILD_HOSTCFLAGS += -I$(srctree)/tools/lib/ -I$(srctree)/tools/include -KBUILD_HOSTCFLAGS += -I$(srctree)/tools/perf - -HOSTCFLAGS_bpf_load.o += -Wno-unused-variable - -KBUILD_HOSTLDLIBS += $(LIBBPF) -lelf -HOSTLDLIBS_tracex4 += -lrt -HOSTLDLIBS_trace_output += -lrt -HOSTLDLIBS_map_perf_test += -lrt -HOSTLDLIBS_test_overhead += -lrt -HOSTLDLIBS_xdpsock += -pthread - ifeq ($(ARCH), arm) # Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux # headers when arm instruction set identification is requested. ARM_ARCH_SELECTOR := $(filter -D__LINUX_ARM_ARCH__%, $(KBUILD_CFLAGS)) BPF_EXTRA_CFLAGS := $(ARM_ARCH_SELECTOR) -KBUILD_HOSTCFLAGS += $(ARM_ARCH_SELECTOR) +TPROGS_CFLAGS += $(ARM_ARCH_SELECTOR) endif +TPROGS_LDLIBS := $(KBUILD_HOSTLDLIBS) +TPROGS_CFLAGS += $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) +TPROGS_CFLAGS += -I$(objtree)/usr/include +TPROGS_CFLAGS += -I$(srctree)/tools/lib/bpf/ +TPROGS_CFLAGS += -I$(srctree)/tools/testing/selftests/bpf/ +TPROGS_CFLAGS += -I$(srctree)/tools/lib/ +TPROGS_CFLAGS += -I$(srctree)/tools/include +TPROGS_CFLAGS += -I$(srctree)/tools/perf + +TPROGCFLAGS_bpf_load.o += -Wno-unused-variable + +TPROGS_LDLIBS += $(LIBBPF) -lelf +TPROGLDLIBS_tracex4 += -lrt +TPROGLDLIBS_trace_output += -lrt +TPROGLDLIBS_map_perf_test += -lrt +TPROGLDLIBS_test_overhead += -lrt +TPROGLDLIBS_xdpsock += -pthread + # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang LLC ?= llc @@ -283,6 +284,8 @@ $(obj)/hbm_out_kern.o: $(src)/hbm.h $(src)/hbm_kern.h $(obj)/hbm.o: $(src)/hbm.h $(obj)/hbm_edt_kern.o: $(src)/hbm.h $(src)/hbm_kern.h +-include $(BPF_SAMPLES_PATH)/Makefile.target + # asm/sysreg.h - inline assembly used by it is incompatible with llvm. # But, there is no easy way to fix it, so just exclude it since it is # useless for BPF samples. -- cgit v1.2.3 From 10cb3d8706dbaa0521e761b96b3be5b7a497ae3f Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:02 +0300 Subject: samples/bpf: Use own flags but not HOSTCFLAGS While compiling natively, the host's cflags and ldflags are equal to ones used from HOSTCFLAGS and HOSTLDFLAGS. When cross compiling it should have own, used for target arch. While verification, for arm, arm64 and x86_64 the following flags were used always: -Wall -O2 -fomit-frame-pointer -Wmissing-prototypes -Wstrict-prototypes So, add them as they were verified and used before adding Makefile.target and lets omit "-fomit-frame-pointer" as were proposed while review, as no sense in such optimization for samples. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011002808.28206-10-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 91bfb421c278..57a15ff938a6 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -176,8 +176,10 @@ BPF_EXTRA_CFLAGS := $(ARM_ARCH_SELECTOR) TPROGS_CFLAGS += $(ARM_ARCH_SELECTOR) endif -TPROGS_LDLIBS := $(KBUILD_HOSTLDLIBS) -TPROGS_CFLAGS += $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) +TPROGS_CFLAGS += -Wall -O2 +TPROGS_CFLAGS += -Wmissing-prototypes +TPROGS_CFLAGS += -Wstrict-prototypes + TPROGS_CFLAGS += -I$(objtree)/usr/include TPROGS_CFLAGS += -I$(srctree)/tools/lib/bpf/ TPROGS_CFLAGS += -I$(srctree)/tools/testing/selftests/bpf/ -- cgit v1.2.3 From a833effa15903d07946645fc5e76b3b18a591409 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:03 +0300 Subject: samples/bpf: Use target CC environment for HDR_PROBE No need in hacking HOSTCC to be cross-compiler any more, so drop this trick and use target CC for HDR_PROBE. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-11-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 57a15ff938a6..a6c33496e8ca 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -205,15 +205,14 @@ BTF_PAHOLE ?= pahole # Detect that we're cross compiling and use the cross compiler ifdef CROSS_COMPILE -HOSTCC = $(CROSS_COMPILE)gcc CLANG_ARCH_ARGS = --target=$(notdir $(CROSS_COMPILE:%-=%)) endif # Don't evaluate probes and warnings if we need to run make recursively ifneq ($(src),) HDR_PROBE := $(shell printf "\#include \n struct list_head { int a; }; int main() { return 0; }" | \ - $(HOSTCC) $(KBUILD_HOSTCFLAGS) -x c - -o /dev/null 2>/dev/null && \ - echo okay) + $(CC) $(TPROGS_CFLAGS) $(TPROGS_LDFLAGS) -x c - \ + -o /dev/null 2>/dev/null && echo okay) ifeq ($(HDR_PROBE),) $(warning WARNING: Detected possible issues with include path.) -- cgit v1.2.3 From 5c26f9a783581058c5de93627ae64139c4b32ceb Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:04 +0300 Subject: libbpf: Don't use cxx to test_libpf target No need to use C++ for test_libbpf target when libbpf is on C and it can be tested with C, after this change the CXXFLAGS in makefiles can be avoided, at least in bpf samples, when sysroot is used, passing same C/LDFLAGS as for lib. Add "return 0" in test_libbpf to avoid warn, but also remove spaces at start of the lines to keep same style and avoid warns while apply. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-12-ivan.khoronzhuk@linaro.org --- tools/lib/bpf/Makefile | 18 +++++------------- tools/lib/bpf/test_libbpf.c | 20 ++++++++++++++++++++ tools/lib/bpf/test_libbpf.cpp | 18 ------------------ 3 files changed, 25 insertions(+), 31 deletions(-) create mode 100644 tools/lib/bpf/test_libbpf.c delete mode 100644 tools/lib/bpf/test_libbpf.cpp diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 1270955e4845..46280b5ad48d 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -52,7 +52,7 @@ ifndef VERBOSE endif FEATURE_USER = .libbpf -FEATURE_TESTS = libelf libelf-mmap bpf reallocarray cxx +FEATURE_TESTS = libelf libelf-mmap bpf reallocarray FEATURE_DISPLAY = libelf bpf INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi @@ -142,15 +142,7 @@ GLOBAL_SYM_COUNT = $(shell readelf -s --wide $(BPF_IN) | \ VERSIONED_SYM_COUNT = $(shell readelf -s --wide $(OUTPUT)libbpf.so | \ grep -Eo '[^ ]+@LIBBPF_' | cut -d@ -f1 | sort -u | wc -l) -CMD_TARGETS = $(LIB_TARGET) $(PC_FILE) - -CXX_TEST_TARGET = $(OUTPUT)test_libbpf - -ifeq ($(feature-cxx), 1) - CMD_TARGETS += $(CXX_TEST_TARGET) -endif - -TARGETS = $(CMD_TARGETS) +CMD_TARGETS = $(LIB_TARGET) $(PC_FILE) $(OUTPUT)test_libbpf all: fixdep $(Q)$(MAKE) all_cmd @@ -190,8 +182,8 @@ $(OUTPUT)libbpf.so.$(LIBBPF_VERSION): $(BPF_IN) $(OUTPUT)libbpf.a: $(BPF_IN) $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ -$(OUTPUT)test_libbpf: test_libbpf.cpp $(OUTPUT)libbpf.a - $(QUIET_LINK)$(CXX) $(INCLUDES) $^ -lelf -o $@ +$(OUTPUT)test_libbpf: test_libbpf.c $(OUTPUT)libbpf.a + $(QUIET_LINK)$(CC) $(INCLUDES) $^ -lelf -o $@ $(OUTPUT)libbpf.pc: $(QUIET_GEN)sed -e "s|@PREFIX@|$(prefix)|" \ @@ -266,7 +258,7 @@ config-clean: $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null clean: - $(call QUIET_CLEAN, libbpf) $(RM) $(TARGETS) $(CXX_TEST_TARGET) \ + $(call QUIET_CLEAN, libbpf) $(RM) $(CMD_TARGETS) \ *.o *~ *.a *.so *.so.$(LIBBPF_MAJOR_VERSION) .*.d .*.cmd \ *.pc LIBBPF-CFLAGS bpf_helper_defs.h $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf diff --git a/tools/lib/bpf/test_libbpf.c b/tools/lib/bpf/test_libbpf.c new file mode 100644 index 000000000000..f0eb2727b766 --- /dev/null +++ b/tools/lib/bpf/test_libbpf.c @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#include "libbpf.h" +#include "bpf.h" +#include "btf.h" + +/* do nothing, just make sure we can link successfully */ + +int main(int argc, char *argv[]) +{ + /* libbpf.h */ + libbpf_set_print(NULL); + + /* bpf.h */ + bpf_prog_get_fd_by_id(0); + + /* btf.h */ + btf__new(NULL, 0); + + return 0; +} diff --git a/tools/lib/bpf/test_libbpf.cpp b/tools/lib/bpf/test_libbpf.cpp deleted file mode 100644 index fc134873bb6d..000000000000 --- a/tools/lib/bpf/test_libbpf.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ -#include "libbpf.h" -#include "bpf.h" -#include "btf.h" - -/* do nothing, just make sure we can link successfully */ - -int main(int argc, char *argv[]) -{ - /* libbpf.h */ - libbpf_set_print(NULL); - - /* bpf.h */ - bpf_prog_get_fd_by_id(0); - - /* btf.h */ - btf__new(NULL, 0); -} -- cgit v1.2.3 From 793a349cd8192ad67c784d231011591a57eac001 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:05 +0300 Subject: libbpf: Add C/LDFLAGS to libbpf.so and test_libpf targets In case of C/LDFLAGS there is no way to pass them correctly to build command, for instance when --sysroot is used or external libraries are used, like -lelf, wich can be absent in toolchain. This can be used for samples/bpf cross-compiling allowing to get elf lib from sysroot. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Acked-by: Andrii Nakryiko Link: https://lore.kernel.org/bpf/20191011002808.28206-13-ivan.khoronzhuk@linaro.org --- tools/lib/bpf/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 46280b5ad48d..75b538577c17 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -174,8 +174,9 @@ bpf_helper_defs.h: $(srctree)/include/uapi/linux/bpf.h $(OUTPUT)libbpf.so: $(OUTPUT)libbpf.so.$(LIBBPF_VERSION) $(OUTPUT)libbpf.so.$(LIBBPF_VERSION): $(BPF_IN) - $(QUIET_LINK)$(CC) --shared -Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \ - -Wl,--version-script=$(VERSION_SCRIPT) $^ -lelf -o $@ + $(QUIET_LINK)$(CC) $(LDFLAGS) \ + --shared -Wl,-soname,libbpf.so.$(LIBBPF_MAJOR_VERSION) \ + -Wl,--version-script=$(VERSION_SCRIPT) $^ -lelf -o $@ @ln -sf $(@F) $(OUTPUT)libbpf.so @ln -sf $(@F) $(OUTPUT)libbpf.so.$(LIBBPF_MAJOR_VERSION) @@ -183,7 +184,7 @@ $(OUTPUT)libbpf.a: $(BPF_IN) $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ $(OUTPUT)test_libbpf: test_libbpf.c $(OUTPUT)libbpf.a - $(QUIET_LINK)$(CC) $(INCLUDES) $^ -lelf -o $@ + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) $^ -lelf -o $@ $(OUTPUT)libbpf.pc: $(QUIET_GEN)sed -e "s|@PREFIX@|$(prefix)|" \ -- cgit v1.2.3 From d8ceae91e9f031232d225a7159cca36e9eefdf85 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:06 +0300 Subject: samples/bpf: Provide C/LDFLAGS to libbpf In order to build lib using C/LD flags of target arch, provide them to libbpf make. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011002808.28206-14-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index a6c33496e8ca..6b161326ac67 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -248,7 +248,8 @@ clean: $(LIBBPF): FORCE # Fix up variables inherited from Kbuild that tools/ build system won't like - $(MAKE) -C $(dir $@) RM='rm -rf' LDFLAGS= srctree=$(BPF_SAMPLES_PATH)/../../ O= + $(MAKE) -C $(dir $@) RM='rm -rf' EXTRA_CFLAGS="$(TPROGS_CFLAGS)" \ + LDFLAGS=$(TPROGS_LDFLAGS) srctree=$(BPF_SAMPLES_PATH)/../../ O= $(obj)/syscall_nrs.h: $(obj)/syscall_nrs.s FORCE $(call filechk,offsets,__SYSCALL_NRS_H__) -- cgit v1.2.3 From b2327c107d6255e4ea591042120514bedcdc616a Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:07 +0300 Subject: samples/bpf: Add sysroot support Basically it only enables that was added by previous couple fixes. Sysroot contains correct libs installed and its headers. Useful when working with NFC or virtual machine. Usage example: clean (on demand) make ARCH=arm -C samples/bpf clean make ARCH=arm -C tools clean make ARCH=arm clean configure and install headers: make ARCH=arm defconfig make ARCH=arm headers_install build samples/bpf: make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- samples/bpf/ \ SYSROOT="path/to/sysroot" Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011002808.28206-15-ivan.khoronzhuk@linaro.org --- samples/bpf/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 6b161326ac67..4df11ddb9c75 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -187,6 +187,11 @@ TPROGS_CFLAGS += -I$(srctree)/tools/lib/ TPROGS_CFLAGS += -I$(srctree)/tools/include TPROGS_CFLAGS += -I$(srctree)/tools/perf +ifdef SYSROOT +TPROGS_CFLAGS += --sysroot=$(SYSROOT) +TPROGS_LDFLAGS := -L$(SYSROOT)/usr/lib +endif + TPROGCFLAGS_bpf_load.o += -Wno-unused-variable TPROGS_LDLIBS += $(LIBBPF) -lelf -- cgit v1.2.3 From 1600c9c26f6bbdd29fb1b44f13fb751846d2ebe8 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Fri, 11 Oct 2019 03:28:08 +0300 Subject: samples/bpf: Add preparation steps and sysroot info to readme Add couple preparation steps: clean and configuration. Also add newly added sysroot support info to cross-compile section. Signed-off-by: Ivan Khoronzhuk Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011002808.28206-16-ivan.khoronzhuk@linaro.org --- samples/bpf/README.rst | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/samples/bpf/README.rst b/samples/bpf/README.rst index 5f27e4faca50..cc1f00a1ee06 100644 --- a/samples/bpf/README.rst +++ b/samples/bpf/README.rst @@ -14,6 +14,20 @@ Compiling requires having installed: Note that LLVM's tool 'llc' must support target 'bpf', list version and supported targets with command: ``llc --version`` +Clean and configuration +----------------------- + +It can be needed to clean tools, samples or kernel before trying new arch or +after some changes (on demand):: + + make -C tools clean + make -C samples/bpf clean + make clean + +Configure kernel, defconfig for instance:: + + make defconfig + Kernel headers -------------- @@ -68,9 +82,26 @@ It is also possible to point make to the newly compiled 'llc' or Cross compiling samples ----------------------- In order to cross-compile, say for arm64 targets, export CROSS_COMPILE and ARCH -environment variables before calling make. This will direct make to build -samples for the cross target. +environment variables before calling make. But do this before clean, +cofiguration and header install steps described above. This will direct make to +build samples for the cross target:: + + export ARCH=arm64 + export CROSS_COMPILE="aarch64-linux-gnu-" + +Headers can be also installed on RFS of target board if need to keep them in +sync (not necessarily and it creates a local "usr/include" directory also):: + + make INSTALL_HDR_PATH=~/some_sysroot/usr headers_install + +Pointing LLC and CLANG is not necessarily if it's installed on HOST and have +in its targets appropriate arm64 arch (usually it has several arches). +Build samples:: + + make samples/bpf/ + +Or build samples with SYSROOT if some header or library is absent in toolchain, +say libelf, providing address to file system containing headers and libs, +can be RFS of target board:: -export ARCH=arm64 -export CROSS_COMPILE="aarch64-linux-gnu-" -make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang + make samples/bpf/ SYSROOT=~/some_sysroot -- cgit v1.2.3 From 3fbe31ae7ec4ec284a908cef7218f19e951ee55b Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 11 Oct 2019 15:01:45 -0700 Subject: selftests/bpf: Enforce libbpf build before BPF programs are built Given BPF programs rely on libbpf's bpf_helper_defs.h, which is auto-generated during libbpf build, libbpf build has to happen before we attempt progs/*.c build. Enforce it as order-only dependency. Fixes: 24f25763d6de ("libbpf: auto-generate list of BPF helper definitions") Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011220146.3798961-2-andriin@fb.com --- tools/testing/selftests/bpf/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 40552fb441e5..f958643d36da 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -256,7 +256,8 @@ ifeq ($(DWARF2BTF),y) $(BTF_PAHOLE) -J $@ endif -$(OUTPUT)/%.o: progs/%.c +# libbpf has to be built before BPF programs due to bpf_helper_defs.h +$(OUTPUT)/%.o: progs/%.c | $(BPFOBJ) ($(CLANG) $(BPF_CFLAGS) $(CLANG_CFLAGS) -O2 -target bpf -emit-llvm \ -c $< -o - || echo "clang failed") | \ $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ -- cgit v1.2.3 From 598dc04fa0f131371cb120f2bf4e594f42f00057 Mon Sep 17 00:00:00 2001 From: Andrii Nakryiko Date: Fri, 11 Oct 2019 15:01:46 -0700 Subject: selftests/bpf: Remove obsolete pahole/BTF support detection Given lots of selftests won't work without recent enough Clang/LLVM that fully supports BTF, there is no point in maintaining outdated BTF support detection and fall-back to pahole logic. Just assume we have everything we need. Signed-off-by: Andrii Nakryiko Signed-off-by: Alexei Starovoitov Link: https://lore.kernel.org/bpf/20191011220146.3798961-3-andriin@fb.com --- tools/testing/selftests/bpf/Makefile | 54 ++++-------------------------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f958643d36da..00d05c5e2d57 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -15,8 +15,6 @@ endif CLANG ?= clang LLC ?= llc LLVM_OBJCOPY ?= llvm-objcopy -LLVM_READELF ?= llvm-readelf -BTF_PAHOLE ?= pahole BPF_GCC ?= $(shell command -v bpf-gcc;) CFLAGS += -g -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(BPFDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include \ -Dbpf_prog_load=bpf_prog_test_load \ @@ -126,16 +124,6 @@ force: $(BPFOBJ): force $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/ -PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) - -# Let newer LLVM versions transparently probe the kernel for availability -# of full BPF instruction set. -ifeq ($(PROBE),) - CPU ?= probe -else - CPU ?= generic -endif - # Get Clang's default includes on this system, as opposed to those seen by # '-target bpf'. This fixes "missing" files on some architectures/distros, # such as asm/byteorder.h, asm/socket.h, asm/sockios.h, sys/cdefs.h etc. @@ -147,8 +135,9 @@ $(shell $(1) -v -E - &1 \ | sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }') endef CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG)) -BPF_CFLAGS = -I. -I./include/uapi -I../../../include/uapi \ - -I$(BPFDIR) -I$(OUTPUT)/../usr/include -D__TARGET_ARCH_$(SRCARCH) +BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \ + -I. -I./include/uapi -I../../../include/uapi \ + -I$(BPFDIR) -I$(OUTPUT)/../usr/include CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \ -Wno-compare-distinct-pointer-types @@ -162,28 +151,6 @@ $(OUTPUT)/test_stack_map.o: test_queue_stack_map.h $(OUTPUT)/flow_dissector_load.o: flow_dissector_load.h $(OUTPUT)/test_progs.o: flow_dissector_load.h -BTF_LLC_PROBE := $(shell $(LLC) -march=bpf -mattr=help 2>&1 | grep dwarfris) -BTF_PAHOLE_PROBE := $(shell $(BTF_PAHOLE) --help 2>&1 | grep BTF) -BTF_OBJCOPY_PROBE := $(shell $(LLVM_OBJCOPY) --help 2>&1 | grep -i 'usage.*llvm') -BTF_LLVM_PROBE := $(shell echo "int main() { return 0; }" | \ - $(CLANG) -target bpf -O2 -g -c -x c - -o ./llvm_btf_verify.o; \ - $(LLVM_READELF) -S ./llvm_btf_verify.o | grep BTF; \ - /bin/rm -f ./llvm_btf_verify.o) - -ifneq ($(BTF_LLVM_PROBE),) - BPF_CFLAGS += -g -else -ifneq ($(BTF_LLC_PROBE),) -ifneq ($(BTF_PAHOLE_PROBE),) -ifneq ($(BTF_OBJCOPY_PROBE),) - BPF_CFLAGS += -g - LLC_FLAGS += -mattr=dwarfris - DWARF2BTF = y -endif -endif -endif -endif - TEST_PROGS_CFLAGS := -I. -I$(OUTPUT) TEST_MAPS_CFLAGS := -I. -I$(OUTPUT) TEST_VERIFIER_CFLAGS := -I. -I$(OUTPUT) -Iverifier @@ -212,11 +179,8 @@ $(ALU32_BUILD_DIR)/%.o: progs/%.c $(ALU32_BUILD_DIR)/test_progs_32 \ | $(ALU32_BUILD_DIR) ($(CLANG) $(BPF_CFLAGS) $(CLANG_CFLAGS) -O2 -target bpf -emit-llvm \ -c $< -o - || echo "clang failed") | \ - $(LLC) -march=bpf -mattr=+alu32 -mcpu=$(CPU) $(LLC_FLAGS) \ + $(LLC) -march=bpf -mcpu=probe -mattr=+alu32 $(LLC_FLAGS) \ -filetype=obj -o $@ -ifeq ($(DWARF2BTF),y) - $(BTF_PAHOLE) -J $@ -endif endif ifneq ($(BPF_GCC),) @@ -251,19 +215,13 @@ endif $(OUTPUT)/test_xdp.o: progs/test_xdp.c ($(CLANG) $(BPF_CFLAGS) $(CLANG_CFLAGS) -O2 -emit-llvm -c $< -o - || \ echo "clang failed") | \ - $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ -ifeq ($(DWARF2BTF),y) - $(BTF_PAHOLE) -J $@ -endif + $(LLC) -march=bpf -mcpu=probe $(LLC_FLAGS) -filetype=obj -o $@ # libbpf has to be built before BPF programs due to bpf_helper_defs.h $(OUTPUT)/%.o: progs/%.c | $(BPFOBJ) ($(CLANG) $(BPF_CFLAGS) $(CLANG_CFLAGS) -O2 -target bpf -emit-llvm \ -c $< -o - || echo "clang failed") | \ - $(LLC) -march=bpf -mcpu=$(CPU) $(LLC_FLAGS) -filetype=obj -o $@ -ifeq ($(DWARF2BTF),y) - $(BTF_PAHOLE) -J $@ -endif + $(LLC) -march=bpf -mcpu=probe $(LLC_FLAGS) -filetype=obj -o $@ PROG_TESTS_DIR = $(OUTPUT)/prog_tests $(PROG_TESTS_DIR): -- cgit v1.2.3