Skip to content

Commit

Permalink
libbpf/ebpf: Add pages for print helpers
Browse files Browse the repository at this point in the history
This commit adds pages for the print helpers currntly available in the
libbpf ebpf side library.

Signed-off-by: Dylan Reimerink <[email protected]>
  • Loading branch information
dylandreimerink committed Nov 18, 2024
1 parent f738cba commit 985a8c5
Show file tree
Hide file tree
Showing 5 changed files with 249 additions and 3 deletions.
4 changes: 4 additions & 0 deletions docs/ebpf-library/libbpf/ebpf/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,7 @@
- [`__bpf_unreachable`](__bpf_unreachable.md)
- [`bpf_tail_call_static`](bpf_tail_call_static.md)
- [`bpf_ksym_exists`](bpf_ksym_exists.md)
- <nospell>Printf macros</nospell>
- [`BPF_SEQ_PRINTF`](bpf_seq_printf.md)
- [`BPF_SNPRINTF`](bpf_snprintf.md)
- [`bpf_printk`](bpf_printk.md)
101 changes: 101 additions & 0 deletions docs/ebpf-library/libbpf/ebpf/bpf_printk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: "Libbpf eBPF macro 'bpf_printk'"
description: "This page documents the 'bpf_printk' libbpf eBPF macro, including its definition, usage, and examples."
---
# Libbpf eBPF macro `bpf_printk`

