Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linux/concepts: Add functions concept page #56

Merged
merged 1 commit into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .aspell.en.pws
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,5 @@ Mellanox
init
UID
GID
decl
inlining
1 change: 1 addition & 0 deletions docs/linux/concepts/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
* [`index.md`](index.md)
* [Maps](maps.md)
* [Verifier](verifier.md)
* [Functions](functions.md)
* [Concurrency](concurrency.md)
* [Pinning](pinning.md)
* [Tail calls](tail-calls.md)
Expand Down
49 changes: 49 additions & 0 deletions docs/linux/concepts/functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: Functions
description: This page explains the concept of eBPF functions, the different ways to use them, and how their usage has changed over time.
---
# Functions

When we talk about a function, we are referring to a function you would write in C or comparable programming language. In eBPF, the term function, program, and sub-program are often used interchangeably. A program refers to a function with a single argument, that being the context. A program can be attached to a hook point. Sub-programs, also referred to as BPF-to-BPF functions, are functions with zero to five arguments, they cannot be attached to a hook point, and are called from a program or special mechanism.

## Calling convention

The eBPF instruction set defines the calling convention for functions, these include programs, sub-programs, helper functions and kfuncs. Every function no matter who defines it uses the same calling convention. The R0 register is uses as the return value, a function should set it before returning unless it is a void function. Registers R1-R5 are used for arguments, R1 for the first argument, R2 for the second, and so on. Unlike calling conventions on native architectures, arguments are never passed via the stack. So 5 arguments is a hard limit, structures must be used to work around this. Registers R1-5 are clobbered after a function call, the verifier will not allow you to read from them until they are set with a known value. R6-9 are callee saved registers, they are preserved across function calls.

## BPF to BPF functions (sub-programs)

