Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1431466 > unrolled thread

[RFC PATCH v2 00/26] perf tools: Support uBPF script

Started byHe Kuang <hekuang@huawei.com>
First post2016-06-26 13:30 +0200
Last post2016-06-29 15:10 +0200
Articles 14 — 5 participants

Back to article view | Back to linux.kernel


Contents

  [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

#1431466 — [RFC PATCH v2 00/26] perf tools: Support uBPF script

FromHe Kuang <hekuang@huawei.com>
Date2016-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]


#1431467 — [RFC PATCH v2 21/26] bpf: Support bpf load/store boundary check for ubpf

FromHe Kuang <hekuang@huawei.com>
Date2016-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]


#1431468 — [RFC PATCH v2 01/26] tools include: Adopt byte ordering macros from byteorder/generic.h

FromHe Kuang <hekuang@huawei.com>
Date2016-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]


#1431469 — [RFC PATCH v2 12/26] perf bpf: Add libbpf-internal.h header file

FromHe Kuang <hekuang@huawei.com>
Date2016-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]


#1431470 — [RFC PATCH v2 03/26] bpf: split __bpf_prog_run code into new file

FromHe Kuang <hekuang@huawei.com>
Date2016-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]


#1431471 — [RFC PATCH v2 06/26] tools include: Add (atomic|atomic64)_add implementation from the kernel sources

FromHe Kuang <hekuang@huawei.com>
Date2016-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]


#1431583

FromAlexei Starovoitov <alexei.starovoitov@gmail.com>
Date2016-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]


#1431675

FromHekuang <hekuang@huawei.com>
Date2016-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]


#1432912

FromHekuang <hekuang@huawei.com>
Date2016-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]


#1433040

FromAlexei Starovoitov <alexei.starovoitov@gmail.com>
Date2016-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]


#1433652

FromHekuang <hekuang@huawei.com>
Date2016-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]


#1433658

From"Wangnan (F)" <wangnan0@huawei.com>
Date2016-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]


#1433705

FromAlexei Starovoitov <alexei.starovoitov@gmail.com>
Date2016-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]


#1433720

Frompi3orama <pi3orama@163.com>
Date2016-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