Merge branch 'bpf-riscv-jit'

Björn Töpel says:

====================
This v2 series adds an RV64G BPF JIT to the kernel.

At the moment the RISC-V Linux port does not support
CONFIG_HAVE_KPROBES (Patrick Stählin sent out an RFC last year), which
means that CONFIG_BPF_EVENTS is not supported. Thus, no tests
involving BPF_PROG_TYPE_TRACEPOINT, BPF_PROG_TYPE_PERF_EVENT,
BPF_PROG_TYPE_KPROBE and BPF_PROG_TYPE_RAW_TRACEPOINT passes.

The implementation does not support "far branching" (>4KiB).

Test results:
  # modprobe test_bpf
  test_bpf: Summary: 378 PASSED, 0 FAILED, [366/366 JIT'ed]

  # echo 1 > /proc/sys/kernel/unprivileged_bpf_disabled
  # ./test_verifier
  ...
  Summary: 761 PASSED, 507 SKIPPED, 2 FAILED

Note that "test_verifier" was run with one build with
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y and one without, otherwise
many of the the tests that require unaligned access were skipped.

CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y:
  # echo 1 > /proc/sys/kernel/unprivileged_bpf_disabled
  # ./test_verifier | grep -c 'NOTE.*unknown align'
  0

No CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS:
  # echo 1 > /proc/sys/kernel/unprivileged_bpf_disabled
  # ./test_verifier | grep -c 'NOTE.*unknown align'
  59

The two failing test_verifier tests are:
  "ld_abs: vlan + abs, test 1"
  "ld_abs: jump around ld_abs"

This is due to that "far branching" involved in those tests.
All tests where done on QEMU emulator version 3.1.50
(v3.1.0-688-g8ae951fbc106). I'll test it on real hardware, when I get
access to it.

I'm routing this patch via bpf-next/netdev mailing list (after a
conversation with Palmer at FOSDEM), mainly because the other JITs
went that path.

Again, thanks for all the comments!

Cheers,
Björn

v1 -> v2:
* Added JMP32 support. (Daniel)
* Add RISC-V to Documentation/sysctl/net.txt. (Daniel)
* Fixed seen_call() asymmetry. (Daniel)
* Fixed broken bpf_flush_icache() range. (Daniel)
* Added alignment annotations to some selftests.

RFCv1 -> v1:
* Cleaned up the Kconfig and net/Makefile. (Christoph)
* Removed the entry-stub and squashed the build/config changes to be
  part of the JIT implementation. (Christoph)
* Simplified the register tracking code. (Daniel)
* Removed unused macros. (Daniel)
* Added myself as maintainer and updated documentation. (Daniel)
* Removed HAVE_EFFICIENT_UNALIGNED_ACCESS. (Christoph, Palmer)
* Added tail-calls and cleaned up the code.
====================

Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
Daniel Borkmann 2019-02-05 16:56:11 +01:00
commit 90d304b7f7
14 changed files with 1654 additions and 8 deletions

View File

@ -464,10 +464,11 @@ breakpoints: 0 1
JIT compiler JIT compiler
------------ ------------
The Linux kernel has a built-in BPF JIT compiler for x86_64, SPARC, PowerPC, The Linux kernel has a built-in BPF JIT compiler for x86_64, SPARC,
ARM, ARM64, MIPS and s390 and can be enabled through CONFIG_BPF_JIT. The JIT PowerPC, ARM, ARM64, MIPS, RISC-V and s390 and can be enabled through
compiler is transparently invoked for each attached filter from user space CONFIG_BPF_JIT. The JIT compiler is transparently invoked for each
or for internal kernel users if it has been previously enabled by root: attached filter from user space or for internal kernel users if it has
been previously enabled by root:
echo 1 > /proc/sys/net/core/bpf_jit_enable echo 1 > /proc/sys/net/core/bpf_jit_enable
@ -603,9 +604,10 @@ got from bpf_prog_create(), and 'ctx' the given context (e.g.
skb pointer). All constraints and restrictions from bpf_check_classic() apply skb pointer). All constraints and restrictions from bpf_check_classic() apply
before a conversion to the new layout is being done behind the scenes! before a conversion to the new layout is being done behind the scenes!
Currently, the classic BPF format is being used for JITing on most 32-bit Currently, the classic BPF format is being used for JITing on most
architectures, whereas x86-64, aarch64, s390x, powerpc64, sparc64, arm32 perform 32-bit architectures, whereas x86-64, aarch64, s390x, powerpc64,
JIT compilation from eBPF instruction set. sparc64, arm32, riscv (RV64G) perform JIT compilation from eBPF
instruction set.
Some core changes of the new internal format: Some core changes of the new internal format:

View File

@ -52,6 +52,7 @@ two flavors of JITs, the newer eBPF JIT currently supported on:
- sparc64 - sparc64
- mips64 - mips64
- s390x - s390x
- riscv
And the older cBPF JIT supported on the following archs: And the older cBPF JIT supported on the following archs:
- mips - mips

