| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 1 | # BPF Compiler Collection (BCC) |
| 2 | |
| 3 | This directory contains source code for BCC, a toolkit for creating small |
| 4 | programs that can be dynamically loaded into a Linux kernel. |
| 5 | |
| 6 | The compiler relies upon eBPF (Extended Berkeley Packet Filters), which is a |
| 7 | feature in Linux kernels starting from 3.19. Currently, this compiler leverages |
| 8 | features which are mostly available in Linux 4.1 and above. |
| 9 | |
| 10 | ## Motivation |
| 11 | |
| 12 | BPF guarantees that the programs loaded into the kernel cannot crash, and |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 13 | cannot run forever, but yet BPF is general purpose enough to perform many |
| 14 | arbitrary types of computation. Currently, it is possible to write a program in |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 15 | C that will compile into a valid BPF program, yet it is vastly easier to |
| 16 | write a C program that will compile into invalid BPF (C is like that). The user |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 17 | won't know until trying to run the program whether it was valid or not. |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 18 | |
| 19 | With a BPF-specific frontend, one should be able to write in a language and |
| 20 | receive feedback from the compiler on the validity as it pertains to a BPF |
| 21 | backend. This toolkit aims to provide a frontend that can only create valid BPF |
| 22 | programs while still harnessing its full flexibility. |
| 23 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 24 | Furthermore, current integrations with BPF have a kludgy workflow, sometimes |
| 25 | involving compiling directly in a linux kernel source tree. This toolchain aims |
| 26 | to minimize the time that a developer spends getting BPF compiled, and instead |
| 27 | focus on the applications that can be written and the problems that can be |
| 28 | solved with BPF. |
| 29 | |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 30 | The features of this toolkit include: |
| 31 | * End-to-end BPF workflow in a shared library |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 32 | * A modified C language for BPF backends |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 33 | * Integration with llvm-bpf backend for JIT |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 34 | * Dynamic (un)loading of JITed programs |
| 35 | * Support for BPF kernel hooks: socket filters, tc classifiers, |
| 36 | tc actions, and kprobes |
| 37 | * Bindings for Python |
| 38 | * Examples for socket filters, tc classifiers, and kprobes |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 39 | |
| 40 | In the future, more bindings besides python will likely be supported. Feel free |
| 41 | to add support for the language of your choice and send a pull request! |
| 42 | |
| 43 | ## Examples |
| 44 | |
| 45 | This toolchain is currently composed of two parts: a C wrapper around LLVM, and |
| 46 | a Python API to interact with the running program. Later, we will go into more |
| 47 | detail of how this all works. |
| 48 | |
| 49 | ### Hello, World |
| 50 | |
| 51 | First, we should include the BPF class from the bpf module: |
| 52 | ```python |
| 53 | from bpf import BPF |
| 54 | ``` |
| 55 | |
| 56 | Since the C code is so short, we will embed it inside the python script. |
| 57 | |
| 58 | The BPF program always takes at least one argument, which is a pointer to the |
| 59 | context for this type of program. Different program types have different calling |
| 60 | conventions, but for this one we don't care so `void *` is fine. |
| 61 | ```python |
| 62 | prog = """ |
| 63 | int hello(void *ctx) { |
| 64 | bpf_trace_printk("Hello, World!\\n"); |
| 65 | return 0; |
| 66 | }; |
| 67 | """ |
| 68 | b = BPF(text=prog) |
| 69 | ``` |
| 70 | |
| 71 | For this example, we will call the program every time `fork()` is called by a |
| 72 | userspace process. Underneath the hood, fork translates to the `clone` syscall, |
| 73 | so we will attach our program to the kernel symbol `sys_clone`. |
| 74 | ```python |
| 75 | fn = b.load_func("hello", BPF.KPROBE) |
| 76 | BPF.attach_kprobe(fn, "sys_clone") |
| 77 | ``` |
| 78 | |
| 79 | The python process will then print the trace printk circular buffer until ctrl-c |
| 80 | is pressed. The BPF program is removed from the kernel when the userspace |
| 81 | process that loaded it closes the fd (or exits). |
| 82 | ```python |
| 83 | from subprocess import call |
| 84 | try: |
| 85 | call(["cat", "/sys/kernel/debug/tracing/trace_pipe"]) |
| 86 | except KeyboardInterrupt: |
| 87 | pass |
| 88 | ``` |
| 89 | |
| 90 | Output: |
| 91 | ``` |
| 92 | bcc/examples$ sudo python hello_world.py |
| 93 | python-7282 [002] d... 3757.488508: : Hello, World! |
| 94 | ``` |
| 95 | |
| 96 | [Source code listing](examples/hello_world.py) |
| 97 | |
| 98 | ### Networking |
| 99 | |
| 100 | Walkthrough TBD, see |
| 101 | [Neighbor Sharing example](examples/tc_neighbor_sharing.py) for longer |
| 102 | example. |
| 103 | |
| 104 | ### Tracing |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 105 | |
| 106 | ## Requirements |
| 107 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 108 | To get started using this toolchain in binary format, one needs: |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 109 | * Linux kernel 4.1 or newer, with these flags enabled: |
| Brenden Blanco | 8310291 | 2015-06-09 17:43:27 -0700 | [diff] [blame] | 110 | * `CONFIG_BPF=y` |
| 111 | * `CONFIG_BPF_SYSCALL=y` |
| 112 | * `CONFIG_NET_CLS_BPF=m` [optional, for tc filters] |
| 113 | * `CONFIG_NET_ACT_BPF=m` [optional, for tc actions] |
| 114 | * `CONFIG_BPF_JIT=y` |
| 115 | * `CONFIG_HAVE_BPF_JIT=y` |
| 116 | * `CONFIG_BPF_EVENTS=y` [optional, for kprobes] |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 117 | * Headers for the above kernel |
| 118 | * gcc, make, python |
| 119 | * python-pyroute2 (for some networking features only) |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 120 | |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 121 | ## Getting started |
| 122 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 123 | As of this writing, binary packages for the above requirements are available |
| 124 | in unstable formats. Both Ubuntu and Fedora have 4.2-rcX builds with the above |
| 125 | flags defaulted to on. LLVM provides 3.7 Ubuntu packages (but not Fedora yet). |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 126 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 127 | ### Ubuntu - Docker edition |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 128 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 129 | The build dependencies are captured in a [Dockerfile](Dockerfile.ubuntu), the |
| 130 | output of which is a .deb for easy installation. |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 131 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 132 | * Start with a recent Ubuntu install (tested with 14.04 LTS) |
| 133 | * Install a [>= 4.2 kernel](http://kernel.ubuntu.com/~kernel-ppa/mainline/) |
| 134 | with headers |
| 135 | * Reboot |
| 136 | * Install [docker](https://docs.docker.com/installation/ubuntulinux/) |
| 137 | (`wget -qO- https://get.docker.com/ | sh`) |
| 138 | * Run the Dockerfile for Ubuntu - results in an installable .deb |
| 139 | * `git clone https://github.com/iovisor/bcc; cd bcc` |
| 140 | * `docker build -t bcc -f Dockerfile.ubuntu .` |
| 141 | * `docker run --rm -v /tmp:/mnt bcc sh -c "cp /root/bcc/build/*.deb /mnt"` |
| 142 | * `sudo dpkg -i /tmp/libbcc*.deb` |
| 143 | * Run the example |
| 144 | * `sudo python /usr/share/bcc/examples/hello_world.py` |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 145 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 146 | ### Fedora - Docker edition |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 147 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 148 | The build dependencies are captured in a [Dockerfile](Dockerfile.fedora), the |
| 149 | output of which is a .rpm for easy installation. This version takes longer since |
| 150 | LLVM needs to be compiled from source. |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 151 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 152 | * Start with a recent Fedora install (tested with F22) |
| 153 | * Install a [>= 4.2 kernel](http://alt.fedoraproject.org/pub/alt/rawhide-kernel-nodebug/x86_64/) |
| 154 | with headers |
| 155 | * Reboot |
| 156 | * Install [docker](https://docs.docker.com/installation/fedora/) |
| 157 | * Run the Dockerfile for Fedora - results in an installable .rpm |
| 158 | * `git clone https://github.com/iovisor/bcc; cd bcc` |
| 159 | * `docker build -t bcc -f Dockerfile.fedora .` |
| 160 | * `docker run --rm -v /tmp:/mnt bcc sh -c "cp /root/bcc/build/*.rpm /mnt"` |
| 161 | * `sudo rpm -ivh /tmp/libbcc*.rpm` |
| 162 | * Run the example |
| 163 | * `sudo python /usr/share/bcc/examples/hello_world.py` |
| Brenden Blanco | 8310291 | 2015-06-09 17:43:27 -0700 | [diff] [blame] | 164 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 165 | ### Ubuntu - From source |
| Brenden Blanco | 8310291 | 2015-06-09 17:43:27 -0700 | [diff] [blame] | 166 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 167 | To build the toolchain from source, one needs: |
| 168 | * LLVM 3.7 or newer, compiled with BPF support (default=on) |
| 169 | * Clang 3.7, built from the same tree as LLVM |
| 170 | * cmake, gcc (>=4.7), flex, bison |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 171 | |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 172 | * Add the [LLVM binary repo](http://llvm.org/apt/) to your apt sources |
| Brenden Blanco | 34aafe9 | 2015-07-07 13:10:21 -0700 | [diff] [blame] | 173 | * `echo "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty main" | sudo tee /etc/apt/sources.list.d/llvm.list` |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 174 | * `wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -` |
| 175 | * `sudo apt-get update` |
| 176 | * Install build dependencies |
| Brenden Blanco | 34aafe9 | 2015-07-07 13:10:21 -0700 | [diff] [blame] | 177 | * `sudo apt-get -y install bison build-essential cmake flex git libedit-dev python zlib1g-dev` |
| Brenden Blanco | 46176a1 | 2015-07-07 13:05:22 -0700 | [diff] [blame] | 178 | * Install LLVM and Clang development libs |
| 179 | * `sudo apt-get -y install libllvm3.7 llvm-3.7-dev libclang-3.7-dev` |
| 180 | * Install and compile BCC |
| 181 | * `git clone https://github.com/iovisor/bcc.git` |
| 182 | * `mkdir bcc/build; cd bcc/build` |
| 183 | * `cmake .. -DCMAKE_INSTALL_PREFIX=/usr` |
| 184 | * `make -j$(grep -c ^process /proc/cpuinfo)` |
| 185 | * `sudo make install` |
| Brenden Blanco | 452de20 | 2015-05-03 10:43:07 -0700 | [diff] [blame] | 186 | |
| Brenden | c3c4fc1 | 2015-05-03 08:33:53 -0700 | [diff] [blame] | 187 | ## Release notes |
| 188 | |
| 189 | * 0.1 |
| 190 | * Initial commit |