Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1431466 > unrolled thread
| Started by | He Kuang <hekuang@huawei.com> |
|---|---|
| First post | 2016-06-26 13:30 +0200 |
| Last post | 2016-06-29 15:10 +0200 |
| Articles | 14 — 5 participants |
Back to article view | Back to linux.kernel
[RFC PATCH v2 00/26] perf tools: Support uBPF script He Kuang <hekuang@huawei.com> - 2016-06-26 13:30 +0200
[RFC PATCH v2 21/26] bpf: Support bpf load/store boundary check for ubpf He Kuang <hekuang@huawei.com> - 2016-06-26 13:30 +0200
[RFC PATCH v2 01/26] tools include: Adopt byte ordering macros from byteorder/generic.h He Kuang <hekuang@huawei.com> - 2016-06-26 13:30 +0200
[RFC PATCH v2 12/26] perf bpf: Add libbpf-internal.h header file He Kuang <hekuang@huawei.com> - 2016-06-26 13:30 +0200
[RFC PATCH v2 03/26] bpf: split __bpf_prog_run code into new file He Kuang <hekuang@huawei.com> - 2016-06-26 13:30 +0200
[RFC PATCH v2 06/26] tools include: Add (atomic|atomic64)_add implementation from the kernel sources He Kuang <hekuang@huawei.com> - 2016-06-26 13:30 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script Alexei Starovoitov <alexei.starovoitov@gmail.com> - 2016-06-26 22:50 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script Hekuang <hekuang@huawei.com> - 2016-06-27 04:20 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script Hekuang <hekuang@huawei.com> - 2016-06-28 14:00 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script Alexei Starovoitov <alexei.starovoitov@gmail.com> - 2016-06-28 17:00 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script Hekuang <hekuang@huawei.com> - 2016-06-29 12:20 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script "Wangnan (F)" <wangnan0@huawei.com> - 2016-06-29 12:50 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script Alexei Starovoitov <alexei.starovoitov@gmail.com> - 2016-06-29 14:40 +0200
Re: [RFC PATCH v2 00/26] perf tools: Support uBPF script pi3orama <pi3orama@163.com> - 2016-06-29 15:10 +0200
| From | He Kuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-26 13:30 +0200 |
| Subject | [RFC PATCH v2 00/26] perf tools: Support uBPF script |
| Message-ID | <rOgqd-2jQ-3@gated-at.bofh.it> |
This patchset is based on Wang Nan's v1:
http://thread.gmane.org/gmane.linux.kernel/2203717/focus=2203707
"""
This patch set allows to perf invoke some user space BPF scripts on
some point. uBPF scripts and kernel BPF scripts reside in one BPF
object. They communicate with each other with BPF maps. uBPF
scripts can invoke helper functions provided by perf.
At least following new features can be achieved based on uBPF
support:
1) Report statistical result:
Like DTrace, perf print statistical report before quit. No need
to extract data using 'perf report'. Statistical method is
controled by user.
2) Control perf's behavior:
Dynamically adjust period of different events. Policy is defined
by user.
"""
and modified by following the reviewers' suggestions.
v1-v2:
- Split bpf vm part out of kernel/bpf/core.c and link to it instead
of using ubpf library(Suggested by Alexei Starovoitov). And add
runtime bounds check just like ubpf library does.
- Introduce bpf_engine(engine-kbpf, engine-ubpf) operations and
getting rid of the complicate macros(Suggested by Arnaldo).
- Use void pointer to reference kbpf/ubpf entries.(Suggested by
Arnaldo)
The test case in the v1 cover letter still works but there's a slight
problem which should be pointed out to clarify the usage of ubpf
function arguments.
-int perf_record_end(int samples)
+struct perf_record_end_ctx {
+ int samples;
+ int dummy;
+};
+int perf_record_end(struct perf_record_end_ctx *ctx)
And the argument 'samples' should be referenced as 'ctx->samples'.
Thank you.
He Kuang (17):
bpf: extract jmp and default handler and introduce UBPF_BUILD flag
tools include: Add (atomic|atomic64)_add implementation from the
kernel sources
perf bpf: Implement empty instruction handler and build bpf-vm
perf bpf: Remove unused code in libbpf
perf bpf: Store arbitrary entries instread fd array in bpf_program
perf bpf: Add libbpf-internal.h header file
perf bpf: Add abstraction for bpf program methods
perf bpf: Add -Wextra to cflags for more warnings and fix them
perf bpf: Introduce the entity and engine for userspace bpf
perf bpf: Add method for fetching nth ubpf vm
perf bpf: Add methods to set/check ubpf engine for bpf programs
perf bpf: Add ubpf helper function slots and set/get methods
bpf: Support bpf load/store boundary check for ubpf
perf bpf: Implement boundary check code in ubpf
perf record: Add uBPF hooks at beginning and end of perf record
perf bpf: Fillup bpf jmp_call handler
perf bpf: Implement run_ubpf_program
Wang Nan (9):
tools include: Adopt byte ordering macros from byteorder/generic.h
tools include: Fix wrong macro definitions for cpu_to_le* for big
endian
bpf: split __bpf_prog_run code into new file
tools include: Sync math64.h and div64.h
perf bpf: Add map related BPF helper
perf bpf: Add UBPF flags and makefile options
perf tools: Register basic uBPF helpers
perf bpf: Accept uBPF programs
perf tests: Add uBPF test case
include/linux/filter.h | 1 +
kernel/bpf/Makefile | 2 +-
kernel/bpf/core.c | 487 -------------------
kernel/bpf/vm.c | 517 +++++++++++++++++++++
tools/arch/x86/include/asm/atomic.h | 28 ++
tools/include/asm-generic/atomic-gcc.h | 10 +
tools/include/asm-generic/div64.h | 234 ++++++++++
tools/include/linux/byteorder/generic.h | 48 ++
tools/include/linux/kernel.h | 7 +-
tools/include/linux/math64.h | 247 ++++++++++
tools/include/linux/types.h | 4 +
tools/lib/bpf/Build | 2 +
tools/lib/bpf/Makefile | 6 +-
tools/lib/bpf/bpf.c | 24 +
tools/lib/bpf/bpf.h | 2 +
tools/lib/bpf/engine-kbpf.c | 131 ++++++
tools/lib/bpf/engine-ubpf.c | 134 ++++++
tools/lib/bpf/libbpf-internal.h | 76 +++
tools/lib/bpf/libbpf.c | 216 ++-------
tools/lib/bpf/libbpf.h | 43 +-
tools/perf/MANIFEST | 3 +
tools/perf/Makefile.perf | 2 +
tools/perf/builtin-record.c | 4 +
tools/perf/config/Makefile | 4 +
tools/perf/perf.c | 3 +
tools/perf/tests/Build | 8 +
tools/perf/tests/bpf-script-test-ubpf.c | 88 ++++
tools/perf/tests/bpf.c | 78 +++-
tools/perf/tests/llvm.c | 4 +
tools/perf/tests/llvm.h | 2 +
tools/perf/util/Build | 3 +
tools/perf/util/bpf-loader.c | 23 +-
tools/perf/util/bpf-vm.c | 89 ++++
tools/perf/util/bpf-vm.h | 8 +
tools/perf/util/intel-bts.c | 5 -
.../util/intel-pt-decoder/intel-pt-pkt-decoder.c | 7 +-
tools/perf/util/ubpf-helpers-list.h | 11 +
tools/perf/util/ubpf-helpers.c | 73 +++
tools/perf/util/ubpf-helpers.h | 21 +
tools/perf/util/ubpf-hooks-list.h | 34 ++
tools/perf/util/ubpf-hooks.c | 81 ++++
tools/perf/util/ubpf-hooks.h | 41 ++
42 files changed, 2126 insertions(+), 685 deletions(-)
create mode 100644 kernel/bpf/vm.c
create mode 100644 tools/include/asm-generic/div64.h
create mode 100644 tools/include/linux/byteorder/generic.h
create mode 100644 tools/include/linux/math64.h
create mode 100644 tools/lib/bpf/engine-kbpf.c
create mode 100644 tools/lib/bpf/engine-ubpf.c
create mode 100644 tools/lib/bpf/libbpf-internal.h
create mode 100644 tools/perf/tests/bpf-script-test-ubpf.c
create mode 100644 tools/perf/util/bpf-vm.c
create mode 100644 tools/perf/util/bpf-vm.h
create mode 100644 tools/perf/util/ubpf-helpers-list.h
create mode 100644 tools/perf/util/ubpf-helpers.c
create mode 100644 tools/perf/util/ubpf-helpers.h
create mode 100644 tools/perf/util/ubpf-hooks-list.h
create mode 100644 tools/perf/util/ubpf-hooks.c
create mode 100644 tools/perf/util/ubpf-hooks.h
--
1.8.5.2
[toc] | [next] | [standalone]
| From | He Kuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-26 13:30 +0200 |
| Subject | [RFC PATCH v2 21/26] bpf: Support bpf load/store boundary check for ubpf |
| Message-ID | <rOgqf-2jQ-67@gated-at.bofh.it> |
| In reply to | #1431466 |
A boundary check is added before each store/load instruction, since we
don't have a verifier in userspace bpf. There's no functionality
change without UBPF_BUILD flag.
Signed-off-by: He Kuang <hekuang@huawei.com>
---
kernel/bpf/vm.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/vm.c b/kernel/bpf/vm.c
index add5669..0ddb592 100644
--- a/kernel/bpf/vm.c
+++ b/kernel/bpf/vm.c
@@ -76,9 +76,13 @@ static inline int bpf_vm_jmp_tail_call_handler(u64 *regs, u32 *p_tail_call_cnt,
*p_insn = prog->insnsi;
return 0;
}
-#endif /* UBPF_BUILD */
-
+#define BOUNDS_CHECK_STORE(size)
+#define BOUNDS_CHECK_LOAD(size)
unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
+#else
+unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn,
+ size_t ctx_len)
+#endif /* UBPF_BUILD */
{
u64 stack[MAX_BPF_STACK / sizeof(u64)];
u64 regs[MAX_BPF_REG], tmp;
@@ -419,12 +423,15 @@ select_insn:
/* STX and ST and LDX*/
#define LDST(SIZEOP, SIZE) \
STX_MEM_##SIZEOP: \
+ BOUNDS_CHECK_STORE(sizeof(SIZE)); \
*(SIZE *)(unsigned long) (DST + insn->off) = SRC; \
CONT; \
ST_MEM_##SIZEOP: \
+ BOUNDS_CHECK_STORE(sizeof(SIZE)); \
*(SIZE *)(unsigned long) (DST + insn->off) = IMM; \
CONT; \
LDX_MEM_##SIZEOP: \
+ BOUNDS_CHECK_LOAD(sizeof(SIZE)); \
DST = *(SIZE *)(unsigned long) (SRC + insn->off); \
CONT;
--
1.8.5.2
[toc] | [prev] | [next] | [standalone]
| From | He Kuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-26 13:30 +0200 |
| Subject | [RFC PATCH v2 01/26] tools include: Adopt byte ordering macros from byteorder/generic.h |
| Message-ID | <rOgqf-2jQ-61@gated-at.bofh.it> |
| In reply to | #1431466 |
From: Wang Nan <wangnan0@huawei.com> This patch adopts the macros for byte order conversion from "include/linux/byteorder/generic.h" to "tools/include/linux/byteorder/generic.h" tools/perf/MANIFEST is also updated for 'make perf-*-src-pkg'. Signed-off-by: Wang Nan <wangnan0@huawei.com> Signed-off-by: He Kuang <hekuang@huawei.com> --- tools/include/linux/byteorder/generic.h | 48 +++++++++++++++++++++++++++++++++ tools/perf/MANIFEST | 1 + 2 files changed, 49 insertions(+) create mode 100644 tools/include/linux/byteorder/generic.h diff --git a/tools/include/linux/byteorder/generic.h b/tools/include/linux/byteorder/generic.h new file mode 100644 index 0000000..41b4507 --- /dev/null +++ b/tools/include/linux/byteorder/generic.h @@ -0,0 +1,48 @@ +#ifndef _TOOLS_LINUX_BYTEORDER_GENERIC_H +#define _TOOLS_LINUX_BYTEORDER_GENERIC_H + +#include <endian.h> +#include <byteswap.h> + +#define cpu_to_le64 __cpu_to_le64 +#define le64_to_cpu __le64_to_cpu +#define cpu_to_le32 __cpu_to_le32 +#define le32_to_cpu __le32_to_cpu +#define cpu_to_le16 __cpu_to_le16 +#define le16_to_cpu __le16_to_cpu +#define cpu_to_be64 __cpu_to_be64 +#define be64_to_cpu __be64_to_cpu +#define cpu_to_be32 __cpu_to_be32 +#define be32_to_cpu __be32_to_cpu +#define cpu_to_be16 __cpu_to_be16 +#define be16_to_cpu __be16_to_cpu + +#if __BYTE_ORDER == __BIG_ENDIAN +#define __cpu_to_le16 bswap_16 +#define __cpu_to_le32 bswap_32 +#define __cpu_to_le64 bswap_64 +#define __le16_to_cpu bswap_16 +#define __le32_to_cpu bswap_32 +#define __le64_to_cpu bswap_64 +#define __cpu_to_be16 +#define __cpu_to_be32 +#define __cpu_to_be64 +#define __be16_to_cpu +#define __be32_to_cpu +#define __be64_to_cpu +#else +#define __cpu_to_le16 +#define __cpu_to_le32 +#define __cpu_to_le64 +#define __le16_to_cpu +#define __le32_to_cpu +#define __le64_to_cpu +#define __cpu_to_be16 bswap_16 +#define __cpu_to_be32 bswap_32 +#define __cpu_to_be64 bswap_64 +#define __be16_to_cpu bswap_16 +#define __be32_to_cpu bswap_32 +#define __be64_to_cpu bswap_64 +#endif + +#endif /* _TOOLS_LINUX_BYTEORDER_GENERIC_H */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 8c8c6b9..80ac3d4 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -46,6 +46,7 @@ tools/include/asm-generic/bitops/hweight.h tools/include/asm-generic/bitops.h tools/include/linux/atomic.h tools/include/linux/bitops.h +tools/include/linux/byteorder/generic.h tools/include/linux/compiler.h tools/include/linux/filter.h tools/include/linux/hash.h -- 1.8.5.2
[toc] | [prev] | [next] | [standalone]
| From | He Kuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-26 13:30 +0200 |
| Subject | [RFC PATCH v2 12/26] perf bpf: Add libbpf-internal.h header file |
| Message-ID | <rOgqf-2jQ-69@gated-at.bofh.it> |
| In reply to | #1431466 |
Split part of codes in libbpf.c out for internal usage, debug print
functions are changed to non-static for other files to use.
Signed-off-by: He Kuang <hekuang@huawei.com>
---
tools/lib/bpf/libbpf-internal.h | 65 +++++++++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf.c | 68 +++++------------------------------------
2 files changed, 72 insertions(+), 61 deletions(-)
create mode 100644 tools/lib/bpf/libbpf-internal.h
diff --git a/tools/lib/bpf/libbpf-internal.h b/tools/lib/bpf/libbpf-internal.h
new file mode 100644
index 0000000..1c1619c
--- /dev/null
+++ b/tools/lib/bpf/libbpf-internal.h
@@ -0,0 +1,65 @@
+#ifndef _LIBBPF_INTERNAL_H
+#define _LIBBPF_INTERNAL_H
+
+#include "libbpf.h"
+
+#define __printf(a, b) __attribute__((format(printf, a, b)))
+
+#define __pr(func, fmt, ...) \
+do { \
+ if ((func)) \
+ (func)("libbpf: " fmt, ##__VA_ARGS__); \
+} while (0)
+
+extern libbpf_print_fn_t __pr_bpf_warning;
+extern libbpf_print_fn_t __pr_bpf_info;
+extern libbpf_print_fn_t __pr_bpf_debug;
+
+#define pr_warning(fmt, ...) __pr(__pr_bpf_warning, fmt, ##__VA_ARGS__)
+#define pr_info(fmt, ...) __pr(__pr_bpf_info, fmt, ##__VA_ARGS__)
+#define pr_debug(fmt, ...) __pr(__pr_bpf_debug, fmt, ##__VA_ARGS__)
+
+/* Copied from tools/perf/util/util.h */
+#ifndef zfree
+# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
+#endif
+
+#ifndef zclose
+# define zclose(fd) ({ \
+ int ___err = 0; \
+ if ((fd) >= 0) \
+ ___err = close((fd)); \
+ fd = -1; \
+ ___err; })
+#endif
+
+/*
+ * bpf_prog should be a better name but it has been used in
+ * linux/filter.h.
+ */
+struct bpf_program {
+ /* Index in elf obj file, for relocation use. */
+ int idx;
+ char *section_name;
+ struct bpf_insn *insns;
+ size_t insns_cnt;
+
+ struct {
+ int insn_idx;
+ int map_idx;
+ } *reloc_desc;
+ int nr_reloc;
+
+ struct bpf_engine *engine;
+ struct {
+ int nr;
+ void *entries;
+ } instances;
+ bpf_program_prep_t preprocessor;
+
+ struct bpf_object *obj;
+ void *priv;
+ bpf_program_clear_priv_t clear_priv;
+};
+
+#endif /* _LIBBPF_INTERNAL_H */
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 97f72b2..0ad6c9e 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -23,8 +23,7 @@
#include "libbpf.h"
#include "bpf.h"
-
-#define __printf(a, b) __attribute__((format(printf, a, b)))
+#include "libbpf-internal.h"
__printf(1, 2)
static int __base_pr(const char *format, ...)
@@ -38,27 +37,17 @@ static int __base_pr(const char *format, ...)
return err;
}
-static __printf(1, 2) libbpf_print_fn_t __pr_warning = __base_pr;
-static __printf(1, 2) libbpf_print_fn_t __pr_info = __base_pr;
-static __printf(1, 2) libbpf_print_fn_t __pr_debug;
-
-#define __pr(func, fmt, ...) \
-do { \
- if ((func)) \
- (func)("libbpf: " fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define pr_warning(fmt, ...) __pr(__pr_warning, fmt, ##__VA_ARGS__)
-#define pr_info(fmt, ...) __pr(__pr_info, fmt, ##__VA_ARGS__)
-#define pr_debug(fmt, ...) __pr(__pr_debug, fmt, ##__VA_ARGS__)
+__printf(1, 2) libbpf_print_fn_t __pr_bpf_warning = __base_pr;
+__printf(1, 2) libbpf_print_fn_t __pr_bpf_info = __base_pr;
+__printf(1, 2) libbpf_print_fn_t __pr_bpf_debug;
void libbpf_set_print(libbpf_print_fn_t warn,
libbpf_print_fn_t info,
libbpf_print_fn_t debug)
{
- __pr_warning = warn;
- __pr_info = info;
- __pr_debug = debug;
+ __pr_bpf_warning = warn;
+ __pr_bpf_info = info;
+ __pr_bpf_debug = debug;
}
#define STRERR_BUFSIZE 128
@@ -114,55 +103,12 @@ int libbpf_strerror(int err, char *buf, size_t size)
goto out; \
} while(0)
-
-/* Copied from tools/perf/util/util.h */
-#ifndef zfree
-# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
-#endif
-
-#ifndef zclose
-# define zclose(fd) ({ \
- int ___err = 0; \
- if ((fd) >= 0) \
- ___err = close((fd)); \
- fd = -1; \
- ___err; })
-#endif
-
#ifdef HAVE_LIBELF_MMAP_SUPPORT
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ_MMAP
#else
# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
#endif
-/*
- * bpf_prog should be a better name but it has been used in
- * linux/filter.h.
- */
-struct bpf_program {
- /* Index in elf obj file, for relocation use. */
- int idx;
- char *section_name;
- struct bpf_insn *insns;
- size_t insns_cnt;
-
- struct {
- int insn_idx;
- int map_idx;
- } *reloc_desc;
- int nr_reloc;
-
- struct {
- int nr;
- void *entries;
- } instances;
- bpf_program_prep_t preprocessor;
-
- struct bpf_object *obj;
- void *priv;
- bpf_program_clear_priv_t clear_priv;
-};
-
struct bpf_map {
int fd;
char *name;
--
1.8.5.2
[toc] | [prev] | [next] | [standalone]
| From | He Kuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-26 13:30 +0200 |
| Subject | [RFC PATCH v2 03/26] bpf: split __bpf_prog_run code into new file |
| Message-ID | <rOgqf-2jQ-57@gated-at.bofh.it> |
| In reply to | #1431466 |
From: Wang Nan <wangnan0@huawei.com>
Split out function __bpf_prog_run() and related macros from bpf/core.c
into bpf/vm.c.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@huawei.com>
---
include/linux/filter.h | 1 +
kernel/bpf/Makefile | 2 +-
kernel/bpf/core.c | 487 ------------------------------------------------
kernel/bpf/vm.c | 492 +++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 494 insertions(+), 488 deletions(-)
create mode 100644 kernel/bpf/vm.c
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 6fc31ef..71da095 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -504,6 +504,7 @@ void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp);
u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
+unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn);
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog);
bool bpf_helper_changes_skb_data(void *func);
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index eed911d..6958399 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -1,4 +1,4 @@
-obj-y := core.o
+obj-y := core.o vm.o
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index b94a365..4f20791 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -31,27 +31,6 @@
#include <asm/unaligned.h>
-/* Registers */
-#define BPF_R0 regs[BPF_REG_0]
-#define BPF_R1 regs[BPF_REG_1]
-#define BPF_R2 regs[BPF_REG_2]
-#define BPF_R3 regs[BPF_REG_3]
-#define BPF_R4 regs[BPF_REG_4]
-#define BPF_R5 regs[BPF_REG_5]
-#define BPF_R6 regs[BPF_REG_6]
-#define BPF_R7 regs[BPF_REG_7]
-#define BPF_R8 regs[BPF_REG_8]
-#define BPF_R9 regs[BPF_REG_9]
-#define BPF_R10 regs[BPF_REG_10]
-
-/* Named registers */
-#define DST regs[insn->dst_reg]
-#define SRC regs[insn->src_reg]
-#define FP regs[BPF_REG_FP]
-#define ARG1 regs[BPF_REG_ARG1]
-#define CTX regs[BPF_REG_CTX]
-#define IMM insn->imm
-
/* No hurry in this branch
*
* Exported for the bpf jit load helper.
@@ -458,472 +437,6 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
}
EXPORT_SYMBOL_GPL(__bpf_call_base);
-/**
- * __bpf_prog_run - run eBPF program on a given context
- * @ctx: is the data we are operating on
- * @insn: is the array of eBPF instructions
- *
- * Decode and execute eBPF instructions.
- */
-static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
-{
- u64 stack[MAX_BPF_STACK / sizeof(u64)];
- u64 regs[MAX_BPF_REG], tmp;
- static const void *jumptable[256] = {
- [0 ... 255] = &&default_label,
- /* Now overwrite non-defaults ... */
- /* 32 bit ALU operations */
- [BPF_ALU | BPF_ADD | BPF_X] = &&ALU_ADD_X,
- [BPF_ALU | BPF_ADD | BPF_K] = &&ALU_ADD_K,
- [BPF_ALU | BPF_SUB | BPF_X] = &&ALU_SUB_X,
- [BPF_ALU | BPF_SUB | BPF_K] = &&ALU_SUB_K,
- [BPF_ALU | BPF_AND | BPF_X] = &&ALU_AND_X,
- [BPF_ALU | BPF_AND | BPF_K] = &&ALU_AND_K,
- [BPF_ALU | BPF_OR | BPF_X] = &&ALU_OR_X,
- [BPF_ALU | BPF_OR | BPF_K] = &&ALU_OR_K,
- [BPF_ALU | BPF_LSH | BPF_X] = &&ALU_LSH_X,
- [BPF_ALU | BPF_LSH | BPF_K] = &&ALU_LSH_K,
- [BPF_ALU | BPF_RSH | BPF_X] = &&ALU_RSH_X,
- [BPF_ALU | BPF_RSH | BPF_K] = &&ALU_RSH_K,
- [BPF_ALU | BPF_XOR | BPF_X] = &&ALU_XOR_X,
- [BPF_ALU | BPF_XOR | BPF_K] = &&ALU_XOR_K,
- [BPF_ALU | BPF_MUL | BPF_X] = &&ALU_MUL_X,
- [BPF_ALU | BPF_MUL | BPF_K] = &&ALU_MUL_K,
- [BPF_ALU | BPF_MOV | BPF_X] = &&ALU_MOV_X,
- [BPF_ALU | BPF_MOV | BPF_K] = &&ALU_MOV_K,
- [BPF_ALU | BPF_DIV | BPF_X] = &&ALU_DIV_X,
- [BPF_ALU | BPF_DIV | BPF_K] = &&ALU_DIV_K,
- [BPF_ALU | BPF_MOD | BPF_X] = &&ALU_MOD_X,
- [BPF_ALU | BPF_MOD | BPF_K] = &&ALU_MOD_K,
- [BPF_ALU | BPF_NEG] = &&ALU_NEG,
- [BPF_ALU | BPF_END | BPF_TO_BE] = &&ALU_END_TO_BE,
- [BPF_ALU | BPF_END | BPF_TO_LE] = &&ALU_END_TO_LE,
- /* 64 bit ALU operations */
- [BPF_ALU64 | BPF_ADD | BPF_X] = &&ALU64_ADD_X,
- [BPF_ALU64 | BPF_ADD | BPF_K] = &&ALU64_ADD_K,
- [BPF_ALU64 | BPF_SUB | BPF_X] = &&ALU64_SUB_X,
- [BPF_ALU64 | BPF_SUB | BPF_K] = &&ALU64_SUB_K,
- [BPF_ALU64 | BPF_AND | BPF_X] = &&ALU64_AND_X,
- [BPF_ALU64 | BPF_AND | BPF_K] = &&ALU64_AND_K,
- [BPF_ALU64 | BPF_OR | BPF_X] = &&ALU64_OR_X,
- [BPF_ALU64 | BPF_OR | BPF_K] = &&ALU64_OR_K,
- [BPF_ALU64 | BPF_LSH | BPF_X] = &&ALU64_LSH_X,
- [BPF_ALU64 | BPF_LSH | BPF_K] = &&ALU64_LSH_K,
- [BPF_ALU64 | BPF_RSH | BPF_X] = &&ALU64_RSH_X,
- [BPF_ALU64 | BPF_RSH | BPF_K] = &&ALU64_RSH_K,
- [BPF_ALU64 | BPF_XOR | BPF_X] = &&ALU64_XOR_X,
- [BPF_ALU64 | BPF_XOR | BPF_K] = &&ALU64_XOR_K,
- [BPF_ALU64 | BPF_MUL | BPF_X] = &&ALU64_MUL_X,
- [BPF_ALU64 | BPF_MUL | BPF_K] = &&ALU64_MUL_K,
- [BPF_ALU64 | BPF_MOV | BPF_X] = &&ALU64_MOV_X,
- [BPF_ALU64 | BPF_MOV | BPF_K] = &&ALU64_MOV_K,
- [BPF_ALU64 | BPF_ARSH | BPF_X] = &&ALU64_ARSH_X,
- [BPF_ALU64 | BPF_ARSH | BPF_K] = &&ALU64_ARSH_K,
- [BPF_ALU64 | BPF_DIV | BPF_X] = &&ALU64_DIV_X,
- [BPF_ALU64 | BPF_DIV | BPF_K] = &&ALU64_DIV_K,
- [BPF_ALU64 | BPF_MOD | BPF_X] = &&ALU64_MOD_X,
- [BPF_ALU64 | BPF_MOD | BPF_K] = &&ALU64_MOD_K,
- [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG,
- /* Call instruction */
- [BPF_JMP | BPF_CALL] = &&JMP_CALL,
- [BPF_JMP | BPF_CALL | BPF_X] = &&JMP_TAIL_CALL,
- /* Jumps */
- [BPF_JMP | BPF_JA] = &&JMP_JA,
- [BPF_JMP | BPF_JEQ | BPF_X] = &&JMP_JEQ_X,
- [BPF_JMP | BPF_JEQ | BPF_K] = &&JMP_JEQ_K,
- [BPF_JMP | BPF_JNE | BPF_X] = &&JMP_JNE_X,
- [BPF_JMP | BPF_JNE | BPF_K] = &&JMP_JNE_K,
- [BPF_JMP | BPF_JGT | BPF_X] = &&JMP_JGT_X,
- [BPF_JMP | BPF_JGT | BPF_K] = &&JMP_JGT_K,
- [BPF_JMP | BPF_JGE | BPF_X] = &&JMP_JGE_X,
- [BPF_JMP | BPF_JGE | BPF_K] = &&JMP_JGE_K,
- [BPF_JMP | BPF_JSGT | BPF_X] = &&JMP_JSGT_X,
- [BPF_JMP | BPF_JSGT | BPF_K] = &&JMP_JSGT_K,
- [BPF_JMP | BPF_JSGE | BPF_X] = &&JMP_JSGE_X,
- [BPF_JMP | BPF_JSGE | BPF_K] = &&JMP_JSGE_K,
- [BPF_JMP | BPF_JSET | BPF_X] = &&JMP_JSET_X,
- [BPF_JMP | BPF_JSET | BPF_K] = &&JMP_JSET_K,
- /* Program return */
- [BPF_JMP | BPF_EXIT] = &&JMP_EXIT,
- /* Store instructions */
- [BPF_STX | BPF_MEM | BPF_B] = &&STX_MEM_B,
- [BPF_STX | BPF_MEM | BPF_H] = &&STX_MEM_H,
- [BPF_STX | BPF_MEM | BPF_W] = &&STX_MEM_W,
- [BPF_STX | BPF_MEM | BPF_DW] = &&STX_MEM_DW,
- [BPF_STX | BPF_XADD | BPF_W] = &&STX_XADD_W,
- [BPF_STX | BPF_XADD | BPF_DW] = &&STX_XADD_DW,
- [BPF_ST | BPF_MEM | BPF_B] = &&ST_MEM_B,
- [BPF_ST | BPF_MEM | BPF_H] = &&ST_MEM_H,
- [BPF_ST | BPF_MEM | BPF_W] = &&ST_MEM_W,
- [BPF_ST | BPF_MEM | BPF_DW] = &&ST_MEM_DW,
- /* Load instructions */
- [BPF_LDX | BPF_MEM | BPF_B] = &&LDX_MEM_B,
- [BPF_LDX | BPF_MEM | BPF_H] = &&LDX_MEM_H,
- [BPF_LDX | BPF_MEM | BPF_W] = &&LDX_MEM_W,
- [BPF_LDX | BPF_MEM | BPF_DW] = &&LDX_MEM_DW,
- [BPF_LD | BPF_ABS | BPF_W] = &&LD_ABS_W,
- [BPF_LD | BPF_ABS | BPF_H] = &&LD_ABS_H,
- [BPF_LD | BPF_ABS | BPF_B] = &&LD_ABS_B,
- [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W,
- [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H,
- [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B,
- [BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW,
- };
- u32 tail_call_cnt = 0;
- void *ptr;
- int off;
-
-#define CONT ({ insn++; goto select_insn; })
-#define CONT_JMP ({ insn++; goto select_insn; })
-
- FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)];
- ARG1 = (u64) (unsigned long) ctx;
-
-select_insn:
- goto *jumptable[insn->code];
-
- /* ALU */
-#define ALU(OPCODE, OP) \
- ALU64_##OPCODE##_X: \
- DST = DST OP SRC; \
- CONT; \
- ALU_##OPCODE##_X: \
- DST = (u32) DST OP (u32) SRC; \
- CONT; \
- ALU64_##OPCODE##_K: \
- DST = DST OP IMM; \
- CONT; \
- ALU_##OPCODE##_K: \
- DST = (u32) DST OP (u32) IMM; \
- CONT;
-
- ALU(ADD, +)
- ALU(SUB, -)
- ALU(AND, &)
- ALU(OR, |)
- ALU(LSH, <<)
- ALU(RSH, >>)
- ALU(XOR, ^)
- ALU(MUL, *)
-#undef ALU
- ALU_NEG:
- DST = (u32) -DST;
- CONT;
- ALU64_NEG:
- DST = -DST;
- CONT;
- ALU_MOV_X:
- DST = (u32) SRC;
- CONT;
- ALU_MOV_K:
- DST = (u32) IMM;
- CONT;
- ALU64_MOV_X:
- DST = SRC;
- CONT;
- ALU64_MOV_K:
- DST = IMM;
- CONT;
- LD_IMM_DW:
- DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32;
- insn++;
- CONT;
- ALU64_ARSH_X:
- (*(s64 *) &DST) >>= SRC;
- CONT;
- ALU64_ARSH_K:
- (*(s64 *) &DST) >>= IMM;
- CONT;
- ALU64_MOD_X:
- if (unlikely(SRC == 0))
- return 0;
- div64_u64_rem(DST, SRC, &tmp);
- DST = tmp;
- CONT;
- ALU_MOD_X:
- if (unlikely(SRC == 0))
- return 0;
- tmp = (u32) DST;
- DST = do_div(tmp, (u32) SRC);
- CONT;
- ALU64_MOD_K:
- div64_u64_rem(DST, IMM, &tmp);
- DST = tmp;
- CONT;
- ALU_MOD_K:
- tmp = (u32) DST;
- DST = do_div(tmp, (u32) IMM);
- CONT;
- ALU64_DIV_X:
- if (unlikely(SRC == 0))
- return 0;
- DST = div64_u64(DST, SRC);
- CONT;
- ALU_DIV_X:
- if (unlikely(SRC == 0))
- return 0;
- tmp = (u32) DST;
- do_div(tmp, (u32) SRC);
- DST = (u32) tmp;
- CONT;
- ALU64_DIV_K:
- DST = div64_u64(DST, IMM);
- CONT;
- ALU_DIV_K:
- tmp = (u32) DST;
- do_div(tmp, (u32) IMM);
- DST = (u32) tmp;
- CONT;
- ALU_END_TO_BE:
- switch (IMM) {
- case 16:
- DST = (__force u16) cpu_to_be16(DST);
- break;
- case 32:
- DST = (__force u32) cpu_to_be32(DST);
- break;
- case 64:
- DST = (__force u64) cpu_to_be64(DST);
- break;
- }
- CONT;
- ALU_END_TO_LE:
- switch (IMM) {
- case 16:
- DST = (__force u16) cpu_to_le16(DST);
- break;
- case 32:
- DST = (__force u32) cpu_to_le32(DST);
- break;
- case 64:
- DST = (__force u64) cpu_to_le64(DST);
- break;
- }
- CONT;
-
- /* CALL */
- JMP_CALL:
- /* Function call scratches BPF_R1-BPF_R5 registers,
- * preserves BPF_R6-BPF_R9, and stores return value
- * into BPF_R0.
- */
- BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3,
- BPF_R4, BPF_R5);
- CONT;
-
- JMP_TAIL_CALL: {
- struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
- struct bpf_array *array = container_of(map, struct bpf_array, map);
- struct bpf_prog *prog;
- u64 index = BPF_R3;
-
- if (unlikely(index >= array->map.max_entries))
- goto out;
-
- if (unlikely(tail_call_cnt > MAX_TAIL_CALL_CNT))
- goto out;
-
- tail_call_cnt++;
-
- prog = READ_ONCE(array->ptrs[index]);
- if (unlikely(!prog))
- goto out;
-
- /* ARG1 at this point is guaranteed to point to CTX from
- * the verifier side due to the fact that the tail call is
- * handeled like a helper, that is, bpf_tail_call_proto,
- * where arg1_type is ARG_PTR_TO_CTX.
- */
- insn = prog->insnsi;
- goto select_insn;
-out:
- CONT;
- }
- /* JMP */
- JMP_JA:
- insn += insn->off;
- CONT;
- JMP_JEQ_X:
- if (DST == SRC) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JEQ_K:
- if (DST == IMM) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JNE_X:
- if (DST != SRC) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JNE_K:
- if (DST != IMM) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JGT_X:
- if (DST > SRC) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JGT_K:
- if (DST > IMM) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JGE_X:
- if (DST >= SRC) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JGE_K:
- if (DST >= IMM) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JSGT_X:
- if (((s64) DST) > ((s64) SRC)) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JSGT_K:
- if (((s64) DST) > ((s64) IMM)) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JSGE_X:
- if (((s64) DST) >= ((s64) SRC)) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JSGE_K:
- if (((s64) DST) >= ((s64) IMM)) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JSET_X:
- if (DST & SRC) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_JSET_K:
- if (DST & IMM) {
- insn += insn->off;
- CONT_JMP;
- }
- CONT;
- JMP_EXIT:
- return BPF_R0;
-
- /* STX and ST and LDX*/
-#define LDST(SIZEOP, SIZE) \
- STX_MEM_##SIZEOP: \
- *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \
- CONT; \
- ST_MEM_##SIZEOP: \
- *(SIZE *)(unsigned long) (DST + insn->off) = IMM; \
- CONT; \
- LDX_MEM_##SIZEOP: \
- DST = *(SIZE *)(unsigned long) (SRC + insn->off); \
- CONT;
-
- LDST(B, u8)
- LDST(H, u16)
- LDST(W, u32)
- LDST(DW, u64)
-#undef LDST
- STX_XADD_W: /* lock xadd *(u32 *)(dst_reg + off16) += src_reg */
- atomic_add((u32) SRC, (atomic_t *)(unsigned long)
- (DST + insn->off));
- CONT;
- STX_XADD_DW: /* lock xadd *(u64 *)(dst_reg + off16) += src_reg */
- atomic64_add((u64) SRC, (atomic64_t *)(unsigned long)
- (DST + insn->off));
- CONT;
- LD_ABS_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + imm32)) */
- off = IMM;
-load_word:
- /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are
- * only appearing in the programs where ctx ==
- * skb. All programs keep 'ctx' in regs[BPF_REG_CTX]
- * == BPF_R6, bpf_convert_filter() saves it in BPF_R6,
- * internal BPF verifier will check that BPF_R6 ==
- * ctx.
- *
- * BPF_ABS and BPF_IND are wrappers of function calls,
- * so they scratch BPF_R1-BPF_R5 registers, preserve
- * BPF_R6-BPF_R9, and store return value into BPF_R0.
- *
- * Implicit input:
- * ctx == skb == BPF_R6 == CTX
- *
- * Explicit input:
- * SRC == any register
- * IMM == 32-bit immediate
- *
- * Output:
- * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness
- */
-
- ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp);
- if (likely(ptr != NULL)) {
- BPF_R0 = get_unaligned_be32(ptr);
- CONT;
- }
-
- return 0;
- LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */
- off = IMM;
-load_half:
- ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp);
- if (likely(ptr != NULL)) {
- BPF_R0 = get_unaligned_be16(ptr);
- CONT;
- }
-
- return 0;
- LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */
- off = IMM;
-load_byte:
- ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp);
- if (likely(ptr != NULL)) {
- BPF_R0 = *(u8 *)ptr;
- CONT;
- }
-
- return 0;
- LD_IND_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + src_reg + imm32)) */
- off = IMM + SRC;
- goto load_word;
- LD_IND_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + src_reg + imm32)) */
- off = IMM + SRC;
- goto load_half;
- LD_IND_B: /* BPF_R0 = *(u8 *) (skb->data + src_reg + imm32) */
- off = IMM + SRC;
- goto load_byte;
-
- default_label:
- /* If we ever reach this, we have a bug somewhere. */
- WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code);
- return 0;
-}
-STACK_FRAME_NON_STANDARD(__bpf_prog_run); /* jump table */
-
bool bpf_prog_array_compatible(struct bpf_array *array,
const struct bpf_prog *fp)
{
diff --git a/kernel/bpf/vm.c b/kernel/bpf/vm.c
new file mode 100644
index 0000000..45a2880
--- /dev/null
+++ b/kernel/bpf/vm.c
@@ -0,0 +1,492 @@
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+#include <linux/byteorder/generic.h>
+#include <linux/ratelimit.h>
+#include <linux/compiler.h>
+#include <linux/export.h>
+#include <linux/filter.h>
+#include <linux/kernel.h>
+#include <linux/math64.h>
+#include <linux/frame.h>
+#include <linux/bpf.h>
+
+/* Registers */
+#define BPF_R0 regs[BPF_REG_0]
+#define BPF_R1 regs[BPF_REG_1]
+#define BPF_R2 regs[BPF_REG_2]
+#define BPF_R3 regs[BPF_REG_3]
+#define BPF_R4 regs[BPF_REG_4]
+#define BPF_R5 regs[BPF_REG_5]
+#define BPF_R6 regs[BPF_REG_6]
+#define BPF_R7 regs[BPF_REG_7]
+#define BPF_R8 regs[BPF_REG_8]
+#define BPF_R9 regs[BPF_REG_9]
+#define BPF_R10 regs[BPF_REG_10]
+
+/* Named registers */
+#define DST regs[insn->dst_reg]
+#define SRC regs[insn->src_reg]
+#define FP regs[BPF_REG_FP]
+#define ARG1 regs[BPF_REG_ARG1]
+#define CTX regs[BPF_REG_CTX]
+#define IMM insn->imm
+
+unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
+{
+ u64 stack[MAX_BPF_STACK / sizeof(u64)];
+ u64 regs[MAX_BPF_REG], tmp;
+ static const void *jumptable[256] = {
+ [0 ... 255] = &&default_label,
+ /* Now overwrite non-defaults ... */
+ /* 32 bit ALU operations */
+ [BPF_ALU | BPF_ADD | BPF_X] = &&ALU_ADD_X,
+ [BPF_ALU | BPF_ADD | BPF_K] = &&ALU_ADD_K,
+ [BPF_ALU | BPF_SUB | BPF_X] = &&ALU_SUB_X,
+ [BPF_ALU | BPF_SUB | BPF_K] = &&ALU_SUB_K,
+ [BPF_ALU | BPF_AND | BPF_X] = &&ALU_AND_X,
+ [BPF_ALU | BPF_AND | BPF_K] = &&ALU_AND_K,
+ [BPF_ALU | BPF_OR | BPF_X] = &&ALU_OR_X,
+ [BPF_ALU | BPF_OR | BPF_K] = &&ALU_OR_K,
+ [BPF_ALU | BPF_LSH | BPF_X] = &&ALU_LSH_X,
+ [BPF_ALU | BPF_LSH | BPF_K] = &&ALU_LSH_K,
+ [BPF_ALU | BPF_RSH | BPF_X] = &&ALU_RSH_X,
+ [BPF_ALU | BPF_RSH | BPF_K] = &&ALU_RSH_K,
+ [BPF_ALU | BPF_XOR | BPF_X] = &&ALU_XOR_X,
+ [BPF_ALU | BPF_XOR | BPF_K] = &&ALU_XOR_K,
+ [BPF_ALU | BPF_MUL | BPF_X] = &&ALU_MUL_X,
+ [BPF_ALU | BPF_MUL | BPF_K] = &&ALU_MUL_K,
+ [BPF_ALU | BPF_MOV | BPF_X] = &&ALU_MOV_X,
+ [BPF_ALU | BPF_MOV | BPF_K] = &&ALU_MOV_K,
+ [BPF_ALU | BPF_DIV | BPF_X] = &&ALU_DIV_X,
+ [BPF_ALU | BPF_DIV | BPF_K] = &&ALU_DIV_K,
+ [BPF_ALU | BPF_MOD | BPF_X] = &&ALU_MOD_X,
+ [BPF_ALU | BPF_MOD | BPF_K] = &&ALU_MOD_K,
+ [BPF_ALU | BPF_NEG] = &&ALU_NEG,
+ [BPF_ALU | BPF_END | BPF_TO_BE] = &&ALU_END_TO_BE,
+ [BPF_ALU | BPF_END | BPF_TO_LE] = &&ALU_END_TO_LE,
+ /* 64 bit ALU operations */
+ [BPF_ALU64 | BPF_ADD | BPF_X] = &&ALU64_ADD_X,
+ [BPF_ALU64 | BPF_ADD | BPF_K] = &&ALU64_ADD_K,
+ [BPF_ALU64 | BPF_SUB | BPF_X] = &&ALU64_SUB_X,
+ [BPF_ALU64 | BPF_SUB | BPF_K] = &&ALU64_SUB_K,
+ [BPF_ALU64 | BPF_AND | BPF_X] = &&ALU64_AND_X,
+ [BPF_ALU64 | BPF_AND | BPF_K] = &&ALU64_AND_K,
+ [BPF_ALU64 | BPF_OR | BPF_X] = &&ALU64_OR_X,
+ [BPF_ALU64 | BPF_OR | BPF_K] = &&ALU64_OR_K,
+ [BPF_ALU64 | BPF_LSH | BPF_X] = &&ALU64_LSH_X,
+ [BPF_ALU64 | BPF_LSH | BPF_K] = &&ALU64_LSH_K,
+ [BPF_ALU64 | BPF_RSH | BPF_X] = &&ALU64_RSH_X,
+ [BPF_ALU64 | BPF_RSH | BPF_K] = &&ALU64_RSH_K,
+ [BPF_ALU64 | BPF_XOR | BPF_X] = &&ALU64_XOR_X,
+ [BPF_ALU64 | BPF_XOR | BPF_K] = &&ALU64_XOR_K,
+ [BPF_ALU64 | BPF_MUL | BPF_X] = &&ALU64_MUL_X,
+ [BPF_ALU64 | BPF_MUL | BPF_K] = &&ALU64_MUL_K,
+ [BPF_ALU64 | BPF_MOV | BPF_X] = &&ALU64_MOV_X,
+ [BPF_ALU64 | BPF_MOV | BPF_K] = &&ALU64_MOV_K,
+ [BPF_ALU64 | BPF_ARSH | BPF_X] = &&ALU64_ARSH_X,
+ [BPF_ALU64 | BPF_ARSH | BPF_K] = &&ALU64_ARSH_K,
+ [BPF_ALU64 | BPF_DIV | BPF_X] = &&ALU64_DIV_X,
+ [BPF_ALU64 | BPF_DIV | BPF_K] = &&ALU64_DIV_K,
+ [BPF_ALU64 | BPF_MOD | BPF_X] = &&ALU64_MOD_X,
+ [BPF_ALU64 | BPF_MOD | BPF_K] = &&ALU64_MOD_K,
+ [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG,
+ /* Call instruction */
+ [BPF_JMP | BPF_CALL] = &&JMP_CALL,
+ [BPF_JMP | BPF_CALL | BPF_X] = &&JMP_TAIL_CALL,
+ /* Jumps */
+ [BPF_JMP | BPF_JA] = &&JMP_JA,
+ [BPF_JMP | BPF_JEQ | BPF_X] = &&JMP_JEQ_X,
+ [BPF_JMP | BPF_JEQ | BPF_K] = &&JMP_JEQ_K,
+ [BPF_JMP | BPF_JNE | BPF_X] = &&JMP_JNE_X,
+ [BPF_JMP | BPF_JNE | BPF_K] = &&JMP_JNE_K,
+ [BPF_JMP | BPF_JGT | BPF_X] = &&JMP_JGT_X,
+ [BPF_JMP | BPF_JGT | BPF_K] = &&JMP_JGT_K,
+ [BPF_JMP | BPF_JGE | BPF_X] = &&JMP_JGE_X,
+ [BPF_JMP | BPF_JGE | BPF_K] = &&JMP_JGE_K,
+ [BPF_JMP | BPF_JSGT | BPF_X] = &&JMP_JSGT_X,
+ [BPF_JMP | BPF_JSGT | BPF_K] = &&JMP_JSGT_K,
+ [BPF_JMP | BPF_JSGE | BPF_X] = &&JMP_JSGE_X,
+ [BPF_JMP | BPF_JSGE | BPF_K] = &&JMP_JSGE_K,
+ [BPF_JMP | BPF_JSET | BPF_X] = &&JMP_JSET_X,
+ [BPF_JMP | BPF_JSET | BPF_K] = &&JMP_JSET_K,
+ /* Program return */
+ [BPF_JMP | BPF_EXIT] = &&JMP_EXIT,
+ /* Store instructions */
+ [BPF_STX | BPF_MEM | BPF_B] = &&STX_MEM_B,
+ [BPF_STX | BPF_MEM | BPF_H] = &&STX_MEM_H,
+ [BPF_STX | BPF_MEM | BPF_W] = &&STX_MEM_W,
+ [BPF_STX | BPF_MEM | BPF_DW] = &&STX_MEM_DW,
+ [BPF_STX | BPF_XADD | BPF_W] = &&STX_XADD_W,
+ [BPF_STX | BPF_XADD | BPF_DW] = &&STX_XADD_DW,
+ [BPF_ST | BPF_MEM | BPF_B] = &&ST_MEM_B,
+ [BPF_ST | BPF_MEM | BPF_H] = &&ST_MEM_H,
+ [BPF_ST | BPF_MEM | BPF_W] = &&ST_MEM_W,
+ [BPF_ST | BPF_MEM | BPF_DW] = &&ST_MEM_DW,
+ /* Load instructions */
+ [BPF_LDX | BPF_MEM | BPF_B] = &&LDX_MEM_B,
+ [BPF_LDX | BPF_MEM | BPF_H] = &&LDX_MEM_H,
+ [BPF_LDX | BPF_MEM | BPF_W] = &&LDX_MEM_W,
+ [BPF_LDX | BPF_MEM | BPF_DW] = &&LDX_MEM_DW,
+ [BPF_LD | BPF_ABS | BPF_W] = &&LD_ABS_W,
+ [BPF_LD | BPF_ABS | BPF_H] = &&LD_ABS_H,
+ [BPF_LD | BPF_ABS | BPF_B] = &&LD_ABS_B,
+ [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W,
+ [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H,
+ [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B,
+ [BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW,
+ };
+ u32 tail_call_cnt = 0;
+ void *ptr;
+ int off;
+
+#define CONT ({ insn++; goto select_insn; })
+#define CONT_JMP ({ insn++; goto select_insn; })
+
+ FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)];
+ ARG1 = (u64) (unsigned long) ctx;
+
+select_insn:
+ goto *jumptable[insn->code];
+
+ /* ALU */
+#define ALU(OPCODE, OP) \
+ ALU64_##OPCODE##_X: \
+ DST = DST OP SRC; \
+ CONT; \
+ ALU_##OPCODE##_X: \
+ DST = (u32) DST OP (u32) SRC; \
+ CONT; \
+ ALU64_##OPCODE##_K: \
+ DST = DST OP IMM; \
+ CONT; \
+ ALU_##OPCODE##_K: \
+ DST = (u32) DST OP (u32) IMM; \
+ CONT;
+
+ ALU(ADD, +)
+ ALU(SUB, -)
+ ALU(AND, &)
+ ALU(OR, |)
+ ALU(LSH, <<)
+ ALU(RSH, >>)
+ ALU(XOR, ^)
+ ALU(MUL, *)
+#undef ALU
+ ALU_NEG:
+ DST = (u32) -DST;
+ CONT;
+ ALU64_NEG:
+ DST = -DST;
+ CONT;
+ ALU_MOV_X:
+ DST = (u32) SRC;
+ CONT;
+ ALU_MOV_K:
+ DST = (u32) IMM;
+ CONT;
+ ALU64_MOV_X:
+ DST = SRC;
+ CONT;
+ ALU64_MOV_K:
+ DST = IMM;
+ CONT;
+ LD_IMM_DW:
+ DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32;
+ insn++;
+ CONT;
+ ALU64_ARSH_X:
+ (*(s64 *) &DST) >>= SRC;
+ CONT;
+ ALU64_ARSH_K:
+ (*(s64 *) &DST) >>= IMM;
+ CONT;
+ ALU64_MOD_X:
+ if (unlikely(SRC == 0))
+ return 0;
+ div64_u64_rem(DST, SRC, &tmp);
+ DST = tmp;
+ CONT;
+ ALU_MOD_X:
+ if (unlikely(SRC == 0))
+ return 0;
+ tmp = (u32) DST;
+ DST = do_div(tmp, (u32) SRC);
+ CONT;
+ ALU64_MOD_K:
+ div64_u64_rem(DST, IMM, &tmp);
+ DST = tmp;
+ CONT;
+ ALU_MOD_K:
+ tmp = (u32) DST;
+ DST = do_div(tmp, (u32) IMM);
+ CONT;
+ ALU64_DIV_X:
+ if (unlikely(SRC == 0))
+ return 0;
+ DST = div64_u64(DST, SRC);
+ CONT;
+ ALU_DIV_X:
+ if (unlikely(SRC == 0))
+ return 0;
+ tmp = (u32) DST;
+ do_div(tmp, (u32) SRC);
+ DST = (u32) tmp;
+ CONT;
+ ALU64_DIV_K:
+ DST = div64_u64(DST, IMM);
+ CONT;
+ ALU_DIV_K:
+ tmp = (u32) DST;
+ do_div(tmp, (u32) IMM);
+ DST = (u32) tmp;
+ CONT;
+ ALU_END_TO_BE:
+ switch (IMM) {
+ case 16:
+ DST = (__force u16) cpu_to_be16(DST);
+ break;
+ case 32:
+ DST = (__force u32) cpu_to_be32(DST);
+ break;
+ case 64:
+ DST = (__force u64) cpu_to_be64(DST);
+ break;
+ }
+ CONT;
+ ALU_END_TO_LE:
+ switch (IMM) {
+ case 16:
+ DST = (__force u16) cpu_to_le16(DST);
+ break;
+ case 32:
+ DST = (__force u32) cpu_to_le32(DST);
+ break;
+ case 64:
+ DST = (__force u64) cpu_to_le64(DST);
+ break;
+ }
+ CONT;
+
+ /* CALL */
+ JMP_CALL:
+ /* Function call scratches BPF_R1-BPF_R5 registers,
+ * preserves BPF_R6-BPF_R9, and stores return value
+ * into BPF_R0.
+ */
+ BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3,
+ BPF_R4, BPF_R5);
+ CONT;
+
+ JMP_TAIL_CALL: {
+ struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2;
+ struct bpf_array *array = container_of(map, struct bpf_array, map);
+ struct bpf_prog *prog;
+ u64 index = BPF_R3;
+
+ if (unlikely(index >= array->map.max_entries))
+ goto out;
+
+ if (unlikely(tail_call_cnt > MAX_TAIL_CALL_CNT))
+ goto out;
+
+ tail_call_cnt++;
+
+ prog = READ_ONCE(array->ptrs[index]);
+ if (unlikely(!prog))
+ goto out;
+
+ /* ARG1 at this point is guaranteed to point to CTX from
+ * the verifier side due to the fact that the tail call is
+ * handeled like a helper, that is, bpf_tail_call_proto,
+ * where arg1_type is ARG_PTR_TO_CTX.
+ */
+ insn = prog->insnsi;
+ goto select_insn;
+out:
+ CONT;
+ }
+ /* JMP */
+ JMP_JA:
+ insn += insn->off;
+ CONT;
+ JMP_JEQ_X:
+ if (DST == SRC) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JEQ_K:
+ if (DST == IMM) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JNE_X:
+ if (DST != SRC) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JNE_K:
+ if (DST != IMM) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JGT_X:
+ if (DST > SRC) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JGT_K:
+ if (DST > IMM) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JGE_X:
+ if (DST >= SRC) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JGE_K:
+ if (DST >= IMM) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JSGT_X:
+ if (((s64) DST) > ((s64) SRC)) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JSGT_K:
+ if (((s64) DST) > ((s64) IMM)) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JSGE_X:
+ if (((s64) DST) >= ((s64) SRC)) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JSGE_K:
+ if (((s64) DST) >= ((s64) IMM)) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JSET_X:
+ if (DST & SRC) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_JSET_K:
+ if (DST & IMM) {
+ insn += insn->off;
+ CONT_JMP;
+ }
+ CONT;
+ JMP_EXIT:
+ return BPF_R0;
+
+ /* STX and ST and LDX*/
+#define LDST(SIZEOP, SIZE) \
+ STX_MEM_##SIZEOP: \
+ *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \
+ CONT; \
+ ST_MEM_##SIZEOP: \
+ *(SIZE *)(unsigned long) (DST + insn->off) = IMM; \
+ CONT; \
+ LDX_MEM_##SIZEOP: \
+ DST = *(SIZE *)(unsigned long) (SRC + insn->off); \
+ CONT;
+
+ LDST(B, u8)
+ LDST(H, u16)
+ LDST(W, u32)
+ LDST(DW, u64)
+#undef LDST
+ STX_XADD_W: /* lock xadd *(u32 *)(dst_reg + off16) += src_reg */
+ atomic_add((u32) SRC, (atomic_t *)(unsigned long)
+ (DST + insn->off));
+ CONT;
+ STX_XADD_DW: /* lock xadd *(u64 *)(dst_reg + off16) += src_reg */
+ atomic64_add((u64) SRC, (atomic64_t *)(unsigned long)
+ (DST + insn->off));
+ CONT;
+ LD_ABS_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + imm32)) */
+ off = IMM;
+load_word:
+ /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are
+ * only appearing in the programs where ctx ==
+ * skb. All programs keep 'ctx' in regs[BPF_REG_CTX]
+ * == BPF_R6, bpf_convert_filter() saves it in BPF_R6,
+ * internal BPF verifier will check that BPF_R6 ==
+ * ctx.
+ *
+ * BPF_ABS and BPF_IND are wrappers of function calls,
+ * so they scratch BPF_R1-BPF_R5 registers, preserve
+ * BPF_R6-BPF_R9, and store return value into BPF_R0.
+ *
+ * Implicit input:
+ * ctx == skb == BPF_R6 == CTX
+ *
+ * Explicit input:
+ * SRC == any register
+ * IMM == 32-bit immediate
+ *
+ * Output:
+ * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness
+ */
+
+ ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp);
+ if (likely(ptr != NULL)) {
+ BPF_R0 = get_unaligned_be32(ptr);
+ CONT;
+ }
+
+ return 0;
+ LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */
+ off = IMM;
+load_half:
+ ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp);
+ if (likely(ptr != NULL)) {
+ BPF_R0 = get_unaligned_be16(ptr);
+ CONT;
+ }
+
+ return 0;
+ LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */
+ off = IMM;
+load_byte:
+ ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp);
+ if (likely(ptr != NULL)) {
+ BPF_R0 = *(u8 *)ptr;
+ CONT;
+ }
+
+ return 0;
+ LD_IND_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + src_reg + imm32)) */
+ off = IMM + SRC;
+ goto load_word;
+ LD_IND_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + src_reg + imm32)) */
+ off = IMM + SRC;
+ goto load_half;
+ LD_IND_B: /* BPF_R0 = *(u8 *) (skb->data + src_reg + imm32) */
+ off = IMM + SRC;
+ goto load_byte;
+
+ default_label:
+ /* If we ever reach this, we have a bug somewhere. */
+ WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code);
+ return 0;
+}
+STACK_FRAME_NON_STANDARD(__bpf_prog_run); /* jump table */
--
1.8.5.2
[toc] | [prev] | [next] | [standalone]
| From | He Kuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-26 13:30 +0200 |
| Subject | [RFC PATCH v2 06/26] tools include: Add (atomic|atomic64)_add implementation from the kernel sources |
| Message-ID | <rOgqf-2jQ-65@gated-at.bofh.it> |
| In reply to | #1431466 |
Uses the arch/x86/ kernel code for x86_64/i386, fallbacking to a gcc
intrinsics implementation.
Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
tools/arch/x86/include/asm/atomic.h | 28 ++++++++++++++++++++++++++++
tools/include/asm-generic/atomic-gcc.h | 10 ++++++++++
tools/include/linux/types.h | 4 ++++
3 files changed, 42 insertions(+)
diff --git a/tools/arch/x86/include/asm/atomic.h b/tools/arch/x86/include/asm/atomic.h
index 059e33e..41f814e 100644
--- a/tools/arch/x86/include/asm/atomic.h
+++ b/tools/arch/x86/include/asm/atomic.h
@@ -62,4 +62,32 @@ static inline int atomic_dec_and_test(atomic_t *v)
GEN_UNARY_RMWcc(LOCK_PREFIX "decl", v->counter, "%0", "e");
}
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v.
+ */
+static __always_inline void atomic_add(int i, atomic_t *v)
+{
+ asm volatile(LOCK_PREFIX "addl %1,%0"
+ : "+m" (v->counter)
+ : "ir" (i));
+}
+
+/**
+ * atomic64_add - add integer to atomic64 variable
+ * @i: integer value to add
+ * @v: pointer to type atomic64_t
+ *
+ * Atomically adds @i to @v.
+ */
+static __always_inline void atomic64_add(long i, atomic64_t *v)
+{
+ asm volatile(LOCK_PREFIX "addq %1,%0"
+ : "=m" (v->counter)
+ : "er" (i), "m" (v->counter));
+}
+
#endif /* _TOOLS_LINUX_ASM_X86_ATOMIC_H */
diff --git a/tools/include/asm-generic/atomic-gcc.h b/tools/include/asm-generic/atomic-gcc.h
index 2ba78c9..b615907 100644
--- a/tools/include/asm-generic/atomic-gcc.h
+++ b/tools/include/asm-generic/atomic-gcc.h
@@ -60,4 +60,14 @@ static inline int atomic_dec_and_test(atomic_t *v)
return __sync_sub_and_fetch(&v->counter, 1) == 0;
}
+static inline void atomic_add(int i, atomic_t *v)
+{
+ __sync_add_and_fetch(&v->counter, i);
+}
+
+static inline void atomic64_add(long i, atomic64_t *v)
+{
+ __sync_add_and_fetch(&v->counter, i);
+}
+
#endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */
diff --git a/tools/include/linux/types.h b/tools/include/linux/types.h
index 8ebf627..09b325f 100644
--- a/tools/include/linux/types.h
+++ b/tools/include/linux/types.h
@@ -64,6 +64,10 @@ typedef struct {
int counter;
} atomic_t;
+typedef struct {
+ long counter;
+} atomic64_t;
+
#ifndef __aligned_u64
# define __aligned_u64 __u64 __attribute__((aligned(8)))
#endif
--
1.8.5.2
[toc] | [prev] | [next] | [standalone]
| From | Alexei Starovoitov <alexei.starovoitov@gmail.com> |
|---|---|
| Date | 2016-06-26 22:50 +0200 |
| Message-ID | <rOpa9-7B9-3@gated-at.bofh.it> |
| In reply to | #1431466 |
On Sun, Jun 26, 2016 at 11:20:52AM +0000, He Kuang wrote: > This patchset is based on Wang Nan's v1: > http://thread.gmane.org/gmane.linux.kernel/2203717/focus=2203707 > > """ > This patch set allows to perf invoke some user space BPF scripts on > some point. uBPF scripts and kernel BPF scripts reside in one BPF > object. They communicate with each other with BPF maps. uBPF > scripts can invoke helper functions provided by perf. > > At least following new features can be achieved based on uBPF > support: > > 1) Report statistical result: > > Like DTrace, perf print statistical report before quit. No need > to extract data using 'perf report'. Statistical method is > controled by user. > > 2) Control perf's behavior: > > Dynamically adjust period of different events. Policy is defined > by user. > """ > > and modified by following the reviewers' suggestions. > > v1-v2: > > - Split bpf vm part out of kernel/bpf/core.c and link to it instead > of using ubpf library(Suggested by Alexei Starovoitov). And add > runtime bounds check just like ubpf library does. hmm. I don't think I suggested to hack bpf/core.c into separate file and compile it for userspace... Also I think the prior experience taught us that sharing code between kernel and user space will have lots of headaches long term. I think it makes more sense to use bcc approach. Just have c+py or c+lua or c+c. llvm has x86 backend too. If you integrate clang/llvm (bcc approach) you can compile different functions with different backends... if you don't want to embed the compiler, have two .c files. Compile one for bpf target and another for native.
[toc] | [prev] | [next] | [standalone]
| From | Hekuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-27 04:20 +0200 |
| Message-ID | <rOujv-2A6-5@gated-at.bofh.it> |
| In reply to | #1431583 |
hi 在 2016/6/27 4:48, Alexei Starovoitov 写道: > On Sun, Jun 26, 2016 at 11:20:52AM +0000, He Kuang wrote: >> This patchset is based on Wang Nan's v1: >> http://thread.gmane.org/gmane.linux.kernel/2203717/focus=2203707 >> >> """ >> This patch set allows to perf invoke some user space BPF scripts on >> some point. uBPF scripts and kernel BPF scripts reside in one BPF >> object. They communicate with each other with BPF maps. uBPF >> scripts can invoke helper functions provided by perf. >> >> At least following new features can be achieved based on uBPF >> support: >> >> 1) Report statistical result: >> >> Like DTrace, perf print statistical report before quit. No need >> to extract data using 'perf report'. Statistical method is >> controled by user. >> >> 2) Control perf's behavior: >> >> Dynamically adjust period of different events. Policy is defined >> by user. >> """ >> >> and modified by following the reviewers' suggestions. >> >> v1-v2: >> >> - Split bpf vm part out of kernel/bpf/core.c and link to it instead >> of using ubpf library(Suggested by Alexei Starovoitov). And add >> runtime bounds check just like ubpf library does. > hmm. I don't think I suggested to hack bpf/core.c into separate file > and compile it for userspace... """ Also ubpf was written from scratch with apache2, while perf is gpl, so you can just link kernel/bpf/core.o directly instead of using external libraries. """ This is your comment on ubpf v1 thread. I thought you was suggesting to use code in kernel/bpf/core.o, but because there're difference in __bpf_prog_run() between userspace and kernel, for example the __bpf_call_base is used in kernel, in userspace we get funcs from ubpf function list, we have to modify the existing code in kernel/bpf/core.c. I've got the source code of 'bcc' project, but it seems that bcc does not involve bpf virtual machine, so if we do not use 'kernel/bpf/core.o' solution, and can't use 'ubpf' because of the license reason, any other choices? Thank you. > Also I think the prior experience taught us that sharing code between > kernel and user space will have lots of headaches long term. > I think it makes more sense to use bcc approach. Just have c+py > or c+lua or c+c. llvm has x86 backend too. If you integrate > clang/llvm (bcc approach) you can compile different functions with > different backends... if you don't want to embed the compiler, > have two .c files. Compile one for bpf target and another for native. > >
[toc] | [prev] | [next] | [standalone]
| From | Hekuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-28 14:00 +0200 |
| Message-ID | <rOZQl-6yo-11@gated-at.bofh.it> |
| In reply to | #1431583 |
在 2016/6/27 4:48, Alexei Starovoitov 写道:
> On Sun, Jun 26, 2016 at 11:20:52AM +0000, He Kuang wrote:
>> bounds check just like ubpf library does.
> hmm. I don't think I suggested to hack bpf/core.c into separate file
> and compile it for userspace...
Maybe I misunderstood your suggestion. Now I just let perf check
bpf/core.o in
kernel output directory, if it exsits, perf will link it. The missing
functions referenced by
bpf/core.o can be defined empty in perf.
The above way leaves two minor changes in bpf/core.c:
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index b94a365..0fc6c23 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -452,7 +452,7 @@ struct bpf_prog *bpf_jit_blind_constants(struct
bpf_prog *prog)
* therefore keeping it non-static as well; will also be used by JITs
* anyway later on, so do not let the compiler omit it.
*/
-noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
+noinline u64 __weak __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
{
return 0;
}
@@ -465,7 +465,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
*
* Decode and execute eBPF instructions.
*/
-static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
+unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
{
u64 stack[MAX_BPF_STACK / sizeof(u64)];
u64 regs[MAX_BPF_REG], tmp;
How about this?
Thank you.
> Also I think the prior experience taught us that sharing code between
> kernel and user space will have lots of headaches long term.
> I think it makes more sense to use bcc approach. Just have c+py
> or c+lua or c+c. llvm has x86 backend too. If you integrate
> clang/llvm (bcc approach) you can compile different functions with
> different backends... if you don't want to embed the compiler,
> have two .c files. Compile one for bpf target and another for native.
>
>
[toc] | [prev] | [next] | [standalone]
| From | Alexei Starovoitov <alexei.starovoitov@gmail.com> |
|---|---|
| Date | 2016-06-28 17:00 +0200 |
| Message-ID | <rP2Ex-8qz-1@gated-at.bofh.it> |
| In reply to | #1432912 |
On Tue, Jun 28, 2016 at 07:47:53PM +0800, Hekuang wrote:
>
>
> 在 2016/6/27 4:48, Alexei Starovoitov 写道:
> >On Sun, Jun 26, 2016 at 11:20:52AM +0000, He Kuang wrote:
> >> bounds check just like ubpf library does.
> >hmm. I don't think I suggested to hack bpf/core.c into separate file
> >and compile it for userspace...
>
> Maybe I misunderstood your suggestion. Now I just let perf check bpf/core.o
> in
> kernel output directory, if it exsits, perf will link it. The missing
> functions referenced by
> bpf/core.o can be defined empty in perf.
yes. that's what I meant.
Note that this is still soft dependency on kernel, so things will break
eventually.
> The above way leaves two minor changes in bpf/core.c:
>
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index b94a365..0fc6c23 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -452,7 +452,7 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog
> *prog)
> * therefore keeping it non-static as well; will also be used by JITs
> * anyway later on, so do not let the compiler omit it.
> */
> -noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
> +noinline u64 __weak __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
this part I don't understand. Why do you need to change it?
> {
> return 0;
> }
> @@ -465,7 +465,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
> *
> * Decode and execute eBPF instructions.
> */
> -static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
> +unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
yes. that is good.
> >Also I think the prior experience taught us that sharing code between
> >kernel and user space will have lots of headaches long term.
> >I think it makes more sense to use bcc approach. Just have c+py
> >or c+lua or c+c. llvm has x86 backend too. If you integrate
> >clang/llvm (bcc approach) you can compile different functions with
> >different backends... if you don't want to embed the compiler,
> >have two .c files. Compile one for bpf target and another for native.
I still think that what two .c files without embeded llvm or
one .c with embedded is a better way.
You'll have full C that is fast on x86 or arm instead of
executing things in ubpf.
Or use py/lua wrappers. Equally easy.
[toc] | [prev] | [next] | [standalone]
| From | Hekuang <hekuang@huawei.com> |
|---|---|
| Date | 2016-06-29 12:20 +0200 |
| Message-ID | <rPkL8-2Wd-15@gated-at.bofh.it> |
| In reply to | #1433040 |
hi 在 2016/6/28 22:57, Alexei Starovoitov 写道: > > return 0; > } > @@ -465,7 +465,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base); > * > * Decode and execute eBPF instructions. > */ > -static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) > +unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) > yes. that is good. > >>> Also I think the prior experience taught us that sharing code between >>> kernel and user space will have lots of headaches long term. >>> I think it makes more sense to use bcc approach. Just have c+py >>> or c+lua or c+c. llvm has x86 backend too. If you integrate >>> clang/llvm (bcc approach) you can compile different functions with >>> different backends... if you don't want to embed the compiler, >>> have two .c files. Compile one for bpf target and another for native. > I still think that what two .c files without embeded llvm or > one .c with embedded is a better way. > You'll have full C that is fast on x86 or arm instead of > executing things in ubpf. > Or use py/lua wrappers. Equally easy. > Our goal is the same as you described, that to have one .c file and embeded llvm into perf for compiling it to bpf target for kernel and native for userspace. But there's two problems we may encounter by this way on the phone, which is the most common scenario our work focus on. The first one is the size of bcc/llvm library. It's more than 800MB for libbcc.so and I guess the llvm part takes most of them. Shortly we can run perf as a daemon after the overwrite/control channel be merged (wangnan's recently patches), such a huge memory consumption is not acceptable. Second, I've browsed the bcc source briefly and see that there's two frontend for loading .b and .c, we have to integrate the x86 backend for compiling bpf to native code. That's possible but we still need extra works and it is not ready to use for now. Then we have two other approaches, the first is as 'ubpf v2' which uses one .c file and introduces bpf vm to perf, the second is like you said, use two .c files and compile userspace bpf to native code by using llvm externally. Both the two ways are easy to implement, but we prefer the first one between them because it uses one .c file which is the same as our final approach, and it does not face the huge memory consumption problem, finally, after we solve problems on embeded llvm in perf and lower the memory consumption, we can keep the user interface and replace the bpf vm to llvm frontend+backend. So what's your opinion on this? Thank you.
[toc] | [prev] | [next] | [standalone]
| From | "Wangnan (F)" <wangnan0@huawei.com> |
|---|---|
| Date | 2016-06-29 12:50 +0200 |
| Message-ID | <rPle9-36J-5@gated-at.bofh.it> |
| In reply to | #1433652 |
On 2016/6/29 18:15, Hekuang wrote: > hi > > 在 2016/6/28 22:57, Alexei Starovoitov 写道: >> >> return 0; >> } >> @@ -465,7 +465,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base); >> * >> * Decode and execute eBPF instructions. >> */ >> -static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn >> *insn) >> +unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) >> yes. that is good. >> >>>> Also I think the prior experience taught us that sharing code between >>>> kernel and user space will have lots of headaches long term. >>>> I think it makes more sense to use bcc approach. Just have c+py >>>> or c+lua or c+c. llvm has x86 backend too. If you integrate >>>> clang/llvm (bcc approach) you can compile different functions with >>>> different backends... if you don't want to embed the compiler, >>>> have two .c files. Compile one for bpf target and another for native. >> I still think that what two .c files without embeded llvm or >> one .c with embedded is a better way. >> You'll have full C that is fast on x86 or arm instead of >> executing things in ubpf. >> Or use py/lua wrappers. Equally easy. >> > Our goal is the same as you described, that to have one .c file > and embeded llvm into perf for compiling it to bpf target for > kernel and native for userspace. > > But there's two problems we may encounter by this way on the > phone, which is the most common scenario our work focus on. > > The first one is the size of bcc/llvm library. It's more than > 800MB for libbcc.so and I guess the llvm part takes most of > them. Shortly we can run perf as a daemon after the > overwrite/control channel be merged (wangnan's recently patches), > such a huge memory consumption is not acceptable. > > Second, I've browsed the bcc source briefly and see that there's > two frontend for loading .b and .c, we have to integrate the x86 > backend for compiling bpf to native code. That's possible but we > still need extra works and it is not ready to use for now. > > Then we have two other approaches, the first is as 'ubpf v2' > which uses one .c file and introduces bpf vm to perf, the second > is like you said, use two .c files and compile userspace bpf to > native code by using llvm externally. > Not userspace BPF. There would no userspace BPF if we choose two .c approach. We can compile user space part to a shared library, then make perf load it like a perf plugin. We can even glue BPF.o and native.o into one file with linker trick, then let's push it into smart phone use adb push... Oh, no, not only perf and the two (or one) objects. a dynamic perf requires more than 30 libraries, we need to push them too. > Both the two ways are easy to implement, but we prefer the first > one between them because it uses one .c file which is the same as > our final approach, and it does not face the huge memory > consumption problem, finally, after we solve problems on embeded > llvm in perf and lower the memory consumption, we can keep the > user interface and replace the bpf vm to llvm > frontend+backend. > Yes. The problem we consider now is interface. Before we can use llvm library on smartphone, shall we maintain a '.o + .so' interface separatly? > So what's your opinion on this? > > Thank you. >
[toc] | [prev] | [next] | [standalone]
| From | Alexei Starovoitov <alexei.starovoitov@gmail.com> |
|---|---|
| Date | 2016-06-29 14:40 +0200 |
| Message-ID | <rPmWB-4b3-13@gated-at.bofh.it> |
| In reply to | #1433658 |
On Wed, Jun 29, 2016 at 06:35:12PM +0800, Wangnan (F) wrote: > > > On 2016/6/29 18:15, Hekuang wrote: > >hi > > > >在 2016/6/28 22:57, Alexei Starovoitov 写道: > >> > >> return 0; > >> } > >>@@ -465,7 +465,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base); > >> * > >> * Decode and execute eBPF instructions. > >> */ > >>-static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn > >>*insn) > >>+unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) > >>yes. that is good. > >> > >>>>Also I think the prior experience taught us that sharing code between > >>>>kernel and user space will have lots of headaches long term. > >>>>I think it makes more sense to use bcc approach. Just have c+py > >>>>or c+lua or c+c. llvm has x86 backend too. If you integrate > >>>>clang/llvm (bcc approach) you can compile different functions with > >>>>different backends... if you don't want to embed the compiler, > >>>>have two .c files. Compile one for bpf target and another for native. > >>I still think that what two .c files without embeded llvm or > >>one .c with embedded is a better way. > >>You'll have full C that is fast on x86 or arm instead of > >>executing things in ubpf. > >>Or use py/lua wrappers. Equally easy. > >> > >Our goal is the same as you described, that to have one .c file > >and embeded llvm into perf for compiling it to bpf target for > >kernel and native for userspace. > > > >But there's two problems we may encounter by this way on the > >phone, which is the most common scenario our work focus on. > > > >The first one is the size of bcc/llvm library. It's more than > >800MB for libbcc.so and I guess the llvm part takes most of > >them. Shortly we can run perf as a daemon after the > >overwrite/control channel be merged (wangnan's recently patches), > >such a huge memory consumption is not acceptable. you'll see ~1Gb .so when llvm is compiled with debug info. $ ls -lh libbcc.so.0.1.8 38M Jun 29 07:40 libbcc.so.0.1.8 and that includes full clang, llvm and two bcc front-ends. llvm alone is 14M that is perfectly acceptable even for a phone. > > > >Second, I've browsed the bcc source briefly and see that there's > >two frontend for loading .b and .c, we have to integrate the x86 > >backend for compiling bpf to native code. That's possible but we > >still need extra works and it is not ready to use for now. > > > >Then we have two other approaches, the first is as 'ubpf v2' > >which uses one .c file and introduces bpf vm to perf, the second > >is like you said, use two .c files and compile userspace bpf to > >native code by using llvm externally. > > > > Not userspace BPF. There would no userspace BPF if we choose two > .c approach. We can compile user space part to a shared library, > then make perf load it like a perf plugin. We can even glue BPF.o > and native.o into one file with linker trick, then let's push it > into smart phone use adb push... Oh, no, not only perf and the > two (or one) objects. a dynamic perf requires more than 30 > libraries, we need to push them too. that's a way as well, but I don't see why you need to combine two .o loading bpf.o and native.o independently is easier, no? > >Both the two ways are easy to implement, but we prefer the first > >one between them because it uses one .c file which is the same as > >our final approach, and it does not face the huge memory > >consumption problem, finally, after we solve problems on embeded > >llvm in perf and lower the memory consumption, we can keep the > >user interface and replace the bpf vm to llvm > >frontend+backend. > > > > Yes. The problem we consider now is interface. Before we can use > llvm library on smartphone, shall we maintain a '.o + .so' interface > separatly? what's stopping using llvm on a phone now?
[toc] | [prev] | [next] | [standalone]
| From | pi3orama <pi3orama@163.com> |
|---|---|
| Date | 2016-06-29 15:10 +0200 |
| Message-ID | <rPnpE-4Ak-19@gated-at.bofh.it> |
| In reply to | #1433705 |
发自我的 iPhone > 在 2016年6月29日,下午8:37,Alexei Starovoitov <alexei.starovoitov@gmail.com> 写道: > >> On Wed, Jun 29, 2016 at 06:35:12PM +0800, Wangnan (F) wrote: >> >> >>> On 2016/6/29 18:15, Hekuang wrote: >>> hi >>> >>>> 在 2016/6/28 22:57, Alexei Starovoitov 写道: >>>> >>>> return 0; >>>> } >>>> @@ -465,7 +465,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base); >>>> * >>>> * Decode and execute eBPF instructions. >>>> */ >>>> -static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn >>>> *insn) >>>> +unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) >>>> yes. that is good. >>>> >>>>>> Also I think the prior experience taught us that sharing code between >>>>>> kernel and user space will have lots of headaches long term. >>>>>> I think it makes more sense to use bcc approach. Just have c+py >>>>>> or c+lua or c+c. llvm has x86 backend too. If you integrate >>>>>> clang/llvm (bcc approach) you can compile different functions with >>>>>> different backends... if you don't want to embed the compiler, >>>>>> have two .c files. Compile one for bpf target and another for native. >>>> I still think that what two .c files without embeded llvm or >>>> one .c with embedded is a better way. >>>> You'll have full C that is fast on x86 or arm instead of >>>> executing things in ubpf. >>>> Or use py/lua wrappers. Equally easy. >>> Our goal is the same as you described, that to have one .c file >>> and embeded llvm into perf for compiling it to bpf target for >>> kernel and native for userspace. >>> >>> But there's two problems we may encounter by this way on the >>> phone, which is the most common scenario our work focus on. >>> >>> The first one is the size of bcc/llvm library. It's more than >>> 800MB for libbcc.so and I guess the llvm part takes most of >>> them. Shortly we can run perf as a daemon after the >>> overwrite/control channel be merged (wangnan's recently patches), >>> such a huge memory consumption is not acceptable. > > you'll see ~1Gb .so when llvm is compiled with debug info. > > $ ls -lh libbcc.so.0.1.8 > 38M Jun 29 07:40 libbcc.so.0.1.8 > > and that includes full clang, llvm and two bcc front-ends. > llvm alone is 14M > that is perfectly acceptable even for a phone. > >>> >>> Second, I've browsed the bcc source briefly and see that there's >>> two frontend for loading .b and .c, we have to integrate the x86 >>> backend for compiling bpf to native code. That's possible but we >>> still need extra works and it is not ready to use for now. >>> >>> Then we have two other approaches, the first is as 'ubpf v2' >>> which uses one .c file and introduces bpf vm to perf, the second >>> is like you said, use two .c files and compile userspace bpf to >>> native code by using llvm externally. >> >> Not userspace BPF. There would no userspace BPF if we choose two >> .c approach. We can compile user space part to a shared library, >> then make perf load it like a perf plugin. We can even glue BPF.o >> and native.o into one file with linker trick, then let's push it >> into smart phone use adb push... Oh, no, not only perf and the >> two (or one) objects. a dynamic perf requires more than 30 >> libraries, we need to push them too. > > that's a way as well, but I don't see why you need to combine two .o > loading bpf.o and native.o independently is easier, no? > >>> Both the two ways are easy to implement, but we prefer the first >>> one between them because it uses one .c file which is the same as >>> our final approach, and it does not face the huge memory >>> consumption problem, finally, after we solve problems on embeded >>> llvm in perf and lower the memory consumption, we can keep the >>> user interface and replace the bpf vm to llvm >>> frontend+backend. >> >> Yes. The problem we consider now is interface. Before we can use >> llvm library on smartphone, shall we maintain a '.o + .so' interface >> separatly? > > what's stopping using llvm on a phone now? Size is the only consideration now. If we can shrink LLVM library to less than 20MB then embedding libLLVM is really worth a try. We'll try to compile to arm64 tomorrow. I have seen some discussions on it so I think it would not be very hard. Thank you for your information!
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web