Skip to content

Commit 03f5781

Browse files
wyqkpborkmann
authored andcommitted
bpf, x86_32: add eBPF JIT compiler for ia32
The JIT compiler emits ia32 bit instructions. Currently, It supports eBPF only. Classic BPF is supported because of the conversion by BPF core. Almost all instructions from eBPF ISA supported except the following: BPF_ALU64 | BPF_DIV | BPF_K BPF_ALU64 | BPF_DIV | BPF_X BPF_ALU64 | BPF_MOD | BPF_K BPF_ALU64 | BPF_MOD | BPF_X BPF_STX | BPF_XADD | BPF_W BPF_STX | BPF_XADD | BPF_DW It doesn't support BPF_JMP|BPF_CALL with BPF_PSEUDO_CALL at the moment. IA32 has few general purpose registers, EAX|EDX|ECX|EBX|ESI|EDI. I use EAX|EDX|ECX|EBX as temporary registers to simulate instructions in eBPF ISA, and allocate ESI|EDI to BPF_REG_AX for constant blinding, all others eBPF registers, R0-R10, are simulated through scratch space on stack. The reasons behind the hardware registers allocation policy are: 1:MUL need EAX:EDX, shift operation need ECX, so they aren't fit for general eBPF 64bit register simulation. 2:We need at least 4 registers to simulate most eBPF ISA operations on registers operands instead of on register&memory operands. 3:We need to put BPF_REG_AX on hardware registers, or constant blinding will degrade jit performance heavily. Tested on PC (Intel(R) Core(TM) i5-5200U CPU). Testing results on i5-5200U: 1) test_bpf: Summary: 349 PASSED, 0 FAILED, [319/341 JIT'ed] 2) test_progs: Summary: 83 PASSED, 0 FAILED. 3) test_lpm: OK 4) test_lru_map: OK 5) test_verifier: Summary: 828 PASSED, 0 FAILED. Above tests are all done in following two conditions separately: 1:bpf_jit_enable=1 and bpf_jit_harden=0 2:bpf_jit_enable=1 and bpf_jit_harden=2 Below are some numbers for this jit implementation: Note: I run test_progs in kselftest 100 times continuously for every condition, the numbers are in format: total/times=avg. The numbers that test_bpf reports show almost the same relation. a:jit_enable=0 and jit_harden=0 b:jit_enable=1 and jit_harden=0 test_pkt_access:PASS:ipv4:15622/100=156 test_pkt_access:PASS:ipv4:10674/100=106 test_pkt_access:PASS:ipv6:9130/100=91 test_pkt_access:PASS:ipv6:4855/100=48 test_xdp:PASS:ipv4:240198/100=2401 test_xdp:PASS:ipv4:138912/100=1389 test_xdp:PASS:ipv6:137326/100=1373 test_xdp:PASS:ipv6:68542/100=685 test_l4lb:PASS:ipv4:61100/100=611 test_l4lb:PASS:ipv4:37302/100=373 test_l4lb:PASS:ipv6:101000/100=1010 test_l4lb:PASS:ipv6:55030/100=550 c:jit_enable=1 and jit_harden=2 test_pkt_access:PASS:ipv4:10558/100=105 test_pkt_access:PASS:ipv6:5092/100=50 test_xdp:PASS:ipv4:131902/100=1319 test_xdp:PASS:ipv6:77932/100=779 test_l4lb:PASS:ipv4:38924/100=389 test_l4lb:PASS:ipv6:57520/100=575 The numbers show we get 30%~50% improvement. See Documentation/networking/filter.txt for more information. Changelog: Changes v5-v6: 1:Add do {} while (0) to RETPOLINE_RAX_BPF_JIT for consistence reason. 2:Clean up non-standard comments, reported by Daniel Borkmann. 3:Fix a memory leak issue, repoted by Daniel Borkmann. Changes v4-v5: 1:Delete is_on_stack, BPF_REG_AX is the only one on real hardware registers, so just check with it. 2:Apply commit 1612a98 ("bpf, x64: fix JIT emission for dead code"), suggested by Daniel Borkmann. Changes v3-v4: 1:Fix changelog in commit. I install llvm-6.0, then test_progs willn't report errors. I submit another patch: "bpf: fix misaligned access for BPF_PROG_TYPE_PERF_EVENT program type on x86_32 platform" to fix another problem, after that patch, test_verifier willn't report errors too. 2:Fix clear r0[1] twice unnecessarily in *BPF_IND|BPF_ABS* simulation. Changes v2-v3: 1:Move BPF_REG_AX to real hardware registers for performance reason. 3:Using bpf_load_pointer instead of bpf_jit32.S, suggested by Daniel Borkmann. 4:Delete partial codes in 1c2a088, suggested by Daniel Borkmann. 5:Some bug fixes and comments improvement. Changes v1-v2: 1:Fix bug in emit_ia32_neg64. 2:Fix bug in emit_ia32_arsh_r64. 3:Delete filename in top level comment, suggested by Thomas Gleixner. 4:Delete unnecessary boiler plate text, suggested by Thomas Gleixner. 5:Rewrite some words in changelog. 6:CodingSytle improvement and a little more comments. Signed-off-by: Wang YanQing <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 6f96674 commit 03f5781

File tree

5 files changed

+2588
-6
lines changed

5 files changed

+2588
-6
lines changed

Documentation/sysctl/net.txt

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ through bpf(2) and passing a verifier in the kernel, a JIT will then
4545
translate these BPF proglets into native CPU instructions. There are
4646
two flavors of JITs, the newer eBPF JIT currently supported on:
4747
- x86_64
48+
- x86_32
4849
- arm64
4950
- arm32
5051
- ppc64

arch/x86/Kconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ config X86
137137
select HAVE_DMA_CONTIGUOUS
138138
select HAVE_DYNAMIC_FTRACE
139139
select HAVE_DYNAMIC_FTRACE_WITH_REGS
140-
select HAVE_EBPF_JIT if X86_64
140+
select HAVE_EBPF_JIT
141141
select HAVE_EFFICIENT_UNALIGNED_ACCESS
142142
select HAVE_EXIT_THREAD
143143
select HAVE_FENTRY if X86_64 || DYNAMIC_FTRACE

arch/x86/include/asm/nospec-branch.h

+27-3
Original file line numberDiff line numberDiff line change
@@ -291,28 +291,52 @@ do { \
291291
* lfence
292292
* jmp spec_trap
293293
* do_rop:
294-
* mov %rax,(%rsp)
294+
* mov %rax,(%rsp) for x86_64
295+
* mov %edx,(%esp) for x86_32
295296
* retq
296297
*
297298
* Without retpolines configured:
298299
*
299-
* jmp *%rax
300+
* jmp *%rax for x86_64
301+
* jmp *%edx for x86_32
300302
*/
301303
#ifdef CONFIG_RETPOLINE
304+
#ifdef CONFIG_X86_64
302305
# define RETPOLINE_RAX_BPF_JIT_SIZE 17
303306
# define RETPOLINE_RAX_BPF_JIT() \
307+
do { \
304308
EMIT1_off32(0xE8, 7); /* callq do_rop */ \
305309
/* spec_trap: */ \
306310
EMIT2(0xF3, 0x90); /* pause */ \
307311
EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \
308312
EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \
309313
/* do_rop: */ \
310314
EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \
311-
EMIT1(0xC3); /* retq */
315+
EMIT1(0xC3); /* retq */ \
316+
} while (0)
312317
#else
318+
# define RETPOLINE_EDX_BPF_JIT() \
319+
do { \
320+
EMIT1_off32(0xE8, 7); /* call do_rop */ \
321+
/* spec_trap: */ \
322+
EMIT2(0xF3, 0x90); /* pause */ \
323+
EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \
324+
EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \
325+
/* do_rop: */ \
326+
EMIT3(0x89, 0x14, 0x24); /* mov %edx,(%esp) */ \
327+
EMIT1(0xC3); /* ret */ \
328+
} while (0)
329+
#endif
330+
#else /* !CONFIG_RETPOLINE */
331+
332+
#ifdef CONFIG_X86_64
313333
# define RETPOLINE_RAX_BPF_JIT_SIZE 2
314334
# define RETPOLINE_RAX_BPF_JIT() \
315335
EMIT2(0xFF, 0xE0); /* jmp *%rax */
336+
#else
337+
# define RETPOLINE_EDX_BPF_JIT() \
338+
EMIT2(0xFF, 0xE2) /* jmp *%edx */
339+
#endif
316340
#endif
317341

318342
#endif /* _ASM_X86_NOSPEC_BRANCH_H_ */

arch/x86/net/Makefile

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#
22
# Arch-specific network modules
33
#
4-
OBJECT_FILES_NON_STANDARD_bpf_jit.o += y
54

6-
obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
5+
ifeq ($(CONFIG_X86_32),y)
6+
obj-$(CONFIG_BPF_JIT) += bpf_jit_comp32.o
7+
else
8+
OBJECT_FILES_NON_STANDARD_bpf_jit.o += y
9+
obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
10+
endif

0 commit comments

Comments
 (0)