From 31752fb5e744614ea7cc1d352b9878949962bac3 Mon Sep 17 00:00:00 2001 From: Dylan Reimerink Date: Sat, 23 Nov 2024 16:00:20 +0100 Subject: [PATCH] libbpf/ebpf: Added pages for open coded iterator macros This commit adds pages for the open coded iterator macros that are available in the libbpf ebpf library. Signed-off-by: Dylan Reimerink --- docs/ebpf-library/libbpf/ebpf/SUMMARY.md | 4 + docs/ebpf-library/libbpf/ebpf/bpf_for.md | 55 +++++++++++++ docs/ebpf-library/libbpf/ebpf/bpf_for_each.md | 78 +++++++++++++++++++ docs/ebpf-library/libbpf/ebpf/bpf_repeat.md | 44 +++++++++++ docs/ebpf-library/libbpf/ebpf/index.md | 6 +- 5 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 docs/ebpf-library/libbpf/ebpf/bpf_for.md create mode 100644 docs/ebpf-library/libbpf/ebpf/bpf_for_each.md create mode 100644 docs/ebpf-library/libbpf/ebpf/bpf_repeat.md diff --git a/docs/ebpf-library/libbpf/ebpf/SUMMARY.md b/docs/ebpf-library/libbpf/ebpf/SUMMARY.md index 2a70ab4..f2c4e89 100644 --- a/docs/ebpf-library/libbpf/ebpf/SUMMARY.md +++ b/docs/ebpf-library/libbpf/ebpf/SUMMARY.md @@ -34,3 +34,7 @@ - [`BPF_SEQ_PRINTF`](bpf_seq_printf.md) - [`BPF_SNPRINTF`](bpf_snprintf.md) - [`bpf_printk`](bpf_printk.md) +- Open coded iterator loop macros + - [`bpf_for_each`](bpf_for_each.md) + - [`bpf_for`](bpf_for.md) + - [`bpf_repeat`](bpf_repeat.md) diff --git a/docs/ebpf-library/libbpf/ebpf/bpf_for.md b/docs/ebpf-library/libbpf/ebpf/bpf_for.md new file mode 100644 index 0000000..87a29a8 --- /dev/null +++ b/docs/ebpf-library/libbpf/ebpf/bpf_for.md @@ -0,0 +1,55 @@ +--- +title: "Libbpf eBPF macro 'bpf_for'" +description: "This page documents the 'bpf_for' libbpf eBPF macro, including its definition, usage, and examples." +--- +# Libbpf eBPF macro `bpf_for` + +[:octicons-tag-24: v1.2.0](https://github.com/libbpf/libbpf/releases/tag/v1.2.0) + +The `bpf_for` macro is used to make writing a for loop with an open coded iterator easier. + +## Definition + +```c +#define bpf_for(i, start, end) for ( \ + /* initialize and define destructor */ \ + struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \ + cleanup(bpf_iter_num_destroy))), \ + /* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \ + *___p __attribute__((unused)) = ( \ + bpf_iter_num_new(&___it, (start), (end)), \ + /* this is a workaround for Clang bug: it currently doesn't emit BTF */ \ + /* for bpf_iter_num_destroy() when used from cleanup() attribute */ \ + (void)bpf_iter_num_destroy, (void *)0); \ + ({ \ + /* iteration step */ \ + int *___t = bpf_iter_num_next(&___it); \ + /* termination and bounds check */ \ + (___t && ((i) = *___t, (i) >= (start) && (i) < (end))); \ + }); \ +) +``` + +## Usage + +This macro makes writing a for loop with an open coded iterator easier. `bpf_for` specifically uses the numeric open coded iterator, which instead of looping over kernel structures loops over a range of numbers. +The `bpf_for` macro is a neat shorthand for manually writing the iteration logic. + +The reason you might want to use this instead of a traditional `for` loop is to get a large loop count without making the verifier upset. Using the open code numeric iterator allows for a large number of iterations without inflating complexity and while keeping the current scope. For details see the [loops concept](../../../linux/concepts/loops.md) page. + +### Example + +```c +SEC("raw_tp/sys_enter") +int iter_next_rcu(const void *ctx) +{ + int v; + + // Will print 2, 3, 4, 5 + bpf_for(v, 2, 5) { + bpf_printk("X = %d", v); + } + + return 0; +} +``` diff --git a/docs/ebpf-library/libbpf/ebpf/bpf_for_each.md b/docs/ebpf-library/libbpf/ebpf/bpf_for_each.md new file mode 100644 index 0000000..55dd2b5 --- /dev/null +++ b/docs/ebpf-library/libbpf/ebpf/bpf_for_each.md @@ -0,0 +1,78 @@ +--- +title: "Libbpf eBPF macro 'bpf_for_each'" +description: "This page documents the 'bpf_for_each' libbpf eBPF macro, including its definition, usage, and examples." +--- +# Libbpf eBPF macro `bpf_for_each` + +[:octicons-tag-24: v1.2.0](https://github.com/libbpf/libbpf/releases/tag/v1.2.0) + +The `bpf_for_each` macro is used to make looping over open-coded iterators easier. + +## Definition + +```c +#define bpf_for_each(type, cur, args...) for ( \ + /* initialize and define destructor */ \ + struct bpf_iter_##type ___it __attribute__((aligned(8), /* enforce, just in case */, \ + cleanup(bpf_iter_##type##_destroy))), \ + /* ___p pointer is just to call bpf_iter_##type##_new() *once* to init ___it */ \ + *___p __attribute__((unused)) = ( \ + bpf_iter_##type##_new(&___it, ##args), \ + /* this is a workaround for Clang bug: it currently doesn't emit BTF */ \ + /* for bpf_iter_##type##_destroy() when used from cleanup() attribute */ \ + (void)bpf_iter_##type##_destroy, (void *)0); \ + /* iteration and termination check */ \ + (((cur) = bpf_iter_##type##_next(&___it))); \ +) +``` + +## Usage + +This macro makes looping over open coded iterators easier. Open coded iterators were introduced in kernel [:octicons-tag-24: v6.4](https://github.com/torvalds/linux/commit/06accc8779c1d558a5b5a21f2ac82b0c95827ddd) and allow for iterating/looping over specific kernel data structures. + +Normally, you would have to write iteration logic manually like: +```c +SEC("raw_tp/sys_enter") +int my_example(const void *ctx) +{ + struct bpf_iter_task task_it; + struct task_struct *task_ptr; + + // Initialize the iterator, request to iterate over all processes on the system + bpf_iter_task_new(&task_it, NULL, BPF_TASK_ITER_ALL_PROCS); + + // Loop until `bpf_iter_task_next` returns NULL + while((task_ptr = bpf_iter_task_next(&task_it))) { + // Do something with the task pointer + + if (/* We found the task we are looking for*/) + break; + } + + bpf_iter_task_destroy(&task_it); + return 0; +} +``` + +There are a few different iterator types, all follow the same naming convention: `bpf_iter__{new,next,destroy}`. The `bpf_for_each` macro makes use of this to simplify the iteration logic the user has to write. + +The first argument is the `` part of the iterator functions. The second argument is the variable name that will be used to store the current iterator value. And the rest of the arguments are passed to the `bpf_iter__new` function, the exact meaning depends on the iterator type. + +### Example + +```c +SEC("raw_tp/sys_enter") +int my_example(const void *ctx) +{ + struct task_struct *task_ptr; + bpf_for_each(task, task_ptr, NULL, BPF_TASK_ITER_ALL_PROCS) { + // Do something with the task pointer + + if (/* We found the task we are looking for*/) + break; + } + + return 0; +} +``` + diff --git a/docs/ebpf-library/libbpf/ebpf/bpf_repeat.md b/docs/ebpf-library/libbpf/ebpf/bpf_repeat.md new file mode 100644 index 0000000..f647566 --- /dev/null +++ b/docs/ebpf-library/libbpf/ebpf/bpf_repeat.md @@ -0,0 +1,44 @@ +--- +title: "Libbpf eBPF macro 'bpf_repeat'" +description: "This page documents the 'bpf_repeat' libbpf eBPF macro, including its definition, usage, and examples." +--- +# Libbpf eBPF macro `bpf_repeat` + +[:octicons-tag-24: v1.2.0](https://github.com/libbpf/libbpf/releases/tag/v1.2.0) + +The `bpf_repeat` macro is used it easier to write a loop that repeats X times using open coded iterators. + +## Definition + +```c +#define bpf_repeat(N) for ( \ + /* initialize and define destructor */ \ + struct bpf_iter_num ___it __attribute__((aligned(8), /* enforce, just in case */ \ + cleanup(bpf_iter_num_destroy))), \ + /* ___p pointer is necessary to call bpf_iter_num_new() *once* to init ___it */ \ + *___p __attribute__((unused)) = ( \ + bpf_iter_num_new(&___it, 0, (N)), \ + /* this is a workaround for Clang bug: it currently doesn't emit BTF */ \ + /* for bpf_iter_num_destroy() when used from cleanup() attribute */ \ + (void)bpf_iter_num_destroy, (void *)0); \ + bpf_iter_num_next(&___it); \ + /* nothing here */ \ +) +``` + +## Usage + +This macro makes writing a loop that repeats X times using open coded iterators easier. `bpf_repeat` is a simplified version of the [`bpf_for`](bpf_for.md) macro, which simply executes the loop body `N` times and does not make the iteration count available. + +### Example + +```c +SEC("raw_tp/sys_enter") +int iter_next_rcu(const void *ctx) +{ + bpf_repeat(64) { + if (try_to_do_something()) + break; + } +} +``` diff --git a/docs/ebpf-library/libbpf/ebpf/index.md b/docs/ebpf-library/libbpf/ebpf/index.md index d71c15e..b56f934 100644 --- a/docs/ebpf-library/libbpf/ebpf/index.md +++ b/docs/ebpf-library/libbpf/ebpf/index.md @@ -62,9 +62,9 @@ The file contains definitions for the following: * [`BPF_SNPRINTF`](bpf_snprintf.md) * [`bpf_printk`](bpf_printk.md) * Open coded iterator loop macros - * `bpf_for_each` - * `bpf_for` - * `bpf_repeat` + * [`bpf_for_each`](bpf_for_each.md) + * [`bpf_for`](bpf_for.md) + * [`bpf_repeat`](bpf_repeat.md) ## [`bpf_endian.h`](https://github.com/libbpf/libbpf/blob/master/src/bpf_endian.h)