[:octicons-tag-24: v0.0.6](https://github.com/libbpf/libbpf/releases/tag/v0.0.6)

The `bpf_printk` macro is used to make printing to the kernel trace log easier.

## Definition

The short version (left out the implementation)
```c
/* Helper macro to print out debug messages */
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
```
??? example "The full version"
```c
#ifdef BPF_NO_GLOBAL_DATA
#define BPF_PRINTK_FMT_MOD
#else
#define BPF_PRINTK_FMT_MOD static const
#endif
#define __bpf_printk(fmt, ...) \
({ \
BPF_PRINTK_FMT_MOD char ____fmt[] = fmt; \
bpf_trace_printk(____fmt, sizeof(____fmt), \
##__VA_ARGS__); \
})
/*
* __bpf_vprintk wraps the bpf_trace_vprintk helper with variadic arguments
* instead of an array of u64.
*/
#define __bpf_vprintk(fmt, args...) \
({ \
static const char ___fmt[] = fmt; \
unsigned long long ___param[___bpf_narg(args)]; \
\
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
___bpf_fill(___param, args); \
_Pragma("GCC diagnostic pop") \
\
bpf_trace_vprintk(___fmt, sizeof(___fmt), \
___param, sizeof(___param)); \
})
/* Use __bpf_printk when bpf_printk call has 3 or fewer fmt args
* Otherwise use __bpf_vprintk
*/
#define ___bpf_pick_printk(...) \
___bpf_nth(_, ##__VA_ARGS__, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
__bpf_vprintk, __bpf_vprintk, __bpf_vprintk, __bpf_vprintk, \
__bpf_vprintk, __bpf_vprintk, __bpf_printk /*3*/, __bpf_printk /*2*/,\
__bpf_printk /*1*/, __bpf_printk /*0*/)
/* Helper macro to print out debug messages */
#define bpf_printk(fmt, args...) ___bpf_pick_printk(args)(fmt, ##args)
```
## Usage
This is a macro makes writing to the kernel trace log easier. It does two things, the first is it picks between the [`bpf_trace_printk`](../../../linux/helper-function/bpf_trace_printk.md) and [`bpf_trace_vprintk`](../../../linux/helper-function/bpf_trace_vprintk.md) helper functions. The [`bpf_trace_printk`](../../../linux/helper-function/bpf_trace_printk.md) helper only supports up to 3 arguments besides the format string, but [`bpf_trace_vprintk`](../../../linux/helper-function/bpf_trace_vprintk.md) supports any number of arguments (the macro supports up to 12 arguments).
!!! note
While the [`bpf_trace_printk`](../../../linux/helper-function/bpf_trace_printk.md) helper is supported on most kernels, the [`bpf_trace_vprintk`](../../../linux/helper-function/bpf_trace_vprintk.md) helper is only supported on kernel versions [:octicons-tag-24: v5.16](https://github.com/torvalds/linux/commit/10aceb629e198429c849d5e995c3bb1ba7a9aaa3) and later.
So using this macro with more than 3 arguments on older kernels might cause the verifier to reject your program.
The second thing it does is it turns the literal format string into a `char` array. If `BPF_NO_GLOBAL_DATA` is defined the char array will live on the stack, otherwise it will be turned into a global variable (this only works up to 4 arguments, the [`bpf_trace_vprintk`](../../../linux/helper-function/bpf_trace_vprintk.md) variant always make the format string into a global variable). Without this `char` array the compiler will place strings in a dedicated string ELF section unrecognized by loaders and not emit the proper global variable relocations.
### Example
```c
SEC("tc")
int example_prog(struct __sk_buff *ctx)
{
// Will use bpf_trace_printk
bpf_printk(
"Got a packet from interface %d, src: %pi4, dst: %pi4\\n",
ctx->ingress_ifindex,
ctx->remote_ip4,
ctx->local_ip4,
);
// Will use bpf_trace_vprintk
bpf_printk(
"Got a packet from interface %d, src: %pi4, dst: %pi4, src port: %d, dst port: %d\\n",
ctx->ingress_ifindex,
ctx->remote_ip4,
ctx->local_ip4,
ctx->remote_port,
ctx->local_port,
);
return TC_ACT_OK;
}
```
70 changes: 70 additions & 0 deletions docs/ebpf-library/libbpf/ebpf/bpf_seq_printf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
title: "Libbpf eBPF macro 'BPF_SEQ_PRINTF'"
description: "This page documents the 'BPF_SEQ_PRINTF' libbpf eBPF macro, including its definition, usage, and examples."
---
# Libbpf eBPF macro `BPF_SEQ_PRINTF`

[:octicons-tag-24: v0.0.9](https://github.com/libbpf/libbpf/releases/tag/v0.0.9)

!!! note
This macro was moved from `bpf_tracing.h` to `bpf_helpers.h` in [:octicons-tag-24: v0.5.0](https://github.com/libbpf/libbpf/releases/tag/v0.5.0)

The `BPF_SEQ_PRINTF` macro is used to make printing to bpf iterator sequence files easier.

## Definition

```c
/*
* BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values
* in a structure.
*/
#define BPF_SEQ_PRINTF(seq, fmt, args...) \
({ \
static const char ___fmt[] = fmt; \
unsigned long long ___param[___bpf_narg(args)]; \
\
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
___bpf_fill(___param, args); \
_Pragma("GCC diagnostic pop") \
\
bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \
___param, sizeof(___param)); \
})
```

## Usage

This macro is a wrapper around the [`bpf_seq_printf`](../../../linux/helper-function/bpf_seq_printf.md) helper. It places the literal format string in a global variable, this is necessary to get the compiler to emit code that will be accepted by the verifier.

### Example
```c hl_lines="14 25 26"
SEC("iter/task_file")
int dump_task_file(struct bpf_iter__task_file *ctx)
{
struct seq_file *seq = ctx->meta->seq;
struct task_struct *task = ctx->task;
struct file *file = ctx->file;
__u32 fd = ctx->fd;

if (task == NULL || file == NULL)
return 0;

if (ctx->meta->seq_num == 0) {
count = 0;
BPF_SEQ_PRINTF(seq, " tgid gid fd file\n");
}

if (tgid == task->tgid && task->tgid != task->pid)
count++;

if (last_tgid != task->tgid) {
last_tgid = task->tgid;
unique_tgid_count++;
}

BPF_SEQ_PRINTF(seq, "%8d %8d %8d %lx\n", task->tgid, task->pid, fd,
(long)file->f_op);
return 0;
}
```
71 changes: 71 additions & 0 deletions docs/ebpf-library/libbpf/ebpf/bpf_snprintf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: "Libbpf eBPF macro 'BPF_SNPRINTF'"
description: "This page documents the 'BPF_SNPRINTF' libbpf eBPF macro, including its definition, usage, and examples."
---
# Libbpf eBPF macro `BPF_SNPRINTF`

[:octicons-tag-24: v0.4.0](https://github.com/libbpf/libbpf/releases/tag/v0.4.0)

!!! note
This macro was moved from `bpf_tracing.h` to `bpf_helpers.h` in [:octicons-tag-24: v0.5.0](https://github.com/libbpf/libbpf/releases/tag/v0.5.0)

The `BPF_SNPRINTF` macro is used to make in-BPF string formatting easier.

## Definition

```c
/*
* BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of
* an array of u64.
*/
#define BPF_SNPRINTF(out, out_size, fmt, args...) \
({ \
static const char ___fmt[] = fmt; \
unsigned long long ___param[___bpf_narg(args)]; \
\
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \
___bpf_fill(___param, args); \
_Pragma("GCC diagnostic pop") \
\
bpf_snprintf(out, out_size, ___fmt, \
___param, sizeof(___param)); \
})
```

## Usage

This macro is a wrapper around the [`bpf_snprintf`](../../../linux/helper-function/bpf_snprintf.md) helper. It places the literal format string in a global variable, this is necessary to get the compiler to emit code that will be accepted by the verifier.

### Example
```c hl_lines="17"
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 4096);
} ringbuf SEC(".maps");

SEC("tc")
int example_prog(struct __sk_buff *ctx)
{
const int size = 100;
char *str_out = bpf_ringbuf_reserve(&ringbuf, size, 0);
if (!str_out)
return TC_ACT_OK;

// `len` is the length of the formatted string including NULL-termination char.
// if `len` > `size` then the string was truncated.
// `len` can also be -EBUSY if the per-CPU memory copy buffer is busy.
long len = BPF_SNPRINTF(str_out, size,
"Got a packet from interface %d, src: %pi4, dst: %pi4, src port: %d, dst port: %d\\n",
ctx->ingress_ifindex,
ctx->remote_ip4,
ctx->local_ip4,
ctx->remote_port,
ctx->local_port
);

bpf_ringbuf_submit(str_out, 0);

return TC_ACT_OK;
}
```
6 changes: 3 additions & 3 deletions docs/ebpf-library/libbpf/ebpf/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ The file contains definitions for the following:
* [`bpf_tail_call_static`](bpf_tail_call_static.md)
* [`bpf_ksym_exists`](bpf_ksym_exists.md)
* <nospell>Printf macros</nospell>
* `BPF_SEQ_PRINTF`
* `BPF_SNPRINTF`
* `bpf_printk`
* [`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`
Expand Down

0 comments on commit 985a8c5

Please sign in to comment.