View File

@ -2907,6 +2907,12 @@ L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: arch/powerpc/net/ F: arch/powerpc/net/
BPF JIT for RISC-V (RV64G)
M: Björn Töpel <bjorn.topel@gmail.com>
L: netdev@vger.kernel.org
S: Maintained
F: arch/riscv/net/
BPF JIT for S390 BPF JIT for S390
M: Martin Schwidefsky <schwidefsky@de.ibm.com> M: Martin Schwidefsky <schwidefsky@de.ibm.com>
M: Heiko Carstens <heiko.carstens@de.ibm.com> M: Heiko Carstens <heiko.carstens@de.ibm.com>

View File

@ -49,6 +49,7 @@ config RISCV
select RISCV_TIMER select RISCV_TIMER
select GENERIC_IRQ_MULTI_HANDLER select GENERIC_IRQ_MULTI_HANDLER
select ARCH_HAS_PTE_SPECIAL select ARCH_HAS_PTE_SPECIAL
select HAVE_EBPF_JIT if 64BIT
config MMU config MMU
def_bool y def_bool y

View File

@ -77,7 +77,7 @@ KBUILD_IMAGE := $(boot)/Image.gz
head-y := arch/riscv/kernel/head.o head-y := arch/riscv/kernel/head.o
core-y += arch/riscv/kernel/ arch/riscv/mm/ core-y += arch/riscv/kernel/ arch/riscv/mm/ arch/riscv/net/
libs-y += arch/riscv/lib/ libs-y += arch/riscv/lib/

1
arch/riscv/net/Makefile Normal file
View File

@ -0,0 +1 @@
obj-$(CONFIG_BPF_JIT) += bpf_jit_comp.o

File diff suppressed because it is too large Load Diff

View File

@ -100,6 +100,7 @@
.errstr = "invalid bpf_context access", .errstr = "invalid bpf_context access",
.result = REJECT, .result = REJECT,
.prog_type = BPF_PROG_TYPE_SK_MSG, .prog_type = BPF_PROG_TYPE_SK_MSG,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"invalid read past end of SK_MSG", "invalid read past end of SK_MSG",

View File

@ -687,6 +687,7 @@
}, },
.errstr = "invalid bpf_context access", .errstr = "invalid bpf_context access",
.result = REJECT, .result = REJECT,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"check skb->hash half load not permitted, unaligned 3", "check skb->hash half load not permitted, unaligned 3",

View File

