[PATCH v3 linux-trace 3/8] samples: bpf: simple tracing example in eBPF assembler
simple packet drop monitor: - in-kernel eBPF program attaches to skb:kfree_skb event and records number of packet drops at given location - userspace iterates over the map every second and prints stats Usage: $ sudo dropmon location 0x81695995 count 1 location 0x816d0da9 count 2 location 0x81695995 count 2 location 0x816d0da9 count 2 location 0x81695995 count 3 location 0x816d0da9 count 2 $ addr2line -ape ./bld_x64/vmlinux 0x81695995 0x816d0da9 0x81695995: ./bld_x64/../net/ipv4/icmp.c:1038 0x816d0da9: ./bld_x64/../net/unix/af_unix.c:1231 Signed-off-by: Alexei Starovoitov --- samples/bpf/Makefile |2 + samples/bpf/dropmon.c | 143 + samples/bpf/libbpf.c |7 +++ samples/bpf/libbpf.h |4 ++ 4 files changed, 156 insertions(+) create mode 100644 samples/bpf/dropmon.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index b5b3600dcdf5..789691374562 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -6,7 +6,9 @@ hostprogs-y := test_verifier test_maps hostprogs-y += sock_example hostprogs-y += sockex1 hostprogs-y += sockex2 +hostprogs-y += dropmon +dropmon-objs := dropmon.o libbpf.o test_verifier-objs := test_verifier.o libbpf.o test_maps-objs := test_maps.o libbpf.o sock_example-objs := sock_example.o libbpf.o diff --git a/samples/bpf/dropmon.c b/samples/bpf/dropmon.c new file mode 100644 index ..515504f68506 --- /dev/null +++ b/samples/bpf/dropmon.c @@ -0,0 +1,143 @@ +/* simple packet drop monitor: + * - in-kernel eBPF program attaches to kfree_skb() event and records number + * of packet drops at given location + * - userspace iterates over the map every second and prints stats + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libbpf.h" + +#define TRACEPOINT "/sys/kernel/debug/tracing/events/skb/kfree_skb/id" + +static int dropmon(void) +{ + long long key, next_key, value = 0; + int prog_fd, map_fd, i, event_fd, efd, err; + char buf[32]; + + map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024); + if (map_fd < 0) { + printf("failed to create map '%s'\n", strerror(errno)); + goto cleanup; + } + + /* the following eBPF program is equivalent to C: +* int filter(struct bpf_context *ctx) +* { +* long loc = ctx->arg2; +* long init_val = 1; +* long *value; +* +* value = bpf_map_lookup_elem(MAP_ID, ); +* if (value) { +* __sync_fetch_and_add(value, 1); +* } else { +* bpf_map_update_elem(MAP_ID, , _val, BPF_ANY); +* } +* return 0; +* } +*/ + struct bpf_insn prog[] = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), /* r2 = *(u64 *)(r1 + 8) */ + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), /* *(u64 *)(fp - 8) = r2 */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */ + BPF_LD_MAP_FD(BPF_REG_1, map_fd), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), + BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */ + BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ + BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ + BPF_EXIT_INSN(), + BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 1), /* *(u64 *)(fp - 16) = 1 */ + BPF_MOV64_IMM(BPF_REG_4, BPF_ANY), + BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -16), /* r3 = fp - 16 */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */ + BPF_LD_MAP_FD(BPF_REG_1, map_fd), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem), + BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ + BPF_EXIT_INSN(), + }; + + prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, prog, + sizeof(prog), "GPL"); + if (prog_fd < 0) { + printf("failed to load prog '%s'\n%s", + strerror(errno), bpf_log_buf); + return -1; + } + + + event_fd = open(TRACEPOINT, O_RDONLY, 0); + if (event_fd < 0) { + printf("failed to open event %s\n", TRACEPOINT); + return -1; + } + + err = read(event_fd, buf, sizeof(buf)); + if (err < 0 || err >= sizeof(buf)) { + printf("read from '%s' failed '%s'\n", +
[PATCH v3 linux-trace 3/8] samples: bpf: simple tracing example in eBPF assembler
simple packet drop monitor: - in-kernel eBPF program attaches to skb:kfree_skb event and records number of packet drops at given location - userspace iterates over the map every second and prints stats Usage: $ sudo dropmon location 0x81695995 count 1 location 0x816d0da9 count 2 location 0x81695995 count 2 location 0x816d0da9 count 2 location 0x81695995 count 3 location 0x816d0da9 count 2 $ addr2line -ape ./bld_x64/vmlinux 0x81695995 0x816d0da9 0x81695995: ./bld_x64/../net/ipv4/icmp.c:1038 0x816d0da9: ./bld_x64/../net/unix/af_unix.c:1231 Signed-off-by: Alexei Starovoitov a...@plumgrid.com --- samples/bpf/Makefile |2 + samples/bpf/dropmon.c | 143 + samples/bpf/libbpf.c |7 +++ samples/bpf/libbpf.h |4 ++ 4 files changed, 156 insertions(+) create mode 100644 samples/bpf/dropmon.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index b5b3600dcdf5..789691374562 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -6,7 +6,9 @@ hostprogs-y := test_verifier test_maps hostprogs-y += sock_example hostprogs-y += sockex1 hostprogs-y += sockex2 +hostprogs-y += dropmon +dropmon-objs := dropmon.o libbpf.o test_verifier-objs := test_verifier.o libbpf.o test_maps-objs := test_maps.o libbpf.o sock_example-objs := sock_example.o libbpf.o diff --git a/samples/bpf/dropmon.c b/samples/bpf/dropmon.c new file mode 100644 index ..515504f68506 --- /dev/null +++ b/samples/bpf/dropmon.c @@ -0,0 +1,143 @@ +/* simple packet drop monitor: + * - in-kernel eBPF program attaches to kfree_skb() event and records number + * of packet drops at given location + * - userspace iterates over the map every second and prints stats + */ +#include stdio.h +#include unistd.h +#include linux/bpf.h +#include errno.h +#include linux/unistd.h +#include string.h +#include linux/filter.h +#include stdlib.h +#include sys/types.h +#include sys/stat.h +#include fcntl.h +#include stdbool.h +#include linux/perf_event.h +#include sys/syscall.h +#include sys/ioctl.h +#include libbpf.h + +#define TRACEPOINT /sys/kernel/debug/tracing/events/skb/kfree_skb/id + +static int dropmon(void) +{ + long long key, next_key, value = 0; + int prog_fd, map_fd, i, event_fd, efd, err; + char buf[32]; + + map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(key), sizeof(value), 1024); + if (map_fd 0) { + printf(failed to create map '%s'\n, strerror(errno)); + goto cleanup; + } + + /* the following eBPF program is equivalent to C: +* int filter(struct bpf_context *ctx) +* { +* long loc = ctx-arg2; +* long init_val = 1; +* long *value; +* +* value = bpf_map_lookup_elem(MAP_ID, loc); +* if (value) { +* __sync_fetch_and_add(value, 1); +* } else { +* bpf_map_update_elem(MAP_ID, loc, init_val, BPF_ANY); +* } +* return 0; +* } +*/ + struct bpf_insn prog[] = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, 8), /* r2 = *(u64 *)(r1 + 8) */ + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_2, -8), /* *(u64 *)(fp - 8) = r2 */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */ + BPF_LD_MAP_FD(BPF_REG_1, map_fd), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4), + BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */ + BPF_RAW_INSN(BPF_STX | BPF_XADD | BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* xadd r0 += r1 */ + BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ + BPF_EXIT_INSN(), + BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 1), /* *(u64 *)(fp - 16) = 1 */ + BPF_MOV64_IMM(BPF_REG_4, BPF_ANY), + BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -16), /* r3 = fp - 16 */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = fp - 8 */ + BPF_LD_MAP_FD(BPF_REG_1, map_fd), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_update_elem), + BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ + BPF_EXIT_INSN(), + }; + + prog_fd = bpf_prog_load(BPF_PROG_TYPE_TRACEPOINT, prog, + sizeof(prog), GPL); + if (prog_fd 0) { + printf(failed to load prog '%s'\n%s, + strerror(errno), bpf_log_buf); + return -1; + } + + + event_fd = open(TRACEPOINT, O_RDONLY, 0); + if (event_fd 0) { + printf(failed to open event %s\n, TRACEPOINT); + return -1; +