Skip to content

Commit

Permalink
bpf(): make union bpf_attr Linux ABI compatible (#3948)
Browse files Browse the repository at this point in the history
* bpf(): make union bpf_attr Linux ABI compatible

At this point we also take the first steps to fixing the existing ABI
incompatibility. On the Linux side, care was taken to avoid most padding
in bpf_attr. By forcing the compiler to refuse implicit padding we
get a good heuristic for fields in the incorrect order.

These changes mean that union bpf_attr in linux/bpf.h is not source compatible
with the Linux header anymore. It's not possible to be source compatible and ABI
compatible at the same time because we're already using Linux type names with
ABI incompatible definitions. For example BPF_OBJ_NAME_LEN differs, and the order
of fields in struct bpf_prog_info, etc. also does not match.

Change the definition of union bpf_attr to be more convenient to work with.
This allows refactoring the macro magic used to check for forwards and backwards
compatibility into a class, which ends up a lot less error prone.

* Address feedback from Dave Thaler

* Address second round of review from Dave Thaler
  • Loading branch information
lmb authored Oct 28, 2024
1 parent 8862f74 commit 7637920
Show file tree
Hide file tree
Showing 3 changed files with 433 additions and 322 deletions.
213 changes: 129 additions & 84 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ enum bpf_stats_type
BPF_STATS_TYPE_UNKNOWN
};

// All types below must be ABI compatible with the Linux bpf() syscalls. This means
// that the order, size and alignment of the types must match uapi/linux/bpf.h in
// a tagged release of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/.
// Constants must also match.
//
// Names do not have to match, but try to keep them the same as much as possible.
// In case of conflicts prefix them with "sys_" or "SYS_".

enum bpf_cmd_id
{
BPF_MAP_CREATE,
Expand All @@ -58,119 +66,172 @@ enum bpf_cmd_id
BPF_OBJ_GET,
BPF_PROG_ATTACH,
BPF_PROG_DETACH,
BPF_PROG_TEST_RUN,
BPF_PROG_GET_NEXT_ID,
BPF_MAP_GET_NEXT_ID,
BPF_LINK_GET_NEXT_ID,
BPF_PROG_GET_FD_BY_ID,
BPF_MAP_GET_FD_BY_ID,
BPF_MAP_LOOKUP_AND_DELETE_ELEM,
BPF_LINK_GET_FD_BY_ID,
BPF_OBJ_GET_INFO_BY_FD,
BPF_LINK_DETACH,
BPF_PROG_BIND_MAP,
BPF_PROG_TEST_RUN,
BPF_MAP_LOOKUP_AND_DELETE_ELEM = 21,
BPF_LINK_GET_FD_BY_ID = 30,
BPF_LINK_GET_NEXT_ID,
BPF_LINK_DETACH = 34,
BPF_PROG_BIND_MAP = 35,
BPF_PROG_RUN = BPF_PROG_TEST_RUN,
};

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(default : 4820) // reject implicit padding
#endif

/// Attributes used by BPF_MAP_CREATE.
typedef struct
{
enum bpf_map_type map_type; ///< Type of map to create.
uint32_t key_size; ///< Size in bytes of keys.
uint32_t value_size; ///< Size in bytes of values.
uint32_t max_entries; ///< Maximum number of entries in the map.
uint32_t map_flags; ///< Flags (currently 0).
} sys_bpf_map_create_attr_t;

typedef struct
{
uint32_t map_fd; ///< File descriptor of map.
uint32_t _pad0;
uint64_t key; ///< Pointer to key to look up.
uint64_t value; ///< Pointer to value.
uint64_t flags; ///< Not supported, must be zero.
} sys_bpf_map_lookup_attr_t;

typedef struct
{
uint32_t map_fd; ///< File descriptor of map.
uint32_t _pad0;
uint64_t key; ///< Pointer to key to delete.
} sys_bpf_map_delete_attr_t;

typedef struct
{
uint32_t map_fd; ///< File descriptor of map.
uint32_t _pad0;
uint64_t key; ///< Pointer to key to look up.
uint64_t next_key; ///< Pointer to next key.
} sys_bpf_map_next_key_attr_t;

typedef struct
{
uint32_t start_id; ///< ID to look for an ID after. The start_id need not exist.
uint32_t next_id; ///< On return, contains the next ID.
} sys_bpf_map_next_id_attr_t;

typedef struct
{
enum bpf_prog_type prog_type; ///< Program type to use for loading the program.
uint32_t insn_cnt; ///< Number of instructions in the array.
uint64_t insns; ///< Array of instructions.
uint64_t license; ///< Optional pointer to a string specifying the license (currently ignored on Windows).
uint32_t log_level; ///< Logging level (currently ignored on Windows).
uint32_t log_size; ///< Size in bytes of the log buffer.
uint64_t log_buf; ///< Pointer to a buffer in which log info can be written.
uint32_t kern_version; ///< Kernel version (currently ignored on Windows).
uint32_t prog_flags; ///< Not supported, must be zero.
} sys_bpf_prog_load_attr_t;

