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

Add support for program loading flags - breaking change version #3763

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions docs/eBpfExtensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,12 @@ ebpf_extension_data_t* extension_data = (ebpf_extension_data_t*)ClientRegistrati
attach_parameter = extension_data->data;
```

### `ebpf_extension_data_t` Struct
This structure contains the additional data passed from the application to the attach provider. It contains the following fields:
* `data` Attach type specific data. See documentation for the attach type provider for the format of this data.
* `data_size` The length of the attach type specific data.
* `prog_attach_flags` A collection of attach type specific flags passed from the application to the attach provider.

The per-client data structure should be returned as the `ProviderBindingContext` output parameter.

Upon
Expand Down
2 changes: 2 additions & 0 deletions ebpfapi/Source.def
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ EXPORTS
bpf_program__attach_xdp
bpf_program__autoload
bpf_program__fd
bpf_program__flags
bpf_program__get_expected_attach_type
bpf_program__get_type=bpf_program__type
bpf_program__insn_cnt
Expand All @@ -90,6 +91,7 @@ EXPORTS
bpf_program__section_name
bpf_program__set_autoload
bpf_program__set_expected_attach_type
bpf_program__set_flags
bpf_program__set_type
bpf_program__type
bpf_program__unload
Expand Down
25 changes: 25 additions & 0 deletions include/bpf/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,31 @@ void
ring_buffer__free(struct ring_buffer* rb);
/** @} */

/**
* @brief Query the BPF program flags.
*
* @param[in] prog A pointer to the BPF program.
* @return The flags of the BPF program.
*/
__u32
bpf_program__flags(const struct bpf_program* prog);

/**
* @brief Set the BPF program flags.
* The set of flags is defined by the program type. Neither libbpf nor the eBPF runtime check the flags and only
* the extension that handles this program type will interpret them. See the documentation for the
* program type for what flags are defined for that program type.
*
* @param[in] prog A pointer to the BPF program.
* @param[in] flags The flags to set.
*
* @retval 0 The operation was successful.
* @retval <0 An error occurred, and errno was set.
*
*/
int
bpf_program__set_flags(struct bpf_program* prog, __u32 flags);

#else
#pragma warning(push)
#pragma warning(disable : 4200) // Zero-sized array in struct/union
Expand Down
2 changes: 2 additions & 0 deletions include/ebpf_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ typedef struct _ebpf_extension_data
{
ebpf_extension_header_t header;
const void* data;
size_t data_size;
uint64_t prog_attach_flags;
} ebpf_extension_data_t;

typedef struct _ebpf_attach_provider_data
Expand Down
8 changes: 8 additions & 0 deletions include/ebpf_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ typedef enum _ebpf_helper_function
#define EBPF_ATTACH_CLIENT_DATA_CURRENT_VERSION 1
#define EBPF_PROGRAM_INFORMATION_CLIENT_DATA_CURRENT_VERSION 1

#define EBPF_ATTACH_CLIENT_DATA_VERSION_SIZE EBPF_SIZE_INCLUDING_FIELD(ebpf_extension_data_t, prog_attach_flags)
#define EBPF_ATTACH_CLIENT_DATA_VERSION_TOTAL_SIZE sizeof(ebpf_extension_data_t)
#define EBPF_ATTACH_CLIENT_DATA_HEADER_VERSION \
{ \
EBPF_ATTACH_CLIENT_DATA_CURRENT_VERSION, EBPF_ATTACH_CLIENT_DATA_VERSION_SIZE, \
EBPF_ATTACH_CLIENT_DATA_VERSION_TOTAL_SIZE \
}

// Version 1 of the eBPF extension data structures and their lengths.
#define EBPF_ATTACH_PROVIDER_DATA_CURRENT_VERSION 1
#define EBPF_ATTACH_PROVIDER_DATA_CURRENT_VERSION_SIZE EBPF_SIZE_INCLUDING_FIELD(ebpf_attach_provider_data_t, link_type)
Expand Down
13 changes: 13 additions & 0 deletions libs/api/api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef struct bpf_program
bool pinned;
const char* log_buffer;
uint32_t log_buffer_size;
uint64_t flags;
} ebpf_program_t;

typedef struct bpf_map
Expand Down Expand Up @@ -759,3 +760,15 @@ ebpf_api_thread_local_cleanup() noexcept;
*/
void
ebpf_api_thread_local_initialize() noexcept;

/**
* @brief Set the flags on a program
*
* @param[in] program_fd File descriptor for the program.
* @param[in] flags Flags to set on the program.
*
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_ARGUMENT One or more parameters are wrong.
*/
_Must_inspect_result_ ebpf_result_t
ebpf_program_set_flags(fd_t program_fd, uint64_t flags) noexcept;
30 changes: 30 additions & 0 deletions libs/api/ebpf_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2131,6 +2131,12 @@ _initialize_ebpf_programs_native(
result = EBPF_NO_MEMORY;
goto Exit;
}
if (program->flags != 0) {
result = ebpf_program_set_flags(program->fd, program->flags);
if (result != EBPF_SUCCESS) {
goto Exit;
}
}
program->handle = program_handles[i];
program_handles[i] = ebpf_handle_invalid;
program->program_type = info.type_uuid;
Expand Down Expand Up @@ -3293,6 +3299,13 @@ _Requires_lock_not_held_(_ebpf_state_mutex) static ebpf_result_t

program->fd = _create_file_descriptor_for_handle(program->handle);

if (program->flags != 0) {
result = ebpf_program_set_flags(program->fd, program->flags);
if (result != EBPF_SUCCESS) {
break;
}
}

// Populate load_info.
ebpf_program_load_info load_info = {0};
load_info.object_name = const_cast<char*>(object->object_name);
Expand Down Expand Up @@ -4673,3 +4686,20 @@ ebpf_api_thread_local_initialize() noexcept
// Nothing to do.
// Added for symmetry with ebpf_api_thread_local_cleanup.
}

_Must_inspect_result_ ebpf_result_t
ebpf_program_set_flags(fd_t program_fd, uint64_t flags) noexcept
{
ebpf_handle_t program_handle = _get_handle_from_file_descriptor(program_fd);
if (program_handle == ebpf_handle_invalid) {
return EBPF_INVALID_FD;
}

ebpf_operation_program_set_flags_request_t request;
request.header.id = ebpf_operation_id_t::EBPF_OPERATION_PROGRAM_SET_FLAGS;
request.header.length = sizeof(request);
request.program_handle = program_handle;
request.flags = flags;

return win32_error_code_to_ebpf_result(invoke_ioctl(request));
}
16 changes: 16 additions & 0 deletions libs/api/libbpf_program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,3 +755,19 @@ bpf_prog_test_run_opts(int prog_fd, struct bpf_test_run_opts* opts)

return 0;
}

__u32
bpf_program__flags(const struct bpf_program* prog)
{
return static_cast<uint32_t>(prog->flags);
}

int
bpf_program__set_flags(struct bpf_program* prog, __u32 flags)
{
if (prog->object->loaded) {
Alan-Jowett marked this conversation as resolved.
Show resolved Hide resolved
return libbpf_err(-EBUSY);
}
prog->flags = flags;
return 0;
}
25 changes: 25 additions & 0 deletions libs/execution_context/ebpf_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2119,6 +2119,30 @@ _ebpf_core_protocol_ring_buffer_map_write_data(_In_ const ebpf_operation_ring_bu
EBPF_RETURN_RESULT(result);
}

static ebpf_result_t
_ebpf_core_protocol_program_set_flags(_In_ const ebpf_operation_program_set_flags_request_t* request)
{
EBPF_LOG_ENTRY();

ebpf_program_t* program = NULL;

ebpf_result_t result =
EBPF_OBJECT_REFERENCE_BY_HANDLE(request->program_handle, EBPF_OBJECT_PROGRAM, (ebpf_core_object_t**)&program);

if (result != EBPF_SUCCESS) {
goto Exit;
}

ebpf_program_set_flags(program, request->flags);

Exit:
if (program) {
EBPF_OBJECT_RELEASE_REFERENCE((ebpf_core_object_t*)program);
}

EBPF_RETURN_RESULT(result);
}

static void*
_ebpf_core_map_find_element(ebpf_map_t* map, const uint8_t* key)
{
Expand Down Expand Up @@ -2660,6 +2684,7 @@ static ebpf_protocol_handler_t _ebpf_protocol_handlers[] = {
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_FIXED_REPLY(map_delete_element_batch, keys, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_VARIABLE_REPLY(
map_get_next_key_value_batch, previous_key, data, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_NO_REPLY(program_set_flags, PROTOCOL_ALL_MODES),
};

_Must_inspect_result_ ebpf_result_t
Expand Down
14 changes: 9 additions & 5 deletions libs/execution_context/ebpf_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ _ebpf_link_client_detach_provider(void* client_binding_context)
}

static void
_ebpf_link_free(_Frees_ptr_ ebpf_core_object_t* object)
_ebpf_link_free(_In_ _Frees_ptr_ ebpf_core_object_t* object)
{
ebpf_link_t* link = (ebpf_link_t*)object;
ebpf_free((void*)link->client_data.data);
Expand Down Expand Up @@ -290,7 +290,9 @@ ebpf_link_create(
ebpf_lock_state_t state = ebpf_lock_lock(&local_link->lock);
lock_held = true;

local_link->client_data.header.size = context_data_length;
ebpf_extension_header_t header = EBPF_ATTACH_CLIENT_DATA_HEADER_VERSION;

local_link->client_data.header = header;

if (context_data_length > 0) {
local_link->client_data.data = ebpf_allocate_with_tag(context_data_length, EBPF_POOL_TAG_LINK);
Expand All @@ -299,6 +301,7 @@ ebpf_link_create(
goto Exit;
}
memcpy((void*)local_link->client_data.data, context_data, context_data_length);
local_link->client_data.data_size = context_data_length;
}

local_link->module_id.Guid = module_id;
Expand Down Expand Up @@ -365,6 +368,7 @@ ebpf_link_attach_program(_Inout_ ebpf_link_t* link, _Inout_ ebpf_program_t* prog

link->program = program;
link->program_type = ebpf_program_type_uuid(link->program);
link->client_data.prog_attach_flags = ebpf_program_get_flags(link->program);

// Attach the program to the link.
ebpf_program_attach_link(program, link);
Expand Down Expand Up @@ -660,10 +664,10 @@ ebpf_link_get_info(

// Copy any additional parameters.
size_t size = sizeof(struct bpf_link_info) - FIELD_OFFSET(struct bpf_link_info, attach_data);
if ((link->client_data.header.size > 0) && (link->client_data.header.size <= size)) {
memcpy(&info->attach_data, link->client_data.data, link->client_data.header.size);
}

if ((link->client_data.data_size > 0) && (link->client_data.data_size <= size)) {
memcpy(&info->attach_data, link->client_data.data, link->client_data.data_size);
}
ebpf_lock_unlock((ebpf_lock_t*)&link->lock, state);

*info_size = sizeof(*info);
Expand Down
15 changes: 14 additions & 1 deletion libs/execution_context/ebpf_program.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ typedef struct _ebpf_program
size_t helper_function_count;
uint32_t* helper_function_ids;
bool helper_ids_set;
uint64_t flags;

// Lock protecting the fields below.
ebpf_lock_t lock;
Expand Down Expand Up @@ -2663,4 +2664,16 @@ ebpf_program_get_runtime_state(_In_ const void* program_context, _Outptr_ const
// slot [0] contains the execution context state.
ebpf_context_header_t* header = CONTAINING_RECORD(program_context, ebpf_context_header_t, context);
*state = (ebpf_execution_context_state_t*)header->context_header[0];
}
}

uint64_t
ebpf_program_get_flags(_In_ const ebpf_program_t* program)
{
return program->flags;
}

void
ebpf_program_set_flags(_Inout_ ebpf_program_t* program, uint64_t flags)
{
program->flags = flags;
}
18 changes: 18 additions & 0 deletions libs/execution_context/ebpf_program.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,24 @@ extern "C"
ebpf_program_get_runtime_state(
_In_ const void* program_context, _Outptr_ const ebpf_execution_context_state_t** state);

/**
* @brief Query the flags set on the program.
*
* @param[in] program The program to query.
* @return The flags set on the program.
*/
uint64_t
ebpf_program_get_flags(_In_ const ebpf_program_t* program);

/**
* @brief Set the flags on the program.
*
* @param[in] program The program to set the flags on.
* @param[in] flags The flags to set on the program.
*/
void
ebpf_program_set_flags(_Inout_ ebpf_program_t* program, uint64_t flags);

#ifdef __cplusplus
}
#endif
8 changes: 8 additions & 0 deletions libs/execution_context/ebpf_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ typedef enum _ebpf_operation_id
EBPF_OPERATION_MAP_UPDATE_ELEMENT_BATCH,
EBPF_OPERATION_MAP_DELETE_ELEMENT_BATCH,
EBPF_OPERATION_MAP_GET_NEXT_KEY_VALUE_BATCH,
EBPF_OPERATION_PROGRAM_SET_FLAGS,
} ebpf_operation_id_t;

typedef enum _ebpf_code_type
Expand Down Expand Up @@ -524,3 +525,10 @@ typedef struct _ebpf_operation_map_get_next_key_value_batch_reply
// Data is a concatenation of key+value.
uint8_t data[1];
} ebpf_operation_map_get_next_key_value_batch_reply_t;

typedef struct _ebpf_operation_program_set_flags_request
{
struct _ebpf_operation_header header;
ebpf_handle_t program_handle;
uint64_t flags;
} ebpf_operation_program_set_flags_request_t;
5 changes: 2 additions & 3 deletions libs/shared/shared_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ uint16_t _supported_ebpf_extension_version[] = {
EBPF_PROGRAM_SECTION_INFORMATION_CURRENT_VERSION,
};

#define EBPF_ATTACH_PROVIDER_DATA_SIZE_0 \
EBPF_OFFSET_OF(ebpf_attach_provider_data_t, link_type) + sizeof(enum bpf_link_type)
size_t _ebpf_attach_provider_data_supported_size[] = {EBPF_ATTACH_PROVIDER_DATA_SIZE_0};
#define EBPF_ATTACH_PROVIDER_DATA_SIZE_1 EBPF_SIZE_INCLUDING_FIELD(ebpf_attach_provider_data_t, link_type)
Alan-Jowett marked this conversation as resolved.
Show resolved Hide resolved
size_t _ebpf_attach_provider_data_supported_size[] = {EBPF_ATTACH_PROVIDER_DATA_SIZE_1};

#define EBPF_PROGRAM_TYPE_DESCRIPTOR_SIZE_0 EBPF_OFFSET_OF(ebpf_program_type_descriptor_t, is_privileged) + sizeof(char)
size_t _ebpf_program_type_descriptor_supported_size[] = {EBPF_PROGRAM_TYPE_DESCRIPTOR_SIZE_0};
Expand Down
13 changes: 11 additions & 2 deletions netebpfext/net_ebpf_ext_sock_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,15 @@ _net_ebpf_extension_sock_addr_on_client_attach(

NET_EBPF_EXT_LOG_ENTRY();

if (client_data->header.version < EBPF_ATTACH_CLIENT_DATA_CURRENT_VERSION) {
result = EBPF_INVALID_ARGUMENT;
NET_EBPF_EXT_LOG_MESSAGE(
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR,
NET_EBPF_EXT_TRACELOG_KEYWORD_XDP,
"Attach attempt rejected. Invalid client data version.");
goto Exit;
}

// SOCK_ADDR hook clients must always provide data.
if (client_data == NULL) {
NET_EBPF_EXT_LOG_MESSAGE(
Expand All @@ -584,8 +593,8 @@ _net_ebpf_extension_sock_addr_on_client_attach(
goto Exit;
}

if (client_data->header.size > 0) {
if ((client_data->header.size != sizeof(uint32_t)) || (client_data->data == NULL)) {
if (client_data->data_size > 0) {
if ((client_data->data_size != sizeof(uint32_t)) || (client_data->data == NULL)) {
NET_EBPF_EXT_LOG_MESSAGE(
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR,
NET_EBPF_EXT_TRACELOG_KEYWORD_SOCK_ADDR,
Expand Down
13 changes: 11 additions & 2 deletions netebpfext/net_ebpf_ext_sock_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,17 @@ net_ebpf_extension_sock_ops_on_client_attach(
goto Exit;
}

if (client_data->header.size > 0) {
if ((client_data->header.size != sizeof(uint32_t)) || (client_data->data == NULL)) {
if (client_data->header.version < EBPF_ATTACH_CLIENT_DATA_CURRENT_VERSION) {
result = EBPF_INVALID_ARGUMENT;
NET_EBPF_EXT_LOG_MESSAGE(
NET_EBPF_EXT_TRACELOG_LEVEL_ERROR,
NET_EBPF_EXT_TRACELOG_KEYWORD_XDP,
"Attach attempt rejected. Invalid client data version.");
goto Exit;
}

if (client_data->data_size > 0) {
if ((client_data->data_size != sizeof(uint32_t)) || (client_data->data == NULL)) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
Expand Down
Loading
Loading