[ftrace-bpf 5/5] add BPF_PROG_TYPE_FTRACE support for samples/bpf

From: yupeng0921
Date: Sun Nov 12 2017 - 02:29:07 EST


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: yupeng0921@xxxxxxxxx
---
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