Skip to content

Commit

Permalink
bpf(): improve map and program compatibility
Browse files Browse the repository at this point in the history
Allow passing a name for maps and programs and allow retrieving it via
BPF_OBJ_GET_INFO_BY_FD. This requires a bunch of glue code because the
bpf_prog_info, etc. structs are not compatible with Linux.
  • Loading branch information
lmb committed Dec 16, 2024
1 parent 0213215 commit b549a94
Show file tree
Hide file tree
Showing 12 changed files with 379 additions and 42 deletions.
8 changes: 8 additions & 0 deletions include/ebpf_core_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,11 @@ typedef struct _ebpf_ring_buffer_map_async_query_result
size_t producer;
size_t consumer;
} ebpf_ring_buffer_map_async_query_result_t;

typedef enum _ebpf_object_type
{
EBPF_OBJECT_UNKNOWN,
EBPF_OBJECT_MAP,
EBPF_OBJECT_LINK,
EBPF_OBJECT_PROGRAM,
} ebpf_object_type_t;
52 changes: 46 additions & 6 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ enum bpf_stats_type
// 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_".

#define SYS_BPF_OBJ_NAME_LEN 16U

enum bpf_cmd_id
{
BPF_MAP_CREATE,
Expand Down Expand Up @@ -88,12 +90,15 @@ enum bpf_cmd_id
/// 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; ///< Not supported, must be zero.
uint32_t inner_map_fd; ///< File descriptor of inner map.
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; ///< Not supported, must be zero.
uint32_t inner_map_fd; ///< File descriptor of inner map.
uint32_t numa_node; ///< Not supported, must be zero.
char map_name[SYS_BPF_OBJ_NAME_LEN]; ///< Map name.
uint32_t map_ifindex; ///< Not supported, must be zero.
} sys_bpf_map_create_attr_t;

typedef struct
Expand Down Expand Up @@ -137,6 +142,7 @@ typedef struct
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.
char prog_name[SYS_BPF_OBJ_NAME_LEN]; ///< Program name.
} sys_bpf_prog_load_attr_t;

typedef struct
Expand Down Expand Up @@ -186,6 +192,40 @@ typedef struct
uint64_t info; ///< Pointer to memory in which to write the info obtained.
} sys_bpf_obj_info_attr_t;

typedef struct
{
ebpf_map_type_t type; ///< Type of map.
ebpf_id_t id; ///< Map ID.
uint32_t key_size; ///< Size in bytes of a map key.
uint32_t value_size; ///< Size in bytes of a map value.
uint32_t max_entries; ///< Maximum number of entries allowed in the map.
uint32_t map_flags; ///< Map flags.
char name[SYS_BPF_OBJ_NAME_LEN]; ///< Null-terminated map name.
} sys_bpf_map_info_t;

typedef struct
{
enum bpf_prog_type type; ///< Program type.
ebpf_id_t id; ///< Program ID.
char tag[8]; ///< Program tag.
uint32_t jited_prog_len; ///< Not supported.
uint32_t xlated_prog_len; ///< Not supported.
uint64_t jited_prog_insns; ///< Not supported.
uint64_t xlated_prog_insns; ///< Not supported.
uint64_t load_time; ///< Not supported.
uint32_t created_by_uid; ///< Not supported.
uint32_t nr_map_ids; ///< Number of maps associated with this program.
uint64_t map_ids; ///< Pointer to caller-allocated array to fill map IDs into.
char name[SYS_BPF_OBJ_NAME_LEN]; ///< Null-terminated program name.
} sys_bpf_prog_info_t;

typedef struct
{
enum bpf_link_type type; ///< Link type.
ebpf_id_t id; ///< Link ID.
ebpf_id_t prog_id; ///< Program ID.
} sys_bpf_link_info_t;

/// Attributes used by BPF_LINK_DETACH.
typedef struct
{
Expand Down
5 changes: 4 additions & 1 deletion libs/api/api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,10 @@ ebpf_get_next_program_id(ebpf_id_t start_id, ebpf_id_t _Out_* next_id) noexcept;
*/
_Must_inspect_result_ ebpf_result_t
ebpf_object_get_info_by_fd(
fd_t bpf_fd, _Inout_updates_bytes_to_(*info_size, *info_size) void* info, _Inout_ uint32_t* info_size) noexcept;
fd_t bpf_fd,
_Inout_updates_bytes_to_(*info_size, *info_size) void* info,
_Inout_ uint32_t* info_size,
_Out_opt_ ebpf_object_type_t* type) noexcept;

