API reference#

struct bf_codegen#

Codegen are used to represent filtering rules to be applied for a given front, at a given location in the network stack. It contains a list of programs, which are BPF program aimed to be attached to a given interface. Hence, not all rules have to target all interfaces.

Public Members

enum bf_hook hook#

Hook to attach the programs to.

enum bf_front front#

Source of the filtering rules.

enum bf_verdict policy#

Codegen policy: verdict to be applied by default by the codegen, unless one of the rules matches the packet.

bf_list rules#

List of rules defined by the front, to be attached at hook.

bf_list programs#

List of generated BPF programs for this codegen. One program per interface should be expected, except for the loopback interface.

struct bf_context#

bpfilter working context. Only one context is used during the daemon’s lifetime.

Public Members

struct bf_codegen *codegens[_BF_HOOK_MAX][_BF_FRONT_MAX]#

Codegens used by bpfilter. One codegen per (hook, front) set.

struct bf_counter#

Counters assigne to each rule.

Public Members

uint64_t packets#

Number of packets gone through a rule.

uint64_t bytes#

Number of bytes gone through a rule.

struct bf_fixup#

Public Members

enum bf_fixup_type type#
size_t insn#
size_t offset#
enum bf_fixup_function function#
union bf_fixup
union bf_fixup_attr#

Attributes to use when processing the fixups.

Public Members

int map_fd#
struct bf_fixup_attr
union bf_flavor_attach_attr#

Extra attribute to share between call during 2-steps attach.

Public Members

File descriptor of the link created before the existing program has been detached.

struct bf_flavor_ops#

Define a set of operations that can be performed for a specific BPF flavor.

Public Members

int (*gen_inline_prologue)(struct bf_program *program)#

Generate the flavor-specific prologue of the BPF program.

This function can assume BF_ARG_1 contains the first argument passed to the program, and BF_REG_CTX is properly set, pointing to an initialised context.

The purpose of this callback is to:

  • Ensure ctx.dynptr is a valid BPF dynptr to the packet data.

  • ctx.pkt_size contains the packet size.

  • BPF dynptr slices to layer 2, 3, and 4 (if relevant) are stored within the context, and BF_REG_L{2, 3, 4} are updated to contain the address of the relevant header.

int (*gen_inline_epilogue)(struct bf_program *program)#

Generate the epilogue of the BPF program.

