-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libbpf/ebpf: Add pages for a hand full of misc eBPF macros
This commit adds pages for a hand full of eBPF macros that do not seem to fit in any of the other categories. Signed-off-by: Dylan Reimerink <[email protected]>
- Loading branch information
1 parent
471a339
commit 987e61d
Showing
13 changed files
with
464 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
--- | ||
title: "Libbpf eBPF macro 'KERNEL_VERSION'" | ||
description: "This page documents the 'KERNEL_VERSION' libbpf eBPF macro, including its definition, usage, and examples." | ||
--- | ||
# Libbpf eBPF macro `KERNEL_VERSION` | ||
|
||
[:octicons-tag-24: v0.0.6](https://github.com/libbpf/libbpf/releases/tag/v0.0.6) | ||
|
||
The `KERNEL_VERSION` macros is used to convert from three part {major}.{minor}.{patch} version number to a single integer. | ||
|
||
## Definition | ||
|
||
`#!c #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + ((c) > 255 ? 255 : (c)))` | ||
|
||
## Usage | ||
|
||
This macro can be used together with the kernel version of the machine the program is loaded on. To get this kernel version you define `extern int LINUX_KERNEL_VERSION __kconfig;`. The `LINUX_KERNEL_VERSION` variable has a special meaning an will be resolved by the loader (library). It is encoded the same way as `KERNEL_VERSION`, allowing you to compare the two values. This allows you to write CO-RE like code that can adapt to different kernel versions. | ||
|
||
!!! warning | ||
Version numbers do not always reflect the actual features available in the kernel. Some distributions backport features to older kernels without reflecting this in the version number. If possible, it is always better to probe for the availability of a feature directly instead of inferring it from the kernel version. | ||
|
||
### Example | ||
|
||
```c hl_lines="6" | ||
extern int LINUX_KERNEL_VERSION __kconfig; | ||
|
||
SEC("xdp") | ||
int example_prog(struct xdp_md *ctx) | ||
{ | ||
if (LINUX_KERNEL_VERSION < KERNEL_VERSION(5, 10, 0)) { | ||
// Fall back to old behavior | ||
} else { | ||
// Use new features | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
--- | ||
title: "Libbpf eBPF macro 'SEC'" | ||
description: "This page documents the 'SEC' libbpf eBPF macro, including its definition, usage, and examples." | ||
--- | ||
# Libbpf eBPF macro `SEC` | ||
|
||
[:octicons-tag-24: v0.0.6](https://github.com/libbpf/libbpf/releases/tag/v0.0.6) | ||
|
||
The `SEC` macros is used to tell the compiler in which ELF section to place a symbol. | ||
|
||
## Definition | ||
|
||
`#!c #define SEC(NAME) __attribute__((section(NAME), used))` | ||
|
||
## Usage | ||
|
||
This macro is used to place a symbol in a specific ELF section. You will typically see this on eBPF programs and map definitions, however, they can be used on any symbol. The `NAME` argument is the name of the ELF section. The section in which a symbol is placed often has implicit meaning and can change how a loader (library) such as libbpf will interpret the contents of that section. | ||
|
||
For example the `maps` section is used for legacy map definitions, and BTF based maps have to be placed in the `.maps` section. All programs in the `xdp` section will we loaded as programs of type `BPF_PROG_TYPE_XDP` and attach type `BPF_XDP`, in the `xdp.frags` will also have the `BPF_F_XDP_HAS_FRAGS` flag set for example. | ||
|
||
A table of well-known program sections can be found [here](https://docs.kernel.org/bpf/libbpf/program_types.html). Note that these do not include non-program sections such as `.maps`, `license`, `ksym`, etc. | ||
|
||
### Example | ||
|
||
|
||
```c hl_lines="1" | ||
SEC("xdp") | ||
int example_prog(struct xdp_md *ctx) | ||
{ | ||
void *data_end = (void *)(long)ctx->data_end; | ||
void *data = (void *)(long)ctx->data; | ||
|
||
if (data + sizeof(struct ethhdr) > data_end) | ||
return XDP_DROP; | ||
|
||
struct ethhdr *eth = data; | ||
if (eth->h_proto == htons(ETH_P_IP)) | ||
return XDP_PASS; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--- | ||
title: "Libbpf eBPF macro '__bpf_unreachable'" | ||
description: "This page documents the '__bpf_unreachable' libbpf eBPF macro, including its definition, usage, and examples." | ||
--- | ||
# Libbpf eBPF macro `__bpf_unreachable` | ||
|
||
[:octicons-tag-24: v0.2](https://github.com/libbpf/libbpf/releases/tag/v0.2) | ||
|
||
The `__bpf_unreachable` macro is used to cause a compile time error if the code path is reached. | ||
|
||
## Definition | ||
|
||
`#!c #define __bpf_unreachable() __builtin_trap()` | ||
|
||
## Usage | ||
|
||
This macro asks the compiler to generate a trap instruction, which in a userspace program would crash the program on runtime. However, the eBPF compiler backend does not implement this, so it actually will cause the compiler to emit an error if the code path is reached. | ||
|
||
This is useful if you want to assert at compile time that a certain code path is never reachable to prevent accidental bugs. | ||
|
||
### Example | ||
|
||
In this example, we use the default clause of the switch statement to assert that `my_func` is always called with one of the enum values handled. If `my_enum` is ever extended without updating the switch statement, and the new value is passed to `my_func`, the compiler will emit an error. This will also happen if user input is used to call `my_func` and the input is not properly validated. | ||
|
||
```c hl_lines="15" | ||
enum my_enum { | ||
MY_ENUM_A, | ||
MY_ENUM_B, | ||
}; | ||
|
||
static void __always_inline my_func(enum my_enum e) { | ||
switch (e) { | ||
case MY_ENUM_A: | ||
// Do something | ||
break; | ||
case MY_ENUM_B: | ||
// Do something | ||
break; | ||
default: | ||
__bpf_unreachable(); | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
title: "Libbpf eBPF macro 'barrier'" | ||
description: "This page documents the 'barrier' libbpf eBPF macro, including its definition, usage, and examples." | ||
--- | ||
# Libbpf eBPF macro `barrier` | ||
|
||
[:octicons-tag-24: v0.8.0](https://github.com/libbpf/libbpf/releases/tag/v0.8.0) | ||
|
||
The `barrier` macro is used to prevent the compiler from reordering memory operations. | ||
|
||
## Definition | ||
|
||
`#!c #define barrier() asm volatile("" ::: "memory")` | ||
|
||
## Usage | ||
|
||
This macro inserts what is referred to as a "full memory barrier". Compilers such as GCC and Clang will sometimes reorder memory operations to optimize code, so your actual program may not execute in the order you wrote it. If the order of memory operations is important, you can use the `barrier` macro to tell the compiler to not reorder memory operations across the barrier. | ||
|
||
This is a very specialized tool which you will likely not use often. | ||
|
||
### Example | ||
|
||
!!! example "Docs could be improved" | ||
This part of the docs is incomplete, contributions are very welcome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
--- | ||
title: "Libbpf eBPF macro 'barrier_var'" | ||
description: "This page documents the 'barrier_var' libbpf eBPF macro, including its definition, usage, and examples." | ||
--- | ||
# Libbpf eBPF macro `barrier_var` | ||
|
||
[:octicons-tag-24: v0.8.0](https://github.com/libbpf/libbpf/releases/tag/v0.8.0) | ||
|
||
The `barrier_var` macro is used to prevent the compiler from reordering memory operations for a specific variable. | ||
|
||
## Definition | ||
|
||
`#!c #define barrier_var(var) asm volatile("" : "+r"(var))` | ||
|
||
## Usage | ||
|
||
This macro is a variable-specific compiler (optimization) barrier. It's a no-op which makes compiler believe that there is some black box modification of a given variable and thus prevents compiler from making extra assumption about its value and potential simplifications and optimizations on this variable. | ||
|
||
E.g., compiler might often delay or even omit 32-bit to 64-bit casting of a variable, making some code patterns unverifiable. Putting barrier_var() in place will ensure that cast is performed before the barrier_var() invocation, because compiler has to pessimistically assume that embedded <nospell>asm</nospell> section might perform some extra operations on that variable. | ||
|
||
This is a variable-specific variant of more global [`barrier()`](barrier.md). | ||
|
||
### Example | ||
|
||
!!! example "Docs could be improved" | ||
This part of the docs is incomplete, contributions are very welcome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
--- | ||
title: "Libbpf eBPF macro 'bpf_ksym_exists'" | ||
description: "This page documents the 'bpf_ksym_exists' libbpf eBPF macro, including its definition, usage, and examples." | ||
--- | ||
# Libbpf eBPF macro `bpf_ksym_exists` | ||
|
||
[:octicons-tag-24: v0.2](https://github.com/libbpf/libbpf/releases/tag/v0.2) | ||
|
||
The `bpf_ksym_exists` macro is used to check if a [`__weak`](__weak.md) symbol has been defined. | ||
|
||
## Definition | ||
|
||
```c | ||
#define bpf_ksym_exists(sym) ({ \ | ||
_Static_assert(!__builtin_constant_p(!!sym), #sym " should be marked as __weak"); \ | ||
!!sym; \ | ||
}) | ||
``` | ||
## Usage | ||
This macro is used to check if a weak symbol has been defined. If the symbol is defined, it is better practice to use this macro to check instead of doing a `== 0` check. This is because this macro includes a static assertion to see if the symbol is marked as weak, this can avoid unintended bugs. | ||
### Example | ||
```c hl_lines="6" | ||
extern int bpf_dynptr_from_xdp(struct xdp_md *x, u64 flags, struct bpf_dynptr *ptr__uninit) __weak __ksym; | ||
SEC("xdp.frags") | ||
int example_prog(struct xdp_md *ctx) | ||
{ | ||
if (bpf_ksym_exists(bpf_dynptr_from_xdp)) { | ||
struct bpf_dynptr ptr; | ||
if (bpf_dynptr_from_xdp(ctx, 0, &ptr) < 0) | ||
return XDP_DROP; | ||
__u8 buf[sizeof(struct ethhdr)]; | ||
struct ethhdr *eth = bpf_dynptr_slice(&ptr, buf, sizeof(buf)); | ||
if (!eth) | ||
return XDP_DROP; | ||
if (eth->h_proto == htons(ETH_P_IP)) | ||
return XDP_PASS; | ||
} else { | ||
void *data_end = (void *)(long)ctx->data_end; | ||
void *data = (void *)(long)ctx->data; | ||
if (data + sizeof(struct ethhdr) > data_end) | ||
return XDP_DROP; | ||
struct ethhdr *eth = data; | ||
if (eth->h_proto == htons(ETH_P_IP)) | ||
return XDP_PASS; | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
--- | ||
title: "Libbpf eBPF function 'bpf_tail_call_static'" | ||
description: "This page documents the 'bpf_tail_call_static' libbpf eBPF function, including its definition, usage, and examples." | ||
--- | ||
# Libbpf eBPF function `bpf_tail_call_static` | ||
|
||
[:octicons-tag-24: v0.2](https://github.com/libbpf/libbpf/releases/tag/v0.2) | ||
|
||
The `bpf_tail_call_static` function is used to make an optimized tail call to another eBPF program, but only if the index into the [program array map](../../../linux/map-type/BPF_MAP_TYPE_PROG_ARRAY.md) is a constant. | ||
|
||
## Definition | ||
|
||
```c | ||
static __always_inline void | ||
bpf_tail_call_static(void *ctx, const void *map, const __u32 slot) | ||
{ | ||
if (!__builtin_constant_p(slot)) | ||
__bpf_unreachable(); | ||
|
||
asm volatile("r1 = %[ctx]\n\t" | ||
"r2 = %[map]\n\t" | ||
"r3 = %[slot]\n\t" | ||
"call 12" | ||
:: [ctx]"r"(ctx), [map]"r"(map), [slot]"i"(slot) | ||
: "r0", "r1", "r2", "r3", "r4", "r5"); | ||
} | ||
``` | ||
## Usage | ||
This function emits BPF instructions in a very particular way. It emits a call to the [`bpf_tail_call`](../../../linux/helper-function/bpf_tail_call.md) helper. In addition it makes sure that the parameter registers R1, R2, and R3 are set in the instructions right before the call and that R3 is a constant value. A normal call to `bpf_tail_call` gives the compiler the liberty to move where the parameters are set, which can lead to the verifier not being able to detect that the index is a constant. | ||
The reason why we want the verifier to detect the slot is constant is because the verifier can optimize the the tail call can be a simple jump instead of a retpoline in that specific case. | ||
Retpolines are a security feature that mitigates speculative execution attacks, but also make execution slow. So we gain a performance benefit by using this function. | ||
### Example | ||
```c | ||
#define TAIL_CALL_ZERO 0 | ||
#define TAIL_CALL_ONE 1 | ||
struct { | ||
__uint(type, BPF_MAP_TYPE_PROG_ARRAY); | ||
__uint(max_entries, 2); | ||
__uint(key_size, sizeof(__u32)); | ||
__array(values, int (void *)); | ||
} prog_array_map SEC(".maps") = { | ||
.values = { | ||
[TAIL_CALL_ZERO] = (void *)&tailcall_0, | ||
[TAIL_CALL_ONE] = (void *)&tailcall_1, | ||
}, | ||
}; | ||
SEC("xdp") | ||
int tailcall_0(struct xdp_md *ctx) | ||
{ | ||
return XDP_PASS; | ||
} | ||
SEC("xdp") | ||
int tailcall_1(struct xdp_md *ctx) | ||
{ | ||
return XDP_DROP; | ||
} | ||
SEC("xdp") | ||
int xdp_prog(struct xdp_md *ctx) | ||
{ | ||
void *data_end = (void *)(long)ctx->data_end; | ||
void *data = (void *)(long)ctx->data; | ||
if (data + sizeof(struct ethhdr) > data_end) | ||
return bpf_tail_call_static(skb, &prog_array_map, TAIL_CALL_ONE); | ||
return bpf_tail_call_static(skb, &prog_array_map, TAIL_CALL_ZERO); | ||
} | ||
``` |
Oops, something went wrong.