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

Perf event array map kernel-side implementation. #4144

Open
wants to merge 4 commits 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
15 changes: 8 additions & 7 deletions docs/eBpfExtensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,17 @@ structure from provided data and context buffers.
context structure and populates the returned data and context buffers.
* `required_irql`: IRQL at which the eBPF program is invoked by bpf_prog_test_run_opts.
* `capabilities`: 32-bit integer describing the optional capabilities / features supported by the extension.
* `supports_context_header`: Flag indicating extension supports adding a context header at the start of each context passed to the eBPF program.
* `supports_context_header`: Required flag indicating extension supports adding a context header at the start of each context passed to the eBPF program. This flag must be set.

**Capabilities**

`supports_context_header`:

Flag indicating that extension supports adding a context header at the start of each context passed to the eBPF program.
An extension can choose to opt in to support context header at the start of each program context structure that is
passed to the eBPF program. To support this feature, the extension can use the macro `EBPF_CONTEXT_HEADER` to include
the context header at the start of the program context structure. Even when the context header is added, the pointer
passed to the eBPF program is after the context header.
This is required for all extensions to support so the core can store runtime state needed by helpers.
To support this feature, the extension can use the macro `EBPF_CONTEXT_HEADER` to include
the context header at the start of the program context structure. The context pointer passed to the
eBPF program points immediately after the context header.

*Example*