int (*get_verdict)(enum bf_verdict verdict)#
int (*attach_prog_pre_unload)(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#

Attach a loaded BPF program to the kernel, before unloading the out-of-date program.

There are two callbacks used to attach a program for a given flavor, which are used to ensure the new program is attached before the existing program (attached to the same hook) is detached. attach_prog_pre_unload is called before the existing program is detached and unloaded, attach_prog_post_unload is called once the existing program has been detached from the kernel and unloaded.

This 2-steps process is mandatory for specific flavor (e.g. netfilter), as we want to avoid downtime, while ensuring a given program (for a specific hook and interface) will always use the same priority.

Param program:

Program to attach.

Param prog_fd:

File descriptor of the loaded program.

Param attr:

Extra attribute to share between call during 2-steps attach.

Return:

0 on success, negative ernno code on failure.

int (*attach_prog_post_unload)(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#

Attach a loaded BPF program to the kernel, after the out-of-date program has been detached.

See attach_prog_pre_unload for details.

Param program:

Program to attach.

Param prog_fd:

File descriptor of the loaded program.

Param attr:

Extra attribute to share between call during 2-steps attach.

Return:

0 on success, negative ernno code on failure.

int (*detach_prog)(struct bf_program *program)#
struct bf_front_ops#

Public Members

int (*setup)(void)#

struct bf_front_ops

Todo:

Make bf_front_ops.request_handler take a const struct bf_request.

Setup the front.

int (*teardown)(void)#

Teardown the front.

int (*request_handler)(struct bf_request *request, struct bf_response **response)#

Handle a request.

int (*marsh)(struct bf_marsh **marsh)#
int (*unmarsh)(struct bf_marsh *marsh)#
struct bf_ipt_cache#

Public Members

unsigned int valid_hooks#
unsigned int hook_entry[NF_INET_NUMHOOKS]#
unsigned int underflow[NF_INET_NUMHOOKS]#
unsigned int num_entries#
unsigned int size#
struct ipt_entry *entries#
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.

struct bf_list#

Base structure for the doubly-linked-list data structure.

Warning

From the user’s perspective, the inside of this structure should not be directly accessed. Directly modifying any of the fields should be considered undefined behavior.

Public Members

size_t len#

Number of elements in the list.

bf_list_node *head#

First element of the list, NULL if the list is empty.

bf_list_node *tail#

Last element of the list, NULL if the list is empty.

bf_list_ops ops#
struct bf_list_node#

Node composing a bf_list.

Warning

From the user’s perspective, the inside of this structure should not be directly accessed. Directly modifying any of the fields should be considered undefined behavior.

Public Members

void *data#

The node’s data.

bf_list_node *prev#

Pointer to the previous node. Can be NULL if node is first.

bf_list_node *next#

Pointer to the next node. Can be NULL if node is last.

struct bf_list_ops#

Operation to manipulate bf_list data.

Public Members

bf_list_ops_free free#

Free the data stored in a node. Should be able to handle NULL data.

struct bf_marsh#

Public Members

size_t data_len#

Marshalled data.

Length of marshalled data. It doesn’t include the length of the header.

char data[]#

Marshalled data.

struct bf_match#

Public Members

struct bf_match_ops *ops#
void *data#
struct bf_match_ops#

Public Members

char name[BF_MATCH_OPS_NAME]#
int (*check)(void)#
int (*generate)(void)#
struct bf_nfgroup#

Public Members

bf_list messages#
struct bf_nfmsg#

Public Members

struct nl_msg *msg#
struct bf_nfnest

Public Members

struct bf_nfmsg *parent
bf_nfattr *attr
struct bf_options#

bpfilter runtime configuration

Public Members

bool transient#

If true, bpfilter won’t load or save its state to the filesystem, and all the loaded BPF programs will be unloaded before shuting down. Hence, as long as bpfilter is running, filtering rules will be applied. When bpfilter is stopped, everything is cleaned up.

unsigned int bpf_log_buf_len_pow#

Size of the log buffer when loading a BPF program, as a power of 2.

uint16_t fronts#

Bit flags for enabled fronts.

bool verbose#

If true, print debug log messages (bf_debug).

struct bf_program#

Public Members

uint32_t ifindex#
enum bf_hook hook#
enum bf_front front#
char prog_name[BPF_OBJ_NAME_LEN]#
char map_name[BPF_OBJ_NAME_LEN]#
char prog_pin_path[PIN_PATH_LEN]#
char map_pin_path[PIN_PATH_LEN]#
size_t num_counters#

Number of counters in the counters map. Not all of them are used by the program, but this value is common for all the programs of a given codegen.

uint32_t functions_location[_BF_CODEGEN_FIXUP_FUNCTION_MAX]#
struct bpf_insn *img#
size_t img_size#
size_t img_cap#
bf_list fixups#
int prog_fd#

File descriptor of the program.

int map_fd#

File descriptor of the counters map.

const struct bf_flavor_ops *ops#

Hook-specific ops to use to generate the program.

struct bf_program runtime#

Runtime data used to interact with the program and cache information. This data is not serialized.

struct bf_program_context#

BPF program runtime context.

This structure is used to map data located in the first frame of the generated BPF program. Address to this structure will be stored in BF_REG_CTX register, and fields can be accessed using the convenience macro BF_PROG_CTX_OFF.

Layer 2, 3, and 4 headers are stored in an anonymous union, accessed through the field named lXraw. The various header structures stored in anonymous union are used to ensure lXraw is big enough to store any supported header.

Warning

A static assertion is defined to ensure this structure is aligned on 8-bytes boundaries. This is required by bf_stub_memclear.

Public Members

void *arg#

Argument passed to the BPF program, it content depends on the BPF program type.

struct bpf_dynptr dynptr#

BPF dynamic pointer representing the packet data. Dynamic pointers are used with every program type.

uint64_t pkt_size#

Total size of the packet.

uint32_t l3_offset#

Offset of the layer 3 header in the packet.

uint32_t l4_offset#

Offset of the layer 4 header in the packet.

uint8_t l4_proto#

Layer 4 protocol. Set when the L3 header is processed. Used to define how many bytes to read when processing the packet.

struct ethhdr _ethhdr#
char l2raw#
union bf_program_context

Layer 2 header.

struct iphdr _iphdr#
char l3raw#
union bf_program_context

Layer 3 header.

struct icmphdr _icmphdr#
struct udphdr _udphdr#
struct tcphdr _tcphdr#
char l4raw#
union bf_program_context

Layer 4 header.

struct bf_rule#

Represents a rule to match against packets.

Public Members

uint32_t index#

Rule’s index. Identifies the rule’s within other rules from the same front.

uint32_t ifindex#
uint8_t invflags#
uint32_t src#
uint32_t dst#
uint32_t src_mask#
uint32_t dst_mask#
uint16_t protocol#
bf_list matches#
bool counters#
enum bf_verdict verdict#
file bpf.c
#include “core/bpf.h
#include <net/if.h>
#include <linux/bpf.h>
#include <linux/netfilter.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#include “core/logger.h
#include “generator/nf.h
#include “opts.h
#include “shared/helper.h”

Defines

_bf_ptr_to_u64(ptr)#

Functions

static int _bpf(enum bpf_cmd cmd, union bpf_attr *attr)#

BPF system call.

Parameters:
  • cmd – BPF command to run.

  • attr – Attributes of the system call.

Returns:

System call return value on success, or negative errno value on failure.

int bf_bpf_prog_load(const char *name, unsigned int prog_type, void *img, size_t img_len, enum bpf_attach_type attach_type, int *fd)#

Load a BPF program.

Parameters:
  • name – Name of the BPF program. Can’t be NULL.

  • prog_type – BPF program type.

  • img – BPF program itself. Can’t be NULL.

  • img_len – Size of the BPF program, as a number of instructions.

  • expected_attach_type – Expected attach type of the BPF program. Use bf_hook_to_attach_type to get the proper attach type. 0 is a valid value.

  • fd – If the call succeed, this parameter will contain the loaded program’s file descriptor.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_create(const char *name, unsigned int type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags, int *fd)#

Create a BPF map.

Parameters:
  • name – Name of the map. Can’t be NULL.

  • type – Map type.

  • key_size – Size of a key.

  • value_size – Size of a value.

  • max_entries – Number of entries in the map.

  • flags – Map creation flags.

  • fd – If the call succeed, this parameter will contain the map’s file descriptor.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_freeze(int fd)#

Freeze a BPF map.

A frozen map can’t be modified from userspace.

Parameters:
  • fd – File descriptor of the map.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_lookup_elem(int fd, const void *key, void *value)#

Get an element from a map.

Parameters:
  • fd – File descriptor of the map to search in.

  • key – Key to get the value for. Can’t be NULL.

  • value – Pointer to the value.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_update_elem(int fd, const void *key, void *value)#

Update (or insert) an element in a map.

Parameters:
  • fd – File descriptor of the map to search in.

  • key – Key to get the value for. Can’t be NULL.

  • value – Pointer to the value.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_obj_pin(const char *path, int fd)#

Pin a BPF object to a given path.

Parameters:
  • path – Path to pin the object to. Can’t be NULL.

  • fd – File descriptor of the map.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_obj_get(const char *path, int *fd)#

Get a BPF object, from a path.

Parameters:
  • path – Path of the BPF object to get. Can’t be NULL.

  • fd – On success, contains a file descriptor to the BPF object.

Returns:

0 on success, or negative errno value on failure.

Create a Netfilter BPF link.

Parameters:
  • prog_fd – File descriptor of the program to attach to the link.

  • hook – Netfilter hook to attach the program to.

  • priority – Priority of the program on the hook.

  • link_fd – Link file descriptor, only valid if the return value of the function is 0.

Returns:

0 on success or negative errno value on failure.

Create a XDP BPF link.

Parameters:
  • prog_fd – File descriptor of the program to attach to the link.

  • ifindex – Interface index to attach the program to.

  • link_fd – Link file descriptor, only valid if the return value of the function is 0.

  • mode – XDP program attach mode. See bf_xdp_attach_mode.

Returns:

0 on success, or negative errno value on failure.

Detach a BPF link using its file descriptor.

Parameters:
  • link_fd – File descriptor of the link to detach. You can get a file descriptor using bf_bpf_obj_get.

Returns:

0 on success or negative errno value on failure.

file bpf.h
#include <linux/if_link.h>
#include <stddef.h>
#include <stdint.h>
#include “core/hook.h

Enums

enum bf_xdp_attach_mode#

Values:

enumerator BF_XDP_MODE_SKB = XDP_FLAGS_SKB_MODE#
enumerator BF_XDP_MODE_DRV = XDP_FLAGS_DRV_MODE#
enumerator BF_XDP_MODE_HW = XDP_FLAGS_HW_MODE#

Functions

int bf_bpf_prog_load(const char *name, unsigned int prog_type, void *img, size_t img_len, enum bpf_attach_type attach_type, int *fd)

Load a BPF program.

Parameters:
  • name – Name of the BPF program. Can’t be NULL.

  • prog_type – BPF program type.

  • img – BPF program itself. Can’t be NULL.

  • img_len – Size of the BPF program, as a number of instructions.

  • expected_attach_type – Expected attach type of the BPF program. Use bf_hook_to_attach_type to get the proper attach type. 0 is a valid value.

  • fd – If the call succeed, this parameter will contain the loaded program’s file descriptor.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_create(const char *name, unsigned int type, size_t key_size, size_t value_size, size_t max_entries, uint32_t flags, int *fd)

Create a BPF map.

Parameters:
  • name – Name of the map. Can’t be NULL.

  • type – Map type.

  • key_size – Size of a key.

  • value_size – Size of a value.

  • max_entries – Number of entries in the map.

  • flags – Map creation flags.

  • fd – If the call succeed, this parameter will contain the map’s file descriptor.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_freeze(int fd)

Freeze a BPF map.

A frozen map can’t be modified from userspace.

Parameters:
  • fd – File descriptor of the map.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_lookup_elem(int fd, const void *key, void *value)

Get an element from a map.

Parameters:
  • fd – File descriptor of the map to search in.

  • key – Key to get the value for. Can’t be NULL.

  • value – Pointer to the value.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_map_update_elem(int fd, const void *key, void *value)

Update (or insert) an element in a map.

Parameters:
  • fd – File descriptor of the map to search in.

  • key – Key to get the value for. Can’t be NULL.

  • value – Pointer to the value.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_obj_pin(const char *path, int fd)

Pin a BPF object to a given path.

Parameters:
  • path – Path to pin the object to. Can’t be NULL.

  • fd – File descriptor of the map.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_obj_get(const char *path, int *fd)

Get a BPF object, from a path.

Parameters:
  • path – Path of the BPF object to get. Can’t be NULL.

  • fd – On success, contains a file descriptor to the BPF object.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_nf_link_create(int prog_fd, enum bf_hook hook, int priority, int *link_fd)

Create a Netfilter BPF link.

Parameters:
  • prog_fd – File descriptor of the program to attach to the link.

  • hook – Netfilter hook to attach the program to.

  • priority – Priority of the program on the hook.

  • link_fd – Link file descriptor, only valid if the return value of the function is 0.

Returns:

0 on success or negative errno value on failure.

int bf_bpf_xdp_link_create(int prog_fd, int ifindex, int *link_fd, enum bf_xdp_attach_mode mode)

Create a XDP BPF link.

Parameters:
  • prog_fd – File descriptor of the program to attach to the link.

  • ifindex – Interface index to attach the program to.

  • link_fd – Link file descriptor, only valid if the return value of the function is 0.

  • mode – XDP program attach mode. See bf_xdp_attach_mode.

Returns:

0 on success, or negative errno value on failure.

int bf_bpf_link_detach(int link_fd)

Detach a BPF link using its file descriptor.

Parameters:
  • link_fd – File descriptor of the link to detach. You can get a file descriptor using bf_bpf_obj_get.

Returns:

0 on success or negative errno value on failure.

file btf.c
#include “core/btf.h
#include <bpf/btf.h>
#include <errno.h>
#include <stdlib.h>
#include “core/logger.h
#include “shared/helper.h”

Functions

int bf_btf_setup(void)#

Load current kernel’s BTF data.

This function has to be called early, so BPF program generation can access kernel’s BTF data and use the kfunc’s BTF ID.

Returns:

0 on success, or negative errno value on failure.

void bf_btf_teardown(void)#

Free current kernel’s BTF data.

int bf_btf_get_id(const char *name)#

Get BTF ID of a kernel function.

Linux’ BTF data must be loaded with bf_btf_setup before calling this function.

Parameters:
  • name – Name of the kernel function.

Returns:

BTF ID on success, or negative errno value on failure.

int bf_btf_get_field_off(const char *struct_name, const char *field_name)#

Get the offset of a field in a kernel structure.

Use Linux’ BTF data to find the offset of a specific field in a structure. This function will fail if the offset of a bitfield is requested.

Parameters:
  • struct_name – Name of the structure to find the offset in. Can’t be NULL.

  • field_name – Name of the field to get the offset of. Can’t be NULL.

Returns:

Offset of field_name if found, negative error value on failure.

Variables

static struct btf *_btf = NULL#
file btf.h

Functions

int bf_btf_setup(void)

Load current kernel’s BTF data.

This function has to be called early, so BPF program generation can access kernel’s BTF data and use the kfunc’s BTF ID.

Returns:

0 on success, or negative errno value on failure.

void bf_btf_teardown(void)

Free current kernel’s BTF data.

int bf_btf_get_id(const char *name)

Get BTF ID of a kernel function.

Linux’ BTF data must be loaded with bf_btf_setup before calling this function.

Parameters:
  • name – Name of the kernel function.

Returns:

BTF ID on success, or negative errno value on failure.

int bf_btf_get_field_off(const char *struct_name, const char *field_name)

Get the offset of a field in a kernel structure.

Use Linux’ BTF data to find the offset of a specific field in a structure. This function will fail if the offset of a bitfield is requested.

Parameters:
  • struct_name – Name of the structure to find the offset in. Can’t be NULL.

  • field_name – Name of the field to get the offset of. Can’t be NULL.

Returns:

Offset of field_name if found, negative error value on failure.

file context.c
#include “context.h
#include <errno.h>
#include <stdlib.h>
#include “core/logger.h
#include “core/marsh.h
#include “generator/codegen.h
#include “shared/helper.h”

Defines

_cleanup_bf_context_#

Functions

static void _bf_context_free(struct bf_context **context)#

Free a context.

If context points to a NULL pointer, this function does nothing. Once the function returns, context points to a NULL pointer.

Parameters:
  • context – Context to free. Can’t be NULL.

static int _bf_context_new(struct bf_context **context)#

Create and initialize a new context.

On failure, context is left unchanged.

Parameters:
  • context – New context to create. Can’t be NULL.

Returns:

0 on success, negative errno value on failure.

static void _bf_context_dump(const struct bf_context *context, prefix_t *prefix)#

See bf_context_dump for details.

static int _bf_context_marsh(const struct bf_context *context, struct bf_marsh **marsh)#

Marsh a context.

If the function succeeds, marsh will contain the marshalled context.

Parameters:
  • context – Context to marsh.

  • marsh – Marsh’d context.

Returns:

0 on success, negative errno value on failure.

static int _bf_context_unmarsh(const struct bf_marsh *marsh, struct bf_context **context)#

Unmarsh a context.

marsh is expected to be valid, that is marsh.data_len argument is within bound regarding actual size of marsh.

Parameters:
  • marsh – Marsh’d context to restore.

  • context – Restored context.

Returns:

0 on success, negative errno value on failure.

static struct bf_codegen *_bf_context_get_codegen(const struct bf_context *context, enum bf_hook hook, enum bf_front front)#

See bf_context_get_codegen for details.

static struct bf_codegen *_bf_context_take_codegen(struct bf_context *context, enum bf_hook hook, enum bf_front front)#

See bf_context_take_codegen for details.

static void _bf_context_delete_codegen(struct bf_context *context, enum bf_hook hook, enum bf_front front)#

See bf_context_delete_codegen for details.

static int _bf_context_set_codegen(struct bf_context *context, enum bf_hook hook, enum bf_front front, struct bf_codegen *codegen)#

See bf_context_set_codegen for details.

static void _bf_context_replace_codegen(struct bf_context *context, enum bf_hook hook, enum bf_front front, struct bf_codegen *codegen)#

See bf_context_replace_codegen for details.

int bf_context_setup(void)#

Initialise the global bpfilter context.

Returns:

0 on success, negative error code on failure.

void bf_context_teardown(bool clear)#

Teardown the global bpfilter context.

Parameters:
  • clear – If true, all the BPF programs will be unloaded before clearing the context.

int bf_context_save(struct bf_marsh **marsh)#

Marshel the global bpfilter context.

Parameters:
  • marshbf_marsh structure to fill with the marshalled context.

Returns:

0 on success, negative error code on failure.

int bf_context_load(const struct bf_marsh *marsh)#

Unmarshal the global bpfilter context.

Once this function completes, the global context has been restored from the marshalled context. On failure, the global context is left uninitialized.

Parameters:
  • marshbf_marsh structure containing the marshalled context.

Returns:

0 on success, negative error code on failure.

void bf_context_dump(prefix_t *prefix)#

Dump content of the context.

Parameters:
  • prefix – Prefix to use for the dump.

struct bf_codegen *bf_context_get_codegen(enum bf_hook hook, enum bf_front front)#

Get codegen for a given (hook, front) set.

Parameters:
  • hook – Hook to get the codegen from. Must be a valid hook.

  • front – Front-end to get the codegen from. Must be a valid front-end.

Returns:

The codegen for the given hook and front-end, or NULL if there is no such codegen.

struct bf_codegen *bf_context_take_codegen(enum bf_hook hook, enum bf_front front)#

Take a codegen out of the context for a given (hook, front) set.

The codegen returned must then be freed by the caller. It’s not part of the context anymore.

Parameters:
  • hook – Hook to get the codegen from. Must be a valid hook.

  • front – Front-end to get the codegen from. Must be a valid front-end.

Returns:

The codegen for the given hook and front-end, or NULL if there is no such codegen.

void bf_context_delete_codegen(enum bf_hook hook, enum bf_front front)#

Delete a codegen from the context for a given (hook, front) set.

If a corresponding codegen has been found, then it is removed from the context and deleted. Otherwise the context remain unchanged.

Parameters:
  • hook – Hook to get the codegen from. Must be a valid hook.

  • front – Front-end to get the codegen from. Must be a valid front-end.

int bf_context_set_codegen(enum bf_hook hook, enum bf_front front, struct bf_codegen *codegen)#

Add a codegen to the context.

Parameters:
  • hook – Hook to add the codegen to. Must be a valid hook.

  • front – Front-end to add the codegen to. Must be a valid front-end.

  • codegen – Codegen to add to the context. Can’t be NULL.

Returns:

0 on success, negative error code on failure. If a codegen already exists for the given (hook, front) set, then -EEXIST is returned.

void bf_context_replace_codegen(enum bf_hook hook, enum bf_front front, struct bf_codegen *codegen)#

Replace the codegen for a given (hook, front) set, if any.

If a codegen already exists for the given (hook, front) set, then it is deleted and replaced by codegen. Otherwise, codegen is added to the context.

Parameters:
  • hook – Hook to update the codegen for. Must be a valid hook.

  • front – Front-end to update the codegen for. Must be a valid

  • codegen – Codegen to update the context with. Can’t be NULL.

Variables

static struct bf_context *_global_context = NULL#

Global daemon context. Hidden in this translation unit.

file context.h
#include <stdbool.h>
#include <stddef.h>
#include “core/dump.h
#include “core/hook.h
#include “core/list.h
#include “shared/front.h”

bpfilter runtime context. This file contains the definition of the bf_context structure, which is the main structure used to store the daemon’s runtime context.

bf_context can be serialized and deserialized, including all of its fields. This way, bpfilter can be restarted without unloading the BPF programs and maps.

Like every other bf_* structure, most bf_* functions should expect a valid pointer to a bf_context structure. This is not exactly how it works for bf_context: public functions defined in this header do not require any bf_context, but those are only wrappers around private functions defined in context.c, which do expect a valid pointer to a bf_context. This is done to prevent the user from creating and manipulating multiple contexts, while keeping the API consistent with the other bf_* structures.

Functions

int bf_context_setup(void)

Initialise the global bpfilter context.

Returns:

0 on success, negative error code on failure.

void bf_context_teardown(bool clear)

Teardown the global bpfilter context.

Parameters:
  • clear – If true, all the BPF programs will be unloaded before clearing the context.

void bf_context_dump(prefix_t *prefix)

Dump content of the context.

Parameters:
  • prefix – Prefix to use for the dump.

int bf_context_save(struct bf_marsh **marsh)

Marshel the global bpfilter context.

Parameters:
  • marshbf_marsh structure to fill with the marshalled context.

Returns:

0 on success, negative error code on failure.

int bf_context_load(const struct bf_marsh *marsh)

Unmarshal the global bpfilter context.

Once this function completes, the global context has been restored from the marshalled context. On failure, the global context is left uninitialized.

Parameters:
  • marshbf_marsh structure containing the marshalled context.

Returns:

0 on success, negative error code on failure.

struct bf_codegen *bf_context_get_codegen(enum bf_hook hook, enum bf_front front)

Get codegen for a given (hook, front) set.

Parameters:
  • hook – Hook to get the codegen from. Must be a valid hook.

  • front – Front-end to get the codegen from. Must be a valid front-end.

Returns:

The codegen for the given hook and front-end, or NULL if there is no such codegen.

struct bf_codegen *bf_context_take_codegen(enum bf_hook hook, enum bf_front front)

Take a codegen out of the context for a given (hook, front) set.

The codegen returned must then be freed by the caller. It’s not part of the context anymore.

Parameters:
  • hook – Hook to get the codegen from. Must be a valid hook.

  • front – Front-end to get the codegen from. Must be a valid front-end.

Returns:

The codegen for the given hook and front-end, or NULL if there is no such codegen.

void bf_context_delete_codegen(enum bf_hook hook, enum bf_front front)

Delete a codegen from the context for a given (hook, front) set.

If a corresponding codegen has been found, then it is removed from the context and deleted. Otherwise the context remain unchanged.

Parameters:
  • hook – Hook to get the codegen from. Must be a valid hook.

  • front – Front-end to get the codegen from. Must be a valid front-end.

int bf_context_set_codegen(enum bf_hook hook, enum bf_front front, struct bf_codegen *codegen)

Add a codegen to the context.

Parameters:
  • hook – Hook to add the codegen to. Must be a valid hook.

  • front – Front-end to add the codegen to. Must be a valid front-end.

  • codegen – Codegen to add to the context. Can’t be NULL.

Returns:

0 on success, negative error code on failure. If a codegen already exists for the given (hook, front) set, then -EEXIST is returned.

void bf_context_replace_codegen(enum bf_hook hook, enum bf_front front, struct bf_codegen *codegen)

Replace the codegen for a given (hook, front) set, if any.

If a codegen already exists for the given (hook, front) set, then it is deleted and replaced by codegen. Otherwise, codegen is added to the context.

Parameters:
  • hook – Hook to update the codegen for. Must be a valid hook.

  • front – Front-end to update the codegen for. Must be a valid

  • codegen – Codegen to update the context with. Can’t be NULL.

file counter.h
#include <stdint.h>
#include “shared/helper.h”

Variables

struct bf_counter bf_packed#
file flavor.c
#include “core/flavor.h
#include “generator/nf.h
#include “generator/tc.h
#include “generator/xdp.h
#include “shared/helper.h”

Functions

const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)#

Get the operations structure for a given BPF flavor.

Parameters:
  • type – BPF flavor. Must be valid.

Returns:

Ops structure for a given BPF flavor.

const char *bf_flavor_to_str(enum bf_flavor flavor)#

Convert a bpfilter flavor to a string.

Parameters:
  • flavor – Flavor to convert. Must be valid.

Returns:

String representation of flavor.

file flavor.h
#include “core/verdict.h

“Flavor” as defined by bpfilter are types of BPF program, characterized by the prototype of the main function, the valid returns values, and the way they are attached to the kernel.

A flavor is used to defines specific part of the BPF program for a codegen. For example: access to the packet’s data, return value…

Enums

enum bf_flavor#

Define a valid BPF flavor type for bpfilter.

Values:

enumerator BF_FLAVOR_TC#

TC flavor.

enumerator BF_FLAVOR_NF#

For BPF_PROG_TYPE_NETFILTER programs. Expects a struct bpf_nf_ctx argument.

enumerator BF_FLAVOR_XDP#
enumerator _BF_FLAVOR_MAX#

Functions

const struct bf_flavor_ops *bf_flavor_ops_get(enum bf_flavor flavor)

Get the operations structure for a given BPF flavor.

Parameters:
  • type – BPF flavor. Must be valid.

Returns:

Ops structure for a given BPF flavor.

const char *bf_flavor_to_str(enum bf_flavor flavor)

Convert a bpfilter flavor to a string.

Parameters:
  • flavor – Flavor to convert. Must be valid.

Returns:

String representation of flavor.

file helper.c
#include “core/helper.h
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include “core/logger.h
#include “shared/helper.h”

Functions

int bf_read_file(const char *path, void **buf, size_t *len)#

Read the contents of a file into a buffer.

Parameters:
  • path – Path to the file to read. Can’t be NULL.

  • buf – Pointer to a pointer to a buffer. The buffer will be allocated automatically. The caller is responsible to free it. If bf_read_file fails, buf is left unchanged.

  • len – Length of the allocated buffer. Populated by the function.

Returns:

0 on success, negative errno value on error.

int bf_write_file(const char *path, const void *buf, size_t len)#

Write the contents of a buffer into a file.

Parameters:
  • path – Path to the file to write. Can’t be NULL.

  • buf – Buffer to write.

  • len – Number of bytes to write the to file.

Returns:

0 on success, negative errno value on error.

file helper.h
#include <stddef.h>

Functions

int bf_read_file(const char *path, void **buf, size_t *len)

Read the contents of a file into a buffer.

Parameters:
  • path – Path to the file to read. Can’t be NULL.

  • buf – Pointer to a pointer to a buffer. The buffer will be allocated automatically. The caller is responsible to free it. If bf_read_file fails, buf is left unchanged.

  • len – Length of the allocated buffer. Populated by the function.

Returns:

0 on success, negative errno value on error.

int bf_write_file(const char *path, const void *buf, size_t len)

Write the contents of a buffer into a file.

Parameters:
  • path – Path to the file to write. Can’t be NULL.

  • buf – Buffer to write.

  • len – Number of bytes to write the to file.

Returns:

0 on success, negative errno value on error.

file hook.c
#include “core/hook.h
#include “shared/helper.h”

Functions

const char *bf_hook_to_str(enum bf_hook hook)#

Convert a bpfilter hook to a string.

Parameters:
  • hook – The hook to convert. Must be a valid hook.

Returns:

String representation of the hook.

unsigned int bf_hook_to_bpf_prog_type(enum bf_hook hook)#

Convert a bpfilter hook to a BPF program type.

Parameters:
  • hook – The hook to convert. Must be a valid hook.

Returns:

The BPF program type corresponding to hook.

enum bf_flavor bf_hook_to_flavor(enum bf_hook hook)#

Get the expected flavor for a given hook.

Parameters:
  • hook – BPF hook. Must be valid.

Returns:

bpfilter flavor corresponding to hook.

enum bpf_attach_type bf_hook_to_attach_type(enum bf_hook hook)#

Convert a bpfilter hook to a BPF attach type.

Parameters:
  • hook – The hook to convert. Must be a valid hook.

Returns:

The BPF attach type corresponding to hook.

file hook.h
#include <linux/bpf.h>
#include “core/flavor.h

bpfilter’s BPF programs are attached to hooks in the kernel. This file contains the definitions for the hooks we support.

Enums

enum bf_hook#

Values:

enumerator BF_HOOK_NFT_INGRESS#
enumerator BF_HOOK_TC_INGRESS#
enumerator BF_HOOK_IPT_PRE_ROUTING#
enumerator BF_HOOK_IPT_LOCAL_IN#
enumerator BF_HOOK_IPT_FORWARD#
enumerator BF_HOOK_IPT_LOCAL_OUT#
enumerator BF_HOOK_IPT_POST_ROUTING#
enumerator BF_HOOK_TC_EGRESS#
enumerator _BF_HOOK_MAX#

Functions

const char *bf_hook_to_str(enum bf_hook hook)

Convert a bpfilter hook to a string.

Parameters:
  • hook – The hook to convert. Must be a valid hook.

Returns:

String representation of the hook.

unsigned int bf_hook_to_bpf_prog_type(enum bf_hook hook)

Convert a bpfilter hook to a BPF program type.

Parameters:
  • hook – The hook to convert. Must be a valid hook.

Returns:

The BPF program type corresponding to hook.

enum bf_flavor bf_hook_to_flavor(enum bf_hook hook)

Get the expected flavor for a given hook.

Parameters:
  • hook – BPF hook. Must be valid.

Returns:

bpfilter flavor corresponding to hook.

enum bpf_attach_type bf_hook_to_attach_type(enum bf_hook hook)

Convert a bpfilter hook to a BPF attach type.

Parameters:
  • hook – The hook to convert. Must be a valid hook.

Returns:

The BPF attach type corresponding to hook.

file list.c
#include “list.h
#include <errno.h>
#include <stdlib.h>

Functions

static int bf_list_node_new(bf_list_node **node, void *data)#

Create a new list node, with the given data.

Parameters:
  • node – New node pointer. Must be non-NULL.. If the function fails, this parameter remains unchanged.

  • data – Data to store in the new node. Can be NULL.

Returns:

0 on success or negative errno code on failure.

static void bf_list_node_free(bf_list_node **node, void (*free_data)(void **data))#

Free a list node. Must be non-NULL.

The data contained in the node will also be freed using the function provided in the list’s ops.

Parameters:
  • node – Node to free.

int bf_list_new(bf_list **list, const bf_list_ops *ops)#

Allocate and initialise a new list.

Parameters:
  • list – Pointer to the list to initialise. Must be non-NULL.

  • ops – Operations to use to manipulate the list’s data. Must be non-NULL.

Returns:

0 on success or negative errno code on failure.

void bf_list_free(bf_list **list)#

Free a list.

Parameters:
  • list – Pointer to the list to free. Must be non-NULL.

void bf_list_init(bf_list *list, const bf_list_ops *ops)#

Initialize an allocated list.

Parameters:
  • list – List to initialise. Must be non-NULL.

  • ops – Operations to use to manipulate the list’s data. Must be non-NULL. ops shouldn’t contain any NULL field.

void bf_list_clean(bf_list *list)#

Clean up a list.

Every node in the list is freed. The node’s data is freed using the function provided during initialisation (through bf_list_ops).

Parameters:
  • list – Pointer to the initialised list to clean. Must be non-NULL.

int bf_list_add_head(bf_list *list, void *data)#

Add data at the beginning of the list.

Parameters:
  • list – List to append data to. Must be initialised and non-NULL.

  • data – Data to append to the list. Can be NULL. list takes ownership of the data: it should not be freed.

Returns:

0 on success or negative errno code on failure.

int bf_list_add_tail(bf_list *list, void *data)#

Add data at the end of the list.

Parameters:
  • list – List to append data to. Must be initialised and non-NULL.

  • data – Data to append to the list. Can be NULL. list takes ownership of the data: it should not be freed.

Returns:

0 on success or negative errno code on failure.

void bf_list_delete(bf_list *list, bf_list_node *node)#

Delete node from list.

node is freed and shouldn’t be used once the function returns. The node’s data will be freed using the function provided during initialisation (through bf_list_ops).

Parameters:
  • list – List to remove node from. Must be non-NULL.

  • node – Node to remove from the list. Must be non-NULL.

file list.h
#include <stdbool.h>
#include <stddef.h>
#include “shared/helper.h”

Defines

_cleanup_bf_list_#
bf_list_foreach(list, node)#

Iterate over a bf_list.

Use a temporary variable to store the next node (if any). Hence, a node can be removed from the list during iteration.

Parameters:
  • list – Pointer to the list to iterate over. Must be non-NULL.

  • node – Name of the variable containing the current node. This variable will be created automatically and the caller will be able to use it to access the node.

bf_list_foreach_rev(list, node)#

Reverse iterate over a bf_list.

Use a temporary variable to store the next node (if any). Hence, a node can be removed from the list during iteration.

Parameters:
  • list – Pointer to the list to iterate over. Must be non-NULL.

  • node – Name of the variable containing the current node. This variable will be created automatically and the caller will be able to use it to access the node.

bf_list_default(list_ops)#

Returns an initialised bf_list.

Parameters:
  • ops – Operations to use to manipulate the list’s data. Must be non-NULL.

Returns:

An initialised bf_list.

Typedefs

typedef struct bf_list_node bf_list_node
typedef void (*bf_list_ops_free)(void **data)#

Functions

int bf_list_new(bf_list **list, const bf_list_ops *ops)

Allocate and initialise a new list.

Parameters:
  • list – Pointer to the list to initialise. Must be non-NULL.

  • ops – Operations to use to manipulate the list’s data. Must be non-NULL.

Returns:

0 on success or negative errno code on failure.

void bf_list_free(bf_list **list)

Free a list.

Parameters:
  • list – Pointer to the list to free. Must be non-NULL.

void bf_list_init(bf_list *list, const bf_list_ops *ops)

Initialize an allocated list.

Parameters:
  • list – List to initialise. Must be non-NULL.

  • ops – Operations to use to manipulate the list’s data. Must be non-NULL. ops shouldn’t contain any NULL field.

void bf_list_clean(bf_list *list)

Clean up a list.

Every node in the list is freed. The node’s data is freed using the function provided during initialisation (through bf_list_ops).

Parameters:
  • list – Pointer to the initialised list to clean. Must be non-NULL.

static inline size_t bf_list_size(const bf_list *list)#

Get the number of nodes in the list.

Parameters:
  • list – Initialised list. Must be non-NULL.

Returns:

Number of nodes in the list.

static inline bool bf_list_is_empty(const bf_list *list)#

Check if a list is empty.

Parameters:
  • list – Initialised list. Must be non-NULL.

Returns:

True if the list is empty, false otherwise.

static inline bool bf_list_is_head(const bf_list *list, const bf_list_node *node)#

Check if node is the head of list.

Parameters:
  • list – List. Must be non NULL.

  • node – Node. Must be non NULL.

Returns:

True if node is the head of list, false otherwise.

static inline bool bf_list_is_tail(const bf_list *list, const bf_list_node *node)#

Check if node is the tail of list.

Parameters:
  • list – List. Must be non NULL.

  • node – Node. Must be non NULL.

Returns:

True if node is the tail of list, false otherwise.

int bf_list_add_head(bf_list *list, void *data)

Add data at the beginning of the list.

Parameters:
  • list – List to append data to. Must be initialised and non-NULL.

  • data – Data to append to the list. Can be NULL. list takes ownership of the data: it should not be freed.

Returns:

0 on success or negative errno code on failure.

int bf_list_add_tail(bf_list *list, void *data)

Add data at the end of the list.

Parameters:
  • list – List to append data to. Must be initialised and non-NULL.

  • data – Data to append to the list. Can be NULL. list takes ownership of the data: it should not be freed.

Returns:

0 on success or negative errno code on failure.

void bf_list_delete(bf_list *list, bf_list_node *node)

Delete node from list.

node is freed and shouldn’t be used once the function returns. The node’s data will be freed using the function provided during initialisation (through bf_list_ops).

Parameters:
  • list – List to remove node from. Must be non-NULL.

  • node – Node to remove from the list. Must be non-NULL.

static inline bf_list_node *bf_list_get_head(const bf_list *list)#

Returns the first element of the list.

A bf_list_node object it returned. Use bf_list_node_get_data to get a pointer to the data.

Parameters:
  • list – Initialised list. Must be non-NULL.

Returns:

Pointer to the first node of the list, or NULL if empty.

static inline bf_list_node *bf_list_get_tail(const bf_list *list)#

Returns the last element of the list.

A bf_list_node object it returned. Use bf_list_node_get_data to get a pointer to the data.

Parameters:
  • list – Initialised list. Must be non-NULL.

Returns:

Pointer to the last node of the list, or NULL if empty.

static inline bf_list_node *bf_list_node_next(const bf_list_node *node)#

Get next node.

Parameters:
  • node – Current node. Must be non-NULL.

Returns:

Pointer to the next node, or NULL if end of list.

static inline bf_list_node *bf_list_node_prev(const bf_list_node *node)#

Get previous node.

Parameters:
  • node – Current node. Must be non-NULL.

Returns:

Pointer to the previous node, or NULL if end of list.

static inline void *bf_list_node_get_data(const bf_list_node *node)#

Get the node’s data.

Note that the pointer returned can be NULL, as nothing prevents NULL data to be stored in the node. The pointer returned is owned by the node and should not be freed.

Parameters:
  • node – Current node. Must be non-NULL.

Returns:

Pointer to the data stored in the iterator.

static inline void *bf_list_node_take_data(bf_list_node *node)#

Get the node’s data and remove it from the node.

Once the function returns, the node’s data is set to NULL. The pointer returned is then owned by the caller.

Parameters:
  • node – Current node. Must be non-NULL.

Returns:

Pointer to the data stored in the node.

file logger.c
#include “core/logger.h
#include <stdbool.h>
#include <unistd.h>

Functions

void bf_logger_setup(void)#

Initialise the logging system.

Defines whether the logging system will print in colors or not. If both stdout and stderr are TTYs, then _can_print_color is set to true.

const char *bf_logger_get_color(enum bf_style style)#

Get color string for a given style.

style can be a combination of bf_style weight and color. If _can_print_color is set to false, then an empty string will be returned so to not modify the output style.

Parameters:
  • style – Style to get the color of

Returns:

Style string.

Variables

static bool _can_print_color = false#

If true, log messages will be printed in colors.

file logger.h
#include <stdio.h>
#include “opts.h
#include “shared/helper.h”

Defines

_bf_log_impl(fmt, ...)#

Log an error message to stderr.

Parameters:
  • fmt – Format string.

  • ... – Format arguments.

bf_abort(fmt, ...)#
bf_err(fmt, ...)#
bf_warn(fmt, ...)#
bf_info(fmt, ...)#
bf_dbg(fmt, ...)#
_bf_log_code_impl(code, fmt, ...)#

Log an error message to stderr, append the detail of the error code provided and return the given error code.

Convenience function to be used during error checks. It will log the error message to stderr, append the detail of the error code provided and return the given error code as a negative value. For example:

if (ret < 0) return bf_err_code(ret, “failed to do something”);

Parameters:
  • code – Error code, can be positive or negative.

  • fmt – Format string.

  • ... – Format arguments.

Returns:

The given error code, as a negative value.

bf_err_code(code, fmt, ...)#
bf_warn_code(code, fmt, ...)#
bf_info_code(code, fmt, ...)#
bf_dbg_code(code, fmt, ...)#

Enums

enum bf_style#

Values:

enumerator BF_STYLE_RESET = 0#
enumerator BF_STYLE_NORMAL = 0#
enumerator BF_STYLE_BOLD = 1#
enumerator BF_STYLE_DEFAULT = 1 << 1#
enumerator BF_STYLE_BLACK = 1 << 2#
enumerator BF_STYLE_RED = 1 << 3#
enumerator BF_STYLE_GREEN = 1 << 4#
enumerator BF_STYLE_YELLOW = 1 << 5#
enumerator BF_STYLE_BLUE = 1 << 6#
enumerator BF_STYLE_MAGENTA = 1 << 7#
enumerator BF_STYLE_CYAN = 1 << 8#
enumerator BF_STYLE_LIGHT_GRAY = 1 << 9#
enumerator BF_STYLE_DARK_GRAY = 1 << 10#
enumerator BF_STYLE_LIGHT_RED = 1 << 11#
enumerator BF_STYLE_LIGHT_GREEN = 1 << 12#
enumerator BF_STYLE_LIGHT_YELLOW = 1 << 13#
enumerator BF_STYLE_LIGHT_BLUE = 1 << 14#
enumerator BF_STYLE_LIGHT_MAGENTA = 1 << 15#
enumerator BF_STYLE_LIGHT_CYAN = 1 << 16#
enumerator BF_STYLE_WHITE = 1 << 17#

Functions

void bf_logger_setup(void)

Initialise the logging system.

Defines whether the logging system will print in colors or not. If both stdout and stderr are TTYs, then _can_print_color is set to true.

const char *bf_logger_get_color(enum bf_style style)

Get color string for a given style.

style can be a combination of bf_style weight and color. If _can_print_color is set to false, then an empty string will be returned so to not modify the output style.

Parameters:
  • style – Style to get the color of

Returns:

Style string.

file marsh.c
#include “core/marsh.h
#include <errno.h>
#include <stdlib.h>
#include <string.h>

Functions

int bf_marsh_new(struct bf_marsh **marsh, const void *data, size_t data_len)#

Allocate and initialise a bf_marsh structure.

Parameters:
  • marsh – Marsh to be allocated. On success, contains a pointer to the marsh structure, and is owned by the caller. If the function fails, it’s left unchanged.

  • data – Data to be marshalled.

  • data_len – Length of data.

Returns:

0 on success, negative errno value on error.

void bf_marsh_free(struct bf_marsh **marsh)#

Free a marsh, including its data.

If marsh points to NULL, then nothing is done.

Parameters:
  • marsh – Marsh to free. Must not be NULL.

int bf_marsh_add_child_obj(struct bf_marsh **marsh, const struct bf_marsh *obj)#

Add a child to a marsh, from another marsh.

obj will be added to the data in marsh.

Parameters:
  • marsh – Parent marsh. Must be non NULL.

  • obj – Marsh to be added as a child. Must be non NULL.

Returns:

0 on success, negative errno value on error.

int bf_marsh_add_child_raw(struct bf_marsh **marsh, const void *data, size_t data_len)#

Add a child to a marsh, from raw data.

If data is NULL, nothing is done and marsh remain unchanged. In this case, data_len must be 0.

Parameters:
  • marsh – Parent marsh. Must be non NULL.

  • data – Data to add to the marsh.

  • data_len – Length of the data to add to marsh.

Returns:

0 on success, negative errno value on error.

file marsh.h
#include <stdbool.h>
#include <stddef.h>
#include “shared/helper.h”

Defines

_cleanup_bf_marsh_#

Functions

static inline size_t bf_marsh_size(const struct bf_marsh *marsh)#

Get the total size of marshalled data.

Parameters:
  • marsh – Marshalled data.

Returns:

Total size of marshalled data, including the header.

static inline void *bf_marsh_end(const struct bf_marsh *marsh)#

Get pointer to the end of a bf_marsh structure.

“End” here, means the first byte after the content of the marshalled data.

Parameters:
  • marsh – Marshalled data.

Returns:

Pointer to the end of the marshalled data.

static inline bool bf_marsh_child_is_valid(const struct bf_marsh *marsh, const struct bf_marsh *child)#

Check if child is a valid child for marsh.

A valid marsh is defined by the following criteria:

  • It starts within its parent’s data.

  • Its full length (including the header) is within its parent’s data. A marsh can only be validated relative to its parent. By recursively validating all the children of a marsh, we can validate the whole marsh.

Warning

This function doesn’t check if the marshalled data is valid. It only checks if the marshalled data is within the parent’s data and can be accessed safely.

Parameters:
  • marsh – Parent marsh, must be valid.

  • child – Child marsh to validate. Can be NULL.

Returns:

true if child is a valid child of marsh, false otherwise.

static inline struct bf_marsh *bf_marsh_next_child(const struct bf_marsh *marsh, const struct bf_marsh *child)#

Get marsh’s child located after child.

Parameters:
  • marsh – Parent marsh, must be valid.

  • child – Child of marsh, must be a valid child of marsh or NULL. If child is NULL, the first child of marsh is returned.

Returns:

Next child of marsh after child, or NULL if child is the last valid child of marsh.

int bf_marsh_new(struct bf_marsh **marsh, const void *data, size_t data_len)

Allocate and initialise a bf_marsh structure.

Parameters:
  • marsh – Marsh to be allocated. On success, contains a pointer to the marsh structure, and is owned by the caller. If the function fails, it’s left unchanged.

  • data – Data to be marshalled.

  • data_len – Length of data.

Returns:

0 on success, negative errno value on error.

void bf_marsh_free(struct bf_marsh **marsh)

Free a marsh, including its data.

If marsh points to NULL, then nothing is done.

Parameters:
  • marsh – Marsh to free. Must not be NULL.

int bf_marsh_add_child_obj(struct bf_marsh **marsh, const struct bf_marsh *obj)

Add a child to a marsh, from another marsh.

obj will be added to the data in marsh.

Parameters:
  • marsh – Parent marsh. Must be non NULL.

  • obj – Marsh to be added as a child. Must be non NULL.

Returns:

0 on success, negative errno value on error.

int bf_marsh_add_child_raw(struct bf_marsh **marsh, const void *data, size_t data_len)

Add a child to a marsh, from raw data.

If data is NULL, nothing is done and marsh remain unchanged. In this case, data_len must be 0.

Parameters:
  • marsh – Parent marsh. Must be non NULL.

  • data – Data to add to the marsh.

  • data_len – Length of the data to add to marsh.

Returns:

0 on success, negative errno value on error.

Variables

struct bf_marsh bf_packed
file match.c
#include “match.h
#include <errno.h>
#include <stdlib.h>

Functions

int bf_match_new(struct bf_match **match)#
void bf_match_free(struct bf_match **match)#
file match.h

Defines

BF_MATCH_OPS_NAME#
_cleanup_bf_match_#

Functions

int bf_match_new(struct bf_match **match)
void bf_match_free(struct bf_match **match)
file rule.c
#include “core/rule.h
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include “core/list.h
#include “core/logger.h
#include “core/marsh.h
#include “core/match.h
#include “core/verdict.h
#include “shared/helper.h”

Functions

int bf_rule_new(struct bf_rule **rule)#

Allocated and initialise a new rule.

On failure, rule is left unchanged.

Parameters:
  • rule – On success, points to the allocated rule. Must be non NULL.

Returns:

0 on success, or negative errno value on error.

void bf_rule_free(struct bf_rule **rule)#

Free a rule.

Free rule and set it to NULL. If rule is NULL, nothing is done.

Parameters:
  • rule – Rule to free. Must be non-NULL.

int bf_rule_marsh(const struct bf_rule *rule, struct bf_marsh **marsh)#

Marsh a rule.

Parameters:
  • rule – Rule to marsh. Can’t be NULL.

  • marsh – Output marshalled rule. Allocated by the function, owned by the caller once the function returns. Can’t be NULL.

Returns:

0 on success, negative errno value on error.

int bf_rule_unmarsh(const struct bf_marsh *marsh, struct bf_rule **rule)#

Unmarsh a rule.

Parameters:
  • marsh – Marshalled rule. Must be non NULL.

  • rule – Unmarshalled rule. Allocated by the function, owned by the caller on success.

Returns:

0 on success, negative errno value on error.

void bf_rule_dump(const struct bf_rule *rule, prefix_t *prefix)#

Dump a rule.

Parameters:
  • rule – Rule to dump. Must not be NULL.

  • prefix – Prefix for each printed line.

file rule.h
#include <stdbool.h>
#include <stdint.h>
#include “core/dump.h
#include “core/list.h
#include “core/verdict.h

Defines

_cleanup_bf_rule_#

Functions

int bf_rule_new(struct bf_rule **rule)

Allocated and initialise a new rule.

On failure, rule is left unchanged.

Parameters:
  • rule – On success, points to the allocated rule. Must be non NULL.

Returns:

0 on success, or negative errno value on error.

void bf_rule_free(struct bf_rule **rule)

Free a rule.

Free rule and set it to NULL. If rule is NULL, nothing is done.

Parameters:
  • rule – Rule to free. Must be non-NULL.

int bf_rule_marsh(const struct bf_rule *rule, struct bf_marsh **marsh)

Marsh a rule.

Parameters:
  • rule – Rule to marsh. Can’t be NULL.

  • marsh – Output marshalled rule. Allocated by the function, owned by the caller once the function returns. Can’t be NULL.

Returns:

0 on success, negative errno value on error.

int bf_rule_unmarsh(const struct bf_marsh *marsh, struct bf_rule **rule)

Unmarsh a rule.

Parameters:
  • marsh – Marshalled rule. Must be non NULL.

  • rule – Unmarshalled rule. Allocated by the function, owned by the caller on success.

Returns:

0 on success, negative errno value on error.

void bf_rule_dump(const struct bf_rule *rule, prefix_t *prefix)

Dump a rule.

Parameters:
  • rule – Rule to dump. Must not be NULL.

  • prefix – Prefix for each printed line.

file verdict.c
#include “core/verdict.h
#include “bpfilter/shared/helper.h”

Functions

const char *bf_verdict_to_str(enum bf_verdict verdict)#
file verdict.h

Enums

enum bf_verdict#

Verdict to apply for a rule or chain.

Values:

enumerator BF_VERDICT_ACCEPT#

Accept the packet.

enumerator BF_VERDICT_DROP#

Drop the packet.

enumerator _BF_VERDICT_MAX#

Functions

const char *bf_verdict_to_str(enum bf_verdict verdict)
file filter.h
#include <linux/bpf.h>
#include <linux/bpf_common.h>
#include <stdbool.h>

Defines

BPF_REG_ARG1#
BPF_REG_ARG2#
BPF_REG_ARG3#
BPF_REG_ARG4#
BPF_REG_ARG5#
BPF_REG_CTX#
BPF_REG_FP#
BPF_REG_A#
BPF_REG_X#
BPF_REG_TMP#
BPF_REG_D#
BPF_REG_H#
BPF_REG_AX#
MAX_BPF_EXT_REG#
MAX_BPF_JIT_REG#
BPF_TAIL_CALL#
BPF_PROBE_MEM#
BPF_CALL_ARGS#
BPF_NOSPEC#
BPF_SYM_ELF_TYPE#
MAX_BPF_STACK#
BPF_ALU64_REG(OP, DST, SRC)#
BPF_ALU32_REG(OP, DST, SRC)#
BPF_ALU64_IMM(OP, DST, IMM)#
BPF_ALU32_IMM(OP, DST, IMM)#
BPF_ENDIAN(TYPE, DST, LEN)#
BPF_MOV64_REG(DST, SRC)#
BPF_MOV32_REG(DST, SRC)#
BPF_MOV64_IMM(DST, IMM)#
BPF_MOV32_IMM(DST, IMM)#
BPF_ZEXT_REG(DST)#
BPF_LD_IMM64(DST, IMM)#
BPF_LD_IMM64_RAW(DST, SRC, IMM)#
BPF_LD_MAP_FD(DST, MAP_FD)#
BPF_MOV64_RAW(TYPE, DST, SRC, IMM)#
BPF_MOV32_RAW(TYPE, DST, SRC, IMM)#
BPF_LD_ABS(SIZE, IMM)#
BPF_LD_IND(SIZE, SRC, IMM)#
BPF_LDX_MEM(SIZE, DST, SRC, OFF)#
BPF_STX_MEM(SIZE, DST, SRC, OFF)#
BPF_ATOMIC_OP(SIZE, OP, DST, SRC, OFF)#
BPF_STX_XADD(SIZE, DST, SRC, OFF)#
BPF_ST_MEM(SIZE, DST, OFF, IMM)#
BPF_JMP_REG(OP, DST, SRC, OFF)#
BPF_JMP_IMM(OP, DST, IMM, OFF)#
BPF_JMP32_REG(OP, DST, SRC, OFF)#
BPF_JMP32_IMM(OP, DST, IMM, OFF)#
BPF_JMP_A(OFF)#
BPF_CALL_REL(TGT)#
BPF_EMIT_CALL(FUNC)#
BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM)#
BPF_EXIT_INSN()#
BPF_ST_NOSPEC()#
__BPF_STMT(CODE, K)#
__BPF_JUMP(CODE, K, JT, JF)#
bytes_to_bpf_size(bytes)#
bpf_size_to_bytes(bpf_size)#
BPF_SIZEOF(type)#
BPF_FIELD_SIZEOF(type, field)#
BPF_LDST_BYTES(insn)#
__BPF_MAP_0(m, v, ...)#
__BPF_MAP_1(m, v, t, a, ...)#
__BPF_MAP_2(m, v, t, a, ...)#
__BPF_MAP_3(m, v, t, a, ...)#
__BPF_MAP_4(m, v, t, a, ...)#
__BPF_MAP_5(m, v, t, a, ...)#
__BPF_REG_0(...)#
__BPF_REG_1(...)#
__BPF_REG_2(...)#
__BPF_REG_3(...)#
__BPF_REG_4(...)#
__BPF_REG_5(...)#
__BPF_MAP(n, ...)#
__BPF_REG(n, ...)#
__BPF_CAST(t, a)#
__BPF_V#
__BPF_N#
__BPF_DECL_ARGS(t, a)#
__BPF_DECL_REGS(t, a)#
__BPF_PAD(n)#
BPF_CALL_x(x, name, ...)#
BPF_CALL_0(name, ...)#
BPF_CALL_1(name, ...)#
BPF_CALL_2(name, ...)#
BPF_CALL_3(name, ...)#
BPF_CALL_4(name, ...)#
BPF_CALL_5(name, ...)#
bpf_ctx_range(TYPE, MEMBER)#
bpf_ctx_range_till(TYPE, MEMBER1, MEMBER2)#
bpf_ctx_range_ptr(TYPE, MEMBER)#
bpf_target_off(TYPE, MEMBER, SIZE, PTR_SIZE)#

