2021-06-10 22:02:00 +03:00
|
|
|
// Copyright (c) Microsoft Corporation
|
|
|
|
// SPDX-License-Identifier: MIT
|
2021-04-16 02:15:00 +03:00
|
|
|
|
2021-04-20 01:43:45 +03:00
|
|
|
#include "ebpf_epoch.h"
|
2021-08-06 23:18:47 +03:00
|
|
|
#include "ebpf_handle.h"
|
2021-06-16 23:27:22 +03:00
|
|
|
#include "ebpf_maps.h"
|
2021-04-23 19:21:12 +03:00
|
|
|
#include "ebpf_object.h"
|
2021-08-06 23:18:47 +03:00
|
|
|
#include "ebpf_program.h"
|
2021-04-16 02:15:00 +03:00
|
|
|
|
2021-09-03 06:06:32 +03:00
|
|
|
#define PAD_CACHE(X) ((X + EBPF_CACHE_LINE_SIZE - 1) & ~(EBPF_CACHE_LINE_SIZE - 1))
|
2021-08-18 02:22:32 +03:00
|
|
|
|
2021-04-16 21:59:38 +03:00
|
|
|
typedef struct _ebpf_core_map
|
|
|
|
{
|
2021-04-23 19:21:12 +03:00
|
|
|
ebpf_object_t object;
|
2021-08-11 03:04:07 +03:00
|
|
|
ebpf_utf8_string_t name;
|
2021-08-31 05:14:08 +03:00
|
|
|
ebpf_map_definition_in_memory_t ebpf_map_definition;
|
2021-04-16 21:59:38 +03:00
|
|
|
ebpf_lock_t lock;
|
2021-08-18 02:22:32 +03:00
|
|
|
uint32_t original_value_size;
|
2021-08-31 05:14:08 +03:00
|
|
|
struct _ebpf_core_map* inner_map_template;
|
2021-04-16 21:59:38 +03:00
|
|
|
uint8_t* data;
|
|
|
|
} ebpf_core_map_t;
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
typedef struct _ebpf_core_object_map
|
2021-08-11 22:17:10 +03:00
|
|
|
{
|
|
|
|
ebpf_core_map_t core_map;
|
|
|
|
bool is_program_type_set;
|
|
|
|
ebpf_program_type_t program_type;
|
2021-08-24 04:46:24 +03:00
|
|
|
} ebpf_core_object_map_t;
|
|
|
|
|
2021-09-17 20:28:49 +03:00
|
|
|
typedef struct _ebpf_core_lru_map
|
|
|
|
{
|
|
|
|
ebpf_core_map_t core_map;
|
|
|
|
// https://github.com/microsoft/ebpf-for-windows/issues/557
|
|
|
|
// Investigate replacing this with a heap to speed up finding oldest key.
|
|
|
|
ebpf_hash_table_t* key_history;
|
|
|
|
} ebpf_core_lru_map_t;
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
_Ret_notnull_ static const ebpf_program_type_t*
|
|
|
|
_get_map_program_type(_In_ const ebpf_object_t* object)
|
|
|
|
{
|
|
|
|
const ebpf_core_object_map_t* map = (const ebpf_core_object_map_t*)object;
|
|
|
|
return &map->program_type;
|
|
|
|
}
|
2021-08-11 22:17:10 +03:00
|
|
|
|
2021-04-16 21:59:38 +03:00
|
|
|
typedef struct _ebpf_map_function_table
|
|
|
|
{
|
2021-08-31 05:14:08 +03:00
|
|
|
ebpf_core_map_t* (*create_map)(_In_ const ebpf_map_definition_in_memory_t* map_definition);
|
2021-04-16 21:59:38 +03:00
|
|
|
void (*delete_map)(_In_ ebpf_core_map_t* map);
|
2021-08-11 22:17:10 +03:00
|
|
|
ebpf_result_t (*associate_program)(_In_ ebpf_map_t* map, _In_ const ebpf_program_t* program);
|
2021-04-23 19:48:13 +03:00
|
|
|
uint8_t* (*find_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key);
|
2021-08-06 23:18:47 +03:00
|
|
|
ebpf_object_t* (*get_object_from_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key);
|
2021-08-24 00:49:50 +03:00
|
|
|
ebpf_result_t (*update_entry)(
|
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_ const uint8_t* value, ebpf_map_option_t option);
|
2021-08-06 23:18:47 +03:00
|
|
|
ebpf_result_t (*update_entry_with_handle)(
|
2021-09-10 02:02:42 +03:00
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, uintptr_t value_handle, ebpf_map_option_t option);
|
2021-08-18 02:22:32 +03:00
|
|
|
ebpf_result_t (*update_entry_per_cpu)(
|
2021-08-24 00:49:50 +03:00
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_ const uint8_t* value, ebpf_map_option_t option);
|
2021-05-20 22:38:58 +03:00
|
|
|
ebpf_result_t (*delete_entry)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key);
|
|
|
|
ebpf_result_t (*next_key)(_In_ ebpf_core_map_t* map, _In_ const uint8_t* previous_key, _Out_ uint8_t* next_key);
|
2021-04-16 21:59:38 +03:00
|
|
|
} ebpf_map_function_table_t;
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
ebpf_map_function_table_t ebpf_map_function_tables[];
|
|
|
|
|
2021-08-31 05:14:08 +03:00
|
|
|
const ebpf_map_definition_in_memory_t*
|
2021-06-16 23:27:22 +03:00
|
|
|
ebpf_map_get_definition(_In_ const ebpf_map_t* map)
|
2021-04-16 21:59:38 +03:00
|
|
|
{
|
|
|
|
return &map->ebpf_map_definition;
|
|
|
|
}
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
uint32_t
|
|
|
|
ebpf_map_get_effective_value_size(_In_ const ebpf_map_t* map)
|
|
|
|
{
|
|
|
|
return map->original_value_size;
|
|
|
|
}
|
|
|
|
|
2021-04-16 02:15:00 +03:00
|
|
|
static ebpf_core_map_t*
|
2021-09-10 02:02:42 +03:00
|
|
|
_create_array_map_with_map_struct_size(
|
|
|
|
size_t map_struct_size, _In_ const ebpf_map_definition_in_memory_t* map_definition)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
2021-05-20 22:38:58 +03:00
|
|
|
ebpf_result_t retval;
|
2021-04-16 02:15:00 +03:00
|
|
|
size_t map_data_size = 0;
|
|
|
|
ebpf_core_map_t* map = NULL;
|
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
retval = ebpf_safe_size_t_multiply(map_definition->max_entries, map_definition->value_size, &map_data_size);
|
2021-05-20 22:38:58 +03:00
|
|
|
if (retval != EBPF_SUCCESS) {
|
2021-04-16 02:15:00 +03:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
2021-08-11 22:17:10 +03:00
|
|
|
size_t full_map_size;
|
2021-09-03 06:06:32 +03:00
|
|
|
retval = ebpf_safe_size_t_add(PAD_CACHE(map_struct_size), map_data_size, &full_map_size);
|
2021-05-20 22:38:58 +03:00
|
|
|
if (retval != EBPF_SUCCESS) {
|
2021-04-16 02:15:00 +03:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
// allocate
|
2021-09-03 06:06:32 +03:00
|
|
|
map = ebpf_allocate_cache_aligned(full_map_size);
|
2021-04-16 02:15:00 +03:00
|
|
|
if (map == NULL) {
|
|
|
|
goto Done;
|
|
|
|
}
|
2021-08-11 22:17:10 +03:00
|
|
|
memset(map, 0, full_map_size);
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
map->ebpf_map_definition = *map_definition;
|
2021-09-03 06:06:32 +03:00
|
|
|
map->data = ((uint8_t*)map) + PAD_CACHE(map_struct_size);
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
Done:
|
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2021-08-06 23:18:47 +03:00
|
|
|
static ebpf_core_map_t*
|
2021-08-31 05:14:08 +03:00
|
|
|
_create_array_map(_In_ const ebpf_map_definition_in_memory_t* map_definition)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _create_array_map_with_map_struct_size(sizeof(ebpf_core_map_t), map_definition);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
2021-04-16 02:15:00 +03:00
|
|
|
static void
|
2021-08-06 23:18:47 +03:00
|
|
|
_delete_array_map(_In_ ebpf_core_map_t* map)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
2021-09-03 06:06:32 +03:00
|
|
|
ebpf_free_cache_aligned(map);
|
2021-04-16 02:15:00 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t*
|
2021-09-10 02:02:42 +03:00
|
|
|
_find_array_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
|
|
|
uint32_t key_value;
|
|
|
|
if (!map || !key)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
key_value = *(uint32_t*)key;
|
|
|
|
|
2021-08-11 22:17:10 +03:00
|
|
|
if (key_value >= map->ebpf_map_definition.max_entries)
|
2021-04-16 02:15:00 +03:00
|
|
|
return NULL;
|
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
return &map->data[key_value * map->ebpf_map_definition.value_size];
|
2021-04-16 02:15:00 +03:00
|
|
|
}
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
static ebpf_result_t
|
2021-08-24 00:49:50 +03:00
|
|
|
_update_array_map_entry(
|
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_opt_ const uint8_t* data, ebpf_map_option_t option)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
|
|
|
uint32_t key_value;
|
2021-08-18 02:22:32 +03:00
|
|
|
|
2021-08-24 00:49:50 +03:00
|
|
|
if (!map || !key || (option == EBPF_NOEXIST))
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
key_value = *(uint32_t*)key;
|
|
|
|
|
2021-08-06 23:18:47 +03:00
|
|
|
if (key_value >= map->ebpf_map_definition.max_entries)
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
uint8_t* entry = &map->data[*key * map->ebpf_map_definition.value_size];
|
2021-08-18 02:22:32 +03:00
|
|
|
if (data) {
|
|
|
|
memcpy(entry, data, map->ebpf_map_definition.value_size);
|
|
|
|
} else {
|
|
|
|
memset(entry, 0, map->ebpf_map_definition.value_size);
|
|
|
|
}
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_SUCCESS;
|
2021-04-16 02:15:00 +03:00
|
|
|
}
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
static ebpf_result_t
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_array_map_entry_with_reference(
|
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, ebpf_object_type_t value_type)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
|
|
|
uint32_t key_value;
|
|
|
|
if (!map || !key)
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
key_value = *(uint32_t*)key;
|
|
|
|
|
2021-09-17 20:28:49 +03:00
|
|
|
if (key_value >= map->ebpf_map_definition.max_entries)
|
2021-08-24 21:33:00 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
uint8_t* entry = &map->data[key_value * map->ebpf_map_definition.value_size];
|
2021-08-24 04:46:24 +03:00
|
|
|
ebpf_lock_state_t lock_state = ebpf_lock_lock(&map->lock);
|
2021-09-10 02:02:42 +03:00
|
|
|
if (value_type != EBPF_OBJECT_UNKNOWN) {
|
|
|
|
ebpf_id_t id = *(ebpf_id_t*)entry;
|
|
|
|
ebpf_object_dereference_by_id(id, value_type);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
2021-04-16 02:15:00 +03:00
|
|
|
memset(entry, 0, map->ebpf_map_definition.value_size);
|
2021-08-24 04:46:24 +03:00
|
|
|
ebpf_lock_unlock(&map->lock, lock_state);
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_SUCCESS;
|
2021-04-16 02:15:00 +03:00
|
|
|
}
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
static ebpf_result_t
|
2021-08-06 23:18:47 +03:00
|
|
|
_delete_array_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _delete_array_map_entry_with_reference(map, key, EBPF_OBJECT_UNKNOWN);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
|
|
|
_next_array_map_key(_In_ ebpf_core_map_t* map, _In_ const uint8_t* previous_key, _Out_ uint8_t* next_key)
|
2021-05-11 00:14:49 +03:00
|
|
|
{
|
|
|
|
uint32_t key_value;
|
|
|
|
if (!map || !next_key)
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-05-11 00:14:49 +03:00
|
|
|
|
|
|
|
if (previous_key) {
|
|
|
|
key_value = *(uint32_t*)previous_key;
|
|
|
|
key_value++;
|
|
|
|
} else
|
|
|
|
key_value = 0;
|
|
|
|
|
|
|
|
if (key_value >= map->ebpf_map_definition.max_entries)
|
2021-06-10 05:32:57 +03:00
|
|
|
return EBPF_NO_MORE_KEYS;
|
2021-05-11 00:14:49 +03:00
|
|
|
|
|
|
|
*(uint32_t*)next_key = key_value;
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_SUCCESS;
|
2021-05-11 00:14:49 +03:00
|
|
|
}
|
|
|
|
|
2021-04-16 02:15:00 +03:00
|
|
|
static ebpf_core_map_t*
|
2021-08-31 05:14:08 +03:00
|
|
|
_create_object_array_map(_In_ const ebpf_map_definition_in_memory_t* map_definition)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _create_array_map_with_map_struct_size(sizeof(ebpf_core_object_map_t), map_definition);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_object_array_map(_In_ ebpf_core_map_t* map, ebpf_object_type_t value_type)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
|
|
|
// Release all entry references.
|
|
|
|
for (uint32_t i = 0; i < map->ebpf_map_definition.max_entries; i++) {
|
2021-09-10 02:02:42 +03:00
|
|
|
ebpf_id_t id = *(ebpf_id_t*)&map->data[i * map->ebpf_map_definition.value_size];
|
|
|
|
ebpf_object_dereference_by_id(id, value_type);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
_delete_array_map(map);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
static void
|
|
|
|
_delete_program_array_map(_In_ ebpf_core_map_t* map)
|
|
|
|
{
|
|
|
|
_delete_object_array_map(map, EBPF_OBJECT_PROGRAM);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_delete_map_array_map(_In_ ebpf_core_map_t* map)
|
|
|
|
{
|
|
|
|
_delete_object_array_map(map, EBPF_OBJECT_MAP);
|
|
|
|
}
|
|
|
|
|
2021-08-11 22:17:10 +03:00
|
|
|
static ebpf_result_t
|
|
|
|
_associate_program_with_prog_array_map(_In_ ebpf_core_map_t* map, _In_ const ebpf_program_t* program)
|
|
|
|
{
|
|
|
|
ebpf_assert(map->ebpf_map_definition.type == BPF_MAP_TYPE_PROG_ARRAY);
|
2021-08-24 04:46:24 +03:00
|
|
|
ebpf_core_object_map_t* program_array = (ebpf_core_object_map_t*)map;
|
2021-08-11 22:17:10 +03:00
|
|
|
|
|
|
|
// Validate that the program type is
|
|
|
|
// not in conflict with the map's program type.
|
|
|
|
const ebpf_program_type_t* program_type = ebpf_program_type(program);
|
|
|
|
ebpf_result_t result = EBPF_SUCCESS;
|
|
|
|
|
|
|
|
ebpf_lock_state_t lock_state = ebpf_lock_lock(&map->lock);
|
|
|
|
|
|
|
|
if (!program_array->is_program_type_set) {
|
|
|
|
program_array->is_program_type_set = TRUE;
|
|
|
|
program_array->program_type = *program_type;
|
|
|
|
} else if (memcmp(&program_array->program_type, program_type, sizeof(*program_type)) != 0) {
|
|
|
|
result = EBPF_INVALID_FD;
|
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_lock_unlock(&map->lock, lock_state);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-08-31 05:14:08 +03:00
|
|
|
static bool // Returns true if ok, false if not.
|
|
|
|
_check_value_type(_In_ const ebpf_core_map_t* outer_map, _In_ const ebpf_object_t* value_object)
|
|
|
|
{
|
|
|
|
if (outer_map->ebpf_map_definition.type != BPF_MAP_TYPE_ARRAY_OF_MAPS &&
|
|
|
|
outer_map->ebpf_map_definition.type != BPF_MAP_TYPE_HASH_OF_MAPS) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_core_map_t* template = outer_map->inner_map_template;
|
|
|
|
const ebpf_map_t* value_map = (ebpf_map_t*)value_object;
|
|
|
|
|
2021-09-10 07:11:19 +03:00
|
|
|
bool allowed = (template != NULL) && (value_map->ebpf_map_definition.type == template->ebpf_map_definition.type) &&
|
|
|
|
(value_map->ebpf_map_definition.key_size == template->ebpf_map_definition.key_size) &&
|
|
|
|
(value_map->ebpf_map_definition.value_size == template->ebpf_map_definition.value_size) &&
|
|
|
|
(value_map->ebpf_map_definition.max_entries == template->ebpf_map_definition.max_entries);
|
2021-08-31 05:14:08 +03:00
|
|
|
|
|
|
|
return allowed;
|
|
|
|
}
|
|
|
|
|
2021-08-06 23:18:47 +03:00
|
|
|
static ebpf_result_t
|
2021-08-24 04:46:24 +03:00
|
|
|
_update_array_map_entry_with_handle(
|
|
|
|
_In_ ebpf_core_map_t* map,
|
|
|
|
_In_ const uint8_t* key,
|
|
|
|
ebpf_object_type_t value_type,
|
|
|
|
uintptr_t value_handle,
|
|
|
|
ebpf_map_option_t option)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
if (!map || !key || (option == EBPF_NOEXIST))
|
2021-08-24 04:46:24 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
|
2021-08-06 23:18:47 +03:00
|
|
|
uint32_t index = *(uint32_t*)key;
|
|
|
|
|
|
|
|
if (index >= map->ebpf_map_definition.max_entries)
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
// Convert value handle to an object pointer.
|
2021-08-31 05:14:08 +03:00
|
|
|
ebpf_object_t* value_object;
|
|
|
|
int return_value = ebpf_reference_object_by_handle(value_handle, value_type, &value_object);
|
2021-08-06 23:18:47 +03:00
|
|
|
if (return_value != EBPF_SUCCESS)
|
|
|
|
return return_value;
|
|
|
|
|
|
|
|
// The following addition is safe since it was checked during map creation.
|
2021-08-24 04:46:24 +03:00
|
|
|
size_t actual_value_size = ((size_t)map->ebpf_map_definition.value_size) + sizeof(struct _ebpf_object*);
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-08-11 22:17:10 +03:00
|
|
|
ebpf_result_t result = EBPF_SUCCESS;
|
|
|
|
|
2021-08-31 05:14:08 +03:00
|
|
|
const ebpf_program_type_t* value_program_type =
|
|
|
|
(value_object->get_program_type) ? value_object->get_program_type(value_object) : NULL;
|
|
|
|
|
2021-08-11 22:17:10 +03:00
|
|
|
ebpf_lock_state_t lock_state = ebpf_lock_lock(&map->lock);
|
|
|
|
|
2021-08-31 05:14:08 +03:00
|
|
|
if (value_type == EBPF_OBJECT_MAP) {
|
|
|
|
// Validate that the value is of the correct type.
|
|
|
|
if (!_check_value_type(map, value_object)) {
|
|
|
|
ebpf_object_release_reference(value_object);
|
|
|
|
result = EBPF_INVALID_FD;
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Validate that the value's program type (if any) is
|
|
|
|
// not in conflict with the map's program type.
|
2021-08-24 04:46:24 +03:00
|
|
|
if (value_program_type) {
|
2021-08-31 05:14:08 +03:00
|
|
|
ebpf_core_object_map_t* map_of_objects = (ebpf_core_object_map_t*)map;
|
|
|
|
if (!map_of_objects->is_program_type_set) {
|
|
|
|
map_of_objects->is_program_type_set = TRUE;
|
|
|
|
map_of_objects->program_type = *value_program_type;
|
|
|
|
} else if (memcmp(&map_of_objects->program_type, value_program_type, sizeof(*value_program_type)) != 0) {
|
|
|
|
ebpf_object_release_reference(value_object);
|
2021-08-24 04:46:24 +03:00
|
|
|
result = EBPF_INVALID_FD;
|
|
|
|
goto Done;
|
|
|
|
}
|
2021-08-11 22:17:10 +03:00
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
// Release the reference on the old ID stored here, if any.
|
2021-08-06 23:18:47 +03:00
|
|
|
uint8_t* entry = &map->data[*key * actual_value_size];
|
2021-09-10 02:02:42 +03:00
|
|
|
ebpf_id_t old_id = *(ebpf_id_t*)entry;
|
|
|
|
if (old_id) {
|
|
|
|
ebpf_object_dereference_by_id(old_id, value_type);
|
2021-08-18 02:22:32 +03:00
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
// Store the object ID as the value.
|
|
|
|
memcpy(entry, &value_object->id, map->ebpf_map_definition.value_size);
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-08-11 22:17:10 +03:00
|
|
|
Done:
|
|
|
|
ebpf_lock_unlock(&map->lock, lock_state);
|
|
|
|
|
|
|
|
return result;
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
2021-08-24 04:46:24 +03:00
|
|
|
_update_prog_array_map_entry_with_handle(
|
2021-09-10 02:02:42 +03:00
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, uintptr_t value_handle, ebpf_map_option_t option)
|
2021-08-24 04:46:24 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _update_array_map_entry_with_handle(map, key, EBPF_OBJECT_PROGRAM, value_handle, option);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
|
|
|
_update_map_array_map_entry_with_handle(
|
2021-09-10 02:02:42 +03:00
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, uintptr_t value_handle, ebpf_map_option_t option)
|
|
|
|
{
|
|
|
|
return _update_array_map_entry_with_handle(map, key, EBPF_OBJECT_MAP, value_handle, option);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
|
|
|
_delete_program_array_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
2021-08-24 04:46:24 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _delete_array_map_entry_with_reference(map, key, EBPF_OBJECT_PROGRAM);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_map_array_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _delete_array_map_entry_with_reference(map, key, EBPF_OBJECT_MAP);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Get an object from a map entry that holds objects, such
|
2021-08-24 04:46:24 +03:00
|
|
|
* as a program array or array of maps. The object returned holds a
|
2021-08-06 23:18:47 +03:00
|
|
|
* reference that the caller is responsible for releasing.
|
|
|
|
*
|
|
|
|
* @param[in] map Array map to search.
|
|
|
|
* @param[in] key Pointer to the key to search for.
|
|
|
|
* @returns Object pointer, or NULL if none.
|
|
|
|
*/
|
|
|
|
static _Ret_maybenull_ ebpf_object_t*
|
|
|
|
_get_object_from_array_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
|
|
|
{
|
|
|
|
uint32_t index = *(uint32_t*)key;
|
|
|
|
|
|
|
|
// We need to take a lock here to make sure we can
|
|
|
|
// safely reference the object when another thread
|
|
|
|
// might be trying to delete the entry we find.
|
|
|
|
ebpf_lock_state_t lock_state = ebpf_lock_lock(&map->lock);
|
|
|
|
|
|
|
|
ebpf_object_t* object = NULL;
|
2021-09-10 02:02:42 +03:00
|
|
|
uint8_t* value = _find_array_map_entry(map, (uint8_t*)&index);
|
2021-08-06 23:18:47 +03:00
|
|
|
if (value != NULL) {
|
2021-09-10 02:02:42 +03:00
|
|
|
ebpf_id_t id = *(ebpf_id_t*)&map->data[index * map->ebpf_map_definition.value_size];
|
|
|
|
ebpf_object_type_t value_type =
|
|
|
|
(map->ebpf_map_definition.type == BPF_MAP_TYPE_PROG_ARRAY) ? EBPF_OBJECT_PROGRAM : EBPF_OBJECT_MAP;
|
|
|
|
(void)ebpf_object_reference_by_id(id, value_type, &object);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_lock_unlock(&map->lock, lock_state);
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_core_map_t*
|
2021-09-10 02:02:42 +03:00
|
|
|
_create_hash_map_with_map_struct_size(
|
|
|
|
size_t map_struct_size, _In_ const ebpf_map_definition_in_memory_t* map_definition)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
2021-05-20 22:38:58 +03:00
|
|
|
ebpf_result_t retval;
|
2021-04-16 02:15:00 +03:00
|
|
|
ebpf_core_map_t* map = NULL;
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
map = ebpf_allocate(map_struct_size);
|
2021-04-16 02:15:00 +03:00
|
|
|
if (map == NULL) {
|
2021-05-20 22:38:58 +03:00
|
|
|
retval = EBPF_NO_MEMORY;
|
2021-04-16 02:15:00 +03:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
|
|
|
map->ebpf_map_definition = *map_definition;
|
|
|
|
map->data = NULL;
|
|
|
|
|
2021-08-21 03:29:11 +03:00
|
|
|
// Note:
|
|
|
|
// ebpf_hash_table_t doesn't require synchronization as long as allocations
|
|
|
|
// are performed using the epoch allocator.
|
2021-04-16 02:15:00 +03:00
|
|
|
retval = ebpf_hash_table_create(
|
2021-04-20 01:43:45 +03:00
|
|
|
(ebpf_hash_table_t**)&map->data,
|
|
|
|
ebpf_epoch_allocate,
|
|
|
|
ebpf_epoch_free,
|
|
|
|
map->ebpf_map_definition.key_size,
|
2021-09-10 02:02:42 +03:00
|
|
|
map->ebpf_map_definition.value_size,
|
2021-08-21 03:29:11 +03:00
|
|
|
map->ebpf_map_definition.max_entries,
|
2021-04-20 02:12:08 +03:00
|
|
|
NULL);
|
2021-05-20 22:38:58 +03:00
|
|
|
if (retval != EBPF_SUCCESS) {
|
2021-04-16 02:15:00 +03:00
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
retval = EBPF_SUCCESS;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
Done:
|
2021-05-20 22:38:58 +03:00
|
|
|
if (retval != EBPF_SUCCESS) {
|
2021-04-16 02:15:00 +03:00
|
|
|
if (map && map->data) {
|
|
|
|
ebpf_hash_table_destroy((ebpf_hash_table_t*)map->data);
|
|
|
|
}
|
|
|
|
ebpf_free(map);
|
|
|
|
map = NULL;
|
|
|
|
}
|
|
|
|
return map;
|
|
|
|
}
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
static ebpf_core_map_t*
|
2021-08-31 05:14:08 +03:00
|
|
|
_create_hash_map(_In_ const ebpf_map_definition_in_memory_t* map_definition)
|
2021-08-24 04:46:24 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _create_hash_map_with_map_struct_size(sizeof(ebpf_core_map_t), map_definition);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_core_map_t*
|
2021-08-31 05:14:08 +03:00
|
|
|
_create_object_hash_map(_In_ const ebpf_map_definition_in_memory_t* map_definition)
|
2021-08-24 04:46:24 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _create_hash_map_with_map_struct_size(sizeof(ebpf_core_object_map_t), map_definition);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
2021-09-17 20:28:49 +03:00
|
|
|
static ebpf_core_map_t*
|
|
|
|
_create_lru_hash_map(_In_ const ebpf_map_definition_in_memory_t* map_definition)
|
|
|
|
{
|
|
|
|
ebpf_core_lru_map_t* map =
|
|
|
|
(ebpf_core_lru_map_t*)_create_hash_map_with_map_struct_size(sizeof(ebpf_core_lru_map_t), map_definition);
|
|
|
|
if (map) {
|
|
|
|
ebpf_result_t retval;
|
|
|
|
// Note:
|
|
|
|
// ebpf_hash_table_t doesn't require synchronization as long as allocations
|
|
|
|
// are performed using the epoch allocator.
|
|
|
|
retval = ebpf_hash_table_create(
|
|
|
|
&map->key_history,
|
|
|
|
ebpf_epoch_allocate,
|
|
|
|
ebpf_epoch_free,
|
|
|
|
map->core_map.ebpf_map_definition.key_size,
|
|
|
|
sizeof(uint64_t),
|
|
|
|
map->core_map.ebpf_map_definition.max_entries,
|
|
|
|
NULL);
|
|
|
|
if (retval != EBPF_SUCCESS) {
|
|
|
|
ebpf_hash_table_destroy((ebpf_hash_table_t*)map->core_map.data);
|
|
|
|
ebpf_free(map);
|
|
|
|
map = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (map) ? &map->core_map : NULL;
|
|
|
|
}
|
|
|
|
|
2021-04-16 02:15:00 +03:00
|
|
|
static void
|
2021-08-06 23:18:47 +03:00
|
|
|
_delete_hash_map(_In_ ebpf_core_map_t* map)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
|
|
|
ebpf_hash_table_destroy((ebpf_hash_table_t*)map->data);
|
|
|
|
ebpf_free(map);
|
|
|
|
}
|
|
|
|
|
2021-09-17 20:28:49 +03:00
|
|
|
static void
|
|
|
|
_delete_lru_hash_map(_In_ ebpf_core_map_t* map)
|
|
|
|
{
|
|
|
|
ebpf_core_lru_map_t* lru_map = EBPF_FROM_FIELD(ebpf_core_lru_map_t, core_map, map);
|
|
|
|
ebpf_hash_table_destroy(lru_map->key_history);
|
|
|
|
ebpf_hash_table_destroy((ebpf_hash_table_t*)lru_map->core_map.data);
|
|
|
|
ebpf_free(map);
|
|
|
|
}
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
static void
|
|
|
|
_delete_object_hash_map(_In_ ebpf_core_map_t* map)
|
|
|
|
{
|
|
|
|
// Release all entry references.
|
|
|
|
uint8_t* next_key;
|
|
|
|
for (uint8_t* previous_key = NULL;; previous_key = next_key) {
|
|
|
|
uint8_t* value;
|
|
|
|
ebpf_result_t result =
|
|
|
|
ebpf_hash_table_next_key_pointer_and_value((ebpf_hash_table_t*)map->data, NULL, &next_key, &value);
|
|
|
|
if (result != EBPF_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
2021-09-10 02:02:42 +03:00
|
|
|
ebpf_id_t id = *(ebpf_id_t*)value;
|
|
|
|
ebpf_object_dereference_by_id(id, EBPF_OBJECT_MAP);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
_delete_hash_map(map);
|
|
|
|
}
|
|
|
|
|
2021-09-17 20:28:49 +03:00
|
|
|
static ebpf_result_t
|
|
|
|
_update_key_history(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, bool remove)
|
|
|
|
{
|
|
|
|
uint64_t now;
|
|
|
|
ebpf_core_lru_map_t* lru_map;
|
|
|
|
if (map->ebpf_map_definition.type != BPF_MAP_TYPE_LRU_HASH) {
|
|
|
|
return EBPF_SUCCESS;
|
|
|
|
}
|
|
|
|
lru_map = EBPF_FROM_FIELD(ebpf_core_lru_map_t, core_map, map);
|
|
|
|
now = ebpf_query_time_since_boot(true);
|
|
|
|
|
|
|
|
if (!remove) {
|
|
|
|
return ebpf_hash_table_update(lru_map->key_history, key, (uint8_t*)&now, EBPF_HASH_TABLE_OPERATION_ANY);
|
|
|
|
} else {
|
|
|
|
return ebpf_hash_table_delete(lru_map->key_history, key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
_reap_oldest_map_entry(_In_ ebpf_core_map_t* map)
|
|
|
|
{
|
|
|
|
uint8_t* previous_key = NULL;
|
|
|
|
uint8_t* next_key = NULL;
|
|
|
|
uint8_t* oldest_key = NULL;
|
|
|
|
uint64_t* key_age = NULL;
|
|
|
|
uint64_t oldest_key_age = MAXUINT64;
|
|
|
|
ebpf_result_t result;
|
|
|
|
ebpf_core_lru_map_t* lru_map;
|
|
|
|
|
|
|
|
if (map->ebpf_map_definition.type != BPF_MAP_TYPE_LRU_HASH) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
lru_map = EBPF_FROM_FIELD(ebpf_core_lru_map_t, core_map, map);
|
|
|
|
|
|
|
|
// Walk through all the keys and values and find the oldest one.
|
|
|
|
for (;;) {
|
|
|
|
result = ebpf_hash_table_next_key_pointer_and_value(
|
|
|
|
lru_map->key_history, previous_key, &next_key, (uint8_t**)&key_age);
|
|
|
|
if (result != EBPF_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*key_age < oldest_key_age) {
|
|
|
|
oldest_key_age = *key_age;
|
|
|
|
oldest_key = next_key;
|
|
|
|
}
|
|
|
|
previous_key = next_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reached the end of the keys, delete the oldest one found.
|
|
|
|
if (result == EBPF_NO_MORE_KEYS && oldest_key != NULL) {
|
|
|
|
ebpf_hash_table_delete((ebpf_hash_table_t*)lru_map->core_map.data, oldest_key);
|
|
|
|
_update_key_history(map, oldest_key, true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-16 02:15:00 +03:00
|
|
|
static uint8_t*
|
2021-08-06 23:18:47 +03:00
|
|
|
_find_hash_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
|
|
|
uint8_t* value = NULL;
|
|
|
|
if (!map || !key)
|
|
|
|
return NULL;
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
if (ebpf_hash_table_find((ebpf_hash_table_t*)map->data, key, &value) != EBPF_SUCCESS) {
|
2021-04-16 02:15:00 +03:00
|
|
|
value = NULL;
|
|
|
|
}
|
|
|
|
|
2021-09-17 20:28:49 +03:00
|
|
|
if (value)
|
|
|
|
_update_key_history(map, key, false);
|
|
|
|
|
2021-04-16 02:15:00 +03:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
/**
|
|
|
|
* @brief Get an object from a map entry that holds objects, such
|
|
|
|
* as a hash of maps. The object returned holds a
|
|
|
|
* reference that the caller is responsible for releasing.
|
|
|
|
*
|
|
|
|
* @param[in] map Hash map to search.
|
|
|
|
* @param[in] key Pointer to the key to search for.
|
|
|
|
* @returns Object pointer, or NULL if none.
|
|
|
|
*/
|
|
|
|
static _Ret_maybenull_ ebpf_object_t*
|
|
|
|
_get_object_from_hash_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
|
|
|
{
|
|
|
|
// We need to take a lock here to make sure we can
|
|
|
|
// safely reference the object when another thread
|
|
|
|
// might be trying to delete the entry we find.
|
|
|
|
ebpf_lock_state_t lock_state = ebpf_lock_lock(&map->lock);
|
|
|
|
|
|
|
|
ebpf_object_t* object = NULL;
|
|
|
|
uint8_t* value = _find_hash_map_entry(map, key);
|
|
|
|
if (value != NULL) {
|
2021-09-10 02:02:42 +03:00
|
|
|
ebpf_id_t id = *(ebpf_id_t*)value;
|
|
|
|
(void)ebpf_object_reference_by_id(id, EBPF_OBJECT_MAP, &object);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_lock_unlock(&map->lock, lock_state);
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
static ebpf_result_t
|
2021-08-24 00:49:50 +03:00
|
|
|
_update_hash_map_entry(
|
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_opt_ const uint8_t* data, ebpf_map_option_t option)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
2021-05-20 22:38:58 +03:00
|
|
|
ebpf_result_t result;
|
2021-05-11 00:14:49 +03:00
|
|
|
size_t entry_count = 0;
|
|
|
|
uint8_t* value;
|
2021-08-24 00:49:50 +03:00
|
|
|
ebpf_hash_table_operations_t hash_table_operation;
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
if (!map || !key)
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
2021-08-24 00:49:50 +03:00
|
|
|
switch (option) {
|
|
|
|
case EBPF_ANY:
|
|
|
|
hash_table_operation = EBPF_HASH_TABLE_OPERATION_ANY;
|
|
|
|
break;
|
|
|
|
case EBPF_NOEXIST:
|
|
|
|
hash_table_operation = EBPF_HASH_TABLE_OPERATION_INSERT;
|
|
|
|
break;
|
|
|
|
case EBPF_EXIST:
|
|
|
|
hash_table_operation = EBPF_HASH_TABLE_OPERATION_REPLACE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
2021-05-11 00:14:49 +03:00
|
|
|
entry_count = ebpf_hash_table_key_count((ebpf_hash_table_t*)map->data);
|
|
|
|
|
|
|
|
if ((entry_count == map->ebpf_map_definition.max_entries) &&
|
2021-09-17 20:28:49 +03:00
|
|
|
(ebpf_hash_table_find((ebpf_hash_table_t*)map->data, key, &value) != EBPF_SUCCESS) &&
|
|
|
|
!_reap_oldest_map_entry(map))
|
2021-05-20 22:38:58 +03:00
|
|
|
result = EBPF_INVALID_ARGUMENT;
|
2021-05-11 00:14:49 +03:00
|
|
|
else
|
2021-09-10 02:02:42 +03:00
|
|
|
result = ebpf_hash_table_update((ebpf_hash_table_t*)map->data, key, data, hash_table_operation);
|
2021-08-21 03:29:11 +03:00
|
|
|
|
2021-09-17 20:28:49 +03:00
|
|
|
if (result == EBPF_SUCCESS)
|
|
|
|
_update_key_history(map, key, false);
|
|
|
|
|
2021-05-11 00:14:49 +03:00
|
|
|
return result;
|
2021-04-16 02:15:00 +03:00
|
|
|
}
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
static ebpf_result_t
|
2021-08-24 04:46:24 +03:00
|
|
|
_update_hash_map_entry_with_handle(
|
|
|
|
_In_ ebpf_core_map_t* map,
|
|
|
|
_In_ const uint8_t* key,
|
|
|
|
ebpf_object_type_t value_type,
|
|
|
|
uintptr_t value_handle,
|
|
|
|
ebpf_map_option_t option)
|
|
|
|
{
|
|
|
|
ebpf_result_t result = EBPF_SUCCESS;
|
|
|
|
ebpf_lock_state_t lock_state;
|
|
|
|
size_t entry_count = 0;
|
2021-09-10 02:02:42 +03:00
|
|
|
if (!map || !key)
|
2021-08-24 04:46:24 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
|
|
|
|
ebpf_hash_table_operations_t hash_table_operation;
|
|
|
|
switch (option) {
|
|
|
|
case EBPF_ANY:
|
|
|
|
hash_table_operation = EBPF_HASH_TABLE_OPERATION_ANY;
|
|
|
|
break;
|
|
|
|
case EBPF_NOEXIST:
|
|
|
|
hash_table_operation = EBPF_HASH_TABLE_OPERATION_INSERT;
|
|
|
|
break;
|
|
|
|
case EBPF_EXIST:
|
|
|
|
hash_table_operation = EBPF_HASH_TABLE_OPERATION_REPLACE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert value handle to an object pointer.
|
|
|
|
struct _ebpf_object* object;
|
|
|
|
int return_value = ebpf_reference_object_by_handle(value_handle, value_type, &object);
|
|
|
|
if (return_value != EBPF_SUCCESS)
|
|
|
|
return return_value;
|
|
|
|
|
|
|
|
// Validate that the object's program type is
|
|
|
|
// not in conflict with the map's program type.
|
|
|
|
const ebpf_program_type_t* program_type = (object->get_program_type) ? object->get_program_type(object) : NULL;
|
|
|
|
ebpf_core_object_map_t* object_map = (ebpf_core_object_map_t*)map;
|
|
|
|
|
|
|
|
lock_state = ebpf_lock_lock(&map->lock);
|
|
|
|
entry_count = ebpf_hash_table_key_count((ebpf_hash_table_t*)map->data);
|
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
uint8_t* old_value = NULL;
|
|
|
|
ebpf_result_t found_result = ebpf_hash_table_find((ebpf_hash_table_t*)map->data, key, &old_value);
|
|
|
|
|
|
|
|
if ((entry_count == map->ebpf_map_definition.max_entries) && (found_result != EBPF_SUCCESS)) {
|
|
|
|
// The hash table is already full.
|
2021-08-24 04:46:24 +03:00
|
|
|
result = EBPF_INVALID_ARGUMENT;
|
2021-09-10 02:02:42 +03:00
|
|
|
} else {
|
2021-08-24 04:46:24 +03:00
|
|
|
if (program_type != NULL) {
|
2021-09-10 02:02:42 +03:00
|
|
|
// Verify that the program type of the object being set is not in
|
|
|
|
// conflict with the map's program type.
|
2021-08-24 04:46:24 +03:00
|
|
|
if (!object_map->is_program_type_set) {
|
|
|
|
object_map->is_program_type_set = TRUE;
|
|
|
|
object_map->program_type = *program_type;
|
|
|
|
} else if (memcmp(&object_map->program_type, program_type, sizeof(*program_type)) != 0) {
|
|
|
|
ebpf_object_release_reference((ebpf_object_t*)object);
|
|
|
|
result = EBPF_INVALID_FD;
|
|
|
|
goto Done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
// Release the reference on the old ID stored here, if any.
|
|
|
|
if (old_value) {
|
|
|
|
ebpf_id_t old_id = *(ebpf_id_t*)old_value;
|
|
|
|
if (old_id) {
|
|
|
|
ebpf_object_dereference_by_id(old_id, value_type);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the new object ID as the value.
|
|
|
|
result =
|
|
|
|
ebpf_hash_table_update((ebpf_hash_table_t*)map->data, key, (uint8_t*)&object->id, hash_table_operation);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
Done:
|
|
|
|
ebpf_lock_unlock(&map->lock, lock_state);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
|
|
|
_update_map_hash_map_entry_with_handle(
|
2021-09-10 02:02:42 +03:00
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, uintptr_t value_handle, ebpf_map_option_t option)
|
2021-08-24 04:46:24 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _update_hash_map_entry_with_handle(map, key, EBPF_OBJECT_MAP, value_handle, option);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_hash_map_entry_with_reference(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, ebpf_object_type_t value_type)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
2021-05-20 22:38:58 +03:00
|
|
|
ebpf_result_t result;
|
2021-04-16 02:15:00 +03:00
|
|
|
if (!map || !key)
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
2021-09-10 02:02:42 +03:00
|
|
|
if (value_type != EBPF_OBJECT_UNKNOWN) {
|
2021-08-24 04:46:24 +03:00
|
|
|
uint8_t* value = NULL;
|
|
|
|
if (ebpf_hash_table_find((ebpf_hash_table_t*)map->data, key, &value) == EBPF_SUCCESS) {
|
2021-09-10 02:02:42 +03:00
|
|
|
ebpf_id_t id = *(ebpf_id_t*)value;
|
|
|
|
ebpf_object_dereference_by_id(id, value_type);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
}
|
2021-04-16 02:15:00 +03:00
|
|
|
result = ebpf_hash_table_delete((ebpf_hash_table_t*)map->data, key);
|
2021-05-11 00:14:49 +03:00
|
|
|
return result;
|
2021-04-16 02:15:00 +03:00
|
|
|
}
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
static ebpf_result_t
|
|
|
|
_delete_hash_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
|
|
|
{
|
2021-09-17 20:28:49 +03:00
|
|
|
_update_key_history(map, key, true);
|
2021-09-10 02:02:42 +03:00
|
|
|
return _delete_hash_map_entry_with_reference(map, key, EBPF_OBJECT_UNKNOWN);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static ebpf_result_t
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_map_hash_map_entry(_In_ ebpf_core_map_t* map, _In_ const uint8_t* key)
|
2021-08-24 04:46:24 +03:00
|
|
|
{
|
2021-09-10 02:02:42 +03:00
|
|
|
return _delete_hash_map_entry_with_reference(map, key, EBPF_OBJECT_MAP);
|
2021-08-24 04:46:24 +03:00
|
|
|
}
|
|
|
|
|
2021-05-20 22:38:58 +03:00
|
|
|
static ebpf_result_t
|
2021-08-06 23:18:47 +03:00
|
|
|
_next_hash_map_key(_In_ ebpf_core_map_t* map, _In_ const uint8_t* previous_key, _Out_ uint8_t* next_key)
|
2021-04-16 02:15:00 +03:00
|
|
|
{
|
2021-05-20 22:38:58 +03:00
|
|
|
ebpf_result_t result;
|
2021-04-16 02:15:00 +03:00
|
|
|
if (!map || !next_key)
|
2021-05-20 22:38:58 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-04-16 02:15:00 +03:00
|
|
|
|
|
|
|
result = ebpf_hash_table_next_key((ebpf_hash_table_t*)map->data, previous_key, next_key);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-08-12 01:39:54 +03:00
|
|
|
static ebpf_result_t
|
2021-08-18 02:22:32 +03:00
|
|
|
_ebpf_adjust_value_pointer(_In_ ebpf_map_t* map, _Inout_ uint8_t** value)
|
2021-08-12 01:39:54 +03:00
|
|
|
{
|
|
|
|
uint32_t current_cpu;
|
2021-09-03 06:06:32 +03:00
|
|
|
uint32_t max_cpu = map->ebpf_map_definition.value_size / PAD_CACHE(map->original_value_size);
|
2021-08-18 02:22:32 +03:00
|
|
|
switch (map->ebpf_map_definition.type) {
|
|
|
|
case BPF_MAP_TYPE_PERCPU_ARRAY:
|
|
|
|
case BPF_MAP_TYPE_PERCPU_HASH:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return EBPF_SUCCESS;
|
2021-08-12 01:39:54 +03:00
|
|
|
}
|
|
|
|
current_cpu = ebpf_get_current_cpu();
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
if (current_cpu > max_cpu) {
|
2021-08-12 01:39:54 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-08-18 02:22:32 +03:00
|
|
|
}
|
2021-09-03 06:06:32 +03:00
|
|
|
(*value) += PAD_CACHE((size_t)map->original_value_size) * current_cpu;
|
2021-08-12 01:39:54 +03:00
|
|
|
return EBPF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
/**
|
|
|
|
* @brief Insert the supplied value into the per-cpu value buffer of the map.
|
|
|
|
* If the map doesn't contain an existing value, create a new all-zero value,
|
|
|
|
* insert it, then set the per-cpu value. Note: This races with updates to the
|
|
|
|
* value buffer from user mode.
|
|
|
|
*
|
|
|
|
* @param[in] map Map to update.
|
|
|
|
* @param[in] key Key to search for.
|
|
|
|
* @param[in] value Value to insert.
|
|
|
|
* @retval EBPF_SUCCESS The operation was successful.
|
|
|
|
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
|
|
|
|
* entry.
|
|
|
|
* @retval EBPF_INVALID_ARGUMENT Unable to perform this operation due to
|
|
|
|
* current CPU > allocated value buffer size.
|
|
|
|
*/
|
|
|
|
ebpf_result_t
|
2021-08-24 00:49:50 +03:00
|
|
|
_update_entry_per_cpu(
|
|
|
|
_In_ ebpf_core_map_t* map, _In_ const uint8_t* key, _In_ const uint8_t* value, ebpf_map_option_t option)
|
2021-08-18 02:22:32 +03:00
|
|
|
{
|
|
|
|
uint8_t* target = ebpf_map_function_tables[map->ebpf_map_definition.type].find_entry(map, key);
|
|
|
|
if (!target) {
|
|
|
|
ebpf_result_t return_value =
|
2021-08-24 00:49:50 +03:00
|
|
|
ebpf_map_function_tables[map->ebpf_map_definition.type].update_entry(map, key, NULL, option);
|
2021-08-18 02:22:32 +03:00
|
|
|
if (return_value != EBPF_SUCCESS) {
|
|
|
|
return return_value;
|
|
|
|
}
|
|
|
|
target = ebpf_map_function_tables[map->ebpf_map_definition.type].find_entry(map, key);
|
|
|
|
if (!target) {
|
|
|
|
return EBPF_NO_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_ebpf_adjust_value_pointer(map, &target) != EBPF_SUCCESS) {
|
2021-08-12 01:39:54 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
2021-08-18 02:22:32 +03:00
|
|
|
}
|
2021-08-12 01:39:54 +03:00
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
memcpy(target, value, ebpf_map_get_effective_value_size(map));
|
2021-08-12 01:39:54 +03:00
|
|
|
return EBPF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-04-16 02:15:00 +03:00
|
|
|
ebpf_map_function_table_t ebpf_map_function_tables[] = {
|
2021-08-04 03:25:50 +03:00
|
|
|
{// BPF_MAP_TYPE_UNSPECIFIED
|
2021-04-16 02:15:00 +03:00
|
|
|
NULL},
|
2021-08-04 03:25:50 +03:00
|
|
|
{// BPF_MAP_TYPE_HASH
|
2021-08-06 23:18:47 +03:00
|
|
|
_create_hash_map,
|
|
|
|
_delete_hash_map,
|
2021-08-11 22:17:10 +03:00
|
|
|
NULL,
|
2021-08-06 23:18:47 +03:00
|
|
|
_find_hash_map_entry,
|
|
|
|
NULL,
|
|
|
|
_update_hash_map_entry,
|
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
NULL,
|
2021-08-06 23:18:47 +03:00
|
|
|
_delete_hash_map_entry,
|
|
|
|
_next_hash_map_key},
|
2021-08-04 03:25:50 +03:00
|
|
|
{// BPF_MAP_TYPE_ARRAY
|
2021-08-06 23:18:47 +03:00
|
|
|
_create_array_map,
|
|
|
|
_delete_array_map,
|
2021-08-11 22:17:10 +03:00
|
|
|
NULL,
|
2021-08-06 23:18:47 +03:00
|
|
|
_find_array_map_entry,
|
|
|
|
NULL,
|
|
|
|
_update_array_map_entry,
|
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
NULL,
|
2021-08-06 23:18:47 +03:00
|
|
|
_delete_array_map_entry,
|
|
|
|
_next_array_map_key},
|
|
|
|
{// BPF_MAP_TYPE_PROG_ARRAY
|
2021-08-24 04:46:24 +03:00
|
|
|
_create_object_array_map,
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_program_array_map,
|
2021-08-11 22:17:10 +03:00
|
|
|
_associate_program_with_prog_array_map,
|
2021-08-06 23:18:47 +03:00
|
|
|
_find_array_map_entry,
|
|
|
|
_get_object_from_array_map_entry,
|
|
|
|
NULL,
|
|
|
|
_update_prog_array_map_entry_with_handle,
|
2021-08-18 02:22:32 +03:00
|
|
|
NULL,
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_program_array_map_entry,
|
2021-08-06 23:18:47 +03:00
|
|
|
_next_array_map_key},
|
2021-08-13 22:13:16 +03:00
|
|
|
{// BPF_MAP_TYPE_PERCPU_HASH
|
2021-08-18 02:22:32 +03:00
|
|
|
_create_hash_map,
|
|
|
|
_delete_hash_map,
|
2021-08-12 01:39:54 +03:00
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
_find_hash_map_entry,
|
2021-08-12 01:39:54 +03:00
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
_update_hash_map_entry,
|
2021-08-12 01:39:54 +03:00
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
_update_entry_per_cpu,
|
|
|
|
_delete_hash_map_entry,
|
|
|
|
_next_hash_map_key},
|
2021-08-13 22:13:16 +03:00
|
|
|
{// BPF_MAP_TYPE_PERCPU_ARRAY
|
2021-08-18 02:22:32 +03:00
|
|
|
_create_array_map,
|
|
|
|
_delete_array_map,
|
2021-08-12 01:39:54 +03:00
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
_find_array_map_entry,
|
2021-08-12 01:39:54 +03:00
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
_update_array_map_entry,
|
2021-08-12 01:39:54 +03:00
|
|
|
NULL,
|
2021-08-18 02:22:32 +03:00
|
|
|
_update_entry_per_cpu,
|
|
|
|
_delete_array_map_entry,
|
|
|
|
_next_array_map_key},
|
2021-08-24 04:46:24 +03:00
|
|
|
{// BPF_MAP_TYPE_HASH_OF_MAPS
|
|
|
|
_create_object_hash_map,
|
|
|
|
_delete_object_hash_map,
|
|
|
|
NULL,
|
|
|
|
_find_hash_map_entry,
|
|
|
|
_get_object_from_hash_map_entry,
|
|
|
|
NULL,
|
|
|
|
_update_map_hash_map_entry_with_handle,
|
|
|
|
NULL,
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_map_hash_map_entry,
|
2021-08-24 04:46:24 +03:00
|
|
|
_next_array_map_key},
|
|
|
|
{// BPF_MAP_TYPE_ARRAY_OF_MAPS
|
|
|
|
_create_object_array_map,
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_map_array_map,
|
2021-08-24 04:46:24 +03:00
|
|
|
NULL,
|
|
|
|
_find_array_map_entry,
|
|
|
|
_get_object_from_array_map_entry,
|
|
|
|
NULL,
|
|
|
|
_update_map_array_map_entry_with_handle,
|
|
|
|
NULL,
|
2021-09-10 02:02:42 +03:00
|
|
|
_delete_map_array_map_entry,
|
2021-08-24 04:46:24 +03:00
|
|
|
_next_array_map_key},
|
2021-09-17 20:28:49 +03:00
|
|
|
{// BPF_MAP_TYPE_LRU_HASH
|
|
|
|
_create_lru_hash_map,
|
|
|
|
_delete_lru_hash_map,
|
|
|
|
NULL,
|
|
|
|
_find_hash_map_entry,
|
|
|
|
NULL,
|
|
|
|
_update_hash_map_entry,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
_delete_hash_map_entry,
|
|
|
|
_next_hash_map_key},
|
2021-05-20 22:38:58 +03:00
|
|
|
};
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-08-20 20:02:21 +03:00
|
|
|
static void
|
|
|
|
_ebpf_map_delete(_In_ ebpf_object_t* object)
|
|
|
|
{
|
|
|
|
ebpf_map_t* map = (ebpf_map_t*)object;
|
|
|
|
|
2021-08-31 05:14:08 +03:00
|
|
|
if (map->inner_map_template != NULL) {
|
|
|
|
ebpf_object_release_reference(&map->inner_map_template->object);
|
|
|
|
}
|
2021-08-20 20:02:21 +03:00
|
|
|
ebpf_free(map->name.value);
|
|
|
|
ebpf_map_function_tables[map->ebpf_map_definition.type].delete_map(map);
|
|
|
|
}
|
|
|
|
|
2021-08-06 23:18:47 +03:00
|
|
|
ebpf_result_t
|
2021-08-11 03:04:07 +03:00
|
|
|
ebpf_map_create(
|
|
|
|
_In_ const ebpf_utf8_string_t* map_name,
|
2021-08-31 05:14:08 +03:00
|
|
|
_In_ const ebpf_map_definition_in_memory_t* ebpf_map_definition,
|
|
|
|
ebpf_handle_t inner_map_handle,
|
2021-08-11 03:04:07 +03:00
|
|
|
_Outptr_ ebpf_map_t** ebpf_map)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
|
|
|
ebpf_map_t* local_map = NULL;
|
2021-08-31 05:14:08 +03:00
|
|
|
ebpf_object_t* inner_map_template_object = NULL;
|
2021-08-11 22:17:10 +03:00
|
|
|
ebpf_map_type_t type = ebpf_map_definition->type;
|
2021-08-11 03:04:07 +03:00
|
|
|
ebpf_result_t result = EBPF_SUCCESS;
|
2021-08-18 02:22:32 +03:00
|
|
|
uint32_t cpu_count;
|
2021-08-23 23:49:26 +03:00
|
|
|
cpu_count = ebpf_get_cpu_count();
|
2021-08-31 05:14:08 +03:00
|
|
|
ebpf_map_definition_in_memory_t local_map_definition = *ebpf_map_definition;
|
2021-08-18 02:22:32 +03:00
|
|
|
switch (local_map_definition.type) {
|
|
|
|
case BPF_MAP_TYPE_PERCPU_HASH:
|
|
|
|
case BPF_MAP_TYPE_PERCPU_ARRAY:
|
2021-09-03 06:06:32 +03:00
|
|
|
local_map_definition.value_size = cpu_count * PAD_CACHE(local_map_definition.value_size);
|
2021-08-18 02:22:32 +03:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-09-11 07:54:07 +03:00
|
|
|
if ((type >= EBPF_COUNT_OF(ebpf_map_function_tables)) || (map_name->length >= BPF_OBJ_NAME_LEN)) {
|
2021-08-11 03:04:07 +03:00
|
|
|
result = EBPF_INVALID_ARGUMENT;
|
|
|
|
goto Exit;
|
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-08-11 03:04:07 +03:00
|
|
|
if (!ebpf_map_function_tables[type].create_map) {
|
|
|
|
result = EBPF_OPERATION_NOT_SUPPORTED;
|
|
|
|
goto Exit;
|
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
if (local_map_definition.size != sizeof(local_map_definition)) {
|
|
|
|
result = EBPF_INVALID_ARGUMENT;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2021-09-14 18:25:56 +03:00
|
|
|
if (inner_map_handle != ebpf_handle_invalid) {
|
2021-08-31 05:14:08 +03:00
|
|
|
// Convert value handle to an object pointer.
|
|
|
|
result = ebpf_reference_object_by_handle(inner_map_handle, EBPF_OBJECT_MAP, &inner_map_template_object);
|
|
|
|
if (result != EBPF_SUCCESS)
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
local_map = ebpf_map_function_tables[type].create_map(&local_map_definition);
|
2021-08-11 03:04:07 +03:00
|
|
|
if (!local_map) {
|
|
|
|
result = EBPF_NO_MEMORY;
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
local_map->original_value_size = ebpf_map_definition->value_size;
|
|
|
|
|
2021-08-11 03:04:07 +03:00
|
|
|
result = ebpf_duplicate_utf8_string(&local_map->name, map_name);
|
|
|
|
if (result != EBPF_SUCCESS) {
|
|
|
|
goto Exit;
|
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
ebpf_map_function_table_t* table = &ebpf_map_function_tables[local_map->ebpf_map_definition.type];
|
|
|
|
ebpf_object_get_program_type_t get_program_type = (table->get_object_from_entry) ? _get_map_program_type : NULL;
|
2021-09-07 19:54:08 +03:00
|
|
|
result = ebpf_object_initialize(&local_map->object, EBPF_OBJECT_MAP, _ebpf_map_delete, get_program_type);
|
|
|
|
if (result != EBPF_SUCCESS) {
|
|
|
|
goto Exit;
|
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
|
2021-08-31 05:14:08 +03:00
|
|
|
local_map->inner_map_template = (ebpf_map_t*)inner_map_template_object;
|
2021-08-06 23:18:47 +03:00
|
|
|
*ebpf_map = local_map;
|
|
|
|
|
2021-08-11 03:04:07 +03:00
|
|
|
Exit:
|
|
|
|
if (result != EBPF_SUCCESS) {
|
|
|
|
if (local_map) {
|
2021-08-31 05:14:08 +03:00
|
|
|
ebpf_object_release_reference(inner_map_template_object);
|
2021-08-11 03:04:07 +03:00
|
|
|
ebpf_free(local_map->name.value);
|
|
|
|
ebpf_free(local_map);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
2021-08-13 22:13:16 +03:00
|
|
|
ebpf_result_t
|
|
|
|
ebpf_map_find_entry(
|
|
|
|
_In_ ebpf_map_t* map,
|
|
|
|
size_t key_size,
|
|
|
|
_In_reads_(key_size) const uint8_t* key,
|
|
|
|
size_t value_size,
|
|
|
|
_Out_writes_(value_size) uint8_t* value,
|
|
|
|
int flags)
|
|
|
|
{
|
2021-08-24 04:46:24 +03:00
|
|
|
uint8_t* return_value = NULL;
|
2021-08-13 22:13:16 +03:00
|
|
|
if (!(flags & EBPF_MAP_FLAG_HELPER) && (key_size != map->ebpf_map_definition.key_size)) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(flags & EBPF_MAP_FLAG_HELPER) && (value_size != map->ebpf_map_definition.value_size)) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
2021-08-24 04:46:24 +03:00
|
|
|
ebpf_map_type_t type = map->ebpf_map_definition.type;
|
|
|
|
if ((flags & EBPF_MAP_FLAG_HELPER) && (ebpf_map_function_tables[type].get_object_from_entry != NULL)) {
|
|
|
|
|
|
|
|
// Disallow reads to prog array maps from this helper call for now.
|
|
|
|
if (type == BPF_MAP_TYPE_PROG_ARRAY) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_object_t* object = ebpf_map_function_tables[type].get_object_from_entry(map, key);
|
|
|
|
|
|
|
|
// Release the extra reference obtained.
|
|
|
|
// REVIEW: is this safe?
|
|
|
|
if (object) {
|
|
|
|
ebpf_object_release_reference(object);
|
|
|
|
return_value = (uint8_t*)object;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return_value = ebpf_map_function_tables[map->ebpf_map_definition.type].find_entry(map, key);
|
2021-08-13 22:13:16 +03:00
|
|
|
}
|
|
|
|
if (return_value == NULL) {
|
|
|
|
return EBPF_OBJECT_NOT_FOUND;
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
2021-08-13 22:13:16 +03:00
|
|
|
if (flags & EBPF_MAP_FLAG_HELPER) {
|
2021-08-18 02:22:32 +03:00
|
|
|
if (_ebpf_adjust_value_pointer(map, &return_value) != EBPF_SUCCESS) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
2021-08-13 22:13:16 +03:00
|
|
|
*(uint8_t**)value = return_value;
|
|
|
|
} else {
|
2021-08-18 02:22:32 +03:00
|
|
|
memcpy(value, return_value, map->ebpf_map_definition.value_size);
|
2021-08-13 22:13:16 +03:00
|
|
|
}
|
|
|
|
return EBPF_SUCCESS;
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
2021-08-11 22:17:10 +03:00
|
|
|
ebpf_result_t
|
|
|
|
ebpf_map_associate_program(_In_ ebpf_map_t* map, _In_ const ebpf_program_t* program)
|
|
|
|
{
|
|
|
|
if (ebpf_map_function_tables[map->ebpf_map_definition.type].associate_program)
|
|
|
|
return ebpf_map_function_tables[map->ebpf_map_definition.type].associate_program(map, program);
|
|
|
|
return EBPF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2021-08-06 23:18:47 +03:00
|
|
|
_Ret_maybenull_ ebpf_program_t*
|
2021-08-13 22:13:16 +03:00
|
|
|
ebpf_map_get_program_from_entry(_In_ ebpf_map_t* map, size_t key_size, _In_reads_(key_size) const uint8_t* key)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
|
|
|
if (key_size != map->ebpf_map_definition.key_size) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ebpf_map_type_t type = map->ebpf_map_definition.type;
|
|
|
|
if (type != BPF_MAP_TYPE_PROG_ARRAY) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ebpf_map_function_tables[type].get_object_from_entry == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return (ebpf_program_t*)ebpf_map_function_tables[type].get_object_from_entry(map, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_result_t
|
2021-08-13 22:13:16 +03:00
|
|
|
ebpf_map_update_entry(
|
|
|
|
_In_ ebpf_map_t* map,
|
|
|
|
size_t key_size,
|
|
|
|
_In_reads_(key_size) const uint8_t* key,
|
|
|
|
size_t value_size,
|
|
|
|
_In_reads_(value_size) const uint8_t* value,
|
2021-08-24 00:49:50 +03:00
|
|
|
ebpf_map_option_t option,
|
2021-08-13 22:13:16 +03:00
|
|
|
int flags)
|
|
|
|
{
|
|
|
|
if (!(flags & EBPF_MAP_FLAG_HELPER) && (key_size != map->ebpf_map_definition.key_size)) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(flags & EBPF_MAP_FLAG_HELPER) && (value_size != map->ebpf_map_definition.value_size)) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
2021-08-18 02:22:32 +03:00
|
|
|
if ((ebpf_map_function_tables[map->ebpf_map_definition.type].update_entry == NULL) ||
|
|
|
|
(ebpf_map_function_tables[map->ebpf_map_definition.type].find_entry == NULL)) {
|
2021-08-06 23:18:47 +03:00
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
2021-08-18 02:22:32 +03:00
|
|
|
|
|
|
|
if ((flags & EBPF_MAP_FLAG_HELPER) &&
|
|
|
|
ebpf_map_function_tables[map->ebpf_map_definition.type].update_entry_per_cpu) {
|
2021-08-24 00:49:50 +03:00
|
|
|
return ebpf_map_function_tables[map->ebpf_map_definition.type].update_entry_per_cpu(map, key, value, option);
|
2021-08-18 02:22:32 +03:00
|
|
|
} else {
|
2021-08-24 00:49:50 +03:00
|
|
|
return ebpf_map_function_tables[map->ebpf_map_definition.type].update_entry(map, key, value, option);
|
2021-08-18 02:22:32 +03:00
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_result_t
|
|
|
|
ebpf_map_update_entry_with_handle(
|
2021-08-13 22:13:16 +03:00
|
|
|
_In_ ebpf_map_t* map,
|
|
|
|
size_t key_size,
|
|
|
|
_In_reads_(key_size) const uint8_t* key,
|
2021-08-24 04:46:24 +03:00
|
|
|
uintptr_t value_handle,
|
|
|
|
ebpf_map_option_t option)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
2021-08-13 22:13:16 +03:00
|
|
|
if (key_size != map->ebpf_map_definition.key_size) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
|
|
|
|
2021-08-06 23:18:47 +03:00
|
|
|
if (ebpf_map_function_tables[map->ebpf_map_definition.type].update_entry_with_handle == NULL) {
|
|
|
|
return EBPF_OPERATION_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
return ebpf_map_function_tables[map->ebpf_map_definition.type].update_entry_with_handle(
|
2021-09-10 02:02:42 +03:00
|
|
|
map, key, value_handle, option);
|
2021-08-06 23:18:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_result_t
|
2021-08-13 22:13:16 +03:00
|
|
|
ebpf_map_delete_entry(_In_ ebpf_map_t* map, size_t key_size, _In_reads_(key_size) const uint8_t* key, int flags)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
2021-08-13 22:13:16 +03:00
|
|
|
if (!(flags & EBPF_MAP_FLAG_HELPER) && (key_size != map->ebpf_map_definition.key_size)) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
return ebpf_map_function_tables[map->ebpf_map_definition.type].delete_entry(map, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
ebpf_result_t
|
2021-08-13 22:13:16 +03:00
|
|
|
ebpf_map_next_key(
|
|
|
|
_In_ ebpf_map_t* map,
|
|
|
|
size_t key_size,
|
|
|
|
_In_reads_opt_(key_size) const uint8_t* previous_key,
|
|
|
|
_Out_writes_(key_size) uint8_t* next_key)
|
2021-08-06 23:18:47 +03:00
|
|
|
{
|
2021-08-13 22:13:16 +03:00
|
|
|
if (key_size != map->ebpf_map_definition.key_size) {
|
|
|
|
return EBPF_INVALID_ARGUMENT;
|
|
|
|
}
|
2021-08-06 23:18:47 +03:00
|
|
|
return ebpf_map_function_tables[map->ebpf_map_definition.type].next_key(map, previous_key, next_key);
|
|
|
|
}
|
2021-09-11 07:54:07 +03:00
|
|
|
|
|
|
|
ebpf_result_t
|
|
|
|
ebpf_map_get_info(
|
|
|
|
_In_ const ebpf_map_t* map, _Out_writes_to_(*info_size, *info_size) uint8_t* buffer, _Inout_ uint16_t* info_size)
|
|
|
|
{
|
|
|
|
struct bpf_map_info* info = (struct bpf_map_info*)buffer;
|
|
|
|
|
|
|
|
if (*info_size < sizeof(*info)) {
|
|
|
|
return EBPF_INSUFFICIENT_BUFFER;
|
|
|
|
}
|
|
|
|
|
|
|
|
info->id = map->object.id;
|
|
|
|
info->type = map->ebpf_map_definition.type;
|
|
|
|
info->key_size = map->ebpf_map_definition.key_size;
|
|
|
|
info->value_size = map->original_value_size;
|
|
|
|
info->max_entries = map->ebpf_map_definition.max_entries;
|
2021-09-21 19:34:13 +03:00
|
|
|
info->inner_map_id = (map->inner_map_template) ? map->inner_map_template->object.id : EBPF_ID_NONE;
|
|
|
|
info->pinned_path_count = map->object.pinned_path_count;
|
2021-09-11 07:54:07 +03:00
|
|
|
strncpy_s(info->name, sizeof(info->name), (char*)map->name.value, map->name.length);
|
|
|
|
|
|
|
|
*info_size = sizeof(*info);
|
|
|
|
return EBPF_SUCCESS;
|
|
|
|
}
|