|
| 1 | +.. SPDX-License-Identifier: GPL-2.0 |
| 2 | +
|
| 3 | +=============== |
| 4 | +libbpf Overview |
| 5 | +=============== |
| 6 | + |
| 7 | +libbpf is a C-based library containing a BPF loader that takes compiled BPF |
| 8 | +object files and prepares and loads them into the Linux kernel. libbpf takes the |
| 9 | +heavy lifting of loading, verifying, and attaching BPF programs to various |
| 10 | +kernel hooks, allowing BPF application developers to focus only on BPF program |
| 11 | +correctness and performance. |
| 12 | + |
| 13 | +The following are the high-level features supported by libbpf: |
| 14 | + |
| 15 | +* Provides high-level and low-level APIs for user space programs to interact |
| 16 | + with BPF programs. The low-level APIs wrap all the bpf system call |
| 17 | + functionality, which is useful when users need more fine-grained control |
| 18 | + over the interactions between user space and BPF programs. |
| 19 | +* Provides overall support for the BPF object skeleton generated by bpftool. |
| 20 | + The skeleton file simplifies the process for the user space programs to access |
| 21 | + global variables and work with BPF programs. |
| 22 | +* Provides BPF-side APIS, including BPF helper definitions, BPF maps support, |
| 23 | + and tracing helpers, allowing developers to simplify BPF code writing. |
| 24 | +* Supports BPF CO-RE mechanism, enabling BPF developers to write portable |
| 25 | + BPF programs that can be compiled once and run across different kernel |
| 26 | + versions. |
| 27 | + |
| 28 | +This document will delve into the above concepts in detail, providing a deeper |
| 29 | +understanding of the capabilities and advantages of libbpf and how it can help |
| 30 | +you develop BPF applications efficiently. |
| 31 | + |
| 32 | +BPF App Lifecycle and libbpf APIs |
| 33 | +================================== |
| 34 | + |
| 35 | +A BPF application consists of one or more BPF programs (either cooperating or |
| 36 | +completely independent), BPF maps, and global variables. The global |
| 37 | +variables are shared between all BPF programs, which allows them to cooperate on |
| 38 | +a common set of data. libbpf provides APIs that user space programs can use to |
| 39 | +manipulate the BPF programs by triggering different phases of a BPF application |
| 40 | +lifecycle. |
| 41 | + |
| 42 | +The following section provides a brief overview of each phase in the BPF life |
| 43 | +cycle: |
| 44 | + |
| 45 | +* **Open phase**: In this phase, libbpf parses the BPF |
| 46 | + object file and discovers BPF maps, BPF programs, and global variables. After |
| 47 | + a BPF app is opened, user space apps can make additional adjustments |
| 48 | + (setting BPF program types, if necessary; pre-setting initial values for |
| 49 | + global variables, etc.) before all the entities are created and loaded. |
| 50 | + |
| 51 | +* **Load phase**: In the load phase, libbpf creates BPF |
| 52 | + maps, resolves various relocations, and verifies and loads BPF programs into |
| 53 | + the kernel. At this point, libbpf validates all the parts of a BPF application |
| 54 | + and loads the BPF program into the kernel, but no BPF program has yet been |
| 55 | + executed. After the load phase, it’s possible to set up the initial BPF map |
| 56 | + state without racing with the BPF program code execution. |
| 57 | + |
| 58 | +* **Attachment phase**: In this phase, libbpf |
| 59 | + attaches BPF programs to various BPF hook points (e.g., tracepoints, kprobes, |
| 60 | + cgroup hooks, network packet processing pipeline, etc.). During this |
| 61 | + phase, BPF programs perform useful work such as processing |
| 62 | + packets, or updating BPF maps and global variables that can be read from user |
| 63 | + space. |
| 64 | + |
| 65 | +* **Tear down phase**: In the tear down phase, |
| 66 | + libbpf detaches BPF programs and unloads them from the kernel. BPF maps are |
| 67 | + destroyed, and all the resources used by the BPF app are freed. |
| 68 | + |
| 69 | +BPF Object Skeleton File |
| 70 | +======================== |
| 71 | + |
| 72 | +BPF skeleton is an alternative interface to libbpf APIs for working with BPF |
| 73 | +objects. Skeleton code abstract away generic libbpf APIs to significantly |
| 74 | +simplify code for manipulating BPF programs from user space. Skeleton code |
| 75 | +includes a bytecode representation of the BPF object file, simplifying the |
| 76 | +process of distributing your BPF code. With BPF bytecode embedded, there are no |
| 77 | +extra files to deploy along with your application binary. |
| 78 | + |
| 79 | +You can generate the skeleton header file ``(.skel.h)`` for a specific object |
| 80 | +file by passing the BPF object to the bpftool. The generated BPF skeleton |
| 81 | +provides the following custom functions that correspond to the BPF lifecycle, |
| 82 | +each of them prefixed with the specific object name: |
| 83 | + |
| 84 | +* ``<name>__open()`` – creates and opens BPF application (``<name>`` stands for |
| 85 | + the specific bpf object name) |
| 86 | +* ``<name>__load()`` – instantiates, loads,and verifies BPF application parts |
| 87 | +* ``<name>__attach()`` – attaches all auto-attachable BPF programs (it’s |
| 88 | + optional, you can have more control by using libbpf APIs directly) |
| 89 | +* ``<name>__destroy()`` – detaches all BPF programs and |
| 90 | + frees up all used resources |
| 91 | + |
| 92 | +Using the skeleton code is the recommended way to work with bpf programs. Keep |
| 93 | +in mind, BPF skeleton provides access to the underlying BPF object, so whatever |
| 94 | +was possible to do with generic libbpf APIs is still possible even when the BPF |
| 95 | +skeleton is used. It's an additive convenience feature, with no syscalls, and no |
| 96 | +cumbersome code. |
| 97 | + |
| 98 | +Other Advantages of Using Skeleton File |
| 99 | +--------------------------------------- |
| 100 | + |
| 101 | +* BPF skeleton provides an interface for user space programs to work with BPF |
| 102 | + global variables. The skeleton code memory maps global variables as a struct |
| 103 | + into user space. The struct interface allows user space programs to initialize |
| 104 | + BPF programs before the BPF load phase and fetch and update data from user |
| 105 | + space afterward. |
| 106 | + |
| 107 | +* The ``skel.h`` file reflects the object file structure by listing out the |
| 108 | + available maps, programs, etc. BPF skeleton provides direct access to all the |
| 109 | + BPF maps and BPF programs as struct fields. This eliminates the need for |
| 110 | + string-based lookups with ``bpf_object_find_map_by_name()`` and |
| 111 | + ``bpf_object_find_program_by_name()`` APIs, reducing errors due to BPF source |
| 112 | + code and user-space code getting out of sync. |
| 113 | + |
| 114 | +* The embedded bytecode representation of the object file ensures that the |
| 115 | + skeleton and the BPF object file are always in sync. |
| 116 | + |
| 117 | +BPF Helpers |
| 118 | +=========== |
| 119 | + |
| 120 | +libbpf provides BPF-side APIs that BPF programs can use to interact with the |
| 121 | +system. The BPF helpers definition allows developers to use them in BPF code as |
| 122 | +any other plain C function. For example, there are helper functions to print |
| 123 | +debugging messages, get the time since the system was booted, interact with BPF |
| 124 | +maps, manipulate network packets, etc. |
| 125 | + |
| 126 | +For a complete description of what the helpers do, the arguments they take, and |
| 127 | +the return value, see the `bpf-helpers |
| 128 | +<https://man7.org/linux/man-pages/man7/bpf-helpers.7.html>`_ man page. |
| 129 | + |
| 130 | +BPF CO-RE (Compile Once – Run Everywhere) |
| 131 | +========================================= |
| 132 | + |
| 133 | +BPF programs work in the kernel space and have access to kernel memory and data |
| 134 | +structures. One limitation that BPF applications come across is the lack of |
| 135 | +portability across different kernel versions and configurations. `BCC |
| 136 | +<https://github.com/iovisor/bcc/>`_ is one of the solutions for BPF |
| 137 | +portability. However, it comes with runtime overhead and a large binary size |
| 138 | +from embedding the compiler with the application. |
| 139 | + |
| 140 | +libbpf steps up the BPF program portability by supporting the BPF CO-RE concept. |
| 141 | +BPF CO-RE brings together BTF type information, libbpf, and the compiler to |
| 142 | +produce a single executable binary that you can run on multiple kernel versions |
| 143 | +and configurations. |
| 144 | + |
| 145 | +To make BPF programs portable libbpf relies on the BTF type information of the |
| 146 | +running kernel. Kernel also exposes this self-describing authoritative BTF |
| 147 | +information through ``sysfs`` at ``/sys/kernel/btf/vmlinux``. |
| 148 | + |
| 149 | +You can generate the BTF information for the running kernel with the following |
| 150 | +command: |
| 151 | + |
| 152 | +:: |
| 153 | + |
| 154 | + $ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h |
| 155 | + |
| 156 | +The command generates a ``vmlinux.h`` header file with all kernel types |
| 157 | +(:doc:`BTF types <../btf>`) that the running kernel uses. Including |
| 158 | +``vmlinux.h`` in your BPF program eliminates dependency on system-wide kernel |
| 159 | +headers. |
| 160 | + |
| 161 | +libbpf enables portability of BPF programs by looking at the BPF program’s |
| 162 | +recorded BTF type and relocation information and matching them to BTF |
| 163 | +information (vmlinux) provided by the running kernel. libbpf then resolves and |
| 164 | +matches all the types and fields, and updates necessary offsets and other |
| 165 | +relocatable data to ensure that BPF program’s logic functions correctly for a |
| 166 | +specific kernel on the host. BPF CO-RE concept thus eliminates overhead |
| 167 | +associated with BPF development and allows developers to write portable BPF |
| 168 | +applications without modifications and runtime source code compilation on the |
| 169 | +target machine. |
| 170 | + |
| 171 | +The following code snippet shows how to read the parent field of a kernel |
| 172 | +``task_struct`` using BPF CO-RE and libbf. The basic helper to read a field in a |
| 173 | +CO-RE relocatable manner is ``bpf_core_read(dst, sz, src)``, which will read |
| 174 | +``sz`` bytes from the field referenced by ``src`` into the memory pointed to by |
| 175 | +``dst``. |
| 176 | + |
| 177 | +.. code-block:: C |
| 178 | + :emphasize-lines: 6 |
| 179 | +
|
| 180 | + //... |
| 181 | + struct task_struct *task = (void *)bpf_get_current_task(); |
| 182 | + struct task_struct *parent_task; |
| 183 | + int err; |
| 184 | +
|
| 185 | + err = bpf_core_read(&parent_task, sizeof(void *), &task->parent); |
| 186 | + if (err) { |
| 187 | + /* handle error */ |
| 188 | + } |
| 189 | +
|
| 190 | + /* parent_task contains the value of task->parent pointer */ |
| 191 | +
|
| 192 | +In the code snippet, we first get a pointer to the current ``task_struct`` using |
| 193 | +``bpf_get_current_task()``. We then use ``bpf_core_read()`` to read the parent |
| 194 | +field of task struct into the ``parent_task`` variable. ``bpf_core_read()`` is |
| 195 | +just like ``bpf_probe_read_kernel()`` BPF helper, except it records information |
| 196 | +about the field that should be relocated on the target kernel. i.e, if the |
| 197 | +``parent`` field gets shifted to a different offset within |
| 198 | +``struct task_struct`` due to some new field added in front of it, libbpf will |
| 199 | +automatically adjust the actual offset to the proper value. |
| 200 | + |
| 201 | +Getting Started with libbpf |
| 202 | +=========================== |
| 203 | + |
| 204 | +Check out the `libbpf-bootstrap <https://github.com/libbpf/libbpf-bootstrap>`_ |
| 205 | +repository with simple examples of using libbpf to build various BPF |
| 206 | +applications. |
| 207 | + |
| 208 | +See also `libbpf API documentation |
| 209 | +<https://libbpf.readthedocs.io/en/latest/api.html>`_. |
| 210 | + |
| 211 | +libbpf and Rust |
| 212 | +=============== |
| 213 | + |
| 214 | +If you are building BPF applications in Rust, it is recommended to use the |
| 215 | +`Libbpf-rs <https://github.com/libbpf/libbpf-rs>`_ library instead of bindgen |
| 216 | +bindings directly to libbpf. Libbpf-rs wraps libbpf functionality in |
| 217 | +Rust-idiomatic interfaces and provides libbpf-cargo plugin to handle BPF code |
| 218 | +compilation and skeleton generation. Using Libbpf-rs will make building user |
| 219 | +space part of the BPF application easier. Note that the BPF program themselves |
| 220 | +must still be written in plain C. |
| 221 | + |
| 222 | +Additional Documentation |
| 223 | +======================== |
| 224 | + |
| 225 | +* `Program types and ELF Sections <https://libbpf.readthedocs.io/en/latest/program_types.html>`_ |
| 226 | +* `API naming convention <https://libbpf.readthedocs.io/en/latest/libbpf_naming_convention.html>`_ |
| 227 | +* `Building libbpf <https://libbpf.readthedocs.io/en/latest/libbpf_build.html>`_ |
| 228 | +* `API documentation Convention <https://libbpf.readthedocs.io/en/latest/libbpf_naming_convention.html#api-documentation-convention>`_ |
0 commit comments