Hi Ingo,
I think it's good to go.
Patch 1 is already in net-next. Patch 3 depends on it.
I'm assuming it's not going to be a problem during merge window.
Patch 3 will have a minor conflict in uapi/linux/bpf.h in linux-next,
since net-next has added new lines to the bpf_prog_type and bpf_func_id enums.
I'm assuming it's not a problem either.
V8->V9:
- fixed comment style and allowed ispunct after %p
- added Steven's Reviewed-by. Thanks Steven!
V7->V8:
- split addition of kprobe flag into separate patch
- switched to __this_cpu_inc in now documented trace_call_bpf()
- converted array into standalone bpf_func_proto and switch statement
(this apporach looks cleanest, especially considering patch 5)
- refactored patch 5 bpf_trace_printk to do strict checking
V6->V7:
- rebase and remove confusing _notrace suffix from preempt_disable/enable
everything else unchanged
V5->V6:
- added simple recursion check to trace_call_bpf()
- added tracex4 example that does kmem_cache_alloc/free tracking.
It remembers every allocated object in a map and user space periodically
prints a set of old objects. With more work in can be made into
simple kmemleak detector.
It was used as a test of recursive kmalloc/kfree: attached to
kprobe/__kmalloc and let program to call kmalloc again.
V4->V5:
- switched to ktime_get_mono_fast_ns() as suggested by Peter
- in libbpf.c fixed zero init of 'union bpf_attr' padding
- fresh rebase on tip/master
V3 discussion:
https://lkml.org/lkml/2015/2/9/738
V3->V4:
- since the boundary of stable ABI in bpf+tracepoints is not clear yet,
I've dropped them for now.
- bpf+syscalls are ok from stable ABI point of view, but bpf+seccomp
would want to do very similar analysis of syscalls, so I've dropped
them as well to take time and define common bpf+syscalls and bpf+seccomp
infra in the future.
- so only bpf+kprobes left. kprobes by definition is not a stable ABI,
so bpf+kprobe is not stable ABI either. To stress on that point added
kernel version attribute that user space must pass along with the program
and kernel will reject programs when version code doesn't match.
So bpf+kprobe is very similar to kernel modules, but unlike modules
version check is not used for safety, but for enforcing 'non-ABI-ness'.
(version check doesn't apply to bpf+sockets which are stable)
Programs are attached to kprobe events via API:
prog_fd = bpf_prog_load(...);
struct perf_event_attr attr = {
.type = PERF_TYPE_TRACEPOINT,
.config = event_id, /* ID of just created kprobe event */
};
event_fd = perf_event_open(&attr,...);
ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
Next step is to prototype TCP stack instrumentation (like web10g) using
bpf+kprobe, but without adding any new code tcp stack.
Though kprobes are slow comparing to tracepoints, they are good enough
for prototyping and trace_marker/debug_tracepoint ideas can accelerate
them in the future.
Alexei Starovoitov (8):
tracing: add kprobe flag
tracing: attach BPF programs to kprobes
tracing: allow BPF programs to call bpf_ktime_get_ns()
tracing: allow BPF programs to call bpf_trace_printk()
samples: bpf: simple non-portable kprobe filter example
samples: bpf: counting example for kfree_skb and write syscall
samples: bpf: IO latency analysis (iosnoop/heatmap)
samples: bpf: kmem_alloc/free tracker
Daniel Borkmann (1):
bpf: make internal bpf API independent of CONFIG_BPF_SYSCALL ifdefs
include/linux/bpf.h | 20 +++-
include/linux/ftrace_event.h | 14 +++
include/uapi/linux/bpf.h | 5 +
include/uapi/linux/perf_event.h | 1 +
kernel/bpf/syscall.c | 7 +-
kernel/events/core.c | 59 +++++++++++
kernel/trace/Makefile | 1 +
kernel/trace/bpf_trace.c | 222 +++++++++++++++++++++++++++++++++++++++
kernel/trace/trace_kprobe.c | 10 +-
samples/bpf/Makefile | 16 +++
samples/bpf/bpf_helpers.h | 6 ++
samples/bpf/bpf_load.c | 125 ++++++++++++++++++++--
samples/bpf/bpf_load.h | 3 +
samples/bpf/libbpf.c | 14 ++-
samples/bpf/libbpf.h | 5 +-
samples/bpf/sock_example.c | 2 +-
samples/bpf/test_verifier.c | 2 +-
samples/bpf/tracex1_kern.c | 50 +++++++++
samples/bpf/tracex1_user.c | 25 +++++
samples/bpf/tracex2_kern.c | 86 +++++++++++++++
samples/bpf/tracex2_user.c | 95 +++++++++++++++++
samples/bpf/tracex3_kern.c | 89 ++++++++++++++++
samples/bpf/tracex3_user.c | 150 ++++++++++++++++++++++++++
samples/bpf/tracex4_kern.c | 54 ++++++++++
samples/bpf/tracex4_user.c | 69 ++++++++++++
25 files changed, 1112 insertions(+), 18 deletions(-)
create mode 100644 kernel/trace/bpf_trace.c
create mode 100644 samples/bpf/tracex1_kern.c
create mode 100644 samples/bpf/tracex1_user.c
create mode 100644 samples/bpf/tracex2_kern.c
create mode 100644 samples/bpf/tracex2_user.c
create mode 100644 samples/bpf/tracex3_kern.c
create mode 100644 samples/bpf/tracex3_user.c
create mode 100644 samples/bpf/tracex4_kern.c
create mode 100644 samples/bpf/tracex4_user.c
--
1.7.9.5
From: Daniel Borkmann <daniel@iogearbox.net>
Socket filter code and other subsystems with upcoming eBPF support should
not need to deal with the fact that we have CONFIG_BPF_SYSCALL defined or
not.
Having the bpf syscall as a config option is a nice thing and I'd expect
it to stay that way for expert users (I presume one day the default setting
of it might change, though), but code making use of it should not care if
it's actually enabled or not.
Instead, hide this via header files and let the rest deal with it.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <redacted>
---
include/linux/bpf.h | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
From: Daniel Borkmann <daniel@iogearbox.net>
Socket filter code and other subsystems with upcoming eBPF support should
not need to deal with the fact that we have CONFIG_BPF_SYSCALL defined or
not.
Having the bpf syscall as a config option is a nice thing and I'd expect
it to stay that way for expert users (I presume one day the default setting
of it might change, though), but code making use of it should not care if
it's actually enabled or not.
Instead, hide this via header files and let the rest deal with it.
Looks good to me.
Reviewed-by: Masami Hiramatsu <redacted>
Thank you,
@@ -129,11 +127,25 @@ struct bpf_prog_aux {};#ifdef CONFIG_BPF_SYSCALL+voidbpf_register_prog_type(structbpf_prog_type_list*tl);+voidbpf_prog_put(structbpf_prog*prog);+structbpf_prog*bpf_prog_get(u32ufd);#else-staticinlinevoidbpf_prog_put(structbpf_prog*prog){}+staticinlinevoidbpf_register_prog_type(structbpf_prog_type_list*tl)+{+}++staticinlinestructbpf_prog*bpf_prog_get(u32ufd)+{+returnERR_PTR(-EOPNOTSUPP);+}++staticinlinevoidbpf_prog_put(structbpf_prog*prog)+{+}#endif-structbpf_prog*bpf_prog_get(u32ufd);+/* verify correctness of eBPF program */intbpf_check(structbpf_prog*fp,unionbpf_attr*attr);
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com
Debugging of BPF programs needs some form of printk from the program,
so let programs call limited trace_printk() with %d %u %x %p modifiers only.
Similar to kernel modules, during program load verifier checks whether program
is calling bpf_trace_printk() and if so, kernel allocates trace_printk buffers
and emits big 'this is debug only' banner.
Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
Reviewed-by: Steven Rostedt <redacted>
---
include/uapi/linux/bpf.h | 1 +
kernel/trace/bpf_trace.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 79 insertions(+)
@@ -90,6 +91,74 @@ static const struct bpf_func_proto bpf_ktime_get_ns_proto = {.ret_type=RET_INTEGER,};+/*+*limitedtrace_printk()+*only%d%u%x%ld%lu%lx%lld%llu%llx%pconversionspecifiersallowed+*/+staticu64bpf_trace_printk(u64r1,u64fmt_size,u64r3,u64r4,u64r5)+{+char*fmt=(char*)(long)r1;+intmod[3]={};+intfmt_cnt=0;+inti;++/*+*bpf_check()->check_func_arg()->check_stack_boundary()+*guaranteesthatfmtpointstobpfprogramstack,+*fmt_sizebytesofitwereinitializedandfmt_size>0+*/+if(fmt[--fmt_size]!=0)+return-EINVAL;++/* check format string for allowed specifiers */+for(i=0;i<fmt_size;i++){+if((!isprint(fmt[i])&&!isspace(fmt[i]))||!isascii(fmt[i]))+return-EINVAL;++if(fmt[i]!='%')+continue;++if(fmt_cnt>=3)+return-EINVAL;++/* fmt[i] != 0 && fmt[last] == 0, so we can access fmt[i + 1] */+i++;+if(fmt[i]=='l'){+mod[fmt_cnt]++;+i++;+}elseif(fmt[i]=='p'){+mod[fmt_cnt]++;+i++;+if(!isspace(fmt[i])&&!ispunct(fmt[i])&&fmt[i]!=0)+return-EINVAL;+fmt_cnt++;+continue;+}++if(fmt[i]=='l'){+mod[fmt_cnt]++;+i++;+}++if(fmt[i]!='d'&&fmt[i]!='u'&&fmt[i]!='x')+return-EINVAL;+fmt_cnt++;+}++return__trace_printk(1/* fake ip will not be printed */,fmt,+mod[0]==2?r3:mod[0]==1?(long)r3:(u32)r3,+mod[1]==2?r4:mod[1]==1?(long)r4:(u32)r4,+mod[2]==2?r5:mod[2]==1?(long)r5:(u32)r5);+}++staticconststructbpf_func_protobpf_trace_printk_proto={+.func=bpf_trace_printk,+.gpl_only=true,+.ret_type=RET_INTEGER,+.arg1_type=ARG_PTR_TO_STACK,+.arg2_type=ARG_CONST_STACK_SIZE,+};+staticconststructbpf_func_proto*kprobe_prog_func_proto(enumbpf_func_idfunc_id){switch(func_id){
One bpf program attaches to kmem_cache_alloc_node() and remembers all allocated
objects in the map.
Another program attaches to kmem_cache_free() and deletes corresponding
object from the map.
User space walks the map every second and prints any objects which are
older than 1 second.
Usage:
$ sudo tracex4
Then start few long living processes. The tracex4 will print:
obj 0xffff880465928000 is 13sec old was allocated at ip ffffffff8105dc32
obj 0xffff88043181c280 is 13sec old was allocated at ip ffffffff8105dc32
obj 0xffff880465848000 is 8sec old was allocated at ip ffffffff8105dc32
obj 0xffff8804338bc280 is 15sec old was allocated at ip ffffffff8105dc32
$ addr2line -fispe vmlinux ffffffff8105dc32
do_fork at fork.c:1665
As soon as processes exit the memory is reclaimed and tracex4 prints nothing.
Similar experiment can be done with __kmalloc/kfree pair.
Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
---
samples/bpf/Makefile | 4 +++
samples/bpf/tracex4_kern.c | 54 ++++++++++++++++++++++++++++++++++
samples/bpf/tracex4_user.c | 69 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 127 insertions(+)
create mode 100644 samples/bpf/tracex4_kern.c
create mode 100644 samples/bpf/tracex4_user.c
@@ -35,6 +38,7 @@ HOSTLOADLIBES_sockex2 += -lelfHOSTLOADLIBES_tracex1+=-lelfHOSTLOADLIBES_tracex2+=-lelfHOSTLOADLIBES_tracex3+=-lelf+HOSTLOADLIBES_tracex4+=-lelf-lrt# point this to your LLVM backend with bpf supportLLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
@@ -0,0 +1,54 @@+/* Copyright (c) 2015 PLUMgrid, http://plumgrid.com+*+*Thisprogramisfreesoftware;youcanredistributeitand/or+*modifyitunderthetermsofversion2oftheGNUGeneralPublic+*LicenseaspublishedbytheFreeSoftwareFoundation.+*/+#include<linux/ptrace.h>+#include<linux/version.h>+#include<uapi/linux/bpf.h>+#include"bpf_helpers.h"++structpair{+u64val;+u64ip;+};++structbpf_map_defSEC("maps")my_map={+.type=BPF_MAP_TYPE_HASH,+.key_size=sizeof(long),+.value_size=sizeof(structpair),+.max_entries=1000000,+};++/* kprobe is NOT a stable ABI+*Thisbpf+kprobeexamplecanstopworkinganytime.+*/+SEC("kprobe/kmem_cache_free")+intbpf_prog1(structpt_regs*ctx)+{+longptr=ctx->si;++bpf_map_delete_elem(&my_map,&ptr);+return0;+}++SEC("kretprobe/kmem_cache_alloc_node")+intbpf_prog2(structpt_regs*ctx)+{+longptr=ctx->ax;+longip=0;++/* get ip address of kmem_cache_alloc_node() caller */+bpf_probe_read(&ip,sizeof(ip),(void*)(ctx->bp+sizeof(ip)));++structpairv={+.val=bpf_ktime_get_ns(),+.ip=ip,+};++bpf_map_update_elem(&my_map,&ptr,&v,BPF_ANY);+return0;+}+char_license[]SEC("license")="GPL";+u32_versionSEC("version")=LINUX_VERSION_CODE;
@@ -0,0 +1,69 @@+/* Copyright (c) 2015 PLUMgrid, http://plumgrid.com+*+*Thisprogramisfreesoftware;youcanredistributeitand/or+*modifyitunderthetermsofversion2oftheGNUGeneralPublic+*LicenseaspublishedbytheFreeSoftwareFoundation.+*/+#include<stdio.h>+#include<stdlib.h>+#include<signal.h>+#include<unistd.h>+#include<stdbool.h>+#include<string.h>+#include<time.h>+#include<linux/bpf.h>+#include"libbpf.h"+#include"bpf_load.h"++structpair{+longlongval;+__u64ip;+};++static__u64time_get_ns(void)+{+structtimespects;++clock_gettime(CLOCK_MONOTONIC,&ts);+returnts.tv_sec*1000000000ull+ts.tv_nsec;+}++staticvoidprint_old_objects(intfd)+{+longlongval=time_get_ns();+__u64key,next_key;+structpairv;++key=write(1,"\e[1;1H\e[2J",12);/* clear screen */++key=-1;+while(bpf_get_next_key(map_fd[0],&key,&next_key)==0){+bpf_lookup_elem(map_fd[0],&next_key,&v);+key=next_key;+if(val-v.val<1000000000ll)+/* object was allocated more then 1 sec ago */+continue;+printf("obj 0x%llx is %2lldsec old was allocated at ip %llx\n",+next_key,(val-v.val)/1000000000ll,v.ip);+}+}++intmain(intac,char**argv)+{+charfilename[256];+inti;++snprintf(filename,sizeof(filename),"%s_kern.o",argv[0]);++if(load_bpf_file(filename)){+printf("%s",bpf_log_buf);+return1;+}++for(i=0;;i++){+print_old_objects(map_fd[1]);+sleep(1);+}++return0;+}
BPF C program attaches to blk_mq_start_request/blk_update_request kprobe events
to calculate IO latency.
For every completed block IO event it computes the time delta in nsec
and records in a histogram map: map[log10(delta)*10]++
User space reads this histogram map every 2 seconds and prints it as a 'heatmap'
using gray shades of text terminal. Black spaces have many events and white
spaces have very few events. Left most space is the smallest latency, right most
space is the largest latency in the range.
Usage:
$ sudo ./tracex3
and do 'sudo dd if=/dev/sda of=/dev/null' in other terminal.
Observe IO latencies and how different activity (like 'make kernel') affects it.
Similar experiments can be done for network transmit latencies, syscalls, etc
'-t' flag prints the heatmap using normal ascii characters:
$ sudo ./tracex3 -t
heatmap of IO latency
# - many events with this latency
- few events
|1us |10us |100us |1ms |10ms |100ms |1s |10s
*ooo. *O.#. # 221
. *# . # 125
.. .o#*.. # 55
. . . . .#O # 37
.# # 175
.#*. # 37
# # 199
. . *#*. # 55
*#..* # 42
# # 266
...***Oo#*OO**o#* . # 629
# # 271
. .#o* o.*o* # 221
. . o* *#O.. # 50
Signed-off-by: Alexei Starovoitov <redacted>
---
samples/bpf/Makefile | 4 ++
samples/bpf/tracex3_kern.c | 89 ++++++++++++++++++++++++++
samples/bpf/tracex3_user.c | 150 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 243 insertions(+)
create mode 100644 samples/bpf/tracex3_kern.c
create mode 100644 samples/bpf/tracex3_user.c
@@ -31,6 +34,7 @@ HOSTLOADLIBES_sockex1 += -lelfHOSTLOADLIBES_sockex2+=-lelfHOSTLOADLIBES_tracex1+=-lelfHOSTLOADLIBES_tracex2+=-lelf+HOSTLOADLIBES_tracex3+=-lelf# point this to your LLVM backend with bpf supportLLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
@@ -0,0 +1,89 @@+/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com+*+*Thisprogramisfreesoftware;youcanredistributeitand/or+*modifyitunderthetermsofversion2oftheGNUGeneralPublic+*LicenseaspublishedbytheFreeSoftwareFoundation.+*/+#include<linux/skbuff.h>+#include<linux/netdevice.h>+#include<linux/version.h>+#include<uapi/linux/bpf.h>+#include"bpf_helpers.h"++structbpf_map_defSEC("maps")my_map={+.type=BPF_MAP_TYPE_HASH,+.key_size=sizeof(long),+.value_size=sizeof(u64),+.max_entries=4096,+};++/* kprobe is NOT a stable ABI+*Thisbpf+kprobeexamplecanstopworkinganytime.+*/+SEC("kprobe/blk_mq_start_request")+intbpf_prog1(structpt_regs*ctx)+{+longrq=ctx->di;+u64val=bpf_ktime_get_ns();++bpf_map_update_elem(&my_map,&rq,&val,BPF_ANY);+return0;+}++staticunsignedintlog2l(unsignedlonglongn)+{+#define S(k) if (n >= (1ull << k)) { i += k; n >>= k; }+inti=-(n==0);+S(32);S(16);S(8);S(4);S(2);S(1);+returni;+#undef S+}++#define SLOTS 100++structbpf_map_defSEC("maps")lat_map={+.type=BPF_MAP_TYPE_ARRAY,+.key_size=sizeof(u32),+.value_size=sizeof(u64),+.max_entries=SLOTS,+};++SEC("kprobe/blk_update_request")+intbpf_prog2(structpt_regs*ctx)+{+longrq=ctx->di;+u64*value,l,base;+u32index;++value=bpf_map_lookup_elem(&my_map,&rq);+if(!value)+return0;++u64cur_time=bpf_ktime_get_ns();+u64delta=cur_time-*value;++bpf_map_delete_elem(&my_map,&rq);++/* the lines below are computing index = log10(delta)*10+*usingintegerarithmetic+*index=29~1usec+*index=59~1msec+*index=89~1sec+*index=99~10secormore+*log10(x)*10=log2(x)*10/log2(10)=log2(x)*3+*/+l=log2l(delta);+base=1ll<<l;+index=(l*64+(delta-base)*64/base)*3/64;++if(index>=SLOTS)+index=SLOTS-1;++value=bpf_map_lookup_elem(&lat_map,&index);+if(value)+__sync_fetch_and_add((long*)value,1);++return0;+}+char_license[]SEC("license")="GPL";+u32_versionSEC("version")=LINUX_VERSION_CODE;
BPF C program attaches to blk_mq_start_request/blk_update_request kprobe events
to calculate IO latency.
...
+/* kprobe is NOT a stable ABI
+ * This bpf+kprobe example can stop working any time.
+ */
+SEC("kprobe/blk_mq_start_request")
+int bpf_prog1(struct pt_regs *ctx)
+{
+ long rq = ctx->di;
+ u64 val = bpf_ktime_get_ns();
+
+ bpf_map_update_elem(&my_map, &rq, &val, BPF_ANY);
+ return 0;
+}
So just to make sure the original BPF instrumentation model is still
upheld: no matter in what way the kernel changes, neither the kprobe,
nor the BPF program can ever crash or corrupt the kernel, assuming the
kprobes, perf and BPF subsystem has no bugs, correct?
So 'stops working' here means that the instrumentation data might not
be reliable if kernel internal interfaces change - but it won't ever
make the kernel unreliable in any fashion. Right?
Thanks,
Ingo
BPF C program attaches to blk_mq_start_request/blk_update_request kprobe events
to calculate IO latency.
...
quoted
+/* kprobe is NOT a stable ABI
+ * This bpf+kprobe example can stop working any time.
+ */
+SEC("kprobe/blk_mq_start_request")
+int bpf_prog1(struct pt_regs *ctx)
+{
+ long rq = ctx->di;
+ u64 val = bpf_ktime_get_ns();
+
+ bpf_map_update_elem(&my_map, &rq, &val, BPF_ANY);
+ return 0;
+}
So just to make sure the original BPF instrumentation model is still
upheld: no matter in what way the kernel changes, neither the kprobe,
nor the BPF program can ever crash or corrupt the kernel, assuming the
kprobes, perf and BPF subsystem has no bugs, correct?
yes. of course. That was always #1 requirement.
So 'stops working' here means that the instrumentation data might not
be reliable if kernel internal interfaces change - but it won't ever
make the kernel unreliable in any fashion. Right?
yes. of course.
The only situations where it can 'stop working':
- in-kernel blk_mq_start_request function is renamed, so kprobe cannot
find it and cannot attach.
- arguments to blk_mq_start_request change. Then ctx->di can be
meaningless and using it as key into map is useless.
- whole logic of blk_mq_start_request/blk_update_request pair changes.
then this sample code won't be measuring any useful io latency.
In all cases kernel will never crash (barring bugs in bpf, kprobe
subsystems).
@@ -14,12 +15,14 @@ sock_example-objs := sock_example.o libbpf.osockex1-objs:=bpf_load.olibbpf.osockex1_user.osockex2-objs:=bpf_load.olibbpf.osockex2_user.otracex1-objs:=bpf_load.olibbpf.otracex1_user.o+tracex2-objs:=bpf_load.olibbpf.otracex2_user.o# Tell kbuild to always build the programsalways:=$(hostprogs-y)always+=sockex1_kern.oalways+=sockex2_kern.oalways+=tracex1_kern.o+always+=tracex2_kern.oHOSTCFLAGS+=-I$(objtree)/usr/include
@@ -27,6 +30,7 @@ HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variableHOSTLOADLIBES_sockex1+=-lelfHOSTLOADLIBES_sockex2+=-lelfHOSTLOADLIBES_tracex1+=-lelf+HOSTLOADLIBES_tracex2+=-lelf# point this to your LLVM backend with bpf supportLLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
@@ -0,0 +1,86 @@+/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com+*+*Thisprogramisfreesoftware;youcanredistributeitand/or+*modifyitunderthetermsofversion2oftheGNUGeneralPublic+*LicenseaspublishedbytheFreeSoftwareFoundation.+*/+#include<linux/skbuff.h>+#include<linux/netdevice.h>+#include<linux/version.h>+#include<uapi/linux/bpf.h>+#include"bpf_helpers.h"++structbpf_map_defSEC("maps")my_map={+.type=BPF_MAP_TYPE_HASH,+.key_size=sizeof(long),+.value_size=sizeof(long),+.max_entries=1024,+};++/* kprobe is NOT a stable ABI+*Thisbpf+kprobeexamplecanstopworkinganytime.+*/+SEC("kprobe/kfree_skb")+intbpf_prog2(structpt_regs*ctx)+{+longloc=0;+longinit_val=1;+long*value;++/* x64 specific: read ip of kfree_skb caller.+*non-portableversionof__builtin_return_address(0)+*/+bpf_probe_read(&loc,sizeof(loc),(void*)ctx->sp);++value=bpf_map_lookup_elem(&my_map,&loc);+if(value)+*value+=1;+else+bpf_map_update_elem(&my_map,&loc,&init_val,BPF_ANY);+return0;+}++staticunsignedintlog2(unsignedintv)+{+unsignedintr;+unsignedintshift;++r=(v>0xFFFF)<<4;v>>=r;+shift=(v>0xFF)<<3;v>>=shift;r|=shift;+shift=(v>0xF)<<2;v>>=shift;r|=shift;+shift=(v>0x3)<<1;v>>=shift;r|=shift;+r|=(v>>1);+returnr;+}++staticunsignedintlog2l(unsignedlongv)+{+unsignedinthi=v>>32;+if(hi)+returnlog2(hi)+32;+else+returnlog2(v);+}++structbpf_map_defSEC("maps")my_hist_map={+.type=BPF_MAP_TYPE_ARRAY,+.key_size=sizeof(u32),+.value_size=sizeof(long),+.max_entries=64,+};++SEC("kprobe/sys_write")+intbpf_prog3(structpt_regs*ctx)+{+longwrite_size=ctx->dx;/* arg3 */+longinit_val=1;+long*value;+u32index=log2l(write_size);++value=bpf_map_lookup_elem(&my_hist_map,&index);+if(value)+__sync_fetch_and_add(value,1);+return0;+}+char_license[]SEC("license")="GPL";+u32_versionSEC("version")=LINUX_VERSION_CODE;
tracex1_kern.c - C program compiled into BPF.
It attaches to kprobe:netif_receive_skb
When skb->dev->name == "lo", it prints sample debug message into trace_pipe
via bpf_trace_printk() helper function.
tracex1_user.c - corresponding user space component that:
- loads bpf program via bpf() syscall
- opens kprobes:netif_receive_skb event via perf_event_open() syscall
- attaches the program to event via ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
- prints from trace_pipe
Note, this bpf program is completely non-portable. It must be recompiled
with current kernel headers. kprobe is not a stable ABI and bpf+kprobe scripts
may stop working any time.
bpf verifier will detect that it's using bpf_trace_printk() and kernel will
print warning banner:
** trace_printk() being used. Allocating extra memory. **
** **
** This means that this is a DEBUG kernel and it is **
** unsafe for production use. **
bpf_trace_printk() should be used for debugging of bpf program only.
Usage:
$ sudo tracex1
ping-19826 [000] d.s2 63103.382648: : skb ffff880466b1ca00 len 84
ping-19826 [000] d.s2 63103.382684: : skb ffff880466b1d300 len 84
ping-19826 [000] d.s2 63104.382533: : skb ffff880466b1ca00 len 84
ping-19826 [000] d.s2 63104.382594: : skb ffff880466b1d300 len 84
Signed-off-by: Alexei Starovoitov <redacted>
---
samples/bpf/Makefile | 4 ++
samples/bpf/bpf_helpers.h | 6 +++
samples/bpf/bpf_load.c | 125 ++++++++++++++++++++++++++++++++++++++++---
samples/bpf/bpf_load.h | 3 ++
samples/bpf/libbpf.c | 14 ++++-
samples/bpf/libbpf.h | 5 +-
samples/bpf/sock_example.c | 2 +-
samples/bpf/test_verifier.c | 2 +-
samples/bpf/tracex1_kern.c | 50 +++++++++++++++++
samples/bpf/tracex1_user.c | 25 +++++++++
10 files changed, 224 insertions(+), 12 deletions(-)
create mode 100644 samples/bpf/tracex1_kern.c
create mode 100644 samples/bpf/tracex1_user.c
@@ -6,23 +6,27 @@ hostprogs-y := test_verifier test_mapshostprogs-y+=sock_examplehostprogs-y+=sockex1hostprogs-y+=sockex2+hostprogs-y+=tracex1test_verifier-objs:=test_verifier.olibbpf.otest_maps-objs:=test_maps.olibbpf.osock_example-objs:=sock_example.olibbpf.osockex1-objs:=bpf_load.olibbpf.osockex1_user.osockex2-objs:=bpf_load.olibbpf.osockex2_user.o+tracex1-objs:=bpf_load.olibbpf.otracex1_user.o# Tell kbuild to always build the programsalways:=$(hostprogs-y)always+=sockex1_kern.oalways+=sockex2_kern.o+always+=tracex1_kern.oHOSTCFLAGS+=-I$(objtree)/usr/includeHOSTCFLAGS_bpf_load.o+=-I$(objtree)/usr/include-Wno-unused-variableHOSTLOADLIBES_sockex1+=-lelfHOSTLOADLIBES_sockex2+=-lelf+HOSTLOADLIBES_tracex1+=-lelf# point this to your LLVM backend with bpf supportLLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
@@ -15,6 +15,12 @@ static int (*bpf_map_update_elem)(void *map, void *key, void *value,(void*)BPF_FUNC_map_update_elem;staticint(*bpf_map_delete_elem)(void*map,void*key)=(void*)BPF_FUNC_map_delete_elem;+staticint(*bpf_probe_read)(void*dst,intsize,void*unsafe_ptr)=+(void*)BPF_FUNC_probe_read;+staticunsignedlonglong(*bpf_ktime_get_ns)(void)=+(void*)BPF_FUNC_ktime_get_ns;+staticint(*bpf_trace_printk)(constchar*fmt,intfmt_size,...)=+(void*)BPF_FUNC_trace_printk;/* llvm builtin functions that eBPF C program may use to*emitBPF_LD_ABSandBPF_LD_INDinstructions
@@ -39,6 +80,41 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size)prog_fd[prog_cnt++]=fd;+if(is_socket)+return0;++strcpy(buf,DEBUGFS);+strcat(buf,"events/kprobes/");+strcat(buf,event);+strcat(buf,"/id");++efd=open(buf,O_RDONLY,0);+if(efd<0){+printf("failed to open event %s\n",event);+return-1;+}++err=read(efd,buf,sizeof(buf));+if(err<0||err>=sizeof(buf)){+printf("read from '%s' failed '%s'\n",event,strerror(errno));+return-1;+}++close(efd);++buf[err]=0;+id=atoi(buf);+attr.config=id;++efd=perf_event_open(&attr,-1/*pid*/,0/*cpu*/,-1/*group_fd*/,0);+if(efd<0){+printf("event %d fd %d err %s\n",id,efd,strerror(errno));+return-1;+}+event_fd[prog_cnt-1]=efd;+ioctl(efd,PERF_EVENT_IOC_ENABLE,0);+ioctl(efd,PERF_EVENT_IOC_SET_BPF,fd);+return0;}
@@ -135,6 +211,9 @@ int load_bpf_file(char *path)if(gelf_getehdr(elf,&ehdr)!=&ehdr)return1;+/* clear all kprobes */+i=system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");+/* scan over all elf sections to get license and map info */for(i=1;i<ehdr.e_shnum;i++){
@@ -149,6 +228,14 @@ int load_bpf_file(char *path)if(strcmp(shname,"license")==0){processed_sec[i]=true;memcpy(license,data->d_buf,data->d_size);+}elseif(strcmp(shname,"version")==0){+processed_sec[i]=true;+if(data->d_size!=sizeof(int)){+printf("invalid size of version section %zd\n",+data->d_size);+return1;+}+memcpy(&kern_version,data->d_buf,sizeof(int));}elseif(strcmp(shname,"maps")==0){processed_sec[i]=true;if(load_maps(data->d_buf,data->d_size))
@@ -178,7 +265,8 @@ int load_bpf_file(char *path)if(parse_relo_and_apply(data,symbols,&shdr,insns))continue;-if(memcmp(shname_prog,"events/",7)==0||+if(memcmp(shname_prog,"kprobe/",7)==0||+memcmp(shname_prog,"kretprobe/",10)==0||memcmp(shname_prog,"socket",6)==0)load_and_attach(shname_prog,insns,data_prog->d_size);}
@@ -193,7 +281,8 @@ int load_bpf_file(char *path)if(get_sec(elf,i,&ehdr,&shname,&shdr,&data))continue;-if(memcmp(shname,"events/",7)==0||+if(memcmp(shname,"kprobe/",7)==0||+memcmp(shname,"kretprobe/",10)==0||memcmp(shname,"socket",6)==0)load_and_attach(shname,data->d_buf,data->d_size);}
@@ -201,3 +290,23 @@ int load_bpf_file(char *path)close(fd);return0;}++voidread_trace_pipe(void)+{+inttrace_fd;++trace_fd=open(DEBUGFS"trace_pipe",O_RDONLY,0);+if(trace_fd<0)+return;++while(1){+staticcharbuf[4096];+ssize_tsz;++sz=read(trace_fd,buf,sizeof(buf));+if(sz){+buf[sz]=0;+puts(buf);+}+}+}
@@ -93,6 +93,11 @@ int bpf_prog_load(enum bpf_prog_type prog_type,.log_level=1,};+/* assign one field outside of struct init to make sure any+*paddingiszeroinitialized+*/+attr.kern_version=kern_version;+bpf_log_buf[0]=0;returnsyscall(__NR_bpf,BPF_PROG_LOAD,&attr,sizeof(attr));
@@ -121,3 +126,10 @@ int open_raw_sock(const char *name)returnsock;}++intperf_event_open(structperf_event_attr*attr,intpid,intcpu,+intgroup_fd,unsignedlongflags)+{+returnsyscall(__NR_perf_event_open,attr,pid,cpu,+group_fd,flags);+}
@@ -0,0 +1,50 @@+/* Copyright (c) 2013-2015 PLUMgrid, http://plumgrid.com+*+*Thisprogramisfreesoftware;youcanredistributeitand/or+*modifyitunderthetermsofversion2oftheGNUGeneralPublic+*LicenseaspublishedbytheFreeSoftwareFoundation.+*/+#include<linux/skbuff.h>+#include<linux/netdevice.h>+#include<uapi/linux/bpf.h>+#include<linux/version.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+*kernelfunctionscanberemoved,renamedorcompletelychangesemantics.+*Numberofargumnetsandtheirposistionscanchange,etc.+*Thisbpf+kprobeexamplecanstopworkinganytime.+*/+SEC("kprobe/__netif_receive_skb_core")+intbpf_prog1(structpt_regs*ctx)+{+/* attaches to kprobe netif_receive_skb,+*looksforpacketsonloobpackdeviceandprintsthem+*/+chardevname[IFNAMSIZ]={};+structnet_device*dev;+structsk_buff*skb;+intlen;++/* non-portable! works for the given kernel only */+skb=(structsk_buff*)ctx->di;++dev=_(skb->dev);++len=_(skb->len);++bpf_probe_read(devname,sizeof(devname),dev->name);++if(devname[0]=='l'&&devname[1]=='o'){+charfmt[]="skb %p len %d\n";+/* using bpf_trace_printk() for DEBUG ONLY */+bpf_trace_printk(fmt,sizeof(fmt),skb,len);+}++return0;+}++char_license[]SEC("license")="GPL";+u32_versionSEC("version")=LINUX_VERSION_CODE;
tracex1_kern.c - C program compiled into BPF.
It attaches to kprobe:netif_receive_skb
When skb->dev->name == "lo", it prints sample debug message into trace_pipe
via bpf_trace_printk() helper function.
tracex1_user.c - corresponding user space component that:
- loads bpf program via bpf() syscall
- opens kprobes:netif_receive_skb event via perf_event_open() syscall
- attaches the program to event via ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
- prints from trace_pipe
Note, this bpf program is completely non-portable. It must be recompiled
with current kernel headers. kprobe is not a stable ABI and bpf+kprobe scripts
may stop working any time.
bpf verifier will detect that it's using bpf_trace_printk() and kernel will
print warning banner:
** trace_printk() being used. Allocating extra memory. **
Printing this might be OK.
** **
** This means that this is a DEBUG kernel and it is **
** unsafe for production use. **
But I think printing that it's unsafe for production use is over the
top: it's up to the admin whether it's safe or unsafe, just like
inserting a kprobe can be safe or unsafe.
Informing that something happened is enough.
Thanks,
Ingo
** **
** This means that this is a DEBUG kernel and it is **
** unsafe for production use. **
But I think printing that it's unsafe for production use is over the
top: it's up to the admin whether it's safe or unsafe, just like
inserting a kprobe can be safe or unsafe.
Informing that something happened is enough.
Well that is Steven's banner and I agree that it's a bit extreme.
I think it's done on purpose to scary people away from using
trace_printk() for anything other than debug.
It applies to both native trace_printk() for kernel debugging and
for bpf_trace_printk() for debugging of bpf programs.
I don't have a strong opinion about native case, but for bpf I do want
this banner to be scary. Otherwise it's too easy to start using
bpf_trace_printk() to pass event notifications to user space.
bpf_trace_printk and trace_pipe parsing shouldn't be used as a way
to communicate between programs and user space.
At the end, in actual production use, bpf programs won't be using it
and no banner will be seen.
Anyway, I don't think I can change this banner in this patch set.
If we decide to relax it, it should be done via Steven's tree.
good point. If it was normal file, for sure it's a bug, but trace_pipe
is a pseudo file and I think read cannot return -1. Regardless, it makes
sense to fix it. Will do. Do you mind I address it as follow up patch?
Or if the rest is ok, can you change the condition to sz>0 while
applying? I can respin the whole thing too, if you like.
Thanks!
bpf_ktime_get_ns() is used by programs to compute time delta between events
or as a timestamp
Signed-off-by: Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org>
Reviewed-by: Steven Rostedt <redacted>
---
include/uapi/linux/bpf.h | 1 +
kernel/trace/bpf_trace.c | 14 ++++++++++++++
2 files changed, 15 insertions(+)
User interface:
struct perf_event_attr attr = {.type = PERF_TYPE_TRACEPOINT, .config = event_id, ...};
event_fd = perf_event_open(&attr,...);
ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
prog_fd is a file descriptor associated with BPF program previously loaded.
event_id is an ID of created kprobe
close(event_fd) - automatically detaches BPF program from it
BPF programs can call in-kernel helper functions to:
- lookup/update/delete elements in maps
- probe_read - wraper of probe_kernel_read() used to access any kernel
data structures
BPF programs receive 'struct pt_regs *' as an input
('struct pt_regs' is architecture dependent)
and return 0 to ignore the event and 1 to store kprobe event into ring buffer.
Note, kprobes are _not_ a stable kernel ABI, so bpf programs attached to
kprobes must be recompiled for every kernel version and user must supply correct
LINUX_VERSION_CODE in attr.kern_version during bpf_prog_load() call.
Signed-off-by: Alexei Starovoitov <redacted>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
---
include/linux/ftrace_event.h | 11 ++++
include/uapi/linux/bpf.h | 3 +
include/uapi/linux/perf_event.h | 1 +
kernel/bpf/syscall.c | 7 ++-
kernel/events/core.c | 59 ++++++++++++++++++
kernel/trace/Makefile | 1 +
kernel/trace/bpf_trace.c | 130 +++++++++++++++++++++++++++++++++++++++
kernel/trace/trace_kprobe.c | 8 +++
8 files changed, 219 insertions(+), 1 deletion(-)
create mode 100644 kernel/trace/bpf_trace.c
@@ -151,6 +152,7 @@ union bpf_attr {__u32log_level;/* verbosity level of verifier */__u32log_size;/* size of user buffer */__aligned_u64log_buf;/* user supplied buffer */+__u32kern_version;/* checked when prog_type=kprobe */};}__attribute__((aligned(8)));
@@ -162,6 +164,7 @@ enum bpf_func_id {BPF_FUNC_map_lookup_elem,/* void *map_lookup_elem(&map, &key) */BPF_FUNC_map_update_elem,/* int map_update_elem(&map, &key, &value, flags) */BPF_FUNC_map_delete_elem,/* int map_delete_elem(&map, &key) */+BPF_FUNC_probe_read,/* int bpf_probe_read(void *dst, int size, void *src) */__BPF_FUNC_MAX_ID,};
@@ -467,7 +468,7 @@ struct bpf_prog *bpf_prog_get(u32 ufd)}/* last field in 'union bpf_attr' used by this command */-#define BPF_PROG_LOAD_LAST_FIELD log_buf+#define BPF_PROG_LOAD_LAST_FIELD kern_versionstaticintbpf_prog_load(unionbpf_attr*attr){
@@ -3976,6 +3981,9 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned loncasePERF_EVENT_IOC_SET_FILTER:returnperf_event_set_filter(event,(void__user*)arg);+casePERF_EVENT_IOC_SET_BPF:+returnperf_event_set_bpf_prog(event,arg);+default:return-ENOTTY;}
@@ -6436,6 +6444,49 @@ static void perf_event_free_filter(struct perf_event *event)ftrace_profile_free_filter(event);}+staticintperf_event_set_bpf_prog(structperf_event*event,u32prog_fd)+{+structbpf_prog*prog;++if(event->attr.type!=PERF_TYPE_TRACEPOINT)+return-EINVAL;++if(event->tp_event->prog)+return-EEXIST;++if(!(event->tp_event->flags&TRACE_EVENT_FL_KPROBE))+/* bpf programs can only be attached to kprobes */+return-EINVAL;++prog=bpf_prog_get(prog_fd);+if(IS_ERR(prog))+returnPTR_ERR(prog);++if(prog->aux->prog_type!=BPF_PROG_TYPE_KPROBE){+/* valid fd, but invalid bpf program type */+bpf_prog_put(prog);+return-EINVAL;+}++event->tp_event->prog=prog;++return0;+}++staticvoidperf_event_free_bpf_prog(structperf_event*event)+{+structbpf_prog*prog;++if(!event->tp_event)+return;++prog=event->tp_event->prog;+if(prog){+event->tp_event->prog=NULL;+bpf_prog_put(prog);+}+}+#elsestaticinlinevoidperf_tp_register(void)
User interface:
struct perf_event_attr attr = {.type = PERF_TYPE_TRACEPOINT, .config = event_id, ...};
event_fd = perf_event_open(&attr,...);
ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd);
prog_fd is a file descriptor associated with BPF program previously loaded.
event_id is an ID of created kprobe
close(event_fd) - automatically detaches BPF program from it
BPF programs can call in-kernel helper functions to:
- lookup/update/delete elements in maps
- probe_read - wraper of probe_kernel_read() used to access any kernel
data structures
BPF programs receive 'struct pt_regs *' as an input
('struct pt_regs' is architecture dependent)
and return 0 to ignore the event and 1 to store kprobe event into ring buffer.
Note, kprobes are _not_ a stable kernel ABI, so bpf programs attached to
kprobes must be recompiled for every kernel version and user must supply correct
LINUX_VERSION_CODE in attr.kern_version during bpf_prog_load() call.
Would you mean that the ABI of kprobe-based BPF programs? Kprobe API/ABIs
(register_kprobe() etc.) are stable, but the code who use kprobes certainly
depends the kernel binary by design. So, if you meant it, BPF programs must
be recompiled for every kernel binaries (including configuration changes,
not only its version).
Thank you,
@@ -151,6 +152,7 @@ union bpf_attr {__u32log_level;/* verbosity level of verifier */__u32log_size;/* size of user buffer */__aligned_u64log_buf;/* user supplied buffer */+__u32kern_version;/* checked when prog_type=kprobe */};}__attribute__((aligned(8)));
@@ -162,6 +164,7 @@ enum bpf_func_id {BPF_FUNC_map_lookup_elem,/* void *map_lookup_elem(&map, &key) */BPF_FUNC_map_update_elem,/* int map_update_elem(&map, &key, &value, flags) */BPF_FUNC_map_delete_elem,/* int map_delete_elem(&map, &key) */+BPF_FUNC_probe_read,/* int bpf_probe_read(void *dst, int size, void *src) */__BPF_FUNC_MAX_ID,};
@@ -467,7 +468,7 @@ struct bpf_prog *bpf_prog_get(u32 ufd)}/* last field in 'union bpf_attr' used by this command */-#define BPF_PROG_LOAD_LAST_FIELD log_buf+#define BPF_PROG_LOAD_LAST_FIELD kern_versionstaticintbpf_prog_load(unionbpf_attr*attr){
@@ -3976,6 +3981,9 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned loncasePERF_EVENT_IOC_SET_FILTER:returnperf_event_set_filter(event,(void__user*)arg);+casePERF_EVENT_IOC_SET_BPF:+returnperf_event_set_bpf_prog(event,arg);+default:return-ENOTTY;}
@@ -6436,6 +6444,49 @@ static void perf_event_free_filter(struct perf_event *event)ftrace_profile_free_filter(event);}+staticintperf_event_set_bpf_prog(structperf_event*event,u32prog_fd)+{+structbpf_prog*prog;++if(event->attr.type!=PERF_TYPE_TRACEPOINT)+return-EINVAL;++if(event->tp_event->prog)+return-EEXIST;++if(!(event->tp_event->flags&TRACE_EVENT_FL_KPROBE))+/* bpf programs can only be attached to kprobes */+return-EINVAL;++prog=bpf_prog_get(prog_fd);+if(IS_ERR(prog))+returnPTR_ERR(prog);++if(prog->aux->prog_type!=BPF_PROG_TYPE_KPROBE){+/* valid fd, but invalid bpf program type */+bpf_prog_put(prog);+return-EINVAL;+}++event->tp_event->prog=prog;++return0;+}++staticvoidperf_event_free_bpf_prog(structperf_event*event)+{+structbpf_prog*prog;++if(!event->tp_event)+return;++prog=event->tp_event->prog;+if(prog){+event->tp_event->prog=NULL;+bpf_prog_put(prog);+}+}+#elsestaticinlinevoidperf_tp_register(void)
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org
Note, kprobes are _not_ a stable kernel ABI, so bpf programs attached to
kprobes must be recompiled for every kernel version and user must supply correct
LINUX_VERSION_CODE in attr.kern_version during bpf_prog_load() call.
Would you mean that the ABI of kprobe-based BPF programs? Kprobe API/ABIs
(register_kprobe() etc.) are stable, but the code who use kprobes certainly
depends the kernel binary by design. So, if you meant it, BPF programs must
be recompiled for every kernel binaries (including configuration changes,
not only its version).
yes. I mainly meant that bpf+kprobe programs must be recompiled
for every kernel binary.
But you're incorrect saying that register_kprobe API is stable.
It's equally kernel dependent.
register_kprobe(struct kprobe *p) is export_gpl, but it takes
kernel internal 'struct kprobe' and it's not declared in uapi header.
Prototype of kprobe_handler_t is also kernel internal, so whoever
is using kprobes must recompile their code every time.
If we want, we can change register_kprobe function name to something
else. Just like kernel modules cannot expect that exported symbols
will stay around from version to version. We don't care when we
break out of tree modules.
Note, kprobes are _not_ a stable kernel ABI, so bpf programs attached to
kprobes must be recompiled for every kernel version and user must supply correct
LINUX_VERSION_CODE in attr.kern_version during bpf_prog_load() call.
Would you mean that the ABI of kprobe-based BPF programs? Kprobe API/ABIs
(register_kprobe() etc.) are stable, but the code who use kprobes certainly
depends the kernel binary by design. So, if you meant it, BPF programs must
be recompiled for every kernel binaries (including configuration changes,
not only its version).
yes. I mainly meant that bpf+kprobe programs must be recompiled
for every kernel binary.
Hmm, if so, as we do in perf (and systemtap too), you'd better check
kernel's build-id instead of the kernel version when loading the
BPF program. It is safer than the KERNEL_VERSION_CODE.
But you're incorrect saying that register_kprobe API is stable.
It's equally kernel dependent.
register_kprobe(struct kprobe *p) is export_gpl, but it takes
kernel internal 'struct kprobe' and it's not declared in uapi header.
Prototype of kprobe_handler_t is also kernel internal, so whoever
is using kprobes must recompile their code every time.
If we want, we can change register_kprobe function name to something
else. Just like kernel modules cannot expect that exported symbols
will stay around from version to version. We don't care when we
break out of tree modules.
Indeed the register_kprobe (and other kprobe related functions)
should not be treated as a stable userland exported ABI/API. :)
Thank you,
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org
Note, kprobes are _not_ a stable kernel ABI, so bpf programs attached to
kprobes must be recompiled for every kernel version and user must supply correct
LINUX_VERSION_CODE in attr.kern_version during bpf_prog_load() call.
Would you mean that the ABI of kprobe-based BPF programs? Kprobe API/ABIs
(register_kprobe() etc.) are stable, but the code who use kprobes certainly
depends the kernel binary by design. So, if you meant it, BPF programs must
be recompiled for every kernel binaries (including configuration changes,
not only its version).
yes. I mainly meant that bpf+kprobe programs must be recompiled
for every kernel binary.
Hmm, if so, as we do in perf (and systemtap too), you'd better check
kernel's build-id instead of the kernel version when loading the
BPF program. It is safer than the KERNEL_VERSION_CODE.
It's not about safety. As I mentioned in cover letter:
"version check is not used for safety, but for enforcing 'non-ABI-ness'"
In other words it's like check-box next to 'terms and conditions'
paragraph that the user has to click before he can continue.
By providing 'kern_version' during loading the user accepts the fact
that bpf+kprobe is not a stable ABI. Nothing more and nothing less.
build-id cannot achieve that, because it cannot be checked from inside
the kernel.
User space tools that will compile ktap/dtrace scripts into bpf might
use build-id for their own purpose, but that's a different discussion.
Note, kprobes are _not_ a stable kernel ABI, so bpf programs attached to
kprobes must be recompiled for every kernel version and user must supply correct
LINUX_VERSION_CODE in attr.kern_version during bpf_prog_load() call.
Would you mean that the ABI of kprobe-based BPF programs? Kprobe API/ABIs
(register_kprobe() etc.) are stable, but the code who use kprobes certainly
depends the kernel binary by design. So, if you meant it, BPF programs must
be recompiled for every kernel binaries (including configuration changes,
not only its version).
yes. I mainly meant that bpf+kprobe programs must be recompiled
for every kernel binary.
Hmm, if so, as we do in perf (and systemtap too), you'd better check
kernel's build-id instead of the kernel version when loading the
BPF program. It is safer than the KERNEL_VERSION_CODE.
It's not about safety. As I mentioned in cover letter:
"version check is not used for safety, but for enforcing 'non-ABI-ness'"
In other words it's like check-box next to 'terms and conditions'
paragraph that the user has to click before he can continue.
By providing 'kern_version' during loading the user accepts the fact
that bpf+kprobe is not a stable ABI. Nothing more and nothing less.
build-id cannot achieve that, because it cannot be checked from inside
the kernel.
Ah, I see. Hmm, I think we'd better have such interface (kernel API).
User space tools that will compile ktap/dtrace scripts into bpf might
use build-id for their own purpose, but that's a different discussion.
Agreed.
I'd like to discuss it since kprobe event interface may also have same
issue.
Thank you,
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org
User space tools that will compile ktap/dtrace scripts into bpf might
use build-id for their own purpose, but that's a different discussion.
Agreed.
I'd like to discuss it since kprobe event interface may also have same
issue.
I'm not sure what 'issue' you're seeing. My understanding is that
build-ids are used by perf to associate binaries with their debug info
and by systemtap to make sure that probes actually match the kernel
they were compiled for. In bpf case it probably will be perf way only.
Are you interested in doing something with bpf ? ;)
I know that Jovi is working on clang-based front-end, He Kuang is doing
something fancy and I'm going to focus on 'tcp instrumentation' once
bpf+kprobes is in. I think these efforts will help us make it
concrete and will establish a path towards bpf+tracepoints
(debug tracepoints or trace markers) and eventual integration with perf.
Here is the wish-list (for kernel and userspace) inspired by Brendan:
- access to pid, uid, tid, comm, etc
- access to kernel stack trace
- access to user-level stack trace
- kernel debuginfo for walking kernel structs, and accessing kprobe
entry args as variables
- tracing of uprobes
- tracing of user markers
- user debuginfo for user structs and args
- easy to use language
- library of scripting features
- nice one-liner syntax
I think there is a lot of interest in bpf+tracing and would be good to
align the efforts.
User space tools that will compile ktap/dtrace scripts into bpf might
use build-id for their own purpose, but that's a different discussion.
Agreed.
I'd like to discuss it since kprobe event interface may also have same
issue.
I'm not sure what 'issue' you're seeing. My understanding is that
build-ids are used by perf to associate binaries with their debug info
and by systemtap to make sure that probes actually match the kernel
they were compiled for. In bpf case it probably will be perf way only.
Ah, I see. So perftools can check the build-id if needed, right?
Are you interested in doing something with bpf ? ;)
Of course :)
I know that Jovi is working on clang-based front-end, He Kuang is doing
something fancy and I'm going to focus on 'tcp instrumentation' once
bpf+kprobes is in. I think these efforts will help us make it
concrete and will establish a path towards bpf+tracepoints
(debug tracepoints or trace markers) and eventual integration with perf.
Here is the wish-list (for kernel and userspace) inspired by Brendan:
- access to pid, uid, tid, comm, etc
- access to kernel stack trace
- access to user-level stack trace
- kernel debuginfo for walking kernel structs, and accessing kprobe
entry args as variables
perf probe can provide this to bpf.
- tracing of uprobes
- tracing of user markers
I'm working on the perf-cache which will also support SDT (based on Hemant Kumar's work).
- user debuginfo for user structs and args
Ditto.
- easy to use language
- library of scripting features
- nice one-liner syntax
I think there is a lot of interest in bpf+tracing and would be good to
align the efforts.
Agreed :)
Thanks!
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org
User space tools that will compile ktap/dtrace scripts into bpf might
use build-id for their own purpose, but that's a different discussion.
Agreed.
I'd like to discuss it since kprobe event interface may also have same
issue.
I'm not sure what 'issue' you're seeing. My understanding is that
build-ids are used by perf to associate binaries with their debug info
and by systemtap to make sure that probes actually match the kernel
they were compiled for. In bpf case it probably will be perf way only.
Ah, I see. So perftools can check the build-id if needed, right?
yes. of course.
quoted
Are you interested in doing something with bpf ? ;)
Of course :)
Great :)
quoted
I know that Jovi is working on clang-based front-end, He Kuang is doing
something fancy and I'm going to focus on 'tcp instrumentation' once
bpf+kprobes is in. I think these efforts will help us make it
concrete and will establish a path towards bpf+tracepoints
(debug tracepoints or trace markers) and eventual integration with perf.
Here is the wish-list (for kernel and userspace) inspired by Brendan:
- access to pid, uid, tid, comm, etc
- access to kernel stack trace
- access to user-level stack trace
- kernel debuginfo for walking kernel structs, and accessing kprobe
entry args as variables
perf probe can provide this to bpf.
I was thinking about deeper integration with perf actually.
perf has all the right infra to find debug info in kernel and user
binaries, to extract and understand all the dwarf stuff.
The future tracing language can use more of it.
The programs should be able refer to names of in-kernel variables
and arguments natively.
When I'm writing a program that attaches to blk_update_request()
I would like to write:
bpf_printk("req %p bytes %d\n", req->q, nr_bytes);
and perf with debug info should be able to figure out that 'req'
is the first function argument, then find out offset of '->q'
within the struct and that 'nr_bytes' is the 3rd argument in
appropriate register. Then generate llvm ir on the fly,
compile it, load into kernel and attach to kprobe event at
this blk_update_request() function. All seamlessly.
quoted
- tracing of uprobes
- tracing of user markers
I'm working on the perf-cache which will also support SDT (based on Hemant Kumar's work).
yep. waiting for SDT stuff to finalize. Would be nice to
have 'follow' button for interesting patches :)
User space tools that will compile ktap/dtrace scripts into bpf might
use build-id for their own purpose, but that's a different discussion.
Agreed.
I'd like to discuss it since kprobe event interface may also have same
issue.
I'm not sure what 'issue' you're seeing. My understanding is that
build-ids are used by perf to associate binaries with their debug info
and by systemtap to make sure that probes actually match the kernel
they were compiled for. In bpf case it probably will be perf way only.
Ah, I see. So perftools can check the build-id if needed, right?
yes. of course.
quoted
quoted
Are you interested in doing something with bpf ? ;)
Of course :)
Great :)
quoted
quoted
I know that Jovi is working on clang-based front-end, He Kuang is doing
something fancy and I'm going to focus on 'tcp instrumentation' once
bpf+kprobes is in. I think these efforts will help us make it
concrete and will establish a path towards bpf+tracepoints
(debug tracepoints or trace markers) and eventual integration with perf.
Here is the wish-list (for kernel and userspace) inspired by Brendan:
- access to pid, uid, tid, comm, etc
- access to kernel stack trace
- access to user-level stack trace
- kernel debuginfo for walking kernel structs, and accessing kprobe
entry args as variables
perf probe can provide this to bpf.
I was thinking about deeper integration with perf actually.
perf has all the right infra to find debug info in kernel and user
binaries, to extract and understand all the dwarf stuff.
The future tracing language can use more of it.
The programs should be able refer to names of in-kernel variables
and arguments natively.
When I'm writing a program that attaches to blk_update_request()
I would like to write:
bpf_printk("req %p bytes %d\n", req->q, nr_bytes);
and perf with debug info should be able to figure out that 'req'
is the first function argument, then find out offset of '->q'
within the struct and that 'nr_bytes' is the 3rd argument in
appropriate register. Then generate llvm ir on the fly,
compile it, load into kernel and attach to kprobe event at
this blk_update_request() function. All seamlessly.
Yes, that is what perf probe providing now. I think it is easy
to do that with probe-finder.c. :)
quoted
quoted
- tracing of uprobes
- tracing of user markers
I'm working on the perf-cache which will also support SDT (based on Hemant Kumar's work).
yep. waiting for SDT stuff to finalize. Would be nice to
have 'follow' button for interesting patches :)
:)
Thank you!
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org
add TRACE_EVENT_FL_KPROBE flag to differentiate kprobe type of tracepoints,
since bpf programs can only be attached to kprobe type of
PERF_TYPE_TRACEPOINT perf events.
Signed-off-by: Alexei Starovoitov <redacted>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
---
include/linux/ftrace_event.h | 3 +++
kernel/trace/trace_kprobe.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
add TRACE_EVENT_FL_KPROBE flag to differentiate kprobe type of tracepoints,
since bpf programs can only be attached to kprobe type of
PERF_TYPE_TRACEPOINT perf events.
Looks ok to me.
Reviewed-by: <redacted>
Thank you!
@@ -1286,7 +1286,7 @@ static int register_kprobe_event(struct trace_kprobe *tk)kfree(call->print_fmt);return-ENODEV;}-call->flags=0;+call->flags=TRACE_EVENT_FL_KPROBE;call->class->reg=kprobe_register;call->data=tk;ret=trace_add_event_call(call);
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org
From: Steven Rostedt <rostedt@goodmis.org> Date: 2015-03-21 04:07:35
On Fri, 20 Mar 2015 16:30:01 -0700
Alexei Starovoitov [off-list ref] wrote:
Hi Ingo,
I think it's good to go.
Patch 1 is already in net-next. Patch 3 depends on it.
I'm assuming it's not going to be a problem during merge window.
Patch 3 will have a minor conflict in uapi/linux/bpf.h in linux-next,
since net-next has added new lines to the bpf_prog_type and bpf_func_id enums.
I'm assuming it's not a problem either.
V8->V9:
- fixed comment style and allowed ispunct after %p
- added Steven's Reviewed-by. Thanks Steven!
Hi Ingo,
I'm fine with this series, so don't let me hold it up from going into
your tree.
Thanks,
-- Steve
On Fri, 20 Mar 2015 16:30:01 -0700
Alexei Starovoitov [off-list ref] wrote:
quoted
Hi Ingo,
I think it's good to go.
Patch 1 is already in net-next. Patch 3 depends on it.
I'm assuming it's not going to be a problem during merge window.
Patch 3 will have a minor conflict in uapi/linux/bpf.h in linux-next,
since net-next has added new lines to the bpf_prog_type and bpf_func_id enums.
I'm assuming it's not a problem either.
V8->V9:
- fixed comment style and allowed ispunct after %p
- added Steven's Reviewed-by. Thanks Steven!
Hi Ingo,
I'm fine with this series, so don't let me hold it up from going into
your tree.
Ok, thanks!
Looks like a very powerful instrumentation interface to me.
Thanks,
Ingo