1*387f9dfdSAndroid Build Coastguard WorkerLua Tools for BCC 2*387f9dfdSAndroid Build Coastguard Worker----------------- 3*387f9dfdSAndroid Build Coastguard Worker 4*387f9dfdSAndroid Build Coastguard WorkerThis directory contains Lua tooling for [BCC][bcc] 5*387f9dfdSAndroid Build Coastguard Worker(the BPF Compiler Collection). 6*387f9dfdSAndroid Build Coastguard Worker 7*387f9dfdSAndroid Build Coastguard WorkerBCC is a toolkit for creating userspace and kernel tracing programs. By 8*387f9dfdSAndroid Build Coastguard Workerdefault, it comes with a library `libbcc`, some example tooling and a Python 9*387f9dfdSAndroid Build Coastguard Workerfrontend for the library. 10*387f9dfdSAndroid Build Coastguard Worker 11*387f9dfdSAndroid Build Coastguard WorkerHere we present an alternate frontend for `libbcc` implemented in LuaJIT. This 12*387f9dfdSAndroid Build Coastguard Workerlets you write the userspace part of your tracer in Lua instead of Python. 13*387f9dfdSAndroid Build Coastguard Worker 14*387f9dfdSAndroid Build Coastguard WorkerSince LuaJIT is a JIT compiled language, tracers implemented in `bcc-lua` 15*387f9dfdSAndroid Build Coastguard Workerexhibit significantly reduced overhead compared to their Python equivalents. 16*387f9dfdSAndroid Build Coastguard WorkerThis is particularly noticeable in tracers that actively use the table APIs to 17*387f9dfdSAndroid Build Coastguard Workerget information from the kernel. 18*387f9dfdSAndroid Build Coastguard Worker 19*387f9dfdSAndroid Build Coastguard WorkerIf your tracer makes extensive use of `BPF_MAP_TYPE_PERF_EVENT_ARRAY` or 20*387f9dfdSAndroid Build Coastguard Worker`BPF_MAP_TYPE_HASH`, you may find the performance characteristics of this 21*387f9dfdSAndroid Build Coastguard Workerimplementation very appealing, as LuaJIT can compile to native code a lot of 22*387f9dfdSAndroid Build Coastguard Workerthe callchain to process the events, and this wrapper has been designed to 23*387f9dfdSAndroid Build Coastguard Workerbenefit from such JIT compilation. 24*387f9dfdSAndroid Build Coastguard Worker 25*387f9dfdSAndroid Build Coastguard Worker## Quickstart Guide 26*387f9dfdSAndroid Build Coastguard Worker 27*387f9dfdSAndroid Build Coastguard WorkerThe following instructions assume Ubuntu 18.04 LTS. 28*387f9dfdSAndroid Build Coastguard Worker 29*387f9dfdSAndroid Build Coastguard Worker1. Clone this repository 30*387f9dfdSAndroid Build Coastguard Worker 31*387f9dfdSAndroid Build Coastguard Worker ``` 32*387f9dfdSAndroid Build Coastguard Worker $ git clone https://github.com/iovisor/bcc.git 33*387f9dfdSAndroid Build Coastguard Worker $ cd bcc/ 34*387f9dfdSAndroid Build Coastguard Worker ``` 35*387f9dfdSAndroid Build Coastguard Worker 36*387f9dfdSAndroid Build Coastguard Worker2. As per the [Ubuntu - Binary](https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---binary) installation istructions, install the required upstream stable and signed packages 37*387f9dfdSAndroid Build Coastguard Worker 38*387f9dfdSAndroid Build Coastguard Worker ``` 39*387f9dfdSAndroid Build Coastguard Worker $ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD 40*387f9dfdSAndroid Build Coastguard Worker $ echo "deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/iovisor.list 41*387f9dfdSAndroid Build Coastguard Worker $ sudo apt-get update 42*387f9dfdSAndroid Build Coastguard Worker $ sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r) 43*387f9dfdSAndroid Build Coastguard Worker ``` 44*387f9dfdSAndroid Build Coastguard Worker 45*387f9dfdSAndroid Build Coastguard Worker3. Install LuaJit and the corresponding development files 46*387f9dfdSAndroid Build Coastguard Worker 47*387f9dfdSAndroid Build Coastguard Worker ``` 48*387f9dfdSAndroid Build Coastguard Worker $ sudo apt-get install luajit luajit-5.1-dev 49*387f9dfdSAndroid Build Coastguard Worker ``` 50*387f9dfdSAndroid Build Coastguard Worker 51*387f9dfdSAndroid Build Coastguard Worker4. Test one of the examples to ensure `libbcc` is properly installed 52*387f9dfdSAndroid Build Coastguard Worker 53*387f9dfdSAndroid Build Coastguard Worker ``` 54*387f9dfdSAndroid Build Coastguard Worker $ sudo src/lua/bcc-probe examples/lua/task_switch.lua 55*387f9dfdSAndroid Build Coastguard Worker ``` 56*387f9dfdSAndroid Build Coastguard Worker 57*387f9dfdSAndroid Build Coastguard Worker## LuaJIT BPF compiler 58*387f9dfdSAndroid Build Coastguard Worker 59*387f9dfdSAndroid Build Coastguard WorkerNow it is also possible to write Lua functions and compile them transparently to BPF bytecode, here is a simple socket filter example: 60*387f9dfdSAndroid Build Coastguard Worker 61*387f9dfdSAndroid Build Coastguard Worker```lua 62*387f9dfdSAndroid Build Coastguard Workerlocal S = require('syscall') 63*387f9dfdSAndroid Build Coastguard Workerlocal bpf = require('bpf') 64*387f9dfdSAndroid Build Coastguard Workerlocal map = bpf.map('array', 256) 65*387f9dfdSAndroid Build Coastguard Worker-- Kernel-space part of the program 66*387f9dfdSAndroid Build Coastguard Workerlocal prog = assert(bpf(function () 67*387f9dfdSAndroid Build Coastguard Worker local proto = pkt.ip.proto -- Get byte (ip.proto) from frame at [23] 68*387f9dfdSAndroid Build Coastguard Worker xadd(map[proto], 1) -- Increment packet count 69*387f9dfdSAndroid Build Coastguard Workerend)) 70*387f9dfdSAndroid Build Coastguard Worker-- User-space part of the program 71*387f9dfdSAndroid Build Coastguard Workerlocal sock = assert(bpf.socket('lo', prog)) 72*387f9dfdSAndroid Build Coastguard Workerfor i=1,10 do 73*387f9dfdSAndroid Build Coastguard Worker local icmp, udp, tcp = map[1], map[17], map[6] 74*387f9dfdSAndroid Build Coastguard Worker print('TCP', tcp, 'UDP', udp, 'ICMP', icmp, 'packets') 75*387f9dfdSAndroid Build Coastguard Worker S.sleep(1) 76*387f9dfdSAndroid Build Coastguard Workerend 77*387f9dfdSAndroid Build Coastguard Worker``` 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard WorkerThe other application of BPF programs is attaching to probes for [perf event tracing][tracing]. That means you can trace events inside the kernel (or user-space), and then collect results - for example histogram of `sendto()` latency, off-cpu time stack traces, syscall latency, and so on. While kernel probes and perf events have unstable ABI, with a dynamic language we can create and use proper type based on the tracepoint ABI on runtime. 80*387f9dfdSAndroid Build Coastguard Worker 81*387f9dfdSAndroid Build Coastguard WorkerRuntime automatically recognizes reads that needs a helper to be accessed. The type casts denote source of the objects, for example the [bashreadline][bashreadline] example that prints entered bash commands from all running shells: 82*387f9dfdSAndroid Build Coastguard Worker 83*387f9dfdSAndroid Build Coastguard Worker```lua 84*387f9dfdSAndroid Build Coastguard Workerlocal ffi = require('ffi') 85*387f9dfdSAndroid Build Coastguard Workerlocal bpf = require('bpf') 86*387f9dfdSAndroid Build Coastguard Worker-- Perf event map 87*387f9dfdSAndroid Build Coastguard Workerlocal sample_t = 'struct { uint64_t pid; char str[80]; }' 88*387f9dfdSAndroid Build Coastguard Workerlocal events = bpf.map('perf_event_array') 89*387f9dfdSAndroid Build Coastguard Worker-- Kernel-space part of the program 90*387f9dfdSAndroid Build Coastguard Workerbpf.uprobe('/bin/bash:readline' function (ptregs) 91*387f9dfdSAndroid Build Coastguard Worker local sample = ffi.new(sample_t) 92*387f9dfdSAndroid Build Coastguard Worker sample.pid = pid_tgid() 93*387f9dfdSAndroid Build Coastguard Worker ffi.copy(sample.str, ffi.cast('char *', req.ax)) -- Cast `ax` to string pointer and copy to buffer 94*387f9dfdSAndroid Build Coastguard Worker perf_submit(events, sample) -- Write sample to perf event map 95*387f9dfdSAndroid Build Coastguard Workerend, true, -1, 0) 96*387f9dfdSAndroid Build Coastguard Worker-- User-space part of the program 97*387f9dfdSAndroid Build Coastguard Workerlocal log = events:reader(nil, 0, sample_t) -- Must specify PID or CPU_ID to observe 98*387f9dfdSAndroid Build Coastguard Workerwhile true do 99*387f9dfdSAndroid Build Coastguard Worker log:block() -- Wait until event reader is readable 100*387f9dfdSAndroid Build Coastguard Worker for _,e in log:read() do -- Collect available reader events 101*387f9dfdSAndroid Build Coastguard Worker print(tonumber(e.pid), ffi.string(e.str)) 102*387f9dfdSAndroid Build Coastguard Worker end 103*387f9dfdSAndroid Build Coastguard Workerend 104*387f9dfdSAndroid Build Coastguard Worker``` 105*387f9dfdSAndroid Build Coastguard Worker 106*387f9dfdSAndroid Build Coastguard WorkerWhere cast to `struct pt_regs` flags the source of data as probe arguments, which means any pointer derived 107*387f9dfdSAndroid Build Coastguard Workerfrom this structure points to kernel and a helper is needed to access it. Casting `req.ax` to pointer is then required for `ffi.copy` semantics, otherwise it would be treated as `u64` and only it's value would be 108*387f9dfdSAndroid Build Coastguard Workercopied. The type detection is automatic most of the times (socket filters and `bpf.tracepoint`), but not with uprobes and kprobes. 109*387f9dfdSAndroid Build Coastguard Worker 110*387f9dfdSAndroid Build Coastguard Worker### Installation 111*387f9dfdSAndroid Build Coastguard Worker 112*387f9dfdSAndroid Build Coastguard Worker```bash 113*387f9dfdSAndroid Build Coastguard Worker$ luarocks install bpf 114*387f9dfdSAndroid Build Coastguard Worker``` 115*387f9dfdSAndroid Build Coastguard Worker 116*387f9dfdSAndroid Build Coastguard Worker### Examples 117*387f9dfdSAndroid Build Coastguard Worker 118*387f9dfdSAndroid Build Coastguard WorkerSee `examples/lua` directory. 119*387f9dfdSAndroid Build Coastguard Worker 120*387f9dfdSAndroid Build Coastguard Worker### Helpers 121*387f9dfdSAndroid Build Coastguard Worker 122*387f9dfdSAndroid Build Coastguard Worker* `print(...)` is a wrapper for `bpf_trace_printk`, the output is captured in `cat /sys/kernel/debug/tracing/trace_pipe` 123*387f9dfdSAndroid Build Coastguard Worker* `bit.*` library **is** supported (`lshift, rshift, arshift, bnot, band, bor, bxor`) 124*387f9dfdSAndroid Build Coastguard Worker* `math.*` library *partially* supported (`log2, log, log10`) 125*387f9dfdSAndroid Build Coastguard Worker* `ffi.cast()` is implemented (including structures and arrays) 126*387f9dfdSAndroid Build Coastguard Worker* `ffi.new(...)` allocates memory on stack, initializers are NYI 127*387f9dfdSAndroid Build Coastguard Worker* `ffi.copy(...)` copies memory (possibly using helpers) between stack/kernel/registers 128*387f9dfdSAndroid Build Coastguard Worker* `ntoh(x[, width])` - convert from network to host byte order. 129*387f9dfdSAndroid Build Coastguard Worker* `hton(x[, width])` - convert from host to network byte order. 130*387f9dfdSAndroid Build Coastguard Worker* `xadd(dst, inc)` - exclusive add, a synchronous `*dst += b` if Lua had `+=` operator 131*387f9dfdSAndroid Build Coastguard Worker 132*387f9dfdSAndroid Build Coastguard WorkerBelow is a list of BPF-specific helpers: 133*387f9dfdSAndroid Build Coastguard Worker 134*387f9dfdSAndroid Build Coastguard Worker* `time()` - return current monotonic time in nanoseconds (uses `bpf_ktime_get_ns`) 135*387f9dfdSAndroid Build Coastguard Worker* `cpu()` - return current CPU number (uses `bpf_get_smp_processor_id`) 136*387f9dfdSAndroid Build Coastguard Worker* `pid_tgid()` - return caller `tgid << 32 | pid` (uses `bpf_get_current_pid_tgid`) 137*387f9dfdSAndroid Build Coastguard Worker* `uid_gid()` - return caller `gid << 32 | uid` (uses `bpf_get_current_uid_gid`) 138*387f9dfdSAndroid Build Coastguard Worker* `comm(var)` - write current process name (uses `bpf_get_current_comm`) 139*387f9dfdSAndroid Build Coastguard Worker* `perf_submit(map, var)` - submit variable to perf event array BPF map 140*387f9dfdSAndroid Build Coastguard Worker* `stack_id(map, flags)` - return stack trace identifier from stack trace BPF map 141*387f9dfdSAndroid Build Coastguard Worker* `load_bytes(off, var)` - helper for direct packet access with `skb_load_bytes()` 142*387f9dfdSAndroid Build Coastguard Worker 143*387f9dfdSAndroid Build Coastguard Worker### Current state 144*387f9dfdSAndroid Build Coastguard Worker 145*387f9dfdSAndroid Build Coastguard Worker* Not all LuaJIT bytecode opcodes are supported *(notable mentions below)* 146*387f9dfdSAndroid Build Coastguard Worker* Closures `UCLO` will probably never be supported, although you can use upvalues inside compiled function. 147*387f9dfdSAndroid Build Coastguard Worker* Type narrowing is opportunistic. Numbers are 64-bit by default, but 64-bit immediate loads are not supported (e.g. `local x = map[ffi.cast('uint64_t', 1000)]`) 148*387f9dfdSAndroid Build Coastguard Worker* Tail calls `CALLT`, and iterators `ITERI` are NYI (as of now) 149*387f9dfdSAndroid Build Coastguard Worker* Arbitrary ctype **is** supported both for map keys and values 150*387f9dfdSAndroid Build Coastguard Worker* Basic optimisations like: constant propagation, partial DCE, liveness analysis and speculative register allocation are implement, but there's no control flow analysis yet. This means the compiler has the visibility when things are used and dead-stores occur, but there's no rewriter pass to eliminate them. 151*387f9dfdSAndroid Build Coastguard Worker* No register sub-allocations, no aggressive use of caller-saved `R1-5`, no aggressive narrowing (this would require variable range assertions and variable relationships) 152*387f9dfdSAndroid Build Coastguard Worker* Slices with not 1/2/4/8 length are NYI (requires allocating a memory on stack and using pointer type) 153*387f9dfdSAndroid Build Coastguard Worker 154*387f9dfdSAndroid Build Coastguard Worker 155*387f9dfdSAndroid Build Coastguard Worker[bcc]: https://github.com/iovisor/bcc 156*387f9dfdSAndroid Build Coastguard Worker[tracing]: http://www.brendangregg.com/blog/2016-03-05/linux-bpf-superpowers.html 157*387f9dfdSAndroid Build Coastguard Worker[bashreadline]: http://www.brendangregg.com/blog/2016-02-08/linux-ebpf-bcc-uprobes.html