diff options
author | David S. Miller <davem@davemloft.net> | 2014-09-09 13:27:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-09-09 13:27:22 -0400 |
commit | afddacc3ccd048c49c7f4f0ad0b6a40730c74715 (patch) | |
tree | f990840a7b9e6afe48ea73a5fdafe1cdc50f936d | |
parent | 5b4c314575ea6edd57c547c2123083d88d8ff4e6 (diff) | |
parent | daedfb22451dd02b35c0549566cbb7cc06bdd53b (diff) |
Merge branch 'ebpf'
Alexei Starovoitov says:
====================
load imm64 insn and uapi/linux/bpf.h
V9->V10
- no changes, added Daniel's ack
Note they're on top of Hannes's patch in the same area [1]
V8 thread with 'why' reasoning and end goal [2]
Original set [3] of ~28 patches I'm planning to present in 4 stages:
I. this 2 patches to fork off llvm upstreaming
II. bpf syscall with manpage and map implementation
III. bpf program load/unload with verifier testsuite (1st user of
instruction macros from bpf.h and 1st user of load imm64 insn)
IV. tracing, etc
[1] http://patchwork.ozlabs.org/patch/385266/
[2] https://lkml.org/lkml/2014/8/27/628
[3] https://lkml.org/lkml/2014/8/26/859
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | Documentation/networking/filter.txt | 8 | ||||
-rw-r--r-- | arch/x86/net/bpf_jit_comp.c | 17 | ||||
-rw-r--r-- | include/linux/filter.h | 74 | ||||
-rw-r--r-- | include/uapi/linux/Kbuild | 1 | ||||
-rw-r--r-- | include/uapi/linux/bpf.h | 65 | ||||
-rw-r--r-- | kernel/bpf/core.c | 5 | ||||
-rw-r--r-- | lib/test_bpf.c | 21 |
7 files changed, 135 insertions, 56 deletions
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt index c48a9704bda8..81916ab5d96f 100644 --- a/Documentation/networking/filter.txt +++ b/Documentation/networking/filter.txt | |||
@@ -951,7 +951,7 @@ Size modifier is one of ... | |||
951 | 951 | ||
952 | Mode modifier is one of: | 952 | Mode modifier is one of: |
953 | 953 | ||
954 | BPF_IMM 0x00 /* classic BPF only, reserved in eBPF */ | 954 | BPF_IMM 0x00 /* used for 32-bit mov in classic BPF and 64-bit in eBPF */ |
955 | BPF_ABS 0x20 | 955 | BPF_ABS 0x20 |
956 | BPF_IND 0x40 | 956 | BPF_IND 0x40 |
957 | BPF_MEM 0x60 | 957 | BPF_MEM 0x60 |
@@ -995,6 +995,12 @@ BPF_XADD | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg | |||
995 | Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW. Note that 1 and | 995 | Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW. Note that 1 and |
996 | 2 byte atomic increments are not supported. | 996 | 2 byte atomic increments are not supported. |
997 | 997 | ||
998 | eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM which consists | ||
999 | of two consecutive 'struct bpf_insn' 8-byte blocks and interpreted as single | ||
1000 | instruction that loads 64-bit immediate value into a dst_reg. | ||
1001 | Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM which loads | ||
1002 | 32-bit immediate value into a register. | ||
1003 | |||
998 | Testing | 1004 | Testing |
999 | ------- | 1005 | ------- |
1000 | 1006 | ||
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 39ccfbb4a723..06f8c17f5484 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c | |||
@@ -393,6 +393,23 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, | |||
393 | EMIT1_off32(add_1reg(0xB8, dst_reg), imm32); | 393 | EMIT1_off32(add_1reg(0xB8, dst_reg), imm32); |
394 | break; | 394 | break; |
395 | 395 | ||
396 | case BPF_LD | BPF_IMM | BPF_DW: | ||
397 | if (insn[1].code != 0 || insn[1].src_reg != 0 || | ||
398 | insn[1].dst_reg != 0 || insn[1].off != 0) { | ||
399 | /* verifier must catch invalid insns */ | ||
400 | pr_err("invalid BPF_LD_IMM64 insn\n"); | ||
401 | return -EINVAL; | ||
402 | } | ||
403 | |||
404 | /* movabsq %rax, imm64 */ | ||
405 | EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg)); | ||
406 | EMIT(insn[0].imm, 4); | ||
407 | EMIT(insn[1].imm, 4); | ||
408 | |||
409 | insn++; | ||
410 | i++; | ||
411 | break; | ||
412 | |||
396 | /* dst %= src, dst /= src, dst %= imm32, dst /= imm32 */ | 413 | /* dst %= src, dst /= src, dst %= imm32, dst /= imm32 */ |
397 | case BPF_ALU | BPF_MOD | BPF_X: | 414 | case BPF_ALU | BPF_MOD | BPF_X: |
398 | case BPF_ALU | BPF_DIV | BPF_X: | 415 | case BPF_ALU | BPF_DIV | BPF_X: |
diff --git a/include/linux/filter.h b/include/linux/filter.h index c78994593355..8f82ef3f1cdd 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
@@ -10,58 +10,12 @@ | |||
10 | #include <linux/workqueue.h> | 10 | #include <linux/workqueue.h> |
11 | #include <uapi/linux/filter.h> | 11 | #include <uapi/linux/filter.h> |
12 | #include <asm/cacheflush.h> | 12 | #include <asm/cacheflush.h> |
13 | #include <uapi/linux/bpf.h> | ||
13 | 14 | ||
14 | struct sk_buff; | 15 | struct sk_buff; |
15 | struct sock; | 16 | struct sock; |
16 | struct seccomp_data; | 17 | struct seccomp_data; |
17 | 18 | ||
18 | /* Internally used and optimized filter representation with extended | ||
19 | * instruction set based on top of classic BPF. | ||
20 | */ | ||
21 | |||
22 | /* instruction classes */ | ||
23 | #define BPF_ALU64 0x07 /* alu mode in double word width */ | ||
24 | |||
25 | /* ld/ldx fields */ | ||
26 | #define BPF_DW 0x18 /* double word */ | ||
27 | #define BPF_XADD 0xc0 /* exclusive add */ | ||
28 | |||
29 | /* alu/jmp fields */ | ||
30 | #define BPF_MOV 0xb0 /* mov reg to reg */ | ||
31 | #define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */ | ||
32 | |||
33 | /* change endianness of a register */ | ||
34 | #define BPF_END 0xd0 /* flags for endianness conversion: */ | ||
35 | #define BPF_TO_LE 0x00 /* convert to little-endian */ | ||
36 | #define BPF_TO_BE 0x08 /* convert to big-endian */ | ||
37 | #define BPF_FROM_LE BPF_TO_LE | ||
38 | #define BPF_FROM_BE BPF_TO_BE | ||
39 | |||
40 | #define BPF_JNE 0x50 /* jump != */ | ||
41 | #define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */ | ||
42 | #define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */ | ||
43 | #define BPF_CALL 0x80 /* function call */ | ||
44 | #define BPF_EXIT 0x90 /* function return */ | ||
45 | |||
46 | /* Register numbers */ | ||
47 | enum { | ||
48 | BPF_REG_0 = 0, | ||
49 | BPF_REG_1, | ||
50 | BPF_REG_2, | ||
51 | BPF_REG_3, | ||
52 | BPF_REG_4, | ||
53 | BPF_REG_5, | ||
54 | BPF_REG_6, | ||
55 | BPF_REG_7, | ||
56 | BPF_REG_8, | ||
57 | BPF_REG_9, | ||
58 | BPF_REG_10, | ||
59 | __MAX_BPF_REG, | ||
60 | }; | ||
61 | |||
62 | /* BPF has 10 general purpose 64-bit registers and stack frame. */ | ||
63 | #define MAX_BPF_REG __MAX_BPF_REG | ||
64 | |||
65 | /* ArgX, context and stack frame pointer register positions. Note, | 19 | /* ArgX, context and stack frame pointer register positions. Note, |
66 | * Arg1, Arg2, Arg3, etc are used as argument mappings of function | 20 | * Arg1, Arg2, Arg3, etc are used as argument mappings of function |
67 | * calls in BPF_CALL instruction. | 21 | * calls in BPF_CALL instruction. |
@@ -166,6 +120,24 @@ enum { | |||
166 | .off = 0, \ | 120 | .off = 0, \ |
167 | .imm = IMM }) | 121 | .imm = IMM }) |
168 | 122 | ||
123 | /* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */ | ||
124 | #define BPF_LD_IMM64(DST, IMM) \ | ||
125 | BPF_LD_IMM64_RAW(DST, 0, IMM) | ||
126 | |||
127 | #define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ | ||
128 | ((struct bpf_insn) { \ | ||
129 | .code = BPF_LD | BPF_DW | BPF_IMM, \ | ||
130 | .dst_reg = DST, \ | ||
131 | .src_reg = SRC, \ | ||
132 | .off = 0, \ | ||
133 | .imm = (__u32) (IMM) }), \ | ||
134 | ((struct bpf_insn) { \ | ||
135 | .code = 0, /* zero is reserved opcode */ \ | ||
136 | .dst_reg = 0, \ | ||
137 | .src_reg = 0, \ | ||
138 | .off = 0, \ | ||
139 | .imm = ((__u64) (IMM)) >> 32 }) | ||
140 | |||
169 | /* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */ | 141 | /* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */ |
170 | 142 | ||
171 | #define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \ | 143 | #define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \ |
@@ -304,14 +276,6 @@ enum { | |||
304 | #define SK_RUN_FILTER(filter, ctx) \ | 276 | #define SK_RUN_FILTER(filter, ctx) \ |
305 | (*filter->prog->bpf_func)(ctx, filter->prog->insnsi) | 277 | (*filter->prog->bpf_func)(ctx, filter->prog->insnsi) |
306 | 278 | ||
307 | struct bpf_insn { | ||
308 | __u8 code; /* opcode */ | ||
309 | __u8 dst_reg:4; /* dest register */ | ||
310 | __u8 src_reg:4; /* source register */ | ||
311 | __s16 off; /* signed offset */ | ||
312 | __s32 imm; /* signed immediate constant */ | ||
313 | }; | ||
314 | |||
315 | #ifdef CONFIG_COMPAT | 279 | #ifdef CONFIG_COMPAT |
316 | /* A struct sock_filter is architecture independent. */ | 280 | /* A struct sock_filter is architecture independent. */ |
317 | struct compat_sock_fprog { | 281 | struct compat_sock_fprog { |
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 24e9033f8b3f..fb3f7b675229 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild | |||
@@ -67,6 +67,7 @@ header-y += bfs_fs.h | |||
67 | header-y += binfmts.h | 67 | header-y += binfmts.h |
68 | header-y += blkpg.h | 68 | header-y += blkpg.h |
69 | header-y += blktrace_api.h | 69 | header-y += blktrace_api.h |
70 | header-y += bpf.h | ||
70 | header-y += bpqether.h | 71 | header-y += bpqether.h |
71 | header-y += bsg.h | 72 | header-y += bsg.h |
72 | header-y += btrfs.h | 73 | header-y += btrfs.h |
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h new file mode 100644 index 000000000000..479ed0b6be16 --- /dev/null +++ b/include/uapi/linux/bpf.h | |||
@@ -0,0 +1,65 @@ | |||
1 | /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of version 2 of the GNU General Public | ||
5 | * License as published by the Free Software Foundation. | ||
6 | */ | ||
7 | #ifndef _UAPI__LINUX_BPF_H__ | ||
8 | #define _UAPI__LINUX_BPF_H__ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | |||
12 | /* Extended instruction set based on top of classic BPF */ | ||
13 | |||
14 | /* instruction classes */ | ||
15 | #define BPF_ALU64 0x07 /* alu mode in double word width */ | ||
16 | |||
17 | /* ld/ldx fields */ | ||
18 | #define BPF_DW 0x18 /* double word */ | ||
19 | #define BPF_XADD 0xc0 /* exclusive add */ | ||
20 | |||
21 | /* alu/jmp fields */ | ||
22 | #define BPF_MOV 0xb0 /* mov reg to reg */ | ||
23 | #define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */ | ||
24 | |||
25 | /* change endianness of a register */ | ||
26 | #define BPF_END 0xd0 /* flags for endianness conversion: */ | ||
27 | #define BPF_TO_LE 0x00 /* convert to little-endian */ | ||
28 | #define BPF_TO_BE 0x08 /* convert to big-endian */ | ||
29 | #define BPF_FROM_LE BPF_TO_LE | ||
30 | #define BPF_FROM_BE BPF_TO_BE | ||
31 | |||
32 | #define BPF_JNE 0x50 /* jump != */ | ||
33 | #define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */ | ||
34 | #define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */ | ||
35 | #define BPF_CALL 0x80 /* function call */ | ||
36 | #define BPF_EXIT 0x90 /* function return */ | ||
37 | |||
38 | /* Register numbers */ | ||
39 | enum { | ||
40 | BPF_REG_0 = 0, | ||
41 | BPF_REG_1, | ||
42 | BPF_REG_2, | ||
43 | BPF_REG_3, | ||
44 | BPF_REG_4, | ||
45 | BPF_REG_5, | ||
46 | BPF_REG_6, | ||
47 | BPF_REG_7, | ||
48 | BPF_REG_8, | ||
49 | BPF_REG_9, | ||
50 | BPF_REG_10, | ||
51 | __MAX_BPF_REG, | ||
52 | }; | ||
53 | |||
54 | /* BPF has 10 general purpose 64-bit registers and stack frame. */ | ||
55 | #define MAX_BPF_REG __MAX_BPF_REG | ||
56 | |||
57 | struct bpf_insn { | ||
58 | __u8 code; /* opcode */ | ||
59 | __u8 dst_reg:4; /* dest register */ | ||
60 | __u8 src_reg:4; /* source register */ | ||
61 | __s16 off; /* signed offset */ | ||
62 | __s32 imm; /* signed immediate constant */ | ||
63 | }; | ||
64 | |||
65 | #endif /* _UAPI__LINUX_BPF_H__ */ | ||
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index b54bb2c2e494..2c2bfaacce66 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c | |||
@@ -242,6 +242,7 @@ static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) | |||
242 | [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W, | 242 | [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W, |
243 | [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H, | 243 | [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H, |
244 | [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B, | 244 | [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B, |
245 | [BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW, | ||
245 | }; | 246 | }; |
246 | void *ptr; | 247 | void *ptr; |
247 | int off; | 248 | int off; |
@@ -301,6 +302,10 @@ select_insn: | |||
301 | ALU64_MOV_K: | 302 | ALU64_MOV_K: |
302 | DST = IMM; | 303 | DST = IMM; |
303 | CONT; | 304 | CONT; |
305 | LD_IMM_DW: | ||
306 | DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32; | ||
307 | insn++; | ||
308 | CONT; | ||
304 | ALU64_ARSH_X: | 309 | ALU64_ARSH_X: |
305 | (*(s64 *) &DST) >>= SRC; | 310 | (*(s64 *) &DST) >>= SRC; |
306 | CONT; | 311 | CONT; |
diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 9a67456ba29a..413890815d3e 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c | |||
@@ -1735,6 +1735,27 @@ static struct bpf_test tests[] = { | |||
1735 | { }, | 1735 | { }, |
1736 | { { 1, 0 } }, | 1736 | { { 1, 0 } }, |
1737 | }, | 1737 | }, |
1738 | { | ||
1739 | "load 64-bit immediate", | ||
1740 | .u.insns_int = { | ||
1741 | BPF_LD_IMM64(R1, 0x567800001234L), | ||
1742 | BPF_MOV64_REG(R2, R1), | ||
1743 | BPF_MOV64_REG(R3, R2), | ||
1744 | BPF_ALU64_IMM(BPF_RSH, R2, 32), | ||
1745 | BPF_ALU64_IMM(BPF_LSH, R3, 32), | ||
1746 | BPF_ALU64_IMM(BPF_RSH, R3, 32), | ||
1747 | BPF_ALU64_IMM(BPF_MOV, R0, 0), | ||
1748 | BPF_JMP_IMM(BPF_JEQ, R2, 0x5678, 1), | ||
1749 | BPF_EXIT_INSN(), | ||
1750 | BPF_JMP_IMM(BPF_JEQ, R3, 0x1234, 1), | ||
1751 | BPF_EXIT_INSN(), | ||
1752 | BPF_ALU64_IMM(BPF_MOV, R0, 1), | ||
1753 | BPF_EXIT_INSN(), | ||
1754 | }, | ||
1755 | INTERNAL, | ||
1756 | { }, | ||
1757 | { { 0, 1 } } | ||
1758 | }, | ||
1738 | }; | 1759 | }; |
1739 | 1760 | ||
1740 | static struct net_device dev; | 1761 | static struct net_device dev; |