Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpf(): improve map and program compatibility #3980

Merged
merged 8 commits into from
Dec 19, 2024
Merged
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/ebpf_core_structs.h
Original file line number Diff line number Diff line change
@@ -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
@@ -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,
@@ -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
@@ -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
@@ -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
{
5 changes: 4 additions & 1 deletion libs/api/api_internal.h
Original file line number Diff line number Diff line change
@@ -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.
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>
@@ -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);
lmb marked this conversation as resolved.
Show resolved Hide resolved
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);
lmb marked this conversation as resolved.
Show resolved Hide resolved
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);
lmb marked this conversation as resolved.
Show resolved Hide resolved
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)
{
@@ -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,
@@ -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);
@@ -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,
@@ -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