Programs generation#

Error handling#

bf_jmpctx is a helper structure to manage jump instructions in the program. It is used to emit a jump instruction and automatically clean it up when the scope is exited, thanks to GCC’s cleanup attribute.

Example:

// Within a function body
{
    _cleanup_bf_jmpctx_ struct bf_jmpctx ctx =
        bf_jmpctx_get(program, BPF_JMP_IMM(BPF_JEQ, BF_REG_2, 0, 0));

    EMIT(program,
        BPF_MOV64_IMM(BF_REG_RET, program->runtime.ops->get_verdict(
            BF_VERDICT_ACCEPT)));
    EMIT(program, BPF_EXIT_INSN());
}
ctx is a variable local to the scope, marked with _cleanup_bf_jmpctx_ . The second argument to bf_jmpctx_get is the jump instruction to emit, with the correct condition. When the scope is exited, the jump instruction is automatically updated to point to the current instruction, which is after the scope.

Hence, all the instructions emitted within the scope will be executed if the condition is not met. If the condition is met, then the program execution will continue with the first instruction after the scope.

Defines

_cleanup_bf_jmpctx_#

Cleanup attribute for a bf_jmpctx variable.

bf_jmpctx_get(program, insn)#

Create a new bf_jmpctx variable.

Parameters:
  • program – The program to emit the jump instruction to. It must be non-NULL.

  • insn – The jump instruction to emit.

Returns:

A new bf_jmpctx variable.

Functions

void bf_jmpctx_cleanup(struct bf_jmpctx *ctx)#

Cleanup function for bf_jmpctx.

Parameters:
  • ctx – The bf_jmpctx variable to clean up.

struct bf_jmpctx#

Public Members

struct bf_program *program#

A helper structure to manage jump instructions in the program.

The program to emit the jump instruction to.

size_t insn_idx#

The index of the jump instruction in the program’s image.

Printing debug messages#

The bf_print_* functions relates to the message printing facilities provided to the generated BPF programs. bpfilter provides a set of predefined messages that can be printed from the BPF programs.

During bpfilter initialization, the predefined messages are concatenated into a unique buffer or nul-separated strings. The offset of each message is saved in bpfilter runtime context for later use. The resulting strings buffer is then stored in a BPF map.

All the log messages defined in bpfilter prefixed with "$IFINDEX:$HOOK:$FRONT: ", so log messages can be mapped back to a specific BPF program.

The file descriptor to the loaded BPF map is stored within bpfilter runtime context. It is not pinned and will be closed when bpfilter is stopped. If any BPF program refers to the map, the kernel will keep it until the last BPF program using it is unloaded. This behaviour is compatible with bpfilter transient mode:

  • If --transient is used, bpfilter will create the map at startup, create zero or more BPF programs using it. When bpfilter is stopped, the map’s file descriptor will be closed and all the BPF programs created by bpfilter will be unloaded. The map will be removed from the system.

  • If --transient is not used, bpfilter will create the map at startup, create zero or more BPF programs using it. When bpfilter is stopped, the map’s file descriptor will be closed. The map will remain on the system if any BPF program refers to it. On the next start, bpfilter will create a new map and use it for new BPF programs, while existing BPF program still refer to the old map. This mechanism prevents conflict if bpfilter is updated and restarted: existing programs use the old map, new programs use the new map.

Note

All the message strings are stored in a single BPF map entry in order to benefit from BPF_PSEUDO_MAP_VALUE which allows lookup free direct value access for maps. Hence, using a unique instruction, bpfilter can load the map’s file descriptor and get the address of a message in the buffer. See https://lore.kernel.org/bpf/20190409210910.32048-2-daniel@iogearbox.net.

Defines

EMIT_PRINT(program, msg_id)#

Emit BPF instructions to print a predefined message.

This function will insert mulitple instruction into the BPF program to: load the messages map’s file descriptor, copy into the argument registers: the message’s length, the program’s ifindex, hook and front. Then it will call bpf_trace_printk() to print the message.

Warning

As every EMIT_* macro, EMIT_PRINT() will call return if an error occurs. Hence, it must be used within a function that returns an integer.

Parameters:
  • program – Program to emit the instructions to. Must not be NULL.

  • msg_id – Identifier of the message to print. See bf_print_msg for the list of predefined messages.

Enums

enum bf_print_msg#

Identifiers of the predefined printable messages.

Values:

enumerator BF_PRINT_NO_DYNPTR#
enumerator BF_PRINT_NO_SLICE#
enumerator BF_PRINT_NO_L2#
enumerator BF_PRINT_NO_L3#
enumerator BF_PRINT_NO_IPV4#
enumerator _BF_PRINT_MAX#

Functions

int bf_print_setup(void)#

Setup context to allow generated BPF programs to print messages.

The various printable messages are stored in an array of strings, this function will concatenate them into a unique nul-separated buffer of string and store it in a BPF map.

Returns:

0 on success, or negative errno value on error.

void bf_print_teardown(void)#

Teardown the printing context.

The file descriptor of the BPF map containing the printable messages will be closed. The map will remain on the system until the last BPF program using it is unloaded.

int bf_print_fd(void)#

Get the file descriptor of the BPF map containing the printable messages.

Returns:

File descriptor of the BPF map containing the printable messages.

size_t bf_print_msg_size(enum bf_print_msg msg_id)#

Get the size of a printable message.

Parameters:
  • msg_id – ID of the message to get the size of.

Returns:

Size of the message.

size_t bf_print_msg_offset(enum bf_print_msg msg_id)#

Get the offset of a printable message in the BPF map.

Parameters:
  • msg_id – ID of the message to get the offset of.

Returns:

Offset of the message in the BPF map.