@ -27,6 +27,7 @@
.data64 = { 1ULL << 63 | 1, } .data64 = { 1ULL << 63 | 1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jset32: BPF_X", "jset32: BPF_X",
@ -58,6 +59,7 @@
.data64 = { 1ULL << 63 | 1, } .data64 = { 1ULL << 63 | 1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jset32: min/max deduction", "jset32: min/max deduction",
@ -93,6 +95,7 @@
.data64 = { -1, } .data64 = { -1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jeq32: BPF_X", "jeq32: BPF_X",
@ -119,6 +122,7 @@
.data64 = { 1ULL << 63 | 1, } .data64 = { 1ULL << 63 | 1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jeq32: min/max deduction", "jeq32: min/max deduction",
@ -154,6 +158,7 @@
.data64 = { -1, } .data64 = { -1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jne32: BPF_X", "jne32: BPF_X",
@ -180,6 +185,7 @@
.data64 = { 1ULL << 63 | 2, } .data64 = { 1ULL << 63 | 2, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jne32: min/max deduction", "jne32: min/max deduction",
@ -218,6 +224,7 @@
.data64 = { 0, } .data64 = { 0, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jge32: BPF_X", "jge32: BPF_X",
@ -244,6 +251,7 @@
.data64 = { (UINT_MAX - 1) | 2ULL << 32, } .data64 = { (UINT_MAX - 1) | 2ULL << 32, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jge32: min/max deduction", "jge32: min/max deduction",
@ -284,6 +292,7 @@
.data64 = { 0, } .data64 = { 0, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jgt32: BPF_X", "jgt32: BPF_X",
@ -310,6 +319,7 @@
.data64 = { (UINT_MAX - 1) | 2ULL << 32, } .data64 = { (UINT_MAX - 1) | 2ULL << 32, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jgt32: min/max deduction", "jgt32: min/max deduction",
@ -350,6 +360,7 @@
.data64 = { INT_MAX, } .data64 = { INT_MAX, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jle32: BPF_X", "jle32: BPF_X",
@ -376,6 +387,7 @@
.data64 = { UINT_MAX, } .data64 = { UINT_MAX, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jle32: min/max deduction", "jle32: min/max deduction",
@ -416,6 +428,7 @@
.data64 = { INT_MAX - 1, } .data64 = { INT_MAX - 1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jlt32: BPF_X", "jlt32: BPF_X",
@ -442,6 +455,7 @@
.data64 = { (INT_MAX - 1) | 3ULL << 32, } .data64 = { (INT_MAX - 1) | 3ULL << 32, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jlt32: min/max deduction", "jlt32: min/max deduction",
@ -482,6 +496,7 @@
.data64 = { -2, } .data64 = { -2, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jsge32: BPF_X", "jsge32: BPF_X",
@ -508,6 +523,7 @@
.data64 = { -2, } .data64 = { -2, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jsge32: min/max deduction", "jsge32: min/max deduction",
@ -548,6 +564,7 @@
.data64 = { 1, } .data64 = { 1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jsgt32: BPF_X", "jsgt32: BPF_X",
@ -574,6 +591,7 @@
.data64 = { 0x7fffffff, } .data64 = { 0x7fffffff, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jsgt32: min/max deduction", "jsgt32: min/max deduction",
@ -614,6 +632,7 @@
.data64 = { 1, } .data64 = { 1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jsle32: BPF_X", "jsle32: BPF_X",
@ -640,6 +659,7 @@
.data64 = { 0x7fffffff | 2ULL << 32, } .data64 = { 0x7fffffff | 2ULL << 32, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jsle32: min/max deduction", "jsle32: min/max deduction",
@ -680,6 +700,7 @@
.data64 = { 1, } .data64 = { 1, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jslt32: BPF_X", "jslt32: BPF_X",
@ -706,6 +727,7 @@
.data64 = { 0x7fffffff | 2ULL << 32, } .data64 = { 0x7fffffff | 2ULL << 32, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jslt32: min/max deduction", "jslt32: min/max deduction",

View File

@ -53,6 +53,7 @@
.data64 = { ~0ULL, } .data64 = { ~0ULL, }
}, },
}, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jset: sign-extend", "jset: sign-extend",
@ -70,6 +71,7 @@
.result = ACCEPT, .result = ACCEPT,
.retval = 2, .retval = 2,
.data = { 1, 0, 0, 0, 0, 0, 0, 1, }, .data = { 1, 0, 0, 0, 0, 0, 0, 1, },
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"jset: known const compare", "jset: known const compare",

View File

@ -46,6 +46,7 @@
.errstr_unpriv = "attempt to corrupt spilled", .errstr_unpriv = "attempt to corrupt spilled",
.errstr = "R0 invalid mem access 'inv", .errstr = "R0 invalid mem access 'inv",
.result = REJECT, .result = REJECT,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"check corrupted spill/fill, LSB", "check corrupted spill/fill, LSB",

View File

@ -83,6 +83,7 @@
.result_unpriv = REJECT, .result_unpriv = REJECT,
.errstr_unpriv = "", .errstr_unpriv = "",
.prog_type = BPF_PROG_TYPE_CGROUP_SKB, .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"spin_lock: test4 direct ld/st", "spin_lock: test4 direct ld/st",
@ -112,6 +113,7 @@
.result_unpriv = REJECT, .result_unpriv = REJECT,
.errstr_unpriv = "", .errstr_unpriv = "",
.prog_type = BPF_PROG_TYPE_CGROUP_SKB, .prog_type = BPF_PROG_TYPE_CGROUP_SKB,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"spin_lock: test5 call within a locked region", "spin_lock: test5 call within a locked region",

View File

@ -512,6 +512,7 @@
.fixup_map_array_48b = { 3 }, .fixup_map_array_48b = { 3 },
.result = ACCEPT, .result = ACCEPT,
.retval = 0xabcdef12, .retval = 0xabcdef12,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"map access: unknown scalar += value_ptr, 3", "map access: unknown scalar += value_ptr, 3",
@ -537,6 +538,7 @@
.result_unpriv = REJECT, .result_unpriv = REJECT,
.errstr_unpriv = "R0 pointer arithmetic of map value goes out of range", .errstr_unpriv = "R0 pointer arithmetic of map value goes out of range",
.retval = 0xabcdef12, .retval = 0xabcdef12,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"map access: unknown scalar += value_ptr, 4", "map access: unknown scalar += value_ptr, 4",
@ -559,6 +561,7 @@
.result = REJECT, .result = REJECT,
.errstr = "R1 max value is outside of the array range", .errstr = "R1 max value is outside of the array range",
.errstr_unpriv = "R1 pointer arithmetic of map value goes out of range", .errstr_unpriv = "R1 pointer arithmetic of map value goes out of range",
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"map access: value_ptr += unknown scalar, 1", "map access: value_ptr += unknown scalar, 1",
@ -598,6 +601,7 @@
.fixup_map_array_48b = { 3 }, .fixup_map_array_48b = { 3 },
.result = ACCEPT, .result = ACCEPT,
.retval = 0xabcdef12, .retval = 0xabcdef12,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
}, },
{ {
"map access: value_ptr += unknown scalar, 3", "map access: value_ptr += unknown scalar, 3",