diff options
| author | Alexei Starovoitov <ast@plumgrid.com> | 2014-09-26 03:17:07 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-09-26 15:05:15 -0400 |
| commit | 3c731eba48e1b0650decfc91a839b80f0e05ce8f (patch) | |
| tree | ad7927653cfca896fd60e2e7b2fb12750e46fd2e /samples | |
| parent | 17a5267067f3c372fec9ffb798d6eaba6b5e6a4c (diff) | |
bpf: mini eBPF library, test stubs and verifier testsuite
1.
the library includes a trivial set of BPF syscall wrappers:
int bpf_create_map(int key_size, int value_size, int max_entries);
int bpf_update_elem(int fd, void *key, void *value);
int bpf_lookup_elem(int fd, void *key, void *value);
int bpf_delete_elem(int fd, void *key);
int bpf_get_next_key(int fd, void *key, void *next_key);
int bpf_prog_load(enum bpf_prog_type prog_type,
const struct sock_filter_int *insns, int insn_len,
const char *license);
bpf_prog_load() stores verifier log into global bpf_log_buf[] array
and BPF_*() macros to build instructions
2.
test stubs configure eBPF infra with 'unspec' map and program types.
These are fake types used by user space testsuite only.
3.
verifier tests valid and invalid programs and expects predefined
error log messages from kernel.
40 tests so far.
$ sudo ./test_verifier
#0 add+sub+mul OK
#1 unreachable OK
#2 unreachable2 OK
#3 out of range jump OK
#4 out of range jump2 OK
#5 test1 ld_imm64 OK
...
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'samples')
| -rw-r--r-- | samples/bpf/Makefile | 12 | ||||
| -rw-r--r-- | samples/bpf/libbpf.c | 94 | ||||
| -rw-r--r-- | samples/bpf/libbpf.h | 172 | ||||
| -rw-r--r-- | samples/bpf/test_verifier.c | 548 |
4 files changed, 826 insertions, 0 deletions
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile new file mode 100644 index 000000000000..634391797856 --- /dev/null +++ b/samples/bpf/Makefile | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | # kbuild trick to avoid linker error. Can be omitted if a module is built. | ||
| 2 | obj- := dummy.o | ||
| 3 | |||
| 4 | # List of programs to build | ||
| 5 | hostprogs-y := test_verifier | ||
| 6 | |||
| 7 | test_verifier-objs := test_verifier.o libbpf.o | ||
| 8 | |||
| 9 | # Tell kbuild to always build the programs | ||
| 10 | always := $(hostprogs-y) | ||
| 11 | |||
| 12 | HOSTCFLAGS += -I$(objtree)/usr/include | ||
diff --git a/samples/bpf/libbpf.c b/samples/bpf/libbpf.c new file mode 100644 index 000000000000..ff6504420738 --- /dev/null +++ b/samples/bpf/libbpf.c | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | /* eBPF mini library */ | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <stdio.h> | ||
| 4 | #include <linux/unistd.h> | ||
| 5 | #include <unistd.h> | ||
| 6 | #include <string.h> | ||
| 7 | #include <linux/netlink.h> | ||
| 8 | #include <linux/bpf.h> | ||
| 9 | #include <errno.h> | ||
| 10 | #include "libbpf.h" | ||
| 11 | |||
| 12 | static __u64 ptr_to_u64(void *ptr) | ||
| 13 | { | ||
| 14 | return (__u64) (unsigned long) ptr; | ||
| 15 | } | ||
| 16 | |||
| 17 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, | ||
| 18 | int max_entries) | ||
| 19 | { | ||
| 20 | union bpf_attr attr = { | ||
| 21 | .map_type = map_type, | ||
| 22 | .key_size = key_size, | ||
| 23 | .value_size = value_size, | ||
| 24 | .max_entries = max_entries | ||
| 25 | }; | ||
| 26 | |||
| 27 | return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr)); | ||
| 28 | } | ||
| 29 | |||
| 30 | int bpf_update_elem(int fd, void *key, void *value) | ||
| 31 | { | ||
| 32 | union bpf_attr attr = { | ||
| 33 | .map_fd = fd, | ||
| 34 | .key = ptr_to_u64(key), | ||
| 35 | .value = ptr_to_u64(value), | ||
| 36 | }; | ||
| 37 | |||
| 38 | return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); | ||
| 39 | } | ||
| 40 | |||
| 41 | int bpf_lookup_elem(int fd, void *key, void *value) | ||
| 42 | { | ||
| 43 | union bpf_attr attr = { | ||
| 44 | .map_fd = fd, | ||
| 45 | .key = ptr_to_u64(key), | ||
| 46 | .value = ptr_to_u64(value), | ||
| 47 | }; | ||
| 48 | |||
| 49 | return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); | ||
| 50 | } | ||
| 51 | |||
| 52 | int bpf_delete_elem(int fd, void *key) | ||
| 53 | { | ||
| 54 | union bpf_attr attr = { | ||
| 55 | .map_fd = fd, | ||
| 56 | .key = ptr_to_u64(key), | ||
| 57 | }; | ||
| 58 | |||
| 59 | return syscall(__NR_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr)); | ||
| 60 | } | ||
| 61 | |||
| 62 | int bpf_get_next_key(int fd, void *key, void *next_key) | ||
| 63 | { | ||
| 64 | union bpf_attr attr = { | ||
| 65 | .map_fd = fd, | ||
| 66 | .key = ptr_to_u64(key), | ||
| 67 | .next_key = ptr_to_u64(next_key), | ||
| 68 | }; | ||
| 69 | |||
| 70 | return syscall(__NR_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr)); | ||
| 71 | } | ||
| 72 | |||
| 73 | #define ROUND_UP(x, n) (((x) + (n) - 1u) & ~((n) - 1u)) | ||
| 74 | |||
| 75 | char bpf_log_buf[LOG_BUF_SIZE]; | ||
| 76 | |||
| 77 | int bpf_prog_load(enum bpf_prog_type prog_type, | ||
| 78 | const struct bpf_insn *insns, int prog_len, | ||
| 79 | const char *license) | ||
| 80 | { | ||
| 81 | union bpf_attr attr = { | ||
| 82 | .prog_type = prog_type, | ||
| 83 | .insns = ptr_to_u64((void *) insns), | ||
| 84 | .insn_cnt = prog_len / sizeof(struct bpf_insn), | ||
| 85 | .license = ptr_to_u64((void *) license), | ||
| 86 | .log_buf = ptr_to_u64(bpf_log_buf), | ||
| 87 | .log_size = LOG_BUF_SIZE, | ||
| 88 | .log_level = 1, | ||
| 89 | }; | ||
| 90 | |||
| 91 | bpf_log_buf[0] = 0; | ||
| 92 | |||
| 93 | return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); | ||
| 94 | } | ||
diff --git a/samples/bpf/libbpf.h b/samples/bpf/libbpf.h new file mode 100644 index 000000000000..8a31babeca5d --- /dev/null +++ b/samples/bpf/libbpf.h | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | /* eBPF mini library */ | ||
| 2 | #ifndef __LIBBPF_H | ||
| 3 | #define __LIBBPF_H | ||
| 4 | |||
| 5 | struct bpf_insn; | ||
| 6 | |||
| 7 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, | ||
| 8 | int max_entries); | ||
| 9 | int bpf_update_elem(int fd, void *key, void *value); | ||
| 10 | int bpf_lookup_elem(int fd, void *key, void *value); | ||
| 11 | int bpf_delete_elem(int fd, void *key); | ||
| 12 | int bpf_get_next_key(int fd, void *key, void *next_key); | ||
| 13 | |||
| 14 | int bpf_prog_load(enum bpf_prog_type prog_type, | ||
| 15 | const struct bpf_insn *insns, int insn_len, | ||
| 16 | const char *license); | ||
| 17 | |||
| 18 | #define LOG_BUF_SIZE 8192 | ||
| 19 | extern char bpf_log_buf[LOG_BUF_SIZE]; | ||
| 20 | |||
| 21 | /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ | ||
| 22 | |||
| 23 | #define BPF_ALU64_REG(OP, DST, SRC) \ | ||
| 24 | ((struct bpf_insn) { \ | ||
| 25 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ | ||
| 26 | .dst_reg = DST, \ | ||
| 27 | .src_reg = SRC, \ | ||
| 28 | .off = 0, \ | ||
| 29 | .imm = 0 }) | ||
| 30 | |||
| 31 | #define BPF_ALU32_REG(OP, DST, SRC) \ | ||
| 32 | ((struct bpf_insn) { \ | ||
| 33 | .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ | ||
| 34 | .dst_reg = DST, \ | ||
| 35 | .src_reg = SRC, \ | ||
| 36 | .off = 0, \ | ||
| 37 | .imm = 0 }) | ||
| 38 | |||
| 39 | /* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */ | ||
| 40 | |||
| 41 | #define BPF_ALU64_IMM(OP, DST, IMM) \ | ||
| 42 | ((struct bpf_insn) { \ | ||
| 43 | .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ | ||
| 44 | .dst_reg = DST, \ | ||
| 45 | .src_reg = 0, \ | ||
| 46 | .off = 0, \ | ||
| 47 | .imm = IMM }) | ||
| 48 | |||
| 49 | #define BPF_ALU32_IMM(OP, DST, IMM) \ | ||
| 50 | ((struct bpf_insn) { \ | ||
| 51 | .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ | ||
| 52 | .dst_reg = DST, \ | ||
| 53 | .src_reg = 0, \ | ||
| 54 | .off = 0, \ | ||
| 55 | .imm = IMM }) | ||
| 56 | |||
| 57 | /* Short form of mov, dst_reg = src_reg */ | ||
| 58 | |||
| 59 | #define BPF_MOV64_REG(DST, SRC) \ | ||
| 60 | ((struct bpf_insn) { \ | ||
| 61 | .code = BPF_ALU64 | BPF_MOV | BPF_X, \ | ||
| 62 | .dst_reg = DST, \ | ||
| 63 | .src_reg = SRC, \ | ||
| 64 | .off = 0, \ | ||
| 65 | .imm = 0 }) | ||
| 66 | |||
| 67 | /* Short form of mov, dst_reg = imm32 */ | ||
| 68 | |||
| 69 | #define BPF_MOV64_IMM(DST, IMM) \ | ||
| 70 | ((struct bpf_insn) { \ | ||
| 71 | .code = BPF_ALU64 | BPF_MOV | BPF_K, \ | ||
| 72 | .dst_reg = DST, \ | ||
| 73 | .src_reg = 0, \ | ||
| 74 | .off = 0, \ | ||
| 75 | .imm = IMM }) | ||
| 76 | |||
| 77 | /* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */ | ||
| 78 | #define BPF_LD_IMM64(DST, IMM) \ | ||
| 79 | BPF_LD_IMM64_RAW(DST, 0, IMM) | ||
| 80 | |||
| 81 | #define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ | ||
| 82 | ((struct bpf_insn) { \ | ||
| 83 | .code = BPF_LD | BPF_DW | BPF_IMM, \ | ||
| 84 | .dst_reg = DST, \ | ||
| 85 | .src_reg = SRC, \ | ||
| 86 | .off = 0, \ | ||
| 87 | .imm = (__u32) (IMM) }), \ | ||
| 88 | ((struct bpf_insn) { \ | ||
| 89 | .code = 0, /* zero is reserved opcode */ \ | ||
| 90 | .dst_reg = 0, \ | ||
| 91 | .src_reg = 0, \ | ||
| 92 | .off = 0, \ | ||
| 93 | .imm = ((__u64) (IMM)) >> 32 }) | ||
| 94 | |||
| 95 | #define BPF_PSEUDO_MAP_FD 1 | ||
| 96 | |||
| 97 | /* pseudo BPF_LD_IMM6 | ||