Functions

static inline bool insn_is_zext(const struct bpf_insn *insn)#
file codegen.c
#include “codegen.h
#include <net/if.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include “core/dump.h
#include “core/logger.h
#include “core/marsh.h
#include “core/rule.h
#include “generator/dump.h
#include “generator/program.h
#include “shared/front.h”
#include “shared/helper.h”

Functions

int bf_codegen_new(struct bf_codegen **codegen)#

Allocate and initialise a new codegen.

Parameters:
  • codegen – Codegen to initialise. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

void bf_codegen_free(struct bf_codegen **codegen)#

Free a codegen.

If one or more programs are loaded, they won’t be unloaded. Use bf_codegen_unload first to ensure programs are unloaded. This behaviour is expected so bf_codegen can be freed without unloading the BPF program, during a daemon restart for example.

Parameters:
  • codegen – Codegen to free. Can’t be NULL.

int bf_codegen_generate(struct bf_codegen *codegen)#

Generate BPF programs for a codegen.

Parameters:
  • codegen – Codegen to generate BPF programs for. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

int bf_codegen_load(struct bf_codegen *codegen, struct bf_codegen *prev_codegen)#

Load the BPF program stored in a codegen.

Each program within the codegen will be loaded and attached to its interface.

Parameters:
  • codegen – Codegen containing the BPF program to load. Can’t be NULL.

  • prev_codegen – Codegen to replace. Can be NULL. bf_codegen_load is responsible for unloading the previous codegen. bf_codegen_load doesn’t own prev_codegen, and won’t free it.