In [:octicons-tag-24: v4.16](https://github.com/torvalds/linux/commit/cc8b0b92a1699bc32f7fec71daa2bfc90de43a4d) BPF to BPF function calls were added. This allows BPF programs to reuse logic within the same program. A function can take up to 5 arguments, limited by the calling convention. It gets a fresh stack frame, which like any stack is free-ed and reused after the program exits. Functions can also access memory on the stack of a caller if a pointer to it is passed as an argument. Functions are limited to a maximum call depth of 8, so recursion of any meaningful depth is not possible.

### Function inlining

By default, the compiler will chose inline a function or to keep it a separate function. Compilers can be encouraged to inline or not inline a function with arguments like `__attribute__((always_inline))` or `__attribute__((noinline))`. Inlined functions do not incur the overhead of a function call as they will become part of the calling function. Inlined functions can also be optimized per call site since arguments are known.

### Tail calls

When function calls are combined with [tail calls](tail-calls.md) the available stack size per program will shrink from `512` bytes to `256` bytes. The reasoning being that when a tail call is made, the current stack frame is reused, but if that tail call is made from a function, the stack of the caller can not be reused. By default, kernel threads are limited to 8k stack sizes. By decreasing the max stack size, it is harder to run out of stack space, though it is still possible.

### Function by function verification

Until [:octicons-tag-24: v5.6](https://github.com/torvalds/linux/commit/51c39bb1d5d105a02e29aa7960f0a395086e6342) the verifier would re-verify that a function was safe for every call site. Meaning that if you have a function which is called 10 times, then the verifier would check for every call that with the given inputs the function was save. This defeats the purpose of functions somewhat since you still incur verifier complexity for every call.

Since [:octicons-tag-24: v5.6](https://github.com/torvalds/linux/commit/51c39bb1d5d105a02e29aa7960f0a395086e6342) a distinction is made between "static" and "global" functions. Static functions are still verified as usual. But global functions undergo "function by function verification". This means that the verifier will verify every function once, and even out of order. It will assume all possible input values are possible, since it will not check every call site anymore. Therefor, functions might require more input checking to pass the verifier. This change reduces verification times and complexity. Static functions are functions marked with the `static` keyword in the C code, global functions regular non-static functions.

### Global function replacement

Also added in [:octicons-tag-24: v5.6](https://github.com/torvalds/linux/commit/be8704ff07d2374bcc5c675526f95e70c6459683) is the ability to replace global functions. The primary use case for this is libxdp which used this to implement XDP program chaining from a dispatcher program.

See [Program Type `BPF_PROG_TYPE_EXT`](../program-type/BPF_PROG_TYPE_EXT.md) for more information.

### Callbacks

In [:octicons-tag-24: v5.13](https://github.com/torvalds/linux/commit/69c087ba6225b574afb6e505b72cb75242a3d844) the verifier was extended to allow for callbacks. Since then a number of helper function and kfuncs have been added that call back into given functions.

### Argument annotations

In [:octicons-tag-24: v6.8](https://github.com/torvalds/linux/commit/94e1c70a34523b5e1529e4ec508316acc6a26a2b) global function argument annotation were added. These are a set of annotations (in practice these are BTF decl tags), which if added to an attribute, tell the verifier to restrict the input values to the function. Possible tags are:

* `__arg_ctx` - The argument is a pointer to a program context.
* `__arg_nonnull` - The argument can not be NULL.
* `__arg_nullable` - The argument can be NULL.
* `__arg_trusted` - The argument must be a [trusted value](kfuncs.md#kf_trusted_args).
* `__arg_arena` - The argument must be a pointer to a [memory arena](../map-type/BPF_MAP_TYPE_ARENA.md).
124 changes: 110 additions & 14 deletions docs/linux/concepts/index.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,116 @@
---
title: Linux eBPF concepts
description: An index of Linux specific eBPF concepts.
hide: toc
---
# Linux eBPF concepts

This is an index of Linux specific eBPF concepts and features.

* [Maps](maps.md)
* [Verifier](verifier.md)
* [Concurrency](concurrency.md)
* [Pinning](pinning.md)
* [Tail calls](tail-calls.md)
* [Loops](loops.md)
* [Timers](timers.md)
* [Resource Limit](resource-limit.md)
* [AF_XDP](af_xdp.md)
* [KFuncs](kfuncs.md)
* [dynptrs](dynptrs.md)
* [token](token.md)
This is an index of Linux specific eBPF concepts and features. For more generic eBPF concepts that are not Linux specific, see the [eBPF concepts](../../concepts/index.md) page.

<div class="grid cards" markdown>

- __Maps__

---

Maps allow for data storage and communication

[:octicons-arrow-right-24: Maps](./maps.md)

- __Verifier__

---

The verifier checks the safety of eBPF programs

[:octicons-arrow-right-24: Verifier](./verifier.md)

- __Functions__

---

This page explains how functions work for eBPF on Linux

[:octicons-arrow-right-24: Functions](./functions.md)

- __Concurrency__

---

This page explains the effects of concurrency on eBPF programs and how to handle it

[:octicons-arrow-right-24: Concurrency](./concurrency.md)

- __Pinning__

---

Pinning allows the file system to reference eBPF objects and keep them alive

[:octicons-arrow-right-24: Pinning](./pinning.md)

- __Tail calls__

---

Tail calls allow for the chaining of eBPF programs

[:octicons-arrow-right-24: Tail calls](./tail-calls.md)

- __Loops__

---

Loops in eBPF are not trivial, this page explains how to use different types of loops

[:octicons-arrow-right-24: Loops](./loops.md)

- __Timers__

---

Timers allow for the scheduling of eBPF functions to execute at a later time

[:octicons-arrow-right-24: Timers](./timers.md)

- __Resource Limit__

---

This page explains how the Linux kernel counts and restricts the resources used by eBPF

[:octicons-arrow-right-24: Resource Limit](./resource-limit.md)

- __AF_XDP__

---

AF_XDP allows you to bypass the kernel network stack and process packets in userspace

[:octicons-arrow-right-24: AF_XDP](./af_xdp.md)

- __KFuncs__

---

KFuncs allow for the calling of kernel functions from eBPF programs

[:octicons-arrow-right-24: KFuncs](./kfuncs.md)

- __Dynamic pointers__

---

Dynamic pointers are pointers with metadata, moving memory safety checks to runtime

[:octicons-arrow-right-24: Dynptrs](./dynptrs.md)

- __eBPF Tokens__

---

eBPF tokens are like authentication tokens for eBPF operations

[:octicons-arrow-right-24: Token](./token.md)

</div>
19 changes: 19 additions & 0 deletions docs/linux/map-type/BPF_MAP_TYPE_ARENA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: "Map Type 'BPF_MAP_TYPE_ARENA'"
description: "This page documents the 'BPF_MAP_TYPE_ARENA' eBPF map type, including its definition, usage, program types that can use it, and examples."
---
# Map type `BPF_MAP_TYPE_ARENA`

<!-- [FEATURE_TAG](BPF_MAP_TYPE_ARENA) -->
[:octicons-tag-24: v6.9](https://github.com/torvalds/linux/commit/317460317a02a1af512697e6e964298dedd8a163)
<!-- [/FEATURE_TAG] -->

!!! example "Docs could be improved"
This part of the docs is incomplete, contributions are very welcome

<!-- ## Usage

## Attributes

## Flags -->

1 change: 1 addition & 0 deletions docs/linux/map-type/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* [`BPF_MAP_TYPE_LRU_PERCPU_HASH`](BPF_MAP_TYPE_LRU_PERCPU_HASH.md)
* [`BPF_MAP_TYPE_LPM_TRIE`](BPF_MAP_TYPE_LPM_TRIE.md)
* [`BPF_MAP_TYPE_BLOOM_FILTER`](BPF_MAP_TYPE_BLOOM_FILTER.md)
* [`BPF_MAP_TYPE_ARENA`](BPF_MAP_TYPE_ARENA.md)
* Map in map
* [`BPF_MAP_TYPE_ARRAY_OF_MAPS`](BPF_MAP_TYPE_ARRAY_OF_MAPS.md)
* [`BPF_MAP_TYPE_HASH_OF_MAPS`](BPF_MAP_TYPE_HASH_OF_MAPS.md)
Expand Down
1 change: 1 addition & 0 deletions docs/linux/map-type/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ These map types are not limited to a very specific use case but can be used in a
* `BPF_MAP_TYPE_LRU_PERCPU_HASH`
* [`BPF_MAP_TYPE_LPM_TRIE`](BPF_MAP_TYPE_LPM_TRIE.md)
* [`BPF_MAP_TYPE_BLOOM_FILTER`](BPF_MAP_TYPE_BLOOM_FILTER.md)
* [`BPF_MAP_TYPE_ARENA`](BPF_MAP_TYPE_ARENA.md)

## Map in map

Expand Down
Loading