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

Reply via email to