/**
* @brief Pin an object to the specified path.
Expand Down
194 changes: 190 additions & 4 deletions libs/api/bpf_syscall.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) eBPF for Windows contributors
// SPDX-License-Identifier: MIT
#include "api_internal.h"
#include "bpf.h"
#include "libbpf.h"
#include "libbpf_internal.h"
#include "linux/bpf.h"

#include <windows.h>
#include <WinError.h>
Expand Down Expand Up @@ -69,6 +72,105 @@ template <typename T> class ExtensibleStruct
}
};

static bool
is_valid_name(_In_z_ const char* name, _Out_opt_ size_t* length)
{
size_t name_length = strnlen(name, SYS_BPF_OBJ_NAME_LEN);

if (length != NULL) {
*length = name_length;
}

return name_length < SYS_BPF_OBJ_NAME_LEN;
}

static void
convert_to_map_info(_Out_ struct bpf_map_info* bpf, _In_ const sys_bpf_map_info_t* sys);
static void
convert_to_sys_map_info(_Out_ sys_bpf_map_info_t* sys, _In_ const struct bpf_map_info* bpf);
static void
convert_to_prog_info(_Out_ struct bpf_prog_info* bpf, _In_ const sys_bpf_prog_info_t* sys);
static void
convert_to_sys_prog_info(_Out_ sys_bpf_prog_info_t* sys, _In_ const struct bpf_prog_info* bpf);
static void
convert_to_link_info(_Out_ struct bpf_link_info* bpf, _In_ const sys_bpf_link_info_t* sys);
static void
convert_to_sys_link_info(_Out_ sys_bpf_link_info_t* sys, _In_ const struct bpf_link_info* bpf);

static int
obj_get_info_by_fd(_In_ sys_bpf_obj_info_attr_t* attr)
{
union
{
struct bpf_map_info map;
struct bpf_prog_info prog;
struct bpf_link_info link;
} tmp = {};
uint32_t info_size = sizeof(tmp);
ebpf_object_type_t type;

ebpf_result_t result = ebpf_object_get_info_by_fd((fd_t)attr->bpf_fd, &tmp, &info_size, &type);
if (result != EBPF_SUCCESS) {
return libbpf_result_err(result);
}

switch (type) {
case EBPF_OBJECT_MAP: {
ExtensibleStruct<sys_bpf_map_info_t> info((void*)attr->info, (size_t)attr->info_len);

convert_to_map_info(&tmp.map, &info);

info_size = sizeof(tmp.map);
result = ebpf_object_get_info_by_fd((fd_t)attr->bpf_fd, &tmp.map, &info_size, NULL);
if (result != EBPF_SUCCESS) {
return libbpf_result_err(result);
}

convert_to_sys_map_info(&info, &tmp.map);
return 0;
}

case EBPF_OBJECT_PROGRAM: {
ExtensibleStruct<sys_bpf_prog_info_t> info((void*)attr->info, (size_t)attr->info_len);
sys_bpf_prog_info_t* sys = &info;

if (sys->jited_prog_len != 0 || sys->xlated_prog_len != 0 || sys->jited_prog_insns != 0 ||
sys->xlated_prog_insns != 0) {
return -EINVAL;
}

convert_to_prog_info(&tmp.prog, &info);

info_size = sizeof(tmp.prog);
result = ebpf_object_get_info_by_fd((fd_t)attr->bpf_fd, &tmp.prog, &info_size, NULL);
if (result != EBPF_SUCCESS) {
return libbpf_result_err(result);
}

convert_to_sys_prog_info(&info, &tmp.prog);
return 0;
}

case EBPF_OBJECT_LINK: {
ExtensibleStruct<sys_bpf_link_info_t> info((void*)attr->info, (size_t)attr->info_len);

convert_to_link_info(&tmp.link, &info);

info_size = sizeof(tmp.link);
result = ebpf_object_get_info_by_fd((fd_t)attr->bpf_fd, &tmp.link, &info_size, NULL);
if (result != EBPF_SUCCESS) {
return libbpf_result_err(result);
}

convert_to_sys_link_info(&info, &tmp.link);
return 0;
}

default:
return -EINVAL;
}
}

int
bpf(int cmd, union bpf_attr* attr, unsigned int size)
{
Expand Down Expand Up @@ -97,11 +199,17 @@ bpf(int cmd, union bpf_attr* attr, unsigned int size)
struct bpf_map_create_opts opts = {
.inner_map_fd = map_create_attr->inner_map_fd,
.map_flags = map_create_attr->map_flags,
.numa_node = map_create_attr->numa_node,
.map_ifindex = map_create_attr->map_ifindex,
};

if (!is_valid_name(map_create_attr->map_name, NULL)) {
return -EINVAL;
}

return bpf_map_create(
map_create_attr->map_type,
nullptr,
map_create_attr->map_name,
map_create_attr->key_size,
map_create_attr->value_size,
map_create_attr->max_entries,
Expand Down Expand Up @@ -175,8 +283,7 @@ bpf(int cmd, union bpf_attr* attr, unsigned int size)
}
case BPF_OBJ_GET_INFO_BY_FD: {
ExtensibleStruct<sys_bpf_obj_info_attr_t> info_by_fd_attr((void*)attr, (size_t)size);
return bpf_obj_get_info_by_fd(
info_by_fd_attr->bpf_fd, (void*)info_by_fd_attr->info, &info_by_fd_attr->info_len);
return obj_get_info_by_fd(&info_by_fd_attr);
}
case BPF_OBJ_PIN: {
ExtensibleStruct<sys_bpf_obj_pin_attr_t> obj_pin_attr((void*)attr, (size_t)size);
Expand Down Expand Up @@ -212,10 +319,21 @@ bpf(int cmd, union bpf_attr* attr, unsigned int size)
.log_size = prog_load_attr->log_size,
.log_buf = (char*)prog_load_attr->log_buf,
};
const char* name = prog_load_attr->prog_name;
size_t name_length;

if (!is_valid_name(name, &name_length)) {
return -EINVAL;
}

if (name_length == 0) {
// Disable using sha256 as object name.
name = "";
}

return bpf_prog_load(
prog_load_attr->prog_type,
nullptr,
name,
(const char*)prog_load_attr->license,
(const struct bpf_insn*)prog_load_attr->insns,
prog_load_attr->insn_cnt,
Expand Down Expand Up @@ -262,3 +380,71 @@ bpf(int cmd, union bpf_attr* attr, unsigned int size)
return -EINVAL;
}
}

#define BPF_TO_SYS(field) sys->field = bpf->field
#define BPF_TO_SYS_STR(field) strncpy_s(sys->field, sizeof(sys->field), bpf->field, _TRUNCATE)
#define BPF_TO_SYS_MEM(field) memcpy(sys->field, bpf->field, sizeof(sys->field))
#define SYS_TO_BPF(field) bpf->field = sys->field
#define SYS_TO_BPF_STR(field) strncpy_s(bpf->field, sys->field, sizeof(bpf->field))
#define SYS_TO_BPF_MEM(field) memcpy(bpf->field, sys->field, sizeof(bpf->field))

static void
convert_to_map_info(_Out_ struct bpf_map_info* bpf, _In_ const sys_bpf_map_info_t* sys)
{
SYS_TO_BPF(type);
SYS_TO_BPF(id);
SYS_TO_BPF(key_size);
SYS_TO_BPF(value_size);
SYS_TO_BPF(max_entries);
SYS_TO_BPF(map_flags);
SYS_TO_BPF_STR(name);
}

static void
convert_to_sys_map_info(_Out_ sys_bpf_map_info_t* sys, _In_ const struct bpf_map_info* bpf)
{
BPF_TO_SYS(type);
BPF_TO_SYS(id);
BPF_TO_SYS(key_size);
BPF_TO_SYS(value_size);
BPF_TO_SYS(max_entries);
BPF_TO_SYS(map_flags);
BPF_TO_SYS_STR(name);
}

static void
convert_to_prog_info(_Out_ struct bpf_prog_info* bpf, _In_ const sys_bpf_prog_info_t* sys)
{
SYS_TO_BPF(type);
SYS_TO_BPF(id);
SYS_TO_BPF(nr_map_ids);
SYS_TO_BPF(map_ids);
SYS_TO_BPF_STR(name);
}

static void
convert_to_sys_prog_info(_Out_ sys_bpf_prog_info_t* sys, _In_ const struct bpf_prog_info* bpf)
{
*sys = {};
BPF_TO_SYS(type);
BPF_TO_SYS(id);
BPF_TO_SYS(nr_map_ids);
BPF_TO_SYS(map_ids);
BPF_TO_SYS_STR(name);
}

static void
convert_to_link_info(_Out_ struct bpf_link_info* bpf, _In_ const sys_bpf_link_info_t* sys)
{
SYS_TO_BPF(type);
SYS_TO_BPF(id);
SYS_TO_BPF(prog_id);
}

static void
convert_to_sys_link_info(_Out_ sys_bpf_link_info_t* sys, _In_ const struct bpf_link_info* bpf)
{
BPF_TO_SYS(type);
BPF_TO_SYS(id);
BPF_TO_SYS(prog_id);
}
Loading

0 comments on commit b549a94

Please sign in to comment.