ebpf-for-windows/libs/platform/ebpf_state.c

145 строки
3.9 KiB
C

// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#include "ebpf_state.h"
#include "ebpf_epoch.h"
#define EBPF_MAX_STATE_ENTRIES 64
// Table to track what state for each thread.
static ebpf_hash_table_t* _ebpf_state_thread_table = NULL;
static int64_t _ebpf_state_next_index = 0;
// Table to track what state for each CPU.
typedef struct _ebpf_state_entry
{
uintptr_t state[EBPF_MAX_STATE_ENTRIES];
} ebpf_state_entry_t;
static _Writable_elements_(_ebpf_state_cpu_table_size) ebpf_state_entry_t* _ebpf_state_cpu_table = NULL;
static uint32_t _ebpf_state_cpu_table_size = 0;
ebpf_result_t
ebpf_state_initiate()
{
ebpf_result_t return_value = EBPF_SUCCESS;
if (ebpf_is_non_preemptible_work_item_supported()) {
_ebpf_state_cpu_table_size = ebpf_get_cpu_count();
_Analysis_assume_(_ebpf_state_cpu_table_size >= 1);
_ebpf_state_cpu_table = ebpf_allocate_cache_aligned(sizeof(ebpf_state_entry_t) * _ebpf_state_cpu_table_size);
if (!_ebpf_state_cpu_table) {
return_value = EBPF_NO_MEMORY;
goto Error;
}
}
return_value = ebpf_hash_table_create(
&_ebpf_state_thread_table,
ebpf_epoch_allocate,
ebpf_epoch_free,
sizeof(uint64_t),
sizeof(ebpf_state_entry_t),
ebpf_get_cpu_count(),
NULL);
if (return_value != EBPF_SUCCESS) {
goto Error;
}
return return_value;
Error:
ebpf_state_terminate();
return return_value;
}
/**
* @brief Uninitialize the eBPF state tracking module.
*
*/
void
ebpf_state_terminate()
{
ebpf_hash_table_destroy(_ebpf_state_thread_table);
ebpf_free_cache_aligned(_ebpf_state_cpu_table);
}
ebpf_result_t
ebpf_state_allocate_index(_Out_ size_t* new_index)
{
if (_ebpf_state_next_index >= EBPF_MAX_STATE_ENTRIES) {
return EBPF_NO_MEMORY;
}
*new_index = ebpf_interlocked_increment_int64(&_ebpf_state_next_index) - 1;
return EBPF_SUCCESS;
}
ebpf_result_t
_ebpf_state_get_entry(_Out_ ebpf_state_entry_t** entry)
{
ebpf_state_entry_t* local_entry = NULL;
if (!ebpf_is_non_preemptible_work_item_supported() || ebpf_is_preemptible()) {
ebpf_result_t return_value;
uint64_t current_thread_id = ebpf_get_current_thread_id();
return_value =
ebpf_hash_table_find(_ebpf_state_thread_table, (const uint8_t*)&current_thread_id, (uint8_t**)&local_entry);
if (return_value == EBPF_KEY_NOT_FOUND) {
ebpf_state_entry_t new_entry = {0};
return_value = ebpf_hash_table_update(
_ebpf_state_thread_table,
(const uint8_t*)&current_thread_id,
(const uint8_t*)&new_entry,
NULL,
EBPF_HASH_TABLE_OPERATION_INSERT);
if (return_value != EBPF_SUCCESS) {
return return_value;
}
return_value = ebpf_hash_table_find(
_ebpf_state_thread_table, (const uint8_t*)&current_thread_id, (uint8_t**)&local_entry);
}
} else {
uint32_t current_cpu = ebpf_get_current_cpu();
if (current_cpu >= _ebpf_state_cpu_table_size) {
return EBPF_OPERATION_NOT_SUPPORTED;
}
local_entry = _ebpf_state_cpu_table + current_cpu;
}
*entry = local_entry;
return EBPF_SUCCESS;
}
ebpf_result_t
ebpf_state_store(size_t index, uintptr_t value)
{
ebpf_state_entry_t* entry = NULL;
ebpf_result_t return_value;
return_value = _ebpf_state_get_entry(&entry);
if (return_value == EBPF_SUCCESS) {
entry->state[index] = value;
}
return return_value;
}
ebpf_result_t
ebpf_state_load(size_t index, _Out_ uintptr_t* value)
{
ebpf_state_entry_t* entry = NULL;
ebpf_result_t return_value;
return_value = _ebpf_state_get_entry(&entry);
if (return_value == EBPF_SUCCESS) {
*value = entry->state[index];
}
return return_value;
}