Returns:

0 on success, or negative errno value on failure.

int bf_codegen_unload(struct bf_codegen *codegen)#

Unload a codegen’s BPF programs.

Parameters:
  • codegen – Codegen containing the BPF program to unload. Can’t be NULL.

Returns:

0 on success, negative error code on failure.

int bf_codegen_marsh(const struct bf_codegen *codegen, struct bf_marsh **marsh)#
int bf_codegen_unmarsh(const struct bf_marsh *marsh, struct bf_codegen **codegen)#
void bf_codegen_dump(const struct bf_codegen *codegen, prefix_t *prefix)#
struct bf_program *bf_codegen_get_program(const struct bf_codegen *codegen, uint32_t ifindex)#

Get a codegen’s BPF program for a given interface.

Parameters:
  • codegen – Codegen containing the BPF program to get. Can’t be NULL.

  • ifindex – Interface to get the BPF program for.

Returns:

BPF program for the given interface, or NULL if not found.

int bf_codegen_get_counter(const struct bf_codegen *codegen, uint32_t counter_idx, struct bf_counter *counter)#

Get packets and bytes counter at a specific index.

Counters are referenced by their index in the counters map. There are 1 more counter in the map than the number of rules. This last counter (the last in the map) is dedicated to the policy.

The counter from all the program generated from codegen are summarised together.

Parameters:
  • codegen – Codegen to get the counter for. Can’t be NULL.

  • counter_idx – Index of the counter to get. If counter_idx doesn’t correspond to a valid index, -E2BIG is returned.

  • counter – Counter structure to fill with the counter values. Can’t be NULL.

Returns:

0 on success, or a negative errno value on failure.

int bf_codegen_update(struct bf_codegen *codegen)#

Update the BPF programs for a codegen.

Parameters:
  • codegen – Codegen to update. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

file codegen.h
#include <stdint.h>
#include “core/counter.h
#include “core/dump.h
#include “core/hook.h
#include “core/list.h
#include “core/verdict.h
#include “shared/front.h”

Defines

_cleanup_bf_codegen_#

Functions

int bf_codegen_new(struct bf_codegen **codegen)

Allocate and initialise a new codegen.

Parameters:
  • codegen – Codegen to initialise. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

void bf_codegen_free(struct bf_codegen **codegen)

Free a codegen.

If one or more programs are loaded, they won’t be unloaded. Use bf_codegen_unload first to ensure programs are unloaded. This behaviour is expected so bf_codegen can be freed without unloading the BPF program, during a daemon restart for example.

Parameters:
  • codegen – Codegen to free. Can’t be NULL.

int bf_codegen_generate(struct bf_codegen *codegen)

Generate BPF programs for a codegen.

Parameters:
  • codegen – Codegen to generate BPF programs for. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

int bf_codegen_update(struct bf_codegen *codegen)

Update the BPF programs for a codegen.

Parameters:
  • codegen – Codegen to update. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

int bf_codegen_load(struct bf_codegen *codegen, struct bf_codegen *prev_codegen)

Load the BPF program stored in a codegen.

Each program within the codegen will be loaded and attached to its interface.

Parameters:
  • codegen – Codegen containing the BPF program to load. Can’t be NULL.

  • prev_codegen – Codegen to replace. Can be NULL. bf_codegen_load is responsible for unloading the previous codegen. bf_codegen_load doesn’t own prev_codegen, and won’t free it.

Returns:

0 on success, or negative errno value on failure.

int bf_codegen_unload(struct bf_codegen *codegen)

Unload a codegen’s BPF programs.

Parameters:
  • codegen – Codegen containing the BPF program to unload. Can’t be NULL.

Returns:

0 on success, negative error code on failure.

int bf_codegen_marsh(const struct bf_codegen *codegen, struct bf_marsh **marsh)
int bf_codegen_unmarsh(const struct bf_marsh *marsh, struct bf_codegen **codegen)
void bf_codegen_dump(const struct bf_codegen *codegen, prefix_t *prefix)
struct bf_program *bf_codegen_get_program(const struct bf_codegen *codegen, uint32_t ifindex)

Get a codegen’s BPF program for a given interface.

Parameters:
  • codegen – Codegen containing the BPF program to get. Can’t be NULL.

  • ifindex – Interface to get the BPF program for.

Returns:

BPF program for the given interface, or NULL if not found.

int bf_codegen_get_counter(const struct bf_codegen *codegen, uint32_t counter_idx, struct bf_counter *counter)

Get packets and bytes counter at a specific index.

Counters are referenced by their index in the counters map. There are 1 more counter in the map than the number of rules. This last counter (the last in the map) is dedicated to the policy.

The counter from all the program generated from codegen are summarised together.

Parameters:
  • codegen – Codegen to get the counter for. Can’t be NULL.

  • counter_idx – Index of the counter to get. If counter_idx doesn’t correspond to a valid index, -E2BIG is returned.

  • counter – Counter structure to fill with the counter values. Can’t be NULL.

Returns:

0 on success, or a negative errno value on failure.

file dump.c
#include “dump.h
#include <stddef.h>
#include <string.h>
#include “opts.h

Defines

_DUMP_HEXDUMP_LEN#

Functions

void bf_dump_prefix_push(prefix_t *prefix)#

Add a symbol to the prefix string.

Parameters:
  • prefix – Prefix string.

prefix_t *bf_dump_prefix_last(prefix_t *prefix)#

Convert previous node to make is the last of the branch.

Parameters:
  • prefix – Prefix string.

Returns:

prefix

void bf_dump_prefix_pop(prefix_t *prefix)#

Remove rightmost branch from the prefix string.

When a subtree is completed and we backout to a different branch, we need to remove the rightmost branch from the prefix to continue.

Parameters:
  • prefix – Prefix string.

void bf_dump_hex(prefix_t *prefix, const void *data, size_t len)#

Dump the data buffer in hexedecimal format.

Each byte in data will be printed as 0x%02x, with 8 bytes on each row.

Parameters:
  • prefix – Prefix string.

  • data – Data buffer to print.

  • len – Size of the data buffer.

file dump.c
#include “generator/dump.h
#include <linux/bpf.h>
#include <linux/bpf_common.h>
#include <stdio.h>
#include “core/dump.h
#include “core/logger.h
#include “generator/program.h
#include “shared/helper.h”

Defines

BF_INSN_CLS(insn)#
BF_INSN_CODE(insn)#
BF_INSN_SRC(insn)#
BF_INSN_MODE(insn)#
BF_INSN_SIZE(insn)#
BF_IMM_BUF_LEN#

Functions

static const char *_bpf_reg(unsigned char reg)#
static const char *_bf_op(const struct bpf_insn *insn)#
static const char *_bf_src(const struct bpf_insn *insn, char (*imm_buf)[BF_IMM_BUF_LEN])#
static void _bf_program_dump_alu_insn(const struct bf_program *program, const size_t *insn_idx, prefix_t *prefix)#
static const char *_bf_jmp_op(const struct bpf_insn *insn)#
static const char *_bpf_helper(const struct bpf_insn *insn)#
static void _bf_program_dump_jmp_insn(const struct bf_program *program, const size_t *insn_idx, prefix_t *prefix)#
static const char *_bpf_ldst_size(const struct bpf_insn *insn)#
static void _bf_program_dump_imm64_insn(const struct bf_program *program, size_t *insn_idx, prefix_t *prefix)#
static void _bf_program_dump_ldst_insn(const struct bf_program *program, size_t *insn_idx, prefix_t *prefix)#
static void _bf_program_dump_insn(const struct bf_program *program, size_t *insn_idx, prefix_t *prefix)#
static void _bf_program_dump_raw(const struct bf_program *program, const size_t *insn_idx, prefix_t *prefix)#
void bf_program_dump_bytecode(const struct bf_program *program, bool with_raw)#
file dump.c
#include “dump.h
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include “core/dump.h
#include “helpers.h
#include “shared/helper.h”

Functions

static inline void ipt_dump_counters(const struct ipt_counters *counters, prefix_t *prefix)#

Dump content of ipt_counters structure.

Parameters:
  • countersipt_counters structure. Must be non-NULL.

  • plog_prefix structure.

static void ipt_dump_ip(const struct ipt_ip *ip, prefix_t *prefix)#

Dump content of ipt_ip structure.

Parameters:
  • ipipt_ip structure. Must be non-NULL.

  • plog_prefix structure.

static void ipt_dump_match(const struct ipt_entry_match *match, prefix_t *prefix)#

Dump content of ipt_entry_match structure.

Parameters:
  • matchipt_entry_match structure. Must be non-NULL.

  • plog_prefix structure.

static inline int _bf_ipt_convert_verdict(int verdict)#
static void ipt_dump_target(const struct ipt_entry_target *target, prefix_t *prefix)#

Dump content of ipt_entry_target structure.

Parameters:
  • targetipt_entry_target structure. Must be non-NULL.

  • plog_prefix structure.

void bf_ipt_dump_replace(struct ipt_replace *ipt, prefix_t *prefix)#

Dump content of bpfilter_ipt_replace structure.

Parameters:
  • ipt – iptable’s ipt_replace structure. Must be non-NULL.

  • prefix – Prefix to print on each line.

Variables

static const char * hook_name [] = {[NF_INET_PRE_ROUTING] = "PRE_ROUTING",   [NF_INET_LOCAL_IN] = "LOCAL_IN",[NF_INET_FORWARD] = "FORWARD",           [NF_INET_LOCAL_OUT] = "LOCAL_OUT",[NF_INET_POST_ROUTING] = "POST_ROUTING",}

Map each hook to its name as a string.

static const char * target_name [] = {[NF_DROP] = "DROP",   [NF_ACCEPT] = "ACCEPT", [NF_STOLEN] = "STOLEN",[NF_QUEUE] = "QUEUE", [NF_REPEAT] = "REPEAT", [NF_STOP] = "STOP",}

Map each target to its name as a string.

file dump.h
#include “core/logger.h

Defines

DUMP(p, fmt, ...)#

Dump prefixed-formatted string.

Parameters:
  • p – Prefix string.

  • fmt – Log format string.

  • ... – Variadic argument list for fmt.

IP4_SPLIT(addr)#

Split 32 bits IPv4 representation into four 8 bits components.

Parameters:
  • addr – 32 bits IPv4 address to split.

IP4_FMT#

Format to use with IP4_SPLIT to print an IPv4.

BIN_SPLIT(byte)#

Split a byte into 8 characters representing each bit.

Parameters:
  • byte – Byte to split.

BIN_FMT#

Format to use with BIN_SPLIT() to print a byte as 8 bits.

DUMP_PREFIX_LEN#

Maximum length of the prefix buffer.

Functions

typedef char (prefix_t)[DUMP_PREFIX_LEN]
void bf_dump_prefix_push(prefix_t *prefix)

Add a symbol to the prefix string.

Parameters:
  • prefix – Prefix string.

prefix_t *bf_dump_prefix_last(prefix_t *prefix)

Convert previous node to make is the last of the branch.

Parameters:
  • prefix – Prefix string.

Returns:

prefix

void bf_dump_prefix_pop(prefix_t *prefix)

Remove rightmost branch from the prefix string.

When a subtree is completed and we backout to a different branch, we need to remove the rightmost branch from the prefix to continue.

Parameters:
  • prefix – Prefix string.

void bf_dump_hex(prefix_t *prefix, const void *data, size_t len)

Dump the data buffer in hexedecimal format.

Each byte in data will be printed as 0x%02x, with 8 bytes on each row.

Parameters:
  • prefix – Prefix string.

  • data – Data buffer to print.

  • len – Size of the data buffer.

file dump.h
#include <stdbool.h>

Functions

void bf_program_dump_bytecode(const struct bf_program *program, bool with_raw)
file dump.h
#include “core/dump.h

Functions

void bf_ipt_dump_replace(struct ipt_replace *ipt, prefix_t *prefix)

Dump content of bpfilter_ipt_replace structure.

Parameters:
  • ipt – iptable’s ipt_replace structure. Must be non-NULL.

  • prefix – Prefix to print on each line.

file fixup.c
#include “fixup.h
#include <errno.h>
#include <stdlib.h>
#include “core/dump.h
#include “shared/helper.h”

Functions

const char *bf_fixup_type_to_str(enum bf_fixup_type type)#
const char *bf_fixup_function_to_str(enum bf_fixup_function function)#
int bf_fixup_new(struct bf_fixup **fixup)#
void bf_fixup_free(struct bf_fixup **fixup)#
void bf_fixup_dump(const struct bf_fixup *fixup, char (*prefix)[DUMP_PREFIX_LEN])#
file fixup.h
#include <stddef.h>
#include “core/dump.h

Defines

_cleanup_bf_fixup_#

Enums

enum bf_fixup_insn_type#

Values:

enumerator BF_CODEGEN_FIXUP_INSN_OFF#
enumerator BF_CODEGEN_FIXUP_INSN_IMM#
enumerator _BF_CODEGEN_FIXUP_INSN_MAX_MAX#
enum bf_fixup_function#

Values:

enumerator BF_CODEGEN_FIXUP_FUNCTION_ADD_COUNTER#
enumerator _BF_CODEGEN_FIXUP_FUNCTION_MAX#
enum bf_fixup_type#

Values:

enumerator BF_CODEGEN_FIXUP_NEXT_RULE#
enumerator BF_CODEGEN_FIXUP_JUMP_TO_CHAIN#
enumerator BF_CODEGEN_FIXUP_COUNTERS_INDEX#
enumerator BF_CODEGEN_FIXUP_MAP_FD#
enumerator BF_CODEGEN_FIXUP_FUNCTION_CALL#
enumerator _BF_CODEGEN_FIXUP_MAX#

Functions

const char *bf_fixup_type_to_str(enum bf_fixup_type type)
const char *bf_fixup_function_to_str(enum bf_fixup_function function)
int bf_fixup_new(struct bf_fixup **fixup)
void bf_fixup_free(struct bf_fixup **fixup)
void bf_fixup_dump(const struct bf_fixup *fixup, char (*prefix)[DUMP_PREFIX_LEN])
file jmp.c
#include “generator/jmp.h
#include “generator/program.h

Functions

void bf_jmpctx_cleanup(struct bf_jmpctx *ctx)

Cleanup function for bf_jmpctx.

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

file jmp.h
#include <linux/bpf.h>
#include <stddef.h>

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.

file nf.c
#include “generator/nf.h
#include <linux/bpf.h>
#include <linux/bpf_common.h>
#include <linux/if_ether.h>
#include <errno.h>
#include <stddef.h>
#include “core/bpf.h
#include “core/btf.h
#include “core/logger.h
#include “core/verdict.h
#include “generator/jmp.h
#include “generator/program.h
#include “generator/reg.h
#include “generator/stub.h
#include “shared/helper.h”
#include “external/filter.h

Functions

static int _nf_gen_inline_prologue(struct bf_program *program)#
static int _nf_gen_inline_epilogue(struct bf_program *program)#
static int _nf_get_verdict(enum bf_verdict verdict)#

Convert a standard verdict into a return value.

Parameters:
  • verdict – Verdict to convert. Must be valid.

Returns:

TC return code corresponding to the verdict, as an integer.

static int _nf_attach_prog_pre_unload(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#
static int _nf_attach_prog_post_unload(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#
static int _nf_detach_prog(struct bf_program *program)#

Unload the Netfilter BPF bytecode image.

Parameters:
  • codegen – Codegen containing the image to unload. Can’t be NULL.

Returns:

0 on success, negative error code on failure.

enum nf_inet_hooks bf_hook_to_nf_hook(enum bf_hook hook)#

Variables

const struct bf_flavor_ops bf_flavor_ops_nf = {.gen_inline_prologue = _nf_gen_inline_prologue, .gen_inline_epilogue = _nf_gen_inline_epilogue, .get_verdict = _nf_get_verdict, .attach_prog_pre_unload = _nf_attach_prog_pre_unload, .attach_prog_post_unload = _nf_attach_prog_post_unload, .detach_prog = _nf_detach_prog,}#
file nf.h
#include <net/if.h>
#include <linux/netfilter.h>
#include “core/flavor.h
#include “core/hook.h

Functions

enum nf_inet_hooks bf_hook_to_nf_hook(enum bf_hook hook)

Variables

const struct bf_flavor_ops bf_flavor_ops_nf
file print.c
#include “generator/print.h
#include <linux/bpf.h>
#include <stddef.h>
#include <stdint.h>
#include “core/bpf.h
#include “core/logger.h
#include “opts.h
#include “shared/helper.h”

Defines

make_print_str(id, str)#

Functions

size_t _bf_compute_offsets(void)#
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.

Variables

size_t offset#
size_t len#
const char *str#
static struct  _bf_print_strings []  = {     make_print_str(BF_PRINT_NO_DYNPTR, "failed to create a dynamic pointer"),     make_print_str(BF_PRINT_NO_SLICE,"failed to create a dynamic pointer slice"),make_print_str(BF_PRINT_NO_L2, "no L2 header available in packet data"),     make_print_str(BF_PRINT_NO_L3, "no L3 header available in packet data"),     make_print_str(BF_PRINT_NO_IPV4, "L3 header is not IPv4"),}
static int _bf_fd#
static const char *_bf_print_strs_path = "/sys/fs/bpf/bf_print_strs"#
file print.h
#include <stddef.h>

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.

file program.c
#include “generator/program.h
#include <net/if.h>
#include <linux/bpf.h>
#include <linux/bpf_common.h>
#include <linux/if_ether.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include “core/bpf.h
#include “core/btf.h
#include “core/counter.h
#include “core/flavor.h
#include “core/logger.h
#include “core/marsh.h
#include “core/rule.h
#include “core/verdict.h
#include “generator/stub.h
#include “shared/helper.h”
#include “external/filter.h

Defines

_BF_PROGRAM_DEFAULT_IMG_SIZE#

Functions

int bf_program_new(struct bf_program **program, int ifindex, enum bf_hook hook, enum bf_front front)#
void bf_program_free(struct bf_program **program)#
int bf_program_marsh(const struct bf_program *program, struct bf_marsh **marsh)#
int bf_program_unmarsh(const struct bf_marsh *marsh, struct bf_program **program)#
void bf_program_dump(const struct bf_program *program, prefix_t *prefix)#
static inline size_t _round_next_power_of_2(size_t x)#
int bf_program_grow_img(struct bf_program *program)#
static void _bf_program_fixup_insn(struct bpf_insn *insn, enum bf_fixup_insn_type type, int32_t v)#
static int _bf_program_fixup(struct bf_program *program, enum bf_fixup_type type, const union bf_fixup_attr *attr)#
static int _bf_program_generate_rule(struct bf_program *program, struct bf_rule *rule)#
static int _bf_program_generate_add_counter(struct bf_program *program)#

Generate a function to update the packets counter.

Assuming:

  • BF_ARG_1: file descriptor of the counters map.

  • BF_ARG_2: index of the rule in the counters map.

  • BF_ARG_3: packet size

    Todo:

    Random jump into the bytecode should be calculated by the daemon, not the developer.

    Create a fixup to jump to the end of a function.

    Set BF_REG_0 to !0 on failure, so we don’t drop the packet.

Parameters:
  • program – Program to emit the function into. Can not be NULL.

Returns:

0 on success, or negative errno value on error.

static int _bf_program_generate_functions(struct bf_program *program)#
static int _bf_program_load_counters_map(struct bf_program *program, int *fd)#
int bf_program_emit(struct bf_program *program, struct bpf_insn insn)#
int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)#
int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type, struct bpf_insn insn)#
int bf_program_emit_fixup_call(struct bf_program *program, enum bf_fixup_function function)#
static int _bf_program_generate_runtime_init(struct bf_program *program)#
int bf_program_generate(struct bf_program *program, bf_list *rules, enum bf_verdict policy)#
int bf_program_update(struct bf_program *program, bf_list *rules, enum bf_verdict policy)#

Update the program’s bytecode.

This function will regenerate the BPF bytecode for program based on the given rules. The new bytecode will be loaded into the kernel to replace the current program. The program’s metadata (ifindex, hook, front) will not be modified.

Note

This function purposefully update the bytecode and the program in one step. This is to ensure that the program is always in a consistent state.

Parameters:
  • program – Program to regenerate. Can not be NULL.

  • rules – List of rules to use to regenerate the program. Can not be NULL.

  • policy – Verdict to use when no rule matches. Must be one of bf_verdict.

Returns:

0 on success, negative errno code on failure.

int bf_program_load(struct bf_program *program, struct bf_program *prev_program)#

Load the program into the kernel.

Parameters:
  • program – Program to load. Can not be NULL.

  • prev_program – Previous program to unload. Can be NULL. If not NULL, bf_program_load will unload prev_program between attach_prog_pre_unload and attach_prog_post_unload calls.

Returns:

0 on success, negative errno code on failure.

int bf_program_unload(struct bf_program *program)#
int bf_program_get_counter(const struct bf_program *program, uint32_t counter_idx, struct bf_counter *counter)#
int bf_codegen_set_counters(struct bf_program *program, const struct bf_counter *counters)#
file program.h
#include <net/if.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <stddef.h>
#include <stdint.h>
#include “core/dump.h
#include “core/hook.h
#include “core/list.h
#include “core/verdict.h
#include “generator/fixup.h
#include “generator/print.h
#include “generator/reg.h
#include “shared/front.h”
#include “external/filter.h

Defines

PIN_PATH_LEN#
BF_PROG_CTX_OFF(field)#

Convenience macro to get the offset of a field in bf_program_context.

EMIT(program, x)#
EMIT_KFUNC_CALL(program, function)#
EMIT_FIXUP(program, type, insn)#
EMIT_FIXUP_CALL(program, function)#
EMIT_LOAD_FD_FIXUP(program, reg)#
_cleanup_bf_program_#

Functions

struct bf_program_context bf_aligned (8)
int bf_program_new(struct bf_program **program, int ifindex, enum bf_hook hook, enum bf_front front)
void bf_program_free(struct bf_program **program)
int bf_program_marsh(const struct bf_program *program, struct bf_marsh **marsh)
int bf_program_unmarsh(const struct bf_marsh *marsh, struct bf_program **program)
void bf_program_dump(const struct bf_program *program, prefix_t *prefix)
int bf_program_grow_img(struct bf_program *program)
int bf_program_emit(struct bf_program *program, struct bpf_insn insn)
int bf_program_emit_kfunc_call(struct bf_program *program, const char *name)
int bf_program_emit_fixup(struct bf_program *program, enum bf_fixup_type type, struct bpf_insn insn)
int bf_program_emit_fixup_call(struct bf_program *program, enum bf_fixup_function function)
int bf_program_generate(struct bf_program *program, bf_list *rules, enum bf_verdict policy)
int bf_program_update(struct bf_program *program, bf_list *rules, enum bf_verdict policy)

Update the program’s bytecode.

This function will regenerate the BPF bytecode for program based on the given rules. The new bytecode will be loaded into the kernel to replace the current program. The program’s metadata (ifindex, hook, front) will not be modified.

Note

This function purposefully update the bytecode and the program in one step. This is to ensure that the program is always in a consistent state.

Parameters:
  • program – Program to regenerate. Can not be NULL.

  • rules – List of rules to use to regenerate the program. Can not be NULL.

  • policy – Verdict to use when no rule matches. Must be one of bf_verdict.

Returns:

0 on success, negative errno code on failure.

int bf_program_load(struct bf_program *program, struct bf_program *prev_program)

Load the program into the kernel.

Parameters:
  • program – Program to load. Can not be NULL.

  • prev_program – Previous program to unload. Can be NULL. If not NULL, bf_program_load will unload prev_program between attach_prog_pre_unload and attach_prog_post_unload calls.

Returns:

0 on success, negative errno code on failure.

int bf_program_unload(struct bf_program *program)
int bf_program_get_counter(const struct bf_program *program, uint32_t counter_idx, struct bf_counter *counter)
int bf_program_set_counters(struct bf_program *program, const struct bf_counter *counters)#

Variables

void *arg#

Argument passed to the BPF program, it content depends on the BPF program type.

struct bpf_dynptr dynptr#

BPF dynamic pointer representing the packet data. Dynamic pointers are used with every program type.

uint64_t pkt_size#

Total size of the packet.

uint32_t l3_offset#

Offset of the layer 3 header in the packet.

uint32_t l4_offset#

Offset of the layer 4 header in the packet.

uint8_t l4_proto#

Layer 4 protocol. Set when the L3 header is processed. Used to define how many bytes to read when processing the packet.

struct ethhdr _ethhdr#
char l2raw#
union

Layer 2 header.

struct iphdr _iphdr#
char l3raw#
union

Layer 3 header.

struct icmphdr _icmphdr#
struct udphdr _udphdr#
struct tcphdr _tcphdr#
char l4raw#
union

Layer 4 header.

struct bf_program bf_aligned#
file reg.h
#include <linux/bpf.h>
#include “external/filter.h

Enums

enum bf_reg#

BPF registers aliases adapted to bpfilter usage.

Values:

enumerator BF_REG_0 = BPF_REG_0#
enumerator BF_REG_1 = BPF_REG_1#
enumerator BF_REG_2 = BPF_REG_2#
enumerator BF_REG_3 = BPF_REG_3#
enumerator BF_REG_4 = BPF_REG_4#
enumerator BF_REG_5 = BPF_REG_5#
enumerator BF_REG_6 = BPF_REG_6#
enumerator BF_REG_7 = BPF_REG_7#
enumerator BF_REG_8 = BPF_REG_8#
enumerator BF_REG_9 = BPF_REG_9#
enumerator BF_REG_10 = BPF_REG_10#
enumerator BF_ARG_1 = BPF_REG_1#
enumerator BF_ARG_2 = BPF_REG_2#
enumerator BF_ARG_3 = BPF_REG_3#
enumerator BF_ARG_4 = BPF_REG_4#
enumerator BF_ARG_5 = BPF_REG_5#
enumerator BF_REG_L2 = BPF_REG_6#
enumerator BF_REG_L3 = BPF_REG_7#
enumerator BF_REG_L4 = BPF_REG_8#
enumerator BF_REG_CTX = BPF_REG_9#
enumerator BF_REG_RET = BPF_REG_0#
enumerator BF_REG_FP = BPF_REG_FP#
file stub.c
#include “generator/stub.h
#include <arpa/inet.h>
#include <linux/bpf.h>
#include “core/flavor.h
#include “generator/jmp.h
#include “generator/program.h
#include “generator/reg.h
#include “shared/helper.h”
#include “external/filter.h

Functions

int bf_stub_memclear(struct bf_program *program, enum bf_reg addr_reg, size_t size)#

Emit instructions to clear a memory region.

Generate BPF instructions to clear (set to 0) a memory region, from a register containing the address of the memory region to clear, and the size.

Warning

The memory area must be aligned on 8 bytes (address and size), as the region is cleared 8 bytes at a time.

Parameters:
  • program – Program to emit instructions into.

  • addr_reg – Register containing the address to clear.

  • size – Size of the memory region to clear.

Returns:

0 on success, or negative errno value on error.

static int _stub_make_ctx_dynptr(struct bf_program *program, enum bf_reg arg_reg, const char *kfunc)#

Generate stub to create a dynptr.

Parameters:
  • program – Program to generate the stub for. Must not be NULL.

  • arg_reg – Register where the first argument to the dynptr creation function is located (SKB or xdp_md structure).

  • kfunc – Name of the kfunc to use to create the dynamic pointer.

Returns:

0 on success, or negative errno value on error.

int bf_stub_make_ctx_xdp_dynptr(struct bf_program *program, enum bf_reg md_reg)#

Emit instructions to get a dynptr for an XDP program.

Prepare arguments and call bpf_dynptr_from_xdp(). If the return value is different from 0, jump to the end of the program and accept the packet.

The initialised dynptr is stored in the program’s runtime context.

Parameters:
  • program – Program to emit instructions into.

  • md_reg – Scratch register containing the pointer to the xdp_md.

Returns:

0 on success, or negative errno value on error.

int bf_stub_make_ctx_skb_dynptr(struct bf_program *program, enum bf_reg skb_reg)#

Emit instructions to get a dynptr for an XDP program.

Prepare arguments and call bpf_dynptr_from_skb(). If the return value is different from 0, jump to the end of the program and accept the packet.

The initialised dynptr is stored in the program’s runtime context.

Parameters:
  • program – Program to emit instructions into.

  • skb_reg – Scratch register containing the pointer to the skb.

Returns:

0 on success, or negative errno value on error.

int bf_stub_get_l2_eth_hdr(struct bf_program *program)#

Emit instructions to get a dynptr slice for the packet’s L2 Ethernet header.

Store bpf_dynptr_slice arguments into:

  • BF_ARG_1: pointer to the dynptr located in the context.

  • BF_ARG_2: offset of the slice, in the dynptr. Always 0, as L2 Ethernet is the first header.

  • BF_ARG_3: pointer to the buffer to store the slice into. Each header buffer is located in the context.

  • BF_ARG_4: size of the buffer. Always ETH_HLEN, as L2 Ethernet is the first header. Then, call bpf_dynptr_slice(). If the return value is different from 0, jump to the end of the program. Finally:

  • Copy the address of the header into BF_REG_L2.

  • Load the header’s h_proto field to determine the L3 protocol. If L3 protocol is not IPv4 (the only supported protocol for now), jump to the end of the program.

  • Store the offset of the L3 header in the context.

Parameters:
  • program – Program to emit instructions into.

Returns:

0 on success, or negative errno value on error.

int bf_stub_get_l3_ipv4_hdr(struct bf_program *program)#

Emit instructions to get a dynptr slice for the packet’s L3 IPv4 header.

Store bpf_dynptr_slice arguments into:

  • BF_ARG_1: pointer to the dynptr located in the context.

  • BF_ARG_2: offset of the slice, in the dynptr. Get it from l3_offset field in the context. This field is either 0, or set when processing layer 2 header.

  • BF_ARG_3: pointer to the buffer to store the slice into.

  • BF_ARG_4: size of the buffer, expected to be an IPv4 header. Then, call bpf_dynptr_slice(). If the return value is different from 0, jump to the end of the program. Finally:

  • Store the address of the header into BF_REG_L3.

  • Compute the offset of the L4 header:

    • Load ip.ihl into BF_REG_1

    • Add ctx.l3_offset to it.

    • Copy it back to the context.

  • Store L4 protocol into the context.

Parameters:
  • program – Program to emit instructions into.

Returns:

0 on success, or negative errno value on error.

int bf_stub_get_l4_hdr(struct bf_program *program)#

Emit instructions to get a dynptr slice for the packet’s L4 header.

Store bpf_dynptr_slice arguments into:

  • BF_ARG_1: pointer to the dynptr located in the context.

  • BF_ARG_2: offset of the slice, in the dynptr. Get it from l4_offset field in the context. This field is set when processing layer 2 header.

  • BF_ARG_3: pointer to the buffer to store the slice into.

  • BF_ARG_4: size of the buffer, need to be computed depending ctx.l4_proto. If ctx.l4_proto is not supported, jump to the end of the program. Then, call bpf_dynptr_slice(). If the return value is different from 0, jump to the end of the program. Finally, copy the address of the header into BF_REG_L4.

Parameters:
  • program – Program to emit instructions into.

Returns:

0 on success, or negative errno value on error.

file stub.h
#include <stddef.h>
#include “generator/reg.h

Functions

int bf_stub_memclear(struct bf_program *program, enum bf_reg addr_reg, size_t size)

Emit instructions to clear a memory region.

Generate BPF instructions to clear (set to 0) a memory region, from a register containing the address of the memory region to clear, and the size.

Warning

The memory area must be aligned on 8 bytes (address and size), as the region is cleared 8 bytes at a time.

Parameters:
  • program – Program to emit instructions into.

  • addr_reg – Register containing the address to clear.

  • size – Size of the memory region to clear.

Returns:

0 on success, or negative errno value on error.

int bf_stub_make_ctx_xdp_dynptr(struct bf_program *program, enum bf_reg md_reg)

Emit instructions to get a dynptr for an XDP program.

Prepare arguments and call bpf_dynptr_from_xdp(). If the return value is different from 0, jump to the end of the program and accept the packet.

The initialised dynptr is stored in the program’s runtime context.

Parameters:
  • program – Program to emit instructions into.

  • md_reg – Scratch register containing the pointer to the xdp_md.

Returns:

0 on success, or negative errno value on error.

int bf_stub_make_ctx_skb_dynptr(struct bf_program *program, enum bf_reg skb_reg)

Emit instructions to get a dynptr for an XDP program.

Prepare arguments and call bpf_dynptr_from_skb(). If the return value is different from 0, jump to the end of the program and accept the packet.

The initialised dynptr is stored in the program’s runtime context.

Parameters:
  • program – Program to emit instructions into.

  • skb_reg – Scratch register containing the pointer to the skb.

Returns:

0 on success, or negative errno value on error.

int bf_stub_get_l2_eth_hdr(struct bf_program *program)

Emit instructions to get a dynptr slice for the packet’s L2 Ethernet header.

Store bpf_dynptr_slice arguments into:

  • BF_ARG_1: pointer to the dynptr located in the context.

  • BF_ARG_2: offset of the slice, in the dynptr. Always 0, as L2 Ethernet is the first header.

  • BF_ARG_3: pointer to the buffer to store the slice into. Each header buffer is located in the context.

  • BF_ARG_4: size of the buffer. Always ETH_HLEN, as L2 Ethernet is the first header. Then, call bpf_dynptr_slice(). If the return value is different from 0, jump to the end of the program. Finally:

  • Copy the address of the header into BF_REG_L2.

  • Load the header’s h_proto field to determine the L3 protocol. If L3 protocol is not IPv4 (the only supported protocol for now), jump to the end of the program.

  • Store the offset of the L3 header in the context.

Parameters:
  • program – Program to emit instructions into.

Returns:

0 on success, or negative errno value on error.

int bf_stub_get_l3_ipv4_hdr(struct bf_program *program)

Emit instructions to get a dynptr slice for the packet’s L3 IPv4 header.

Store bpf_dynptr_slice arguments into:

  • BF_ARG_1: pointer to the dynptr located in the context.

  • BF_ARG_2: offset of the slice, in the dynptr. Get it from l3_offset field in the context. This field is either 0, or set when processing layer 2 header.

  • BF_ARG_3: pointer to the buffer to store the slice into.

  • BF_ARG_4: size of the buffer, expected to be an IPv4 header. Then, call bpf_dynptr_slice(). If the return value is different from 0, jump to the end of the program. Finally:

  • Store the address of the header into BF_REG_L3.

  • Compute the offset of the L4 header:

    • Load ip.ihl into BF_REG_1

    • Add ctx.l3_offset to it.

    • Copy it back to the context.

  • Store L4 protocol into the context.

Parameters:
  • program – Program to emit instructions into.

Returns:

0 on success, or negative errno value on error.

int bf_stub_get_l4_hdr(struct bf_program *program)

Emit instructions to get a dynptr slice for the packet’s L4 header.

Store bpf_dynptr_slice arguments into:

  • BF_ARG_1: pointer to the dynptr located in the context.

  • BF_ARG_2: offset of the slice, in the dynptr. Get it from l4_offset field in the context. This field is set when processing layer 2 header.

  • BF_ARG_3: pointer to the buffer to store the slice into.

  • BF_ARG_4: size of the buffer, need to be computed depending ctx.l4_proto. If ctx.l4_proto is not supported, jump to the end of the program. Then, call bpf_dynptr_slice(). If the return value is different from 0, jump to the end of the program. Finally, copy the address of the header into BF_REG_L4.

Parameters:
  • program – Program to emit instructions into.

Returns:

0 on success, or negative errno value on error.

file tc.c
#include “generator/tc.h
#include <arpa/inet.h>
#include <linux/pkt_cls.h>
#include <bpf/libbpf.h>
#include <errno.h>
#include “core/context.h
#include “core/logger.h
#include “generator/codegen.h
#include “generator/program.h
#include “generator/reg.h
#include “generator/stub.h
#include “shared/front.h”
#include “shared/helper.h”
#include “external/filter.h

Functions

static int _tc_gen_inline_prologue(struct bf_program *program)#
static int _tc_gen_inline_epilogue(struct bf_program *program)#
static int _tc_get_verdict(enum bf_verdict verdict)#

Convert a standard verdict into a return value.

Parameters:
  • verdict – Verdict to convert. Must be valid.

Returns:

TC return code corresponding to the verdict, as an integer.

static int _tc_attach_prog_pre_unload(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#

Attach the loaded TC program to the proper hook.

Todo:

How should priority be handled?

This function, as well as many others, is using libbpf. Not all functions uses libbpf to communicate with the kernel. This should be unified.

Parameters:
  • program – Program to attach to the TC hook. Can’t be NULL, image must have been previously generated.

  • fd – File descriptor of the loaded BPF program. Can’t be negative.

  • attr – Attribute used for 2-step attach workflow.

Returns:

0 on success, negative error code on failure.

static int _tc_attach_prog_post_unload(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#
static int _tc_detach_prog(struct bf_program *program)#

Detach the TC BPF program.

Parameters:
  • program – Attached TC BPF program. Can’t be NULL.

Returns:

0 on success, negative errno value on failure.

enum bpf_tc_attach_point bf_hook_to_tc_hook(enum bf_hook hook)#

Convert bf_hook into a TC hook.

Parameters:
  • hook – Hook to convert. Must be valid TC hook.

Returns:

TC hook, as a bpf_tc_attach_point enumeration value.

Variables

const struct bf_flavor_ops bf_flavor_ops_tc = {.gen_inline_prologue = _tc_gen_inline_prologue, .gen_inline_epilogue = _tc_gen_inline_epilogue, .get_verdict = _tc_get_verdict, .attach_prog_pre_unload = _tc_attach_prog_pre_unload, .attach_prog_post_unload = _tc_attach_prog_post_unload, .detach_prog = _tc_detach_prog,}#
file tc.h
#include “core/flavor.h
#include “core/hook.h

Defines

bf_tc_program_handle(program)#

Generate a handle for a TC codegen.

Handles are a way to identify a BPF program within the TC namespace.

Parameters:
  • codegen – Codegen to generate a handle for.

Returns:

32 bits handle for the codegen.

Functions

enum bpf_tc_attach_point bf_hook_to_tc_hook(enum bf_hook hook)

Convert bf_hook into a TC hook.

Parameters:
  • hook – Hook to convert. Must be valid TC hook.

Returns:

TC hook, as a bpf_tc_attach_point enumeration value.

Variables

const struct bf_flavor_ops bf_flavor_ops_tc
file xdp.c
#include <linux/bpf.h>
#include <linux/bpf_common.h>
#include <stddef.h>
#include <unistd.h>
#include “core/bpf.h
#include “core/flavor.h
#include “core/logger.h
#include “core/verdict.h
#include “generator/program.h
#include “generator/reg.h
#include “generator/stub.h
#include “shared/helper.h”
#include “external/filter.h

Functions

static int _xdp_gen_inline_prologue(struct bf_program *program)#

Generate XDP program prologue.

Warning

bf_stub_get_l2_eth_hdr will check for L3 protocol. If L3 is not IPv4, the program will be terminated.

Parameters:
  • program – Program to generate the prologue for. Must not be NULL.

Returns:

0 on success, or negative errno value on error.

static int _xdp_gen_inline_epilogue(struct bf_program *program)#
static int _xdp_get_verdict(enum bf_verdict verdict)#
static int _xdp_attach_prog_pre_unload(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#
static int _xdp_attach_prog_post_unload(struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)#

Post unload attach callback.

See bf_flavor_ops::attach_prog_post_unload for more details.

Warning

At this point, the previous XDP program has been detached already. Meaning that no packet will be filtering until the function completes.

Parameters:
  • program – Program to unload. Must not be NULL.

  • prog_fd – File descriptor of the program to unload.

  • attr – Flavor-specific attributes. Unused for XDP.

Returns:

0 on success, or negative errno value on failure.

static int _xdp_detach_prog(struct bf_program *program)#

Variables

const struct bf_flavor_ops bf_flavor_ops_xdp = {.gen_inline_prologue = _xdp_gen_inline_prologue, .gen_inline_epilogue = _xdp_gen_inline_epilogue, .get_verdict = _xdp_get_verdict, .attach_prog_pre_unload = _xdp_attach_prog_pre_unload, .attach_prog_post_unload = _xdp_attach_prog_post_unload, .detach_prog = _xdp_detach_prog,}#
file xdp.h
#include “core/flavor.h

Variables

const struct bf_flavor_ops bf_flavor_ops_xdp
file main.c
#include <bits/types/sig_atomic_t.h>
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include “core/btf.h
#include “core/context.h
#include “core/helper.h
#include “core/logger.h
#include “core/marsh.h
#include “generator/print.h
#include “opts.h
#include “shared/front.h”
#include “shared/generic.h”
#include “shared/helper.h”
#include “shared/request.h”
#include “shared/response.h”
#include “xlate/front.h

Functions

void _sig_handler(int sig)#

Set atomic flag to stop the daemon if specific signals are received.

Parameters:
  • sig – Signal number.

static int _bf_ensure_runtime_dir(void)#

Ensure the daemon can use the runtime directory.

Check if the current process can access BF_RUNTIME_DIR. If it doesn’t exists, create it with the appropriate permissions. If it exists, check that it is a directory.

Returns:

0 on success, negative errno value on failure.

static int _bf_load(const char *path)#

Load bpfilter’s runtime context from disk.

Read the daemon’s runtime context from path and initialize the internal context with it.

Parameters:
  • path – Path to the context file.

Returns:

0 on success, negative error code on failure.

static int _bf_save(const char *path)#

Save bpfilter’s runtime context to disk.

Marshel the daemon’s runtime context and save it to path.

Parameters:
  • path – Path to the context file.

Returns:

0 on success, negative error code on failure.

static int _bf_init(int argc, char *argv[])#

Initialize bpfilter’s daemon runtime.

Setup signal handler (for graceful shutdown), load context from disk, and initialise various front-ends.

If no context can be loaded, a new one is initialized from scratch.

Front-ends’ init function is called every time. They are responsible for checking whether they need to perform any initialization or not, depending on the loaded runtime context.

Updated context is saved back to disk.

Todo:

Should the runtime context be saved unconditionally?

Returns:

0 on success, negative error code on failure.

static int _bf_clean(void)#

Clean up bpfilter’s daemon runtime.

Returns:

0 on success, negative error code on failure.

static int _process_request(struct bf_request *request, struct bf_response **response)#

Process a request.

The handler corresponding to request->front will be called (if any). If the handler returns 0, response is expected to be filled, and ready to be returned to the client. If the handler returns a negative error code, response is filled by process_request with a generated error response and 0 is returned. If generating the error response fails, then 0 is returned.

In other words, if 0 is returned, response is ready to be sent back, if a negative error code is returned, an error occured during request processing, and no response is available.

Parameters:
  • request – Request to process.

  • response – Response to fill.

Returns:

0 on success, negative error code on failure.

static int _run(void)#

Loop and process requests.

Create a socket and perform blocking accept() calls. For each connection, receive a request, process it, and send the response back.

If a signal is received, _stop_received will be set to 1 by _sig_handler and blocking call to accept() will be interrupted.

Returns:

0 on success, negative error code on failure.

int main(int argc, char *argv[])#

Variables

static volatile sig_atomic_t _stop_received = 0#

Global flag to indicate whether the daemon should stop.

static const char * context_path   = BF_RUNTIME_DIR "/data.bin"

Path to bpfilter’s runtime context file.

bpfilter will periodically save its internal context back to disk, to prevent spurious service interruption to lose information about the current state of the daemon.

This runtime context is read back when the daemon is restarted, so bpfilter can manage the BPF programs that survived the daemon reboot.

file opts.c
#include “opts.h
#include <argp.h>
#include <stdint.h>
#include “core/logger.h
#include “shared/helper.h”

Functions

static error_t _bf_opts_parser(int key, char *arg, struct argp_state *state)#

argp callback to process command line arguments.

Returns:

0 on succcess, non-zero on failure.

int bf_opts_init(int argc, char *argv[])#
bool bf_opts_transient(void)#
unsigned int bf_opts_bpf_log_buf_len_pow(void)#
bool bf_opts_is_front_enabled(enum bf_front front)#
bool bf_opts_verbose(void)#

Variables

static struct bf_options _opts = {.transient = false, .bpf_log_buf_len_pow = 16, .fronts = 0xffff, .verbose = false,}#
static struct argp_option options [] = {{"transient", 't', 0, 0,"Do not load or save runtime context and remove all BPF programs on shutdown",0},{"buffer-len", 'b', "BUF_LEN_POW", 0,"Size of the BPF log buffer as a power of 2 (only used when --verbose is used). Default: 16.",0},{"no-iptables", 0x01, 0, 0, "Disable iptables support", 0},{"no-nftables", 0x02, 0, 0, "Disable nftables support", 0},{"verbose", 'v', 0, 0, "Print debug logs", 0},{0},}
file opts.h
#include <stdbool.h>
#include “shared/front.h”

Functions

int bf_opts_init(int argc, char *argv[])
bool bf_opts_transient(void)
unsigned int bf_opts_bpf_log_buf_len_pow(void)
bool bf_opts_is_front_enabled(enum bf_front front)
bool bf_opts_verbose(void)
file front.c
#include “front.h
#include “shared/helper.h”

Functions

const struct bf_front_ops *bf_front_ops_get(enum bf_front front)#

Retrieve the bf_front_ops structure for a specific front.

Parameters:
Returns:

Variables

const struct bf_front_ops ipt_front#
const struct bf_front_ops nft_front#
file front.h
#include “shared/front.h”

Functions

const struct bf_front_ops *bf_front_ops_get(enum bf_front front)

Retrieve the bf_front_ops structure for a specific front.

Parameters:
Returns:

file helpers.h
#include <linux/netfilter_ipv4/ip_tables.h>

Defines

ipt_is_hook_enabled(replace, hook)#

Check whether hook is enabled in ipt_replace structure.

Parameters:
  • replaceipt_replace structure.

  • hook – Hook to test.

Returns:

0 if hook is not enabled, any value otherwise.

ipt_get_match(entry, offset)#

Get ipt_entry's match at offset.

Parameters:
  • entryipt_entry structure the get the match from. Must be non-NULL.

  • offset – Offset of the match to get.

Returns:

Pointer to the match at offset in ipt_entry.

ipt_get_target(entry)#

Get ipt_entry's target.

Parameters:
  • entryipt_entry structure to get the target from.

Returns:

Pointer to the target assigned to ipt_entry.

ipt_get_first_rule(replace, hook)#

Get first rule for hook in ipt_replace.

Parameters:
  • replaceipt_replace structure.

  • hook – Hook to get the first rule for.

Returns:

Pointer to the first rule for hook.

ipt_get_next_rule(entry)#

Get rule following ipt_entry.

Parameters:
  • entryipt_entry structure.

Returns:

Pointer to the next rule.

ipt_get_last_rule(replace, hook)#

Get last rule for hook in ipt_replace.

Parameters:
  • replaceipt_replace structure.

  • hook – Hook to get the last rule for.

Returns:

Pointer to the last rule for hook.

file ipt.c
#include “shared/ipt.h”
#include <net/if.h>
#include <linux/in.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include “core/context.h
#include “core/counter.h
#include “core/flavor.h
#include “core/hook.h
#include “core/list.h
#include “core/logger.h
#include “core/marsh.h
#include “core/match.h
#include “core/rule.h
#include “core/verdict.h
#include “generator/codegen.h
#include “generator/program.h
#include “shared/front.h”
#include “shared/helper.h”
#include “shared/request.h”
#include “shared/response.h”
#include “xlate/front.h
#include “xlate/ipt/dump.h
#include “xlate/ipt/helpers.h

Warning

Only LOCAL_IN and LOCAL_OUT chains are currently supported, until BPF_NETFILTER programs can be generated. To ensure only those rules are processed, we store the index and length of the chains statically.

Defines

_cleanup_bf_ipt_cache_#

Functions

static void _bf_ipt_cache_free(struct bf_ipt_cache **cache)#
static int _bf_ipt_setup(void)#
static int _bf_ipt_teardown(void)#
static int _bf_ipt_request_handler(struct bf_request *request, struct bf_response **response)#

Todo:

Wouldn’t it be better to have a separate handler for each request type? In which case struct bf_front_ops would contain a handler for each request type, and the front would handle custom (BF_REQ_CUSTOM) requests itself.

Document that request and responses are not const: they will be free by the daemon once the front is done with them. Hence, the front is free to modify the requests content.

Check bf_assertions: a malformed request could cause the daemon to crash.

Parameters:
  • request

  • response

Returns:

static int _bf_ipt_marsh(struct bf_marsh **marsh)#
static int _bf_ipt_unmarsh(struct bf_marsh *marsh)#
static enum bf_hook _bf_ipt_hook_to_bf_hook(enum nf_inet_hooks ipt_hook)#

Convert an iptables hook to a bpfilter hook.

Parameters:
  • ipt_hook – iptables hook. Must be valid.

Returns:

bpfilter hook.

static int _bf_ipt_cache_new(struct bf_ipt_cache **cache)#
static int _bf_ipt_target_to_verdict(struct ipt_entry_target *ipt_target, enum bf_verdict *verdict)#

Convert an iptables target to a bpfilter verdict.

Parameters:
  • ipt_target – iptables target to convert.

  • verdict – Verdict to store the conversion in.

Returns:

0 on success, negative error code on failure.

static int _bf_ipt_to_match(const struct ipt_entry_match *ipt_match, struct bf_match **match)#

Translate an iptables match into a bpfilter match.

Todo:

Convert actual match content.

Parameters:
  • ipt_match – iptables match to translate.

  • match – Match to store the translation in.

Returns:

0 on success, negative error code on failure.

static int _bf_ipt_to_rule(const struct ipt_entry *ipt_rule, struct bf_rule **rule)#

Translate an iptables rule into a bpfilter rule.

Todo:

Bound check the target.

Parameters:
  • ipt_rule – iptables rule to translate.

  • rule – Rule to store the translation in.

Returns:

0 on success, negative error code on failure.

static bool _ipt_entry_is_empty(const struct ipt_entry *entry)#
static int _ipt_xlate_set_rules(struct ipt_replace *ipt, struct bf_codegen *(*codegens)[_BF_HOOK_MAX])#

Translate iptables rules into bpfilter format.

Parameters:
  • ipt – iptables rules.

  • codegens – Array of codegens, indexed by hook. At most one codegen per hook will be generated.

Returns:

0 on success, negative error code on failure.

static int _bf_ipt_set_rules_handler(struct ipt_replace *replace, size_t len)#

Modify existing iptables rules.

Todo:

If processing for any codegen fails, all codegens should be unloaded and/or discarded.

Parameters:
  • replace – New rules, in iptables format.

  • len – Length of the new rules.

Returns:

0 on success, negative error code on failure.

static int _bf_ipt_set_counters_handler(struct xt_counters_info *counters, size_t len)#

Set counters for a rule.

Todo:

Actually update the counters.

Parameters:
  • counters – iptables structure containing the counters and their value.

  • len – Length of the counters structure.

Returns:

0 on success, negative error code on failure.

int _bf_ipt_get_info_handler(struct bf_request *request, struct bf_response **response)#
int _bf_ipt_get_entries_handler(struct bf_request *request, struct bf_response **response)#

Get the entries of a table, including counters.

Parameters:
  • request

  • response

Returns:

0 on success, negative errno value on failure.

Variables

static struct bf_ipt_cache *_cache = NULL#
static unsigned char _default_ipt_filter[]#

Default iptables filter table. Required to initialize iptables.

const struct bf_front_ops ipt_front = {.setup = _bf_ipt_setup, .teardown = _bf_ipt_teardown, .request_handler = _bf_ipt_request_handler, .marsh = _bf_ipt_marsh, .unmarsh = _bf_ipt_unmarsh,}
file nfgroup.c
#include “xlate/nft/nfgroup.h
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <errno.h>
#include <limits.h>
#include <netlink/msg.h>
#include “core/list.h
#include “shared/response.h”
#include “xlate/nft/nfmsg.h

Functions

int bf_nfgroup_new(struct bf_nfgroup **group)

Create a new Netlink messages group.

Parameters:
  • group – Pointer to the new messages group. Must not be NULL. Will be allocated and initialised by this function. Can’t be NULL.

Returns:

0 on success, or negative errno value on error.

int bf_nfgroup_new_from_stream(struct bf_nfgroup **group, struct nlmsghdr *nlh, size_t length)

Create a new Netlink messages group from a stream of nlmsghdr.

Parameters:
  • msg – Pointer to the new message. Must not be NULL. Will be allocated and initialised by this function.

  • nlh – Pointer to the first nlmsghdr in the stream. Must not be NULL.

  • length – Total length of the stream.

Returns:

0 on success, or negative errno value on error.

void bf_nfgroup_free(struct bf_nfgroup **group)

Free a Netlink messages group.

Parameters:
  • msg – Pointer to the messages group to free. If msg is NULL, nothing is done.

const bf_list *bf_nfgroup_messages(const struct bf_nfgroup *group)

Get the list of messages in the Netlink messages group.

Parameters:
  • group – Netlink messages group to get the list from. Can’t be NULL.

Returns:

bf_list containing the bf_nfmsg

size_t bf_nfgroup_size(const struct bf_nfgroup *group)

Get the total Netlink message size.

The total size of the Netlink message is the sum of the size of all the messages, including padding.

Parameters:
  • group – Netlink messages group to get the size of. Can’t be NULL.

Returns:

Total size of the Netlink messages group.

bool bf_nfgroup_is_empty(const struct bf_nfgroup *group)

Test if a Netlink message group is empty.

Parameters:
  • group – Netlink message to check. Can’t be NULL.

Returns:

True if the Netlink message is empty (no messages), false otherwise.

int bf_nfgroup_add_message(struct bf_nfgroup *group, struct bf_nfmsg *msg)

Add a Netlink message to the Netlink messages group.

Parameters:
  • group – Netlink messages group to add the message to. Can’t be NULL.

  • group – Message to add to the messages group. Can’t be NULL. The Netlink messages group takes onwership of the message.

Returns:

0 on success, or negative errno value on error.

int bf_nfgroup_add_new_message(struct bf_nfgroup *group, struct bf_nfmsg **msg, uint16_t command, uint16_t seqnr)

Create a new Netfilter Netlink message and add it to a Netlink messages group.

The new Netfilter Netlink message is owned by the messages group and should not be freed by the caller.

Parameters:
  • group – Netlink messages group to add the message to. Can’t be NULL.

  • msg – Pointer to the new message. Once the function succeeds, this pointer will be set to the new message. Can be NULL, in which case the caller won’t have access to the new message.

  • command – Netlink message command.

  • seqnr – Netlink message sequence number.

Returns:

0 on success, or negative errno value on error.

int bf_nfgroup_to_response(const struct bf_nfgroup *group, struct bf_response **resp)

Convert a Netlink messages group into a bf_response.

All the Netfilter Netlink messages contained in the group will written contiguously in the payload of a single bf_response .

If only one message is present in the group, the response will contain only the message payload. If more than one message is present, the response will contain a multipart message, with the NLM_F_MULTI flag set on all the messages and a final NLMSG_DONE message.

If the group is empty, the reponse will contain a single NLMSG_DONE message.

Parameters:
  • group – Netlink messages group to convert. Can’t be NULL.

  • resp – Pointer to the new response. Can’t be NULL. A new response will be allocated by this function and the caller will be responsible for freeing it.

Returns:

0 on success, or negative errno value on error.

file nfgroup.h
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include “core/list.h

Netlink allows data to be sent in multipart messages, which is a stream of multiple Netlink messages (each with its own header), flagged with NLM_F_MULTI and ending with a final message of type NLMSG_DONE

bf_nfgroup is an abstraction to represent multipart messages. It contains a list of bf_nfmsg, each of which is a Netlink message.

The messages group can be converted into a single bf_response, which is a contiguous buffer containing all the messages in the group.

Defines

_cleanup_bf_nfgroup_

Cleanup function for bf_nfgroup.

Functions

int bf_nfgroup_new(struct bf_nfgroup **group)

Create a new Netlink messages group.

Parameters:
  • group – Pointer to the new messages group. Must not be NULL. Will be allocated and initialised by this function. Can’t be NULL.

Returns:

0 on success, or negative errno value on error.

int bf_nfgroup_new_from_stream(struct bf_nfgroup **group, struct nlmsghdr *nlh, size_t length)

Create a new Netlink messages group from a stream of nlmsghdr.

Parameters:
  • msg – Pointer to the new message. Must not be NULL. Will be allocated and initialised by this function.

  • nlh – Pointer to the first nlmsghdr in the stream. Must not be NULL.

  • length – Total length of the stream.

Returns:

0 on success, or negative errno value on error.

void bf_nfgroup_free(struct bf_nfgroup **group)

Free a Netlink messages group.

Parameters:
  • msg – Pointer to the messages group to free. If msg is NULL, nothing is done.

const bf_list *bf_nfgroup_messages(const struct bf_nfgroup *group)

Get the list of messages in the Netlink messages group.

Parameters:
  • group – Netlink messages group to get the list from. Can’t be NULL.

Returns:

bf_list containing the bf_nfmsg

size_t bf_nfgroup_size(const struct bf_nfgroup *group)

Get the total Netlink message size.

The total size of the Netlink message is the sum of the size of all the messages, including padding.

Parameters:
  • group – Netlink messages group to get the size of. Can’t be NULL.

Returns:

Total size of the Netlink messages group.

bool bf_nfgroup_is_empty(const struct bf_nfgroup *group)

Test if a Netlink message group is empty.

Parameters:
  • group – Netlink message to check. Can’t be NULL.

Returns:

True if the Netlink message is empty (no messages), false otherwise.

int bf_nfgroup_add_message(struct bf_nfgroup *group, struct bf_nfmsg *msg)

Add a Netlink message to the Netlink messages group.

Parameters:
  • group – Netlink messages group to add the message to. Can’t be NULL.

  • group – Message to add to the messages group. Can’t be NULL. The Netlink messages group takes onwership of the message.

Returns:

0 on success, or negative errno value on error.

int bf_nfgroup_add_new_message(struct bf_nfgroup *group, struct bf_nfmsg **msg, uint16_t command, uint16_t seqnr)

Create a new Netfilter Netlink message and add it to a Netlink messages group.

The new Netfilter Netlink message is owned by the messages group and should not be freed by the caller.

Parameters:
  • group – Netlink messages group to add the message to. Can’t be NULL.

  • msg – Pointer to the new message. Once the function succeeds, this pointer will be set to the new message. Can be NULL, in which case the caller won’t have access to the new message.

  • command – Netlink message command.

  • seqnr – Netlink message sequence number.

Returns:

0 on success, or negative errno value on error.

int bf_nfgroup_to_response(const struct bf_nfgroup *group, struct bf_response **resp)

Convert a Netlink messages group into a bf_response.

All the Netfilter Netlink messages contained in the group will written contiguously in the payload of a single bf_response .

If only one message is present in the group, the response will contain only the message payload. If more than one message is present, the response will contain a multipart message, with the NLM_F_MULTI flag set on all the messages and a final NLMSG_DONE message.

If the group is empty, the reponse will contain a single NLMSG_DONE message.

Parameters:
  • group – Netlink messages group to convert. Can’t be NULL.

  • resp – Pointer to the new response. Can’t be NULL. A new response will be allocated by this function and the caller will be responsible for freeing it.

Returns:

0 on success, or negative errno value on error.

file nfmsg.c
#include “xlate/nft/nfmsg.h
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
#include <errno.h>
#include <limits.h>
#include <netlink/msg.h>
#include “core/logger.h
#include “shared/helper.h”

Functions

int bf_nfmsg_new(struct bf_nfmsg **msg, uint8_t command, uint32_t seqnr)

Create a new Netfilter Netlink message.

Parameters:
  • msg – The new message to allocate and initialise. Can’t be NULL.

  • command – Command to send, can be any of nf_tables_msg_types.

  • seqnr – Sequence number for the message.

Returns:

0 on success, or negative errno value on failure.

int bf_nfmsg_new_done(struct bf_nfmsg **msg)

Create a new Netfilter Netlink NLMSG_DONE message.

Parameters:
  • msg – The new message to allocate and initialise. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

int bf_nfmsg_new_from_nlmsghdr(struct bf_nfmsg **msg, struct nlmsghdr *nlh)

Create a new Netfilter Netlink message from an existing Netlink message.

The provided nlmsghdr must be a valid Netlink message targeted to the NFNL_SUBSYS_NFTABLES subsystem, and containing a nfgenmsg header.

Parameters:
  • msg – The new message to allocate and initialise. Can’t be NULL.

  • nlh – Netlink message to create the Netfilter Netlink message from. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

void bf_nfmsg_free(struct bf_nfmsg **msg)

Free a Netfilter Netlink message.

If msg is NULL, this function has no effect. Before returning, msg is set to NULL.

Parameters:
  • msg – Message to free. Must be non-NULL.

struct nlmsghdr *bf_nfmsg_hdr(const struct bf_nfmsg *msg)

Get the Netlink message header for a Netfilter Netlink message.

Parameters:
  • msg – Message to get the header from. Must be non-NULL.

Returns:

The Netlink message header.

size_t bf_nfmsg_data_len(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s payload size, including padding.

Parameters:
  • msg – Message to get the payload size of. Can’t be NULL.

Returns:

Message’s payload size, including padding.

size_t bf_nfmsg_len(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s size, including header and padding.

Parameters:
  • msg – Message to get the size of. Can’t be NULL.

Returns:

Message’s size, including header and padding.

uint8_t bf_nfmsg_command(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s command.

Parameters:
  • msg – Message to get the command from. Can’t be NULL.

Returns:

The message’s command.

uint32_t bf_nfmsg_seqnr(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s sequence number.

Parameters:
  • msg – Message to get the sequence number from. Can’t be NULL.

Returns:

The message’s sequence number.

int bf_nfmsg_attr_push(struct bf_nfmsg *msg, uint16_t type, const void *data, size_t len)

Push a new attribute into a Netfilter Netlink message.

Parameters:
  • msg – Message to push the attribute to. Can’t be NULL.

  • type – Attribute type.

  • data – Attribute data. Can’t be NULL.

  • len – Attribute data length.

Returns:

0 on success, or negative errno value on failure.

int bf_nfmsg_parse(const struct bf_nfmsg *msg, bf_nfattr **attrs, int maxtype, const bf_nfpolicy *policy)

Parse attributes from a Netfilter Netlink message.

All the attributes contained in the message are parsed and stored in the attrs array. Nested attributes (attributes contained within other) are not parsed, see bf_nfattr_parse instead.

Parameters:
  • msg – Message to parse the attributes from. Can’t be NULL.

  • attrs – Array of attributes to parse. Can’t be NULL.

  • maxtype – Maximum attribute type to parse.

  • policy – Netlink validation policy to use. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

int bf_nfattr_parse(bf_nfattr *attr, bf_nfattr **attrs, int maxtype, const bf_nfpolicy *policy)

Parse attributes nested within a Netlink attribute.

All the attributes contained in the attr are parsed and stored in the attrs array.

Parameters:
  • attr – Attribute to parse the nested attributes from. Can’t be NULL.

  • attrs – Array of attributes to parse. Can’t be NULL.

  • maxtype – Maximum attribute type to parse.

  • policy – Netlink validation policy to use. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

void *bf_nfattr_data(bf_nfattr *attr)

Get the data of a Netlink attribute.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

size_t bf_nfattr_data_len(bf_nfattr *attr)

Get a Netlink attribute’s payload size, including padding.

Parameters:
  • attr – Attribute the get the payload size of. Can’t be NULL.

Returns:

Attribute’s payload size, including padding.

bool bf_nfattr_is_ok(bf_nfattr *attr, size_t remaining)

Check if a Netlink attribute (and its payload) is valid.

If the function returns false, the attribute and its content can’t be accessed safely.

Parameters:
  • attr – Attribute to validate. Can’t be NULL.

  • remaining – Remaining bytes in the parent message or attribute. Can’t be negative.

Returns:

true if the attribute is valid, false otherwise.

bf_nfattr *bf_nfattr_next(bf_nfattr *attr, size_t *remaining)

Get the next Netlink attribute in a message or in a nested attribute.

Parameters:
  • attr – Attribute to get the next attribute from. Can’t be NULL.

  • remaining – Remaining bytes in the parent message or attribute. Can’t be NULL. When the function succeeds, it is updated with the remaining bytes in the parent message or attribute.

Returns:

Pointer to the next attribute, or NULL if there are no more

int bf_nfmsg_nest_init(struct bf_nfnest *nest, struct bf_nfmsg *parent, uint16_t type)

Declares a new nested attribute within parent.

Once a nested attribute has been defined, all the attributes added to the part (parent here) will be added within the nested attribute, until it is closed (bf_nfnest_cleanup).

Parameters:
  • nest – Pointer to the nested attribute. Must be an allocated bf_nfmsg_next structure. Can’t be NULL.

  • parentbf_nfmsg containing the nested attribute.

  • type – Type of the nested attribute.

Returns:

0 on success, negative errno value on error.

void bf_nfnest_cleanup(struct bf_nfnest *nest)

Close a nested attribute.

Parameters:
  • nest – Nested attribute to close. Can’t be NULL.

Variables

static const struct nla_policy _bf_nf_table_policy [__NFTA_TABLE_MAX] = {[NFTA_TABLE_NAME] = {.type = NLA_STRING},[NFTA_TABLE_FLAGS] = {.type = NLA_U32},[NFTA_TABLE_HANDLE] = {.type = NLA_U64},[NFTA_TABLE_USERDATA] = {.type = NLA_BINARY},}
const bf_nfpolicy *bf_nf_table_policy = _bf_nf_table_policy

Netlink validation policy for nft_table_attributes.

static const struct nla_policy _bf_nf_chain_policy [__NFTA_CHAIN_MAX] = {[NFTA_CHAIN_TABLE] = {.type = NLA_STRING},[NFTA_CHAIN_HANDLE] = {.type = NLA_U64},[NFTA_CHAIN_NAME] = {.type = NLA_STRING},[NFTA_CHAIN_HOOK] = {.type = NLA_NESTED},[NFTA_CHAIN_POLICY] = {.type = NLA_U32},[NFTA_CHAIN_TYPE] = {.type = NLA_STRING},[NFTA_CHAIN_COUNTERS] = {.type = NLA_NESTED},[NFTA_CHAIN_FLAGS] = {.type = NLA_U32},[NFTA_CHAIN_ID] = {.type = NLA_U32},[NFTA_CHAIN_USERDATA] = {.type = NLA_BINARY},}
const bf_nfpolicy *bf_nf_chain_policy = _bf_nf_chain_policy

Netlink validation policy for nft_chain_attributes.

static const struct nla_policy _bf_nf_hook_policy [__NFTA_HOOK_MAX] = {[NFTA_HOOK_HOOKNUM] = {.type = NLA_U32},[NFTA_HOOK_PRIORITY] = {.type = NLA_U32},[NFTA_HOOK_DEV] = {.type = NLA_STRING},}
const bf_nfpolicy *bf_nf_hook_policy = _bf_nf_hook_policy

Netlink validation policy for nft_hook_attributes.

static const struct nla_policy _bf_nf_rule_policy [__NFTA_RULE_MAX] = {[NFTA_RULE_TABLE] = {.type = NLA_STRING},[NFTA_RULE_CHAIN] = {.type = NLA_STRING},[NFTA_RULE_HANDLE] = {.type = NLA_U64},[NFTA_RULE_EXPRESSIONS] = {.type = NLA_NESTED},[NFTA_RULE_COMPAT] = {.type = NLA_NESTED},[NFTA_RULE_POSITION] = {.type = NLA_U64},[NFTA_RULE_USERDATA] = {.type = NLA_BINARY},[NFTA_RULE_ID] = {.type = NLA_U32},[NFTA_RULE_POSITION_ID] = {.type = NLA_U32},[NFTA_RULE_CHAIN_ID] = {.type = NLA_U32},}
const bf_nfpolicy *bf_nf_rule_policy = _bf_nf_rule_policy

Netlink validation policy for nft_rule_attributes.

static const struct nla_policy _bf_nf_expr_policy [__NFTA_EXPR_MAX] = {[NFTA_EXPR_NAME] = {.type = NLA_STRING},[NFTA_EXPR_DATA] = {.type = NLA_NESTED},}
const bf_nfpolicy *bf_nf_expr_policy = _bf_nf_expr_policy

Netlink validation policy for nft_expr_attributes.

static const struct nla_policy _bf_nf_counter_policy [NFTA_COUNTER_MAX+1] = {[NFTA_COUNTER_PACKETS] = {.type = NLA_U64},[NFTA_COUNTER_BYTES] = {.type = NLA_U64},}
const bf_nfpolicy *bf_nf_counter_policy = _bf_nf_counter_policy

Netlink validation policy for nft_counter_attributes.

static const struct nla_policy _bf_nf_payload_policy [__NFTA_PAYLOAD_MAX] = {[NFTA_PAYLOAD_SREG] = {.type = NLA_U32},[NFTA_PAYLOAD_DREG] = {.type = NLA_U32},[NFTA_PAYLOAD_BASE] = {.type = NLA_U32},[NFTA_PAYLOAD_OFFSET] = {.type = NLA_U32},[NFTA_PAYLOAD_LEN] = {.type = NLA_U32},[NFTA_PAYLOAD_CSUM_TYPE] = {.type = NLA_U32},[NFTA_PAYLOAD_CSUM_OFFSET] = {.type = NLA_U32},[NFTA_PAYLOAD_CSUM_FLAGS] = {.type = NLA_U32},}
const bf_nfpolicy *bf_nf_payload_policy = _bf_nf_payload_policy

Netlink validation policy for nft_payload_attributes.

static const struct nla_policy _bf_nf_cmp_policy [__NFTA_CMP_MAX] = {[NFTA_CMP_SREG] = {.type = NLA_U32},[NFTA_CMP_OP] = {.type = NLA_U32},[NFTA_CMP_DATA] = {.type = NLA_NESTED},}
const bf_nfpolicy *bf_nf_cmp_policy = _bf_nf_cmp_policy

Netlink validation policy for nft_cmp_attributes.

static const struct nla_policy _bf_nf_immediate_policy [__NFTA_IMMEDIATE_MAX] = {[NFTA_IMMEDIATE_DREG] = {.type = NLA_U32},[NFTA_IMMEDIATE_DATA] = {.type = NLA_NESTED},}
const bf_nfpolicy *bf_nf_immediate_policy = _bf_nf_immediate_policy

Netlink validation policy for nft_immediate_attributes.

static const struct nla_policy _bf_nf_data_policy [__NFTA_DATA_MAX] = {[NFTA_DATA_VALUE] = {.type = NLA_BINARY},[NFTA_DATA_VERDICT] = {.type = NLA_NESTED},}
const bf_nfpolicy *bf_nf_data_policy = _bf_nf_data_policy

Netlink validation policy for nft_data_attributes.

static const struct nla_policy _bf_nf_verdict_policy [__NFTA_VERDICT_MAX] = {[NFTA_VERDICT_CODE] = {.type = NLA_U32},[NFTA_VERDICT_CHAIN] = {.type = NLA_STRING},[NFTA_VERDICT_CHAIN_ID] = {.type = NLA_U32},}
const bf_nfpolicy *bf_nf_verdict_policy = _bf_nf_verdict_policy

Netlink validation policy for nft_verdict_attributes.

file nfmsg.h
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

nftables communicates with the kernel using Netlink messages. To reduce the work needed by nftables to support bpfilter the same communication mechanism is used. Hence, bpfilter will receive Netlink messages from nftables and will send Netlink messages to nftables.

This file provides a set of functions to create, parse, and manipulate Netlink messages. It also provides a set of Netlink validation policies for the different Netlink attributes used by nftables.

All the functions defined in this file are dedicated to Netfilter Netlink messages and are not suitable for generic Netlink communication.

Messages#

bf_nfmsg is a structure used to represent Netlink messages. It is an opaque structure, so the user must go through the dedicated API to create, parse, and manipulate Netlink messages.

Netlink attributes can be pushed into the message using the generic function bf_nfmsg_attr_push. However, for common types, convenience macros are provided to push a string, a uint8_t, a uint16_t, a uint32_t, or a uint64_t attribute.

Attributes#

bf_nfattr is a structure used to represent Netlink attributes. It is an opaque structure, so the user must go through the dedicated API to create, parse, and manipulate Netlink attributes.

Nested attributes#

bf_nfnest represent a virtual stack of nested attributes. It is used to create and close nested attributes within a Netlink message.

bf_nfmsg_nest_init declares a new nested attribute within a bf_nfmsg. Every attribute added to the message after calling this function will be pushed within the nested attribute. When complete, bf_nfnest_cleanup must be called to close the nested attribute.

The nested attribute is a stack, so it is possible to have nested attributes within nested attributes.

Defines

_cleanup_bf_nfmsg_

Cleanup attribute for a bf_nfmsg variable.

bf_nfmsg_attr_push_or_jmp(msg, type, data, size)

Convenience macro to push a new attribute into a Netfilter Netlink message, but jump to a label on failure.

If the attribute push fails, this macro jumps to the label bf_nfmsg_push_failure.

Parameters:
  • msg – Message to push the attribute to. Can’t be NULL.

  • type – Attribute type.

  • data – Attribute data. Can’t be NULL.

  • size – Attribute data length.

bf_nfmsg_push_str(msg, attr, data)

Convenience macro to push a new string attribute into a Netfilter Netlink message. See bf_nfmsg_attr_push for more details.

bf_nfmsg_push_str_or_jmp(part, attr, value)

Convenience macro to push a new string attribute into a Netfilter Netlink message, and jump to a label on failure. See bf_nfmsg_attr_push_or_jmp for more details.

bf_nfmsg_push_u8(msg, attr, data)

Convenience macro to push a new uint8_t attribute into a Netfilter Netlink message. See bf_nfmsg_attr_push for more details.

bf_nfmsg_push_u8_or_jmp(msg, attr, data)

Convenience macro to push a new uint8_t attribute into a Netfilter Netlink message, and jump to a label on failure. See bf_nfmsg_attr_push_or_jmp for more details.

bf_nfmsg_push_u16(msg, attr, data)

Convenience macro to push a new uint16_t attribute into a Netfilter Netlink message. See bf_nfmsg_attr_push for more details.

bf_nfmsg_push_u16_or_jmp(msg, attr, data)

Convenience macro to push a new uint16_t attribute into a Netfilter Netlink message, and jump to a label on failure. See bf_nfmsg_attr_push_or_jmp for more details.

bf_nfmsg_push_u32(msg, attr, data)

Convenience macro to push a new uint32_t attribute into a Netfilter Netlink message. See bf_nfmsg_attr_push for more details.

bf_nfmsg_push_u32_or_jmp(msg, attr, data)

Convenience macro to push a new uint32_t attribute into a Netfilter Netlink message, and jump to a label on failure. See bf_nfmsg_attr_push_or_jmp for more details.

bf_nfmsg_push_u64(msg, attr, data)

Convenience macro to push a new uint64_t attribute into a Netfilter Netlink message. See bf_nfmsg_attr_push for more details.

bf_nfmsg_push_u64_or_jmp(msg, attr, data)

Convenience macro to push a new uint64_t attribute into a Netfilter Netlink message, and jump to a label on failure. See bf_nfmsg_attr_push_or_jmp for more details.

bf_nfattr_get_str(attr)

Get a Netlink attribute’s data as a string.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_u8(attr)

Get a Netlink attribute’s data as a uint8_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_s8(attr)

Get a Netlink attribute’s data as a int8_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_u16(attr)

Get a Netlink attribute’s data as a uint16_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_s16(attr)

Get a Netlink attribute’s data as a int16_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_u32(attr)

Get a Netlink attribute’s data as a uint32_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_s32(attr)

Get a Netlink attribute’s data as a int32_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_u64(attr)

Get a Netlink attribute’s data as a uint64_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

bf_nfattr_get_s64(attr)

Get a Netlink attribute’s data as a int64_t.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

_cleanup_bf_nfnest_

Cleanup attribute for a bf_nfnest variable.

bf_nfnest_or_jmp(parent, type)

Convenience macro to create a new nested attribute context or jump to bf_nfmsg_push_failure on failure.

Parameters:
  • parentbf_nfmsg to create the nested attribute into. Can’t be NULL.

  • type – Type of the nested attribute.

Returns:

0 on success, or negative errno value on error.

Typedefs

typedef struct nlattr bf_nfattr
typedef struct nla_policy bf_nfpolicy

Functions

int bf_nfmsg_new(struct bf_nfmsg **msg, uint8_t command, uint32_t seqnr)

Create a new Netfilter Netlink message.

Parameters:
  • msg – The new message to allocate and initialise. Can’t be NULL.

  • command – Command to send, can be any of nf_tables_msg_types.

  • seqnr – Sequence number for the message.

Returns:

0 on success, or negative errno value on failure.

int bf_nfmsg_new_done(struct bf_nfmsg **msg)

Create a new Netfilter Netlink NLMSG_DONE message.

Parameters:
  • msg – The new message to allocate and initialise. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

int bf_nfmsg_new_from_nlmsghdr(struct bf_nfmsg **msg, struct nlmsghdr *nlh)

Create a new Netfilter Netlink message from an existing Netlink message.

The provided nlmsghdr must be a valid Netlink message targeted to the NFNL_SUBSYS_NFTABLES subsystem, and containing a nfgenmsg header.

Parameters:
  • msg – The new message to allocate and initialise. Can’t be NULL.

  • nlh – Netlink message to create the Netfilter Netlink message from. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

void bf_nfmsg_free(struct bf_nfmsg **msg)

Free a Netfilter Netlink message.

If msg is NULL, this function has no effect. Before returning, msg is set to NULL.

Parameters:
  • msg – Message to free. Must be non-NULL.

struct nlmsghdr *bf_nfmsg_hdr(const struct bf_nfmsg *msg)

Get the Netlink message header for a Netfilter Netlink message.

Parameters:
  • msg – Message to get the header from. Must be non-NULL.

Returns:

The Netlink message header.

size_t bf_nfmsg_len(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s size, including header and padding.

Parameters:
  • msg – Message to get the size of. Can’t be NULL.

Returns:

Message’s size, including header and padding.

size_t bf_nfmsg_data_len(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s payload size, including padding.

Parameters:
  • msg – Message to get the payload size of. Can’t be NULL.

Returns:

Message’s payload size, including padding.

uint8_t bf_nfmsg_command(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s command.

Parameters:
  • msg – Message to get the command from. Can’t be NULL.

Returns:

The message’s command.

uint32_t bf_nfmsg_seqnr(const struct bf_nfmsg *msg)

Get a Netfilter Netlink message’s sequence number.

Parameters:
  • msg – Message to get the sequence number from. Can’t be NULL.

Returns:

The message’s sequence number.

int bf_nfmsg_attr_push(struct bf_nfmsg *msg, uint16_t type, const void *data, size_t len)

Push a new attribute into a Netfilter Netlink message.

Parameters:
  • msg – Message to push the attribute to. Can’t be NULL.

  • type – Attribute type.

  • data – Attribute data. Can’t be NULL.

  • len – Attribute data length.

Returns:

0 on success, or negative errno value on failure.

int bf_nfmsg_parse(const struct bf_nfmsg *msg, bf_nfattr **attrs, int maxtype, const bf_nfpolicy *policy)

Parse attributes from a Netfilter Netlink message.

All the attributes contained in the message are parsed and stored in the attrs array. Nested attributes (attributes contained within other) are not parsed, see bf_nfattr_parse instead.

Parameters:
  • msg – Message to parse the attributes from. Can’t be NULL.

  • attrs – Array of attributes to parse. Can’t be NULL.

  • maxtype – Maximum attribute type to parse.

  • policy – Netlink validation policy to use. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

int bf_nfattr_parse(bf_nfattr *attr, bf_nfattr **attrs, int maxtype, const bf_nfpolicy *policy)

Parse attributes nested within a Netlink attribute.

All the attributes contained in the attr are parsed and stored in the attrs array.

Parameters:
  • attr – Attribute to parse the nested attributes from. Can’t be NULL.

  • attrs – Array of attributes to parse. Can’t be NULL.

  • maxtype – Maximum attribute type to parse.

  • policy – Netlink validation policy to use. Can’t be NULL.

Returns:

0 on success, or negative errno value on failure.

void *bf_nfattr_data(bf_nfattr *attr)

Get the data of a Netlink attribute.

Parameters:
  • attr – Attribute to get the data from. Can’t be NULL.

Returns:

Pointer to the attribute’s data.

size_t bf_nfattr_data_len(bf_nfattr *attr)

Get a Netlink attribute’s payload size, including padding.

Parameters:
  • attr – Attribute the get the payload size of. Can’t be NULL.

Returns:

Attribute’s payload size, including padding.

bool bf_nfattr_is_ok(bf_nfattr *attr, size_t remaining)

Check if a Netlink attribute (and its payload) is valid.

If the function returns false, the attribute and its content can’t be accessed safely.

Parameters:
  • attr – Attribute to validate. Can’t be NULL.

  • remaining – Remaining bytes in the parent message or attribute. Can’t be negative.

Returns:

true if the attribute is valid, false otherwise.

bf_nfattr *bf_nfattr_next(bf_nfattr *attr, size_t *remaining)

Get the next Netlink attribute in a message or in a nested attribute.

Parameters:
  • attr – Attribute to get the next attribute from. Can’t be NULL.

  • remaining – Remaining bytes in the parent message or attribute. Can’t be NULL. When the function succeeds, it is updated with the remaining bytes in the parent message or attribute.

Returns:

Pointer to the next attribute, or NULL if there are no more

int bf_nfmsg_nest_init(struct bf_nfnest *nest, struct bf_nfmsg *parent, uint16_t type)

Declares a new nested attribute within parent.

Once a nested attribute has been defined, all the attributes added to the part (parent here) will be added within the nested attribute, until it is closed (bf_nfnest_cleanup).

Parameters:
  • nest – Pointer to the nested attribute. Must be an allocated bf_nfmsg_next structure. Can’t be NULL.

  • parentbf_nfmsg containing the nested attribute.

  • type – Type of the nested attribute.

Returns:

0 on success, negative errno value on error.

void bf_nfnest_cleanup(struct bf_nfnest *nest)

Close a nested attribute.

Parameters:
  • nest – Nested attribute to close. Can’t be NULL.

Variables

const bf_nfpolicy *bf_nf_table_policy

Netlink validation policy for nft_table_attributes.

const bf_nfpolicy *bf_nf_chain_policy

Netlink validation policy for nft_chain_attributes.

const bf_nfpolicy *bf_nf_hook_policy

Netlink validation policy for nft_hook_attributes.

const bf_nfpolicy *bf_nf_rule_policy

Netlink validation policy for nft_rule_attributes.

const bf_nfpolicy *bf_nf_expr_policy

Netlink validation policy for nft_expr_attributes.

const bf_nfpolicy *bf_nf_counter_policy

Netlink validation policy for nft_counter_attributes.

const bf_nfpolicy *bf_nf_payload_policy

Netlink validation policy for nft_payload_attributes.

const bf_nfpolicy *bf_nf_cmp_policy

Netlink validation policy for nft_cmp_attributes.

const bf_nfpolicy *bf_nf_immediate_policy

Netlink validation policy for nft_immediate_attributes.

const bf_nfpolicy *bf_nf_data_policy

Netlink validation policy for nft_data_attributes.

const bf_nfpolicy *bf_nf_verdict_policy

Netlink validation policy for nft_verdict_attributes.

file nft.c
#include <arpa/inet.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include “core/context.h
#include “core/hook.h
#include “core/logger.h
#include “core/marsh.h
#include “core/rule.h
#include “core/verdict.h
#include “generator/codegen.h
#include “shared/request.h”
#include “shared/response.h”
#include “xlate/front.h
#include “xlate/nft/nfgroup.h
#include “xlate/nft/nfmsg.h

Functions

static int _bf_nft_setup(void)#
static int _bf_nft_teardown(void)#
static int _bf_nft_request_handler(struct bf_request *request, struct bf_response **response)#
static int _bf_nft_marsh(struct bf_marsh **marsh)#
static int _bf_nft_unmarsh(struct bf_marsh *marsh)#
static int _bf_nft_getgen_cb(const struct bf_nfmsg *req, struct bf_nfgroup *res)#
static int _bf_nft_gettable_cb(const struct bf_nfmsg *req, struct bf_nfgroup *res)#
static int _bf_nft_newtable_cb(const struct bf_nfmsg *req)#
static int _bf_nft_newchain_cb(const struct bf_nfmsg *req)#
static int _bf_nft_getchain_cb(const struct bf_nfmsg *req, struct bf_nfgroup *res)#
static int _bf_nft_newrule_cb(const struct bf_nfmsg *req)#
static int _bf_nft_getrule_cb(const struct bf_nfmsg *req, struct bf_nfgroup *res)#
static int _bf_nft_request_handle(const struct bf_nfmsg *req, struct bf_nfgroup *res)#

Variables

static const char *_bf_table_name = "bpfilter"#
static const char *_bf_chain_name = "prerouting"#
const struct bf_front_ops nft_front = {.setup = _bf_nft_setup, .teardown = _bf_nft_teardown, .request_handler = _bf_nft_request_handler, .marsh = _bf_nft_marsh, .unmarsh = _bf_nft_unmarsh,}
static bf_list *_bf_nft_rules = NULL#
page todo

Global _bf_init  (int argc, char *argv[])

Should the runtime context be saved unconditionally?

Global _bf_ipt_request_handler  (struct bf_request *request, struct bf_response **response)

Wouldn’t it be better to have a separate handler for each request type? In which case struct bf_front_ops would contain a handler for each request type, and the front would handle custom (BF_REQ_CUSTOM) requests itself.

Document that request and responses are not const: they will be free by the daemon once the front is done with them. Hence, the front is free to modify the requests content.

Check bf_assertions: a malformed request could cause the daemon to crash.

Global _bf_ipt_set_counters_handler  (struct xt_counters_info *counters, size_t len)

Actually update the counters.

Global _bf_ipt_set_rules_handler  (struct ipt_replace *replace, size_t len)

If processing for any codegen fails, all codegens should be unloaded and/or discarded.

Global _bf_ipt_to_match  (const struct ipt_entry_match *ipt_match, struct bf_match **match)

Convert actual match content.

Global _bf_ipt_to_rule  (const struct ipt_entry *ipt_rule, struct bf_rule **rule)

Bound check the target.

Global _bf_program_generate_add_counter  (struct bf_program *program)

Random jump into the bytecode should be calculated by the daemon, not the developer.

Create a fixup to jump to the end of a function.

Set BF_REG_0 to !0 on failure, so we don’t drop the packet.

Global _bf_program_generate_rule  (struct bf_program *program, struct bf_rule *rule)

do matches too!

Global _tc_attach_prog_pre_unload  (struct bf_program *program, int *prog_fd, union bf_flavor_attach_attr *attr)

How should priority be handled?

This function, as well as many others, is using libbpf. Not all functions uses libbpf to communicate with the kernel. This should be unified.

Global bf_front_ops::setup  )(void)

Make bf_front_ops.request_handler take a const struct bf_request.

dir core
dir external
dir generator
dir xlate/ipt
dir xlate/nft
dir xlate