Skip to content

Commit

Permalink
Merge branch 'main' into issue3576
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan-Jowett authored Jul 17, 2024
2 parents c6dd130 + 6b75459 commit 794322e
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 56 deletions.
3 changes: 2 additions & 1 deletion ebpfapi/Source.def
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ EXPORTS
ebpf_program_attach
ebpf_program_attach_by_fd
ebpf_program_query_info
ebpf_ring_buffer_map_write
ebpf_store_delete_program_information
ebpf_store_delete_section_information
ebpf_store_update_program_information_array
Expand All @@ -141,4 +142,4 @@ EXPORTS
libbpf_prog_type_by_name
libbpf_strerror
ring_buffer__new
ring_buffer__free
ring_buffer__free
14 changes: 14 additions & 0 deletions include/ebpf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,20 @@ extern "C"
_Must_inspect_result_ ebpf_result_t
ebpf_program_test_run(fd_t program_fd, _Inout_ ebpf_test_run_options_t* options) EBPF_NO_EXCEPT;

/**
* @brief Write data into the ring buffer map.
*
* @param [in] ring_buffer_map_fd ring buffer map file descriptor.
* @param [in] data Pointer to data to be written.
* @param [in] data_length Length of data to be written.
* @retval EPBF_SUCCESS Successfully wrote record into ring buffer.
* @retval EBPF_OUT_OF_SPACE Unable to output to ring buffer due to inadequate space.
* @retval EBPF_NO_MEMORY Out of memory.
*/
_Must_inspect_result_ ebpf_result_t
ebpf_ring_buffer_map_write(
fd_t ring_buffer_map_fd, _In_reads_bytes_(data_length) const void* data, size_t data_length) EBPF_NO_EXCEPT;

#ifdef __cplusplus
}
#endif
19 changes: 15 additions & 4 deletions include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// SPDX-License-Identifier: MIT
#pragma once

#pragma pack(push)
#pragma pack(1)
struct tcphdr
{
uint16_t source;
Expand All @@ -27,9 +29,18 @@ struct tcphdr
uint16_t check; // Checksum
uint16_t urg_ptr; // Urgent Pointer
};
#pragma pack(pop)

// Verify the bit fields give the correct header size.
#ifndef C_ASSERT
#define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
#ifndef FIELD_OFFSET
#define FIELD_OFFSET(type, field) ((long)&(((type*)0)->field))
#endif
C_ASSERT(sizeof(struct tcphdr) == 20);