Expand All @@ -135,8 +135,9 @@ typedef struct _sample_program_context_header
sample_program_context_t context;
} sample_program_context_header_t;
```
The extension passes a pointer to `context` inside `sample_program_context_header_t`, and not a pointer to
`sample_program_context_header_t`, when invoking the eBPF program.
The extension passes a pointer to `context` inside `sample_program_context_header_t` and not a pointer to
`sample_program_context_header_t` when invoking the eBPF program. The header is not accessible
by the program.

#### `ebpf_program_info_t` Struct
The various fields of this structure should be set as follows:
Expand Down
19 changes: 19 additions & 0 deletions include/bpf_helper_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -495,3 +495,22 @@ EBPF_HELPER(uint64_t, bpf_ktime_get_ms, ());
#ifndef __doxygen
#define bpf_ktime_get_ms ((bpf_ktime_get_ms_t)BPF_FUNC_ktime_get_ms)
#endif

/**
* @brief Copy data into perf event array map.
*
* @param[in, out] map Pointer to perf event array map.
* @param[in] data Data to copy into perf event array map.
* @param[in] size Length of data.
* @param[in] flags Flags indicating if notification for new data availability should be sent.
* @retval 0 The operation was successful.
* @retval -EBPF_INVALID_ARGUMENT One or more parameters are invalid.
* @retval -EBPF_OPERATION_NOT_SUPPORTED Operation not supported on this program or map.
* @retval -EBPF_NO_MEMORY Unable to allocate resources for this.
* entry.
* @retval -EBPF_OUT_OF_SPACE Map is full.
*/
EBPF_HELPER(int, bpf_perf_event_output, (void* ctx, void* perf_event_array, uint64_t flags, void* data, uint64_t size));
#ifndef __doxygen
#define bpf_perf_event_output ((bpf_perf_event_output_t)BPF_FUNC_perf_event_output)
#endif
33 changes: 25 additions & 8 deletions include/ebpf_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,11 @@ extern "C"
* @deprecated Use ebpf_enumerate_programs() instead.
*/
__declspec(deprecated("Use ebpf_enumerate_programs() instead.")) _Must_inspect_result_ ebpf_result_t
ebpf_enumerate_sections(
_In_z_ const char* file,
bool verbose,
_Outptr_result_maybenull_ ebpf_section_info_t** infos,
_Outptr_result_maybenull_z_ const char** error_message) EBPF_NO_EXCEPT;
ebpf_enumerate_sections(
_In_z_ const char* file,
bool verbose,
_Outptr_result_maybenull_ ebpf_section_info_t** infos,
_Outptr_result_maybenull_z_ const char** error_message) EBPF_NO_EXCEPT;

/**
* @brief Free memory returned from \ref ebpf_enumerate_programs.
Expand All @@ -114,8 +114,8 @@ extern "C"
* @param[in] data Memory to free.
* @deprecated Use ebpf_free_programs() instead.
*/
__declspec(deprecated("Use ebpf_free_programs() instead.")) void ebpf_free_sections(
_In_opt_ _Post_invalid_ ebpf_section_info_t* infos) EBPF_NO_EXCEPT;
__declspec(deprecated("Use ebpf_free_programs() instead.")) void
ebpf_free_sections(_In_opt_ _Post_invalid_ ebpf_section_info_t* infos) EBPF_NO_EXCEPT;

/**
* @brief Convert an eBPF program to human readable byte code.
Expand Down Expand Up @@ -144,7 +144,8 @@ extern "C"
* @param[out] error_message On failure points to a text description of
* the error.
*/
__declspec(deprecated("Use ebpf_api_elf_disassemble_program() instead.")) uint32_t ebpf_api_elf_disassemble_section(
__declspec(deprecated("Use ebpf_api_elf_disassemble_program() instead.")) uint32_t
ebpf_api_elf_disassemble_section(
_In_z_ const char* file,
_In_z_ const char* section,
_Outptr_result_maybenull_z_ const char** disassembly,
Expand Down Expand Up @@ -578,6 +579,22 @@ extern "C"
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;

/**
* @brief Write data into the perf event array map.
*
* @param [in] perf_event_array_map_fd perf event array 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 perf event array.
* @retval EBPF_OUT_OF_SPACE Unable to output to perf event array due to inadequate space.
* @retval EBPF_NO_MEMORY Out of memory.
*/
_Must_inspect_result_ ebpf_result_t
ebpf_perf_event_array_map_write(
fd_t perf_event_array_map_fd,
_In_reads_bytes_(data_length) const void* data,
size_t data_length) EBPF_NO_EXCEPT;

#ifdef __cplusplus
}
#endif
7 changes: 7 additions & 0 deletions include/ebpf_core_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ typedef struct _ebpf_ring_buffer_map_async_query_result
size_t consumer;
} ebpf_ring_buffer_map_async_query_result_t;

typedef struct _ebpf_perf_event_array_map_async_query_result
{
size_t producer;
size_t consumer;
size_t lost_count;
} ebpf_perf_event_array_map_async_query_result_t;

typedef enum _ebpf_object_type
{
EBPF_OBJECT_UNKNOWN,
Expand Down
37 changes: 25 additions & 12 deletions include/ebpf_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,22 @@ typedef enum bpf_map_type
BPF_MAP_TYPE_ARRAY = 2, ///< Array, where the map key is the array index.
BPF_MAP_TYPE_PROG_ARRAY =
3, ///< Array of program fds usable with bpf_tail_call, where the map key is the array index.
BPF_MAP_TYPE_PERCPU_HASH = 4, ///< Per-CPU hash table.
BPF_MAP_TYPE_PERCPU_ARRAY = 5, ///< Per-CPU array.
BPF_MAP_TYPE_HASH_OF_MAPS = 6, ///< Hash table, where the map value is another map.
BPF_MAP_TYPE_ARRAY_OF_MAPS = 7, ///< Array, where the map value is another map.
BPF_MAP_TYPE_LRU_HASH = 8, ///< Least-recently-used hash table.
BPF_MAP_TYPE_LPM_TRIE = 9, ///< Longest prefix match trie.
BPF_MAP_TYPE_QUEUE = 10, ///< Queue.
BPF_MAP_TYPE_LRU_PERCPU_HASH = 11, ///< Per-CPU least-recently-used hash table.
BPF_MAP_TYPE_STACK = 12, ///< Stack.
BPF_MAP_TYPE_RINGBUF = 13 ///< Ring buffer.
BPF_MAP_TYPE_PERCPU_HASH = 4, ///< Per-CPU hash table.
BPF_MAP_TYPE_PERCPU_ARRAY = 5, ///< Per-CPU array.
BPF_MAP_TYPE_HASH_OF_MAPS = 6, ///< Hash table, where the map value is another map.
BPF_MAP_TYPE_ARRAY_OF_MAPS = 7, ///< Array, where the map value is another map.
BPF_MAP_TYPE_LRU_HASH = 8, ///< Least-recently-used hash table.
BPF_MAP_TYPE_LPM_TRIE = 9, ///< Longest prefix match trie.
BPF_MAP_TYPE_QUEUE = 10, ///< Queue.
BPF_MAP_TYPE_LRU_PERCPU_HASH = 11, ///< Per-CPU least-recently-used hash table.
BPF_MAP_TYPE_STACK = 12, ///< Stack.
BPF_MAP_TYPE_RINGBUF = 13, ///< Ring buffer.
BPF_MAP_TYPE_PERF_EVENT_ARRAY = 14, ///< Perf event array.
} ebpf_map_type_t;

#define BPF_MAP_TYPE_PER_CPU(X) \
((X) == BPF_MAP_TYPE_PERCPU_HASH || (X) == BPF_MAP_TYPE_PERCPU_ARRAY || (X) == BPF_MAP_TYPE_LRU_PERCPU_HASH)
#define BPF_MAP_TYPE_PER_CPU(X) \
((X) == BPF_MAP_TYPE_PERCPU_HASH || (X) == BPF_MAP_TYPE_PERCPU_ARRAY || (X) == BPF_MAP_TYPE_LRU_PERCPU_HASH || \
(X) == BPF_MAP_TYPE_PERF_EVENT_ARRAY)

static const char* const _ebpf_map_type_names[] = {
BPF_ENUM_TO_STRING(BPF_MAP_TYPE_UNSPEC),
Expand All @@ -51,6 +53,7 @@ static const char* const _ebpf_map_type_names[] = {
BPF_ENUM_TO_STRING(BPF_MAP_TYPE_LRU_PERCPU_HASH),
BPF_ENUM_TO_STRING(BPF_MAP_TYPE_STACK),
BPF_ENUM_TO_STRING(BPF_MAP_TYPE_RINGBUF),
BPF_ENUM_TO_STRING(BPF_MAP_TYPE_PERF_EVENT_ARRAY),
};

static const char* const _ebpf_map_display_names[] = {
Expand All @@ -68,6 +71,7 @@ static const char* const _ebpf_map_display_names[] = {
"lru_percpu_hash",
"stack",
"ringbuf",
"perf_event_array",
};

typedef enum ebpf_map_option
Expand Down Expand Up @@ -166,6 +170,7 @@ typedef enum
BPF_FUNC_strnlen_s = 29, ///< \ref bpf_strnlen_s
BPF_FUNC_ktime_get_boot_ms = 30, ///< \ref bpf_ktime_get_boot_ms
BPF_FUNC_ktime_get_ms = 31, ///< \ref bpf_ktime_get_ms
BPF_FUNC_perf_event_output = 32, ///< \ref bpf_perf_event_output
} ebpf_helper_id_t;

// Cross-platform BPF program types.
Expand Down Expand Up @@ -408,3 +413,11 @@ struct bpf_prog_info
uint32_t pinned_path_count; ///< Number of pinned paths.
uint32_t link_count; ///< Number of attached links.
};

/* BPF_FUNC_perf_event_output flags. */
#define EBPF_MAP_FLAG_INDEX_MASK 0xffffffffULL
#define EBPF_MAP_FLAG_INDEX_SHIFT 0
#define EBPF_MAP_FLAG_CURRENT_CPU EBPF_MAP_FLAG_INDEX_MASK
/* BPF_FUNC_perf_event_output for program types with data pointer in context */
#define EBPF_MAP_FLAG_CTXLEN_SHIFT 32
#define EBPF_MAP_FLAG_CTXLEN_MASK (0xfffffULL << EBPF_MAP_FLAG_CTXLEN_SHIFT)
32 changes: 32 additions & 0 deletions libs/api/api_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
struct bpf_object;

typedef struct _ebpf_ring_buffer_subscription ring_buffer_subscription_t;
typedef struct _ebpf_perf_event_array_subscription perf_event_array_subscription_t;

typedef struct bpf_program
{
Expand Down Expand Up @@ -659,6 +660,37 @@ ebpf_ring_buffer_map_subscribe(
bool
ebpf_ring_buffer_map_unsubscribe(_In_ _Post_invalid_ ring_buffer_subscription_t* subscription) noexcept;

typedef void (*perf_buffer_sample_fn)(void* ctx, int cpu, void* data, uint32_t size);
typedef void (*perf_buffer_lost_fn)(void* ctx, int cpu, uint64_t cnt);

/**
* @brief Subscribe for notifications from the input perf event array map.
*
* @param[in] perf_event_array_map_fd File descriptor to the perf event array map.
* @param[in, out] sample_callback_context Pointer to supplied context to be passed in notification callback.
* @param[in] sample_callback Function pointer to notification handler.
* @param[in] lost_callback Function pointer to lost record notification handler.
* @param[out] subscription Opaque pointer to perf event array subscription object.
*
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_NO_MEMORY Out of memory.
*/
_Must_inspect_result_ ebpf_result_t
ebpf_perf_event_array_map_subscribe(
fd_t perf_event_array_map_fd,
_Inout_opt_ void* callback_context,
perf_buffer_sample_fn sample_callback,
perf_buffer_lost_fn lost_callback,
_Outptr_ perf_event_array_subscription_t** subscription) noexcept;

/**
* @brief Unsubscribe from the perf event array map event notifications.
*
* @param[in] subscription Pointer to perf event array subscription to be canceled.
*/
bool
ebpf_perf_event_array_map_unsubscribe(_In_ _Post_invalid_ perf_event_array_subscription_t* subscription) noexcept;

/**
* @brief Get list of programs and stats in an ELF eBPF file.
* @param[in] file Name of ELF file containing eBPF program.
Expand Down
Loading
Loading