typedef struct
{
uint32_t target_fd; ///< eBPF target to attach/detach to/from.
uint32_t attach_bpf_fd; ///< File descriptor of program to attach to.
enum bpf_attach_type attach_type; ///< Type of program to attach/detach to/from.
uint32_t attach_flags; ///< Flags affecting the attach operation.
} sys_bpf_prog_attach_attr_t;

typedef struct
{
uint32_t prog_fd; ///< File descriptor of program to run.
uint32_t retval; ///< On return, contains the return value of the program.
uint32_t data_size_in; ///< Size in bytes of input data.
uint32_t data_size_out; ///< Size in bytes of output data.
uint64_t data_in; ///< Pointer to input data.
uint64_t data_out; ///< Pointer to output data.
uint32_t repeat; ///< Number of times to repeat the program.
uint32_t duration; ///< Duration in milliseconds to run the program.
uint32_t ctx_size_in; ///< Size in bytes of input context.
uint32_t ctx_size_out; ///< Size in bytes of output context.
uint64_t ctx_in; ///< Pointer to input context.
uint64_t ctx_out; ///< Pointer to output context.
uint32_t flags; ///< Flags (currently 0).
uint32_t cpu; ///< CPU to run the program on.
uint32_t batch_size; ///< Number of times to run the program in a batch.
uint32_t _pad0;
} sys_bpf_prog_run_attr_t;

typedef struct
{
uint64_t pathname; ///< Path name for pinning.
uint32_t bpf_fd; ///< File descriptor referring to the program or map.
uint32_t flags; ///< Not supported, must be zero.
} sys_bpf_obj_pin_attr_t;

/// Attributes used by BPF_OBJ_GET_INFO_BY_FD.
typedef struct
{
uint32_t bpf_fd; ///< File descriptor referring to an eBPF object.
uint64_t info; ///< Pointer to memory in which to write the info obtained.

/**
* @brief On input, contains the maximum number of bytes to write into the info. On output, contains
* the actual number of bytes written.
*/
uint32_t info_len;
} bpf_obj_info_attr_t;
uint64_t info; ///< Pointer to memory in which to write the info obtained.
} sys_bpf_obj_info_attr_t;

/// Attributes used by BPF_LINK_DETACH.
typedef struct
{
uint32_t link_fd; ///< File descriptor of link to detach.
} bpf_link_detach_attr_t;
} sys_bpf_link_detach_attr_t;

/// Attributes used by BPF_PROG_BIND_MAP.
typedef struct
{
uint32_t prog_fd; ///< File descriptor of program to bind map to.
uint32_t map_fd; ///< File descriptor of map to bind.
uint32_t flags; ///< Flags affecting the bind operation.
} bpf_prog_bind_map_attr_t;
} sys_bpf_prog_bind_map_attr_t;

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4201) // nonstandard extension used: nameless struct/union
#endif
/// Parameters used by the bpf() API.
union bpf_attr
{
// BPF_MAP_CREATE
struct
{
enum bpf_map_type map_type; ///< Type of map to create.
uint32_t key_size; ///< Size in bytes of keys.
uint32_t value_size; ///< Size in bytes of values.
uint32_t max_entries; ///< Maximum number of entries in the map.
uint32_t map_flags; ///< Flags (currently 0).
}; ///< Attributes used by BPF_MAP_CREATE.
sys_bpf_map_create_attr_t map_create; ///< Attributes used by BPF_MAP_CREATE.

// BPF_MAP_LOOKUP_ELEM
// BPF_MAP_UPDATE_ELEM
// BPF_MAP_DELETE_ELEM
sys_bpf_map_lookup_attr_t map_lookup,
map_update; ///< Attributes used by BPF_MAP_LOOKUP_ELEM, BPF_MAP_UPDATE_ELEM and

// BPF_MAP_GET_NEXT_KEY
struct
{
uint32_t map_fd; ///< File descriptor of map.
uint64_t key; ///< Pointer to key to look up.
union
{
uint64_t value; ///< Pointer to value.
uint64_t next_key; ///< Pointer to next key.
};
uint64_t flags; ///< Flags (currently 0).
}; ///< Attributes used by BPF_MAP_LOOKUP_ELEM, BPF_MAP_UPDATE_ELEM, BPF_MAP_DELETE_ELEM, and BPF_MAP_GET_NEXT_KEY.
sys_bpf_map_next_key_attr_t map_get_next_key; ///< Attributes used by BPF_MAP_GET_NEXT_KEY.

// BPF_MAP_DELETE_ELEM
sys_bpf_map_delete_attr_t map_delete; ///< Attributes used by BPF_MAP_DELETE_ELEM.

// BPF_PROG_LOAD
struct
{
enum bpf_prog_type prog_type; ///< Program type to use for loading the program.
uint64_t insns; ///< Array of instructions
uint32_t insn_cnt; ///< Number of instructions in the array.
uint64_t license; ///< Optional pointer to a string specifying the license (currently ignored on Windows).
uint32_t log_level; ///< Logging level (currently ignored on Windows).
uint64_t log_buf; ///< Pointer to a buffer in which log info can be written.
uint32_t log_size; ///< Size in bytes of the log buffer.
uint32_t kern_version; ///< Kernel version (currently ignored on Windows).
}; ///< Attributes used by BPF_PROG_LOAD.
sys_bpf_prog_load_attr_t prog_load; ///< Attributes used by BPF_PROG_LOAD.

// BPF_PROG_ATTACH
// BPF_PROG_DETACH
struct
{
uint32_t target_fd; ///< eBPF target to attach/detach to/from.
uint32_t attach_bpf_fd; ///< File descriptor of program to attach to.
enum bpf_attach_type attach_type; ///< Type of program to attach/detach to/from.
uint32_t attach_flags; ///< Flags affecting the attach operation.
}; ///< Attributes used by BPF_PROG_ATTACH/DETACH.
sys_bpf_prog_attach_attr_t prog_attach, prog_detach; ///< Attributes used by BPF_PROG_ATTACH/DETACH.

// BPF_OBJ_PIN
// BPF_OBJ_GET
struct
{
uint64_t pathname; ///< Path name for pinning.
uint32_t bpf_fd; ///< File descriptor referring to the program or map.
}; ///< Attributes used by BPF_OBJ_PIN and BPF_OBJ_GET.
sys_bpf_obj_pin_attr_t obj_pin, obj_get; ///< Attributes used by BPF_OBJ_PIN and BPF_OBJ_GET.

// BPF_PROG_GET_NEXT_ID
// BPF_MAP_GET_NEXT_ID
// BPF_LINK_GET_NEXT_ID
struct
{
uint32_t start_id; ///< ID to look for an ID after. The start_id need not exist.
uint32_t next_id; ///< On return, contains the next ID.
}; ///< Attributes used by BPF_PROG_GET_NEXT_ID, BPF_MAP_GET_NEXT_ID, and BPF_LINK_GET_NEXT_ID.
sys_bpf_map_next_id_attr_t map_get_next_id, prog_get_next_id,
link_get_next_id; ///< Attributes used by BPF_PROG_GET_NEXT_ID, BPF_MAP_GET_NEXT_ID, and BPF_LINK_GET_NEXT_ID.

// BPF_MAP_GET_FD_BY_ID
uint32_t map_id; ///< ID of map for BPF_MAP_GET_FD_BY_ID to find.
Expand All @@ -182,34 +243,18 @@ union bpf_attr
uint32_t link_id; ///< ID of link for BPF_LINK_GET_FD_BY_ID to find.

// BPF_OBJ_GET_INFO_BY_FD
bpf_obj_info_attr_t info; ///< Attributes used by BPF_OBJ_GET_INFO_BY_FD.
sys_bpf_obj_info_attr_t info; ///< Attributes used by BPF_OBJ_GET_INFO_BY_FD.

// BPF_LINK_DETACH
bpf_link_detach_attr_t link_detach; ///< Attributes used by BPF_LINK_DETACH.
sys_bpf_link_detach_attr_t link_detach; ///< Attributes used by BPF_LINK_DETACH.

// BPF_PROG_BIND_MAP
bpf_prog_bind_map_attr_t prog_bind_map; ///< Attributes used by BPF_PROG_BIND_MAP.
sys_bpf_prog_bind_map_attr_t prog_bind_map; ///< Attributes used by BPF_PROG_BIND_MAP.

// BPF_PROG_TEST_RUN
struct
{
uint32_t prog_fd; ///< File descriptor of program to run.
uint32_t retval; ///< On return, contains the return value of the program.
uint32_t data_size_in; ///< Size in bytes of input data.
uint32_t data_size_out; ///< Size in bytes of output data.
uint64_t data_in; ///< Pointer to input data.
uint64_t data_out; ///< Pointer to output data.
uint32_t repeat; ///< Number of times to repeat the program.
uint32_t duration; ///< Duration in milliseconds to run the program.
uint32_t ctx_size_in; ///< Size in bytes of input context.
uint32_t ctx_size_out; ///< Size in bytes of output context.
uint64_t ctx_in; ///< Pointer to input context.
uint64_t ctx_out; ///< Pointer to output context.
uint32_t flags; ///< Flags (currently 0).
uint32_t cpu; ///< CPU to run the program on.
uint32_t batch_size; ///< Number of times to run the program in a batch.
} test; ///< Attributes used by BPF_PROG_TEST_RUN.
sys_bpf_prog_run_attr_t test; ///< Attributes used by BPF_PROG_TEST_RUN.
};

#ifdef _MSC_VER
#pragma warning(pop)
#endif
Expand Down
Loading

0 comments on commit 7637920

Please sign in to comment.