// check the offset of each field
static_assert(FIELD_OFFSET(struct tcphdr, source) == 0, "source offset mismatch");
static_assert(FIELD_OFFSET(struct tcphdr, dest) == 2, "dest offset mismatch");
static_assert(FIELD_OFFSET(struct tcphdr, seq) == 4, "seq offset mismatch");
static_assert(FIELD_OFFSET(struct tcphdr, ack_seq) == 8, "ack_seq offset mismatch");
// Skip bit fields
static_assert(FIELD_OFFSET(struct tcphdr, window) == 14, "window offset mismatch");
static_assert(FIELD_OFFSET(struct tcphdr, check) == 16, "check offset mismatch");
static_assert(FIELD_OFFSET(struct tcphdr, urg_ptr) == 18, "urg_ptr offset mismatch");
132 changes: 105 additions & 27 deletions libs/api/ebpf_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,17 +510,17 @@ _ebpf_map_lookup_element_batch_helper(
{
EBPF_LOG_ENTRY();
ebpf_result_t result = EBPF_SUCCESS;
ebpf_handle_t map_handle;
uint32_t key_size_u32;
uint32_t value_size_u32;
uint32_t max_entries_u32;
uint32_t type;
ebpf_handle_t map_handle = ebpf_handle_invalid;
uint32_t key_size_u32 = 0;
uint32_t value_size_u32 = 0;
uint32_t max_entries_u32 = 0;
uint32_t type = BPF_MAP_TYPE_UNSPEC;

size_t input_count = *count;
size_t count_returned = 0;
size_t max_entries_per_batch;
size_t key_size;
size_t value_size;
size_t max_entries_per_batch = 0;
size_t key_size = 0;
size_t value_size = 0;

const uint8_t* previous_key = reinterpret_cast<const uint8_t*>(in_batch);

Expand Down Expand Up @@ -558,6 +558,10 @@ _ebpf_map_lookup_element_batch_helper(
goto Exit;
}

if (BPF_MAP_TYPE_PER_CPU(type)) {
value_size = EBPF_PAD_8(value_size) * libbpf_num_possible_cpus();
}

// Compute the maximum number of entries that can be updated in a single batch.
max_entries_per_batch = UINT16_MAX - EBPF_OFFSET_OF(_ebpf_operation_map_get_next_key_value_batch_reply, data);
max_entries_per_batch /= (key_size + value_size);
Expand Down Expand Up @@ -778,9 +782,8 @@ _update_map_element_batch(
uint8_t* source_value = (uint8_t*)value + (key_index + index) * value_size;
uint8_t* destination_key = request->data + index * (key_size + value_size);
uint8_t* destination_value = request->data + index * (key_size + value_size) + key_size;
if (key_size > 0) {
std::copy(source_key, source_key + key_size, destination_key);
}

std::copy(source_key, source_key + key_size, destination_key);
std::copy(source_value, source_value + value_size, destination_value);
}

Expand Down Expand Up @@ -906,15 +909,15 @@ ebpf_map_update_element_batch(
{
EBPF_LOG_ENTRY();
ebpf_result_t result = EBPF_SUCCESS;
ebpf_handle_t map_handle;
uint32_t key_size_u32;
uint32_t value_size_u32;
uint32_t max_entries_u32;
size_t key_size;
size_t value_size;
ebpf_handle_t map_handle = ebpf_handle_invalid;
uint32_t key_size_u32 = 0;
uint32_t value_size_u32 = 0;
uint32_t max_entries_u32 = 0;
size_t key_size = 0;
size_t value_size = 0;
size_t input_count = *count;

uint32_t type;
uint32_t type = BPF_MAP_TYPE_UNSPEC;

ebpf_assert(values);
if (map_fd <= 0) {
Expand Down Expand Up @@ -4342,7 +4345,7 @@ CATCH_NO_MEMORY_EBPF_RESULT

_Must_inspect_result_ ebpf_result_t
ebpf_ring_buffer_map_subscribe(
fd_t ring_buffer_map_fd,
fd_t map_fd,
_Inout_opt_ void* sample_callback_context,
ring_buffer_sample_fn sample_callback,
_Outptr_ ring_buffer_subscription_t** subscription) NO_EXCEPT_TRY
Expand All @@ -4356,22 +4359,41 @@ ebpf_ring_buffer_map_subscribe(

ebpf_result_t result = EBPF_SUCCESS;

*subscription = nullptr;
uint32_t key_size = 0;
uint32_t value_size = 0;
uint32_t max_entries = 0;
uint32_t type;

ebpf_ring_buffer_subscription_ptr local_subscription = std::make_unique<ebpf_ring_buffer_subscription_t>();
ebpf_handle_t map_handle = _get_handle_from_file_descriptor(map_fd);
if (map_handle == ebpf_handle_invalid) {
result = EBPF_INVALID_FD;
EBPF_RETURN_RESULT(result);
}

local_subscription->ring_buffer_map_handle = ebpf_handle_invalid;
result = _get_map_descriptor_properties(map_handle, &type, &key_size, &value_size, &max_entries);
if (result != EBPF_SUCCESS) {
EBPF_RETURN_RESULT(result);
}

// Get the handle to ring buffer map.
ebpf_handle_t ring_buffer_map_handle = _get_handle_from_file_descriptor(ring_buffer_map_fd);
if (ring_buffer_map_handle == ebpf_handle_invalid) {
result = EBPF_INVALID_FD;
if (type != BPF_MAP_TYPE_RINGBUF) {
result = EBPF_INVALID_ARGUMENT;
EBPF_LOG_MESSAGE_ERROR(
EBPF_TRACELOG_LEVEL_ERROR,
EBPF_TRACELOG_KEYWORD_API,
"ring_buffer__new API is called on a map that is not of the ring buffer type.",
result);
EBPF_RETURN_RESULT(result);
}

*subscription = nullptr;

ebpf_ring_buffer_subscription_ptr local_subscription = std::make_unique<ebpf_ring_buffer_subscription_t>();

local_subscription->ring_buffer_map_handle = ebpf_handle_invalid;

if (!Platform::DuplicateHandle(
reinterpret_cast<ebpf_handle_t>(GetCurrentProcess()),
ring_buffer_map_handle,
map_handle,
reinterpret_cast<ebpf_handle_t>(GetCurrentProcess()),
&local_subscription->ring_buffer_map_handle,
0,
Expand Down Expand Up @@ -4439,6 +4461,62 @@ ebpf_ring_buffer_map_subscribe(
}
CATCH_NO_MEMORY_EBPF_RESULT

_Must_inspect_result_ ebpf_result_t
ebpf_ring_buffer_map_write(fd_t map_fd, _In_reads_bytes_(data_length) const void* data, size_t data_length)
NO_EXCEPT_TRY
{
EBPF_LOG_ENTRY();
ebpf_result_t result = EBPF_SUCCESS;
ebpf_handle_t map_handle = ebpf_handle_invalid;
ebpf_protocol_buffer_t request_buffer;
ebpf_operation_ring_buffer_map_write_data_request_t* request;

if (!data || !data_length) {
return EBPF_INVALID_ARGUMENT;
}

try {
uint32_t key_size = 0;
uint32_t value_size = 0;
uint32_t max_entries = 0;
uint32_t type;

map_handle = _get_handle_from_file_descriptor(map_fd);
if (map_handle == ebpf_handle_invalid) {
result = EBPF_INVALID_FD;
EBPF_RETURN_RESULT(result);
}

result = _get_map_descriptor_properties(map_handle, &type, &key_size, &value_size, &max_entries);
if (result != EBPF_SUCCESS) {
EBPF_RETURN_RESULT(result);
}

if (type != BPF_MAP_TYPE_RINGBUF) {
result = EBPF_INVALID_ARGUMENT;
EBPF_LOG_MESSAGE_ERROR(
EBPF_TRACELOG_LEVEL_ERROR,
EBPF_TRACELOG_KEYWORD_API,
"ebpf_ring_buffer_map_write API is called on a map that is not of the ring buffer type.",
result);
EBPF_RETURN_RESULT(result);
}

request_buffer.resize(EBPF_OFFSET_OF(ebpf_operation_ring_buffer_map_write_data_request_t, data) + data_length);
request = reinterpret_cast<_ebpf_operation_ring_buffer_map_write_data_request*>(request_buffer.data());
request->header.length = static_cast<uint16_t>(request_buffer.size());
request->header.id = ebpf_operation_id_t::EBPF_OPERATION_RING_BUFFER_MAP_WRITE_DATA;
request->map_handle = (uint64_t)map_handle;
std::copy((uint8_t*)data, (uint8_t*)data + data_length, request->data);

result = win32_error_code_to_ebpf_result(invoke_ioctl(request_buffer));
} catch (const std::bad_alloc&) {
EBPF_RETURN_RESULT(EBPF_NO_MEMORY);
}
EBPF_RETURN_RESULT(result);
}
CATCH_NO_MEMORY_EBPF_RESULT

bool
ebpf_ring_buffer_map_unsubscribe(_In_ _Post_invalid_ ring_buffer_subscription_t* subscription) NO_EXCEPT_TRY
{
Expand Down
6 changes: 6 additions & 0 deletions libs/api/libbpf_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void* ctx, const s
ebpf_result result = EBPF_SUCCESS;
ring_buffer_t* local_ring_buffer = nullptr;

if (sample_cb == nullptr) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}

try {
std::unique_ptr<ring_buffer_t> ring_buffer = std::make_unique<ring_buffer_t>();
ring_buffer_subscription_t* subscription = nullptr;
Expand All @@ -378,6 +383,7 @@ ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void* ctx, const s
}
Exit:
if (result != EBPF_SUCCESS) {
errno = libbpf_result_err(result);
EBPF_LOG_FUNCTION_ERROR(result);
}
EBPF_RETURN_POINTER(ring_buffer_t*, local_ring_buffer);
Expand Down
46 changes: 43 additions & 3 deletions libs/execution_context/ebpf_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,11 @@ _ebpf_core_protocol_ring_buffer_map_query_buffer(

if (ebpf_map_get_definition(map)->type != BPF_MAP_TYPE_RINGBUF) {
result = EBPF_INVALID_ARGUMENT;
EBPF_LOG_MESSAGE_ERROR(
EBPF_TRACELOG_LEVEL_ERROR,
EBPF_TRACELOG_KEYWORD_CORE,
"query buffer operation called on a map that is not of the ring buffer type.",
result);
goto Exit;
}

Expand Down Expand Up @@ -2053,6 +2058,11 @@ _ebpf_core_protocol_ring_buffer_map_async_query(

if (ebpf_map_get_definition(map)->type != BPF_MAP_TYPE_RINGBUF) {
result = EBPF_INVALID_ARGUMENT;
EBPF_LOG_MESSAGE_ERROR(
EBPF_TRACELOG_LEVEL_ERROR,
EBPF_TRACELOG_KEYWORD_CORE,
"async query operation called on a map that is not of the ring buffer type.",
result);
goto Exit;
}

Expand Down Expand Up @@ -2090,10 +2100,39 @@ _ebpf_core_protocol_program_set_flags(_In_ const ebpf_operation_program_set_flag
ebpf_program_set_flags(program, request->flags);

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

static ebpf_result_t
_ebpf_core_protocol_ring_buffer_map_write_data(_In_ const ebpf_operation_ring_buffer_map_write_data_request_t* request)
{
ebpf_map_t* map = NULL;
size_t data_length = 0;
ebpf_result_t result =
EBPF_OBJECT_REFERENCE_BY_HANDLE(request->map_handle, EBPF_OBJECT_MAP, (ebpf_core_object_t**)&map);
if (result != EBPF_SUCCESS) {
goto Exit;
}
if (ebpf_map_get_definition(map)->type != BPF_MAP_TYPE_RINGBUF) {
result = EBPF_INVALID_ARGUMENT;
EBPF_LOG_MESSAGE_ERROR(
EBPF_TRACELOG_LEVEL_ERROR,
EBPF_TRACELOG_KEYWORD_CORE,
"write data operation called on a map that is not of the ring buffer type.",
result);
goto Exit;
}
result = ebpf_safe_size_t_subtract(
request->header.length,
EBPF_OFFSET_OF(ebpf_operation_ring_buffer_map_write_data_request_t, data),
&data_length);
if (result != EBPF_SUCCESS) {
goto Exit;
}
result = ebpf_ring_buffer_map_output(map, (uint8_t*)request->data, data_length);
Exit:
EBPF_OBJECT_RELEASE_REFERENCE((ebpf_core_object_t*)map);
EBPF_RETURN_RESULT(result);
}

Expand Down Expand Up @@ -2630,6 +2669,7 @@ static ebpf_protocol_handler_t _ebpf_protocol_handlers[] = {
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_NO_REPLY(bind_map, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_FIXED_REPLY(ring_buffer_map_query_buffer, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_FIXED_REPLY_ASYNC(ring_buffer_map_async_query, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_NO_REPLY(ring_buffer_map_write_data, data, PROTOCOL_ALL_MODES),
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_FIXED_REPLY(load_native_module, data, PROTOCOL_NATIVE_MODE),
DECLARE_PROTOCOL_HANDLER_FIXED_REQUEST_VARIABLE_REPLY(load_native_programs, data, PROTOCOL_NATIVE_MODE),
DECLARE_PROTOCOL_HANDLER_VARIABLE_REQUEST_VARIABLE_REPLY_ASYNC(program_test_run, data, data, PROTOCOL_ALL_MODES),
Expand Down
5 changes: 3 additions & 2 deletions libs/execution_context/ebpf_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,10 @@ static const ebpf_extension_program_dispatch_table_t _ebpf_link_dispatch_table_w
};

// Assert that the invoke function is aligned with ebpf_extension_dispatch_table_t->function.
C_ASSERT(
static_assert(
EBPF_OFFSET_OF(ebpf_extension_dispatch_table_t, function) ==
EBPF_OFFSET_OF(ebpf_extension_program_dispatch_table_t, ebpf_program_invoke_function));
EBPF_OFFSET_OF(ebpf_extension_program_dispatch_table_t, ebpf_program_invoke_function),
"Invoke function offset mismatch.");

static void
_ebpf_link_get_client_data(
Expand Down
8 changes: 8 additions & 0 deletions libs/execution_context/ebpf_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ typedef enum _ebpf_operation_id
EBPF_OPERATION_BIND_MAP,
EBPF_OPERATION_RING_BUFFER_MAP_QUERY_BUFFER,
EBPF_OPERATION_RING_BUFFER_MAP_ASYNC_QUERY,
EBPF_OPERATION_RING_BUFFER_MAP_WRITE_DATA,
EBPF_OPERATION_LOAD_NATIVE_MODULE,
EBPF_OPERATION_LOAD_NATIVE_PROGRAMS,
EBPF_OPERATION_PROGRAM_TEST_RUN,
Expand Down Expand Up @@ -391,6 +392,13 @@ typedef struct _ebpf_operation_ring_buffer_map_async_query_reply
ebpf_ring_buffer_map_async_query_result_t async_query_result;
} ebpf_operation_ring_buffer_map_async_query_reply_t;

typedef struct _ebpf_operation_ring_buffer_map_write_data_request
{
struct _ebpf_operation_header header;
ebpf_handle_t map_handle;
uint8_t data[1];
} ebpf_operation_ring_buffer_map_write_data_request_t;

typedef struct _ebpf_operation_load_native_module_request
{
struct _ebpf_operation_header header;
Expand Down
Loading

0 comments on commit 794322e

Please sign in to comment.