let bpf_load.c write prog file descriptor to /sys/kernel/debug/tracing/set_ftrace_bpf if the prog sector name is "ftrace". Add test code ftrace_graph_kern.c and ftrace_graph_user.c in samples/bpf directory. ftrace_graph_kern.c works on the ip_rcv function, return 1 if the packet is received by lo device. ftrace_graph_user.c load the ftrace_graph_kern.c to kernel, and let the graph function tracer only trace ip_rcv function, and check the packet by bpf prog.
Signed-off-by: [email protected] --- samples/bpf/Makefile | 4 +++ samples/bpf/bpf_load.c | 24 +++++++++++++++++ samples/bpf/ftrace_graph_kern.c | 43 +++++++++++++++++++++++++++++ samples/bpf/ftrace_graph_user.c | 45 +++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 1 + tools/testing/selftests/bpf/bpf_helpers.h | 7 +++++ 6 files changed, 124 insertions(+) create mode 100644 samples/bpf/ftrace_graph_kern.c create mode 100644 samples/bpf/ftrace_graph_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 9b4a66e..e7e4010 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -42,6 +42,7 @@ hostprogs-y += xdp_redirect hostprogs-y += xdp_redirect_map hostprogs-y += xdp_monitor hostprogs-y += syscall_tp +hostprogs-y += ftrace_graph # Libbpf dependencies LIBBPF := ../../tools/lib/bpf/bpf.o @@ -87,6 +88,7 @@ xdp_redirect-objs := bpf_load.o $(LIBBPF) xdp_redirect_user.o xdp_redirect_map-objs := bpf_load.o $(LIBBPF) xdp_redirect_map_user.o xdp_monitor-objs := bpf_load.o $(LIBBPF) xdp_monitor_user.o syscall_tp-objs := bpf_load.o $(LIBBPF) syscall_tp_user.o +ftrace_graph-objs := bpf_load.o $(LIBBPF) ftrace_graph_user.o # Tell kbuild to always build the programs always := $(hostprogs-y) @@ -132,6 +134,7 @@ always += xdp_redirect_kern.o always += xdp_redirect_map_kern.o always += xdp_monitor_kern.o always += syscall_tp_kern.o +always += ftrace_graph_kern.o HOSTCFLAGS += -I$(objtree)/usr/include HOSTCFLAGS += -I$(srctree)/tools/lib/ @@ -172,6 +175,7 @@ HOSTLOADLIBES_xdp_redirect += -lelf HOSTLOADLIBES_xdp_redirect_map += -lelf HOSTLOADLIBES_xdp_monitor += -lelf HOSTLOADLIBES_syscall_tp += -lelf +HOSTLOADLIBES_ftrace_graph += -lelf # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 2325d7a..b9e9c14 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c @@ -61,6 +61,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) bool is_kprobe = strncmp(event, "kprobe/", 7) == 0; bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0; bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0; + bool is_ftrace = strncmp(event, "ftrace", 6) == 0; bool is_xdp = strncmp(event, "xdp", 3) == 0; bool is_perf_event = strncmp(event, "perf_event", 10) == 0; bool is_cgroup_skb = strncmp(event, "cgroup/skb", 10) == 0; @@ -71,6 +72,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) enum bpf_prog_type prog_type; char buf[256]; int fd, efd, err, id; + int cnt; struct perf_event_attr attr = {}; attr.type = PERF_TYPE_TRACEPOINT; @@ -84,6 +86,8 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) prog_type = BPF_PROG_TYPE_KPROBE; } else if (is_tracepoint) { prog_type = BPF_PROG_TYPE_TRACEPOINT; + } else if (is_ftrace) { + prog_type = BPF_PROG_TYPE_FTRACE; } else if (is_xdp) { prog_type = BPF_PROG_TYPE_XDP; } else if (is_perf_event) { @@ -128,6 +132,25 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) return populate_prog_array(event, fd); } + if (is_ftrace) { + cnt = snprintf(buf, sizeof(buf), "%d", fd); + efd = open("/sys/kernel/debug/tracing/set_ftrace_bpf", + O_WRONLY, 0); + if (efd < 0) { + printf("open set_ftrace_bpf failed %s\n", + strerror(errno)); + return -1; + } + err = write(efd, buf, cnt); + if (err < 0 || err > cnt) { + printf("write set_ftrace_bpf failed %s\n", + strerror(errno)); + return -1; + } + close(efd); + return 0; + } + if (is_kprobe || is_kretprobe) { if (is_kprobe) event += 7; @@ -572,6 +595,7 @@ static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map) if (memcmp(shname, "kprobe/", 7) == 0 || memcmp(shname, "kretprobe/", 10) == 0 || memcmp(shname, "tracepoint/", 11) == 0 || + memcmp(shname, "ftrace", 6) == 0 || memcmp(shname, "xdp", 3) == 0 || memcmp(shname, "perf_event", 10) == 0 || memcmp(shname, "socket", 6) == 0 || diff --git a/samples/bpf/ftrace_graph_kern.c b/samples/bpf/ftrace_graph_kern.c new file mode 100644 index 0000000..f4d172d --- /dev/null +++ b/samples/bpf/ftrace_graph_kern.c @@ -0,0 +1,43 @@ +/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <uapi/linux/bpf.h> +#include <linux/version.h> +#include <linux/ftrace.h> +#include "bpf_helpers.h" + +#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val; }) + +/* kprobe is NOT a stable ABI + * kernel functions can be removed, renamed or completely change semantics. + * Number of arguments and their positions can change, etc. + * In such case this bpf+kprobe example will no longer be meaningful + */ +SEC("ftrace") +int bpf_prog1(struct ftrace_regs *ctx) +{ + char devname[IFNAMSIZ]; + struct net_device *dev; + struct sk_buff *skb; + + skb = (struct sk_buff *) FTRACE_REGS_PARAM1(ctx); + dev = _(skb->dev); + + bpf_probe_read(devname, sizeof(devname), dev->name); + if (devname[0] == 'l' && devname[1] == 'o') { + char fmt[] = "track dev: %s"; + + bpf_trace_printk(fmt, sizeof(fmt), devname); + return 1; + } else { + return 0; + } +} + +char _license[] SEC("license") = "GPL"; +u32 _version SEC("version") = LINUX_VERSION_CODE; diff --git a/samples/bpf/ftrace_graph_user.c b/samples/bpf/ftrace_graph_user.c new file mode 100644 index 0000000..5b2a085 --- /dev/null +++ b/samples/bpf/ftrace_graph_user.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <linux/bpf.h> +#include <unistd.h> +#include "libbpf.h" +#include "bpf_load.h" + +int main(int ac, char **argv) +{ + FILE *f; + char filename[256]; + int ret; + + snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); + + if (load_bpf_file(filename)) { + printf("%s", bpf_log_buf); + return 1; + } + + ret = system( + "echo ip_rcv > /sys/kernel/debug/tracing/set_graph_function"); + if (ret != 0) { + printf("set_graph_function failed\n"); + return 1; + } + ret = system( + "echo function_graph > /sys/kernel/debug/tracing/current_tracer"); + if (ret != 0) { + printf("set current_tracer faield\n"); + return 1; + } + ret = system( + "echo 1 > /sys/kernel/debug/tracing/tracing_on"); + if (ret != 0) { + printf("tracing_on failed\n"); + return 1; + } + f = popen("nc localhost 9001", "r"); + (void) f; + + read_trace_pipe(); + + return 0; +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 30f2ce7..cced53c 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -118,6 +118,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_UNSPEC, BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_KPROBE, + BPF_PROG_TYPE_FTRACE, BPF_PROG_TYPE_SCHED_CLS, BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_TRACEPOINT, diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 50353c1..dcbc209 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -123,6 +123,13 @@ static int (*bpf_skb_change_head)(void *, int len, int flags) = #define PT_REGS_SP(x) ((x)->sp) #define PT_REGS_IP(x) ((x)->ip) +#define FTRACE_REGS_PARAM1(x) ((x)->rdi) +#define FTRACE_REGS_PARAM2(x) ((x)->rsi) +#define FTRACE_REGS_PARAM3(x) ((x)->rdx) +#define FTRACE_REGS_PARAM4(x) ((x)->rcx) +#define FTRACE_REGS_PARAM5(x) ((x)->r8) +#define FTRACE_REGS_PARAM6(x) ((x)->r9) + #elif defined(__s390x__) #define PT_REGS_PARM1(x) ((x)->gprs[2]) -- 2.7.4

