Implement hash-table iterator (#2566)
* Implement hash-table iterator Signed-off-by: Alan Jowett <alanjo@microsoft.com> * PR feedback Signed-off-by: Alan Jowett <alanjo@microsoft.com> * PR feedback Signed-off-by: Alan Jowett <alanjo@microsoft.com> * PR feedback Signed-off-by: Alan Jowett <alanjo@microsoft.com> * Switch iterator to match BPF_MAP_LOOKUP_BATCH syscall behavior Signed-off-by: Alan Jowett <alanjo@microsoft.com> * Switch iterator to match BPF_MAP_LOOKUP_BATCH syscall behavior Signed-off-by: Alan Jowett <alanjo@microsoft.com> --------- Signed-off-by: Alan Jowett <alanjo@microsoft.com>
This commit is contained in:
Родитель
1955692077
Коммит
c1fecf4e2d
|
@ -7,6 +7,7 @@
|
|||
#include "ebpf_bitmap.h"
|
||||
#include "ebpf_epoch.h"
|
||||
#include "ebpf_handle.h"
|
||||
#include "ebpf_hash_table.h"
|
||||
#include "ebpf_maps.h"
|
||||
#include "ebpf_object.h"
|
||||
#include "ebpf_program.h"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "ebpf_core.h"
|
||||
#include "ebpf_handle.h"
|
||||
#include "ebpf_hash_table.h"
|
||||
#include "ebpf_native.h"
|
||||
#include "ebpf_object.h"
|
||||
#include "ebpf_program.h"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "ebpf_async.h"
|
||||
#include "ebpf_epoch.h"
|
||||
#include "ebpf_hash_table.h"
|
||||
#include "ebpf_tracelog.h"
|
||||
|
||||
typedef struct _ebpf_async_tracker
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "ebpf_epoch.h"
|
||||
#include "ebpf_platform.h"
|
||||
#include "ebpf_hash_table.h"
|
||||
|
||||
// Buckets contain an array of pointers to value and keys.
|
||||
// Buckets are immutable once inserted in to the hash-table and replaced when
|
||||
|
@ -849,3 +849,59 @@ ebpf_hash_table_key_count(_In_ const ebpf_hash_table_t* hash_table)
|
|||
{
|
||||
return hash_table->entry_count;
|
||||
}
|
||||
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_iterate(
|
||||
_In_ const ebpf_hash_table_t* hash_table,
|
||||
_Inout_ size_t* bucket,
|
||||
_Inout_ size_t* count,
|
||||
_Out_writes_(*count) const uint8_t** keys,
|
||||
_Out_writes_(*count) const uint8_t** values)
|
||||
{
|
||||
size_t bucket_index = *bucket;
|
||||
size_t index = 0;
|
||||
size_t remaining_space = *count;
|
||||
size_t next_bucket_count = 0;
|
||||
if (bucket_index >= hash_table->bucket_count) {
|
||||
return EBPF_NO_MORE_KEYS;
|
||||
}
|
||||
|
||||
while (remaining_space > 0) {
|
||||
if (bucket_index >= hash_table->bucket_count) {
|
||||
break;
|
||||
}
|
||||
ebpf_hash_bucket_header_t* bucket_header = hash_table->buckets[bucket_index].header;
|
||||
// Check if the bucket is empty.
|
||||
if (!bucket_header) {
|
||||
bucket_index++;
|
||||
continue;
|
||||
}
|
||||
// Check if the next bucket will fit in the remaining space.
|
||||
next_bucket_count = bucket_header->count;
|
||||
if (remaining_space < next_bucket_count) {
|
||||
break;
|
||||
}
|
||||
// Copy the keys and values.
|
||||
for (size_t i = 0; i < next_bucket_count; i++) {
|
||||
ebpf_hash_bucket_entry_t* entry = _ebpf_hash_table_bucket_entry(hash_table->key_size, bucket_header, i);
|
||||
if (!entry) {
|
||||
return EBPF_INVALID_ARGUMENT;
|
||||
}
|
||||
keys[index] = entry->key;
|
||||
values[index] = entry->data;
|
||||
index++;
|
||||
remaining_space--;
|
||||
}
|
||||
bucket_index++;
|
||||
}
|
||||
|
||||
// If the bucket_index did not change, then there wasn't enough space to copy the next bucket.
|
||||
if (*bucket == bucket_index) {
|
||||
*count = next_bucket_count;
|
||||
return EBPF_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
*bucket = bucket_index;
|
||||
*count = index;
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
// Copyright (c) Microsoft Corporation
|
||||
// SPDX-License-Identifier: MIT
|
||||
#pragma once
|
||||
|
||||
#include "ebpf_platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define EBPF_HASH_TABLE_NO_LIMIT 0
|
||||
#define EBPF_HASH_TABLE_DEFAULT_BUCKET_COUNT 64
|
||||
|
||||
typedef enum _ebpf_hash_table_operations
|
||||
{
|
||||
EBPF_HASH_TABLE_OPERATION_ANY = 0,
|
||||
EBPF_HASH_TABLE_OPERATION_INSERT = 1,
|
||||
EBPF_HASH_TABLE_OPERATION_REPLACE = 2,
|
||||
} ebpf_hash_table_operations_t;
|
||||
|
||||
typedef struct _ebpf_hash_table ebpf_hash_table_t;
|
||||
|
||||
typedef enum _ebpf_hash_table_notification_type
|
||||
{
|
||||
EBPF_HASH_TABLE_NOTIFICATION_TYPE_ALLOCATE, //< A key + value have been allocated.
|
||||
EBPF_HASH_TABLE_NOTIFICATION_TYPE_FREE, //< A key + value have been freed.
|
||||
EBPF_HASH_TABLE_NOTIFICATION_TYPE_USE, //< A key + value have been used.
|
||||
} ebpf_hash_table_notification_type_t;
|
||||
|
||||
typedef void (*ebpf_hash_table_notification_function)(
|
||||
_Inout_ void* context,
|
||||
_In_ ebpf_hash_table_notification_type_t type,
|
||||
_In_ const uint8_t* key,
|
||||
_Inout_ uint8_t* value);
|
||||
|
||||
typedef _Must_inspect_result_ _Ret_writes_maybenull_(size) void* (*ebpf_hash_table_allocate)(size_t size);
|
||||
|
||||
typedef void (*ebpf_hash_table_free)(_Frees_ptr_opt_ void* memory);
|
||||
|
||||
typedef void (*ebpf_hash_table_extract_function)(
|
||||
_In_ const uint8_t* value,
|
||||
_Outptr_result_buffer_((*length_in_bits + 7) / 8) const uint8_t** data,
|
||||
_Out_ size_t* length_in_bits);
|
||||
|
||||
/**
|
||||
* @brief Options to pass to ebpf_hash_table_create.
|
||||
*
|
||||
* Some fields are required, others are optional. If an optional field is
|
||||
* not specified, a default value will be used.
|
||||
*/
|
||||
typedef struct _ebpf_hash_table_creation_options
|
||||
{
|
||||
// Required fields.
|
||||
size_t key_size; //< Size of key in bytes.
|
||||
size_t value_size; //< Size of value in bytes.
|
||||
// Optional fields.
|
||||
ebpf_hash_table_extract_function extract_function; //< Function to extract key from stored value.
|
||||
ebpf_hash_table_allocate allocate; //< Function to allocate memory - defaults to ebpf_epoch_allocate.
|
||||
ebpf_hash_table_free free; //< Function to free memory - defaults to ebpf_epoch_free.
|
||||
size_t bucket_count; //< Number of buckets to use - defaults to EBPF_HASH_TABLE_DEFAULT_BUCKET_COUNT.
|
||||
size_t max_entries; //< Maximum number of entries in the hash table - defaults to EBPF_HASH_TABLE_NO_LIMIT.
|
||||
size_t supplemental_value_size; //< Size of supplemental value to store in each entry - defaults to 0.
|
||||
void* notification_context; //< Context to pass to notification functions.
|
||||
ebpf_hash_table_notification_function
|
||||
notification_callback; //< Function to call when value storage is allocated or freed.
|
||||
} ebpf_hash_table_creation_options_t;
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize a hash table.
|
||||
*
|
||||
* @param[out] hash_table Pointer to memory that will contain hash table on
|
||||
* success.
|
||||
* @param[in] options Options to control hash table creation.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
|
||||
* hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_create(
|
||||
_Out_ ebpf_hash_table_t** hash_table, _In_ const ebpf_hash_table_creation_options_t* options);
|
||||
|
||||
/**
|
||||
* @brief Remove all items from the hash table and release memory.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to release.
|
||||
*/
|
||||
void
|
||||
ebpf_hash_table_destroy(_In_opt_ _Post_ptr_invalid_ ebpf_hash_table_t* hash_table);
|
||||
|
||||
/**
|
||||
* @brief Find an element in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to search.
|
||||
* @param[in] key Key to find in hash table.
|
||||
* @param[out] value Pointer to value if found.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NOT_FOUND Key not found in hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_find(_In_ const ebpf_hash_table_t* hash_table, _In_ const uint8_t* key, _Outptr_ uint8_t** value);
|
||||
|
||||
/**
|
||||
* @brief Insert or update an entry in the hash table.
|
||||
*
|
||||
* @param[in, out] hash_table Hash-table to update.
|
||||
* @param[in] key Key to find and insert or update.
|
||||
* @param[in] value Value to insert into hash table or NULL to insert zero entry.
|
||||
* @param[in] operation One of ebpf_hash_table_operations_t operations.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MEMORY Unable to allocate memory for this
|
||||
* entry in the hash table.
|
||||
* @retval EBPF_OUT_OF_SPACE Unable to insert this entry in the hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_update(
|
||||
_Inout_ ebpf_hash_table_t* hash_table,
|
||||
_In_ const uint8_t* key,
|
||||
_In_opt_ const uint8_t* value,
|
||||
ebpf_hash_table_operations_t operation);
|
||||
|
||||
/**
|
||||
* @brief Remove an entry from the hash table.
|
||||
*
|
||||
* @param[in, out] hash_table Hash-table to update.
|
||||
* @param[in] key Key to find and remove.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NOT_FOUND Key not found in hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_delete(_Inout_ ebpf_hash_table_t* hash_table, _In_ const uint8_t* key);
|
||||
|
||||
/**
|
||||
* @brief Fetch pointers to keys and values from one or more buckets in the hash table. Whole buckets worth of keys
|
||||
* and values are returned at a time, with *count being the number of keys and values returned. If *count is too
|
||||
* small to hold all the keys and values in the next bucket, EBPF_INSUFFICIENT_BUFFER is returned.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to iterate.
|
||||
* @param[in,out] cookie Cookie to pass to the iterator or NULL to restart. Updated on return.
|
||||
* @param[in,out] count On input, the number of keys and values that can be stored in the buffers. On output, the
|
||||
* number of keys and values returned.
|
||||
* @param[out] keys An array of pointers to keys in the hash table.
|
||||
* @param[out] values An array of pointers to values in the hash table.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_INVALID_ARGUMENT An invalid argument was passed to this function.
|
||||
* @retval EBPF_NO_MORE_KEYS No more keys.
|
||||
* @retval EBPF_INSUFFICIENT_BUFFER The buffer is too small to hold all the keys and values in the bucket and *count
|
||||
* has been updated to reflect the number of keys and values in the next bucket.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_iterate(
|
||||
_In_ const ebpf_hash_table_t* hash_table,
|
||||
_Inout_ size_t* bucket,
|
||||
_Inout_ size_t* count,
|
||||
_Out_writes_(*count) const uint8_t** keys,
|
||||
_Out_writes_(*count) const uint8_t** values);
|
||||
|
||||
/**
|
||||
* @brief Find the next key in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @param[in] previous_key Previous key or NULL to restart.
|
||||
* @param[out] next_key Next key if it exists.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MORE_KEYS No keys exist in the hash table that
|
||||
* are lexicographically after the specified key.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_next_key(
|
||||
_In_ const ebpf_hash_table_t* hash_table, _In_opt_ const uint8_t* previous_key, _Out_ uint8_t* next_key);
|
||||
|
||||
/**
|
||||
* @brief Returns the next (key, value) pair in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @param[in] previous_key Previous key or NULL to restart.
|
||||
* @param[out] next_key Next key if it exists.
|
||||
* @param[out] next_value If non-NULL, returns the next value if it exists.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MORE_KEYS No keys exist in the hash table that
|
||||
* are lexicographically after the specified key.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_next_key_and_value(
|
||||
_In_ const ebpf_hash_table_t* hash_table,
|
||||
_In_opt_ const uint8_t* previous_key,
|
||||
_Out_ uint8_t* next_key,
|
||||
_Inout_opt_ uint8_t** next_value);
|
||||
|
||||
/**
|
||||
* @brief Returns the next (key, value) pair in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @param[in] previous_key Previous key or NULL to restart.
|
||||
* @param[out] next_key_pointer Pointer to next key if one exists.
|
||||
* @param[out] next_value If non-NULL, returns the next value if it exists.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MORE_KEYS No keys exist in the hash table that
|
||||
* are lexicographically after the specified key.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_next_key_pointer_and_value(
|
||||
_In_ const ebpf_hash_table_t* hash_table,
|
||||
_In_opt_ const uint8_t* previous_key,
|
||||
_Outptr_ uint8_t** next_key_pointer,
|
||||
_Outptr_opt_ uint8_t** next_value);
|
||||
|
||||
/**
|
||||
* @brief Get the number of keys in the hash table
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @return Count of entries in the hash table.
|
||||
*/
|
||||
size_t
|
||||
ebpf_hash_table_key_count(_In_ const ebpf_hash_table_t* hash_table);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -17,6 +17,7 @@
|
|||
#define EBPF_FILE_ID EBPF_FILE_ID_PINNING_TABLE
|
||||
|
||||
#include "ebpf_core_structs.h"
|
||||
#include "ebpf_hash_table.h"
|
||||
#include "ebpf_object.h"
|
||||
#include "ebpf_pinning_table.h"
|
||||
#include "ebpf_tracelog.h"
|
||||
|
|
|
@ -36,9 +36,6 @@ extern "C"
|
|||
#define EBPF_PAD_CACHE(X) ((X + EBPF_CACHE_LINE_SIZE - 1) & ~(EBPF_CACHE_LINE_SIZE - 1))
|
||||
#define EBPF_PAD_8(X) ((X + 7) & ~7)
|
||||
|
||||
#define EBPF_HASH_TABLE_NO_LIMIT 0
|
||||
#define EBPF_HASH_TABLE_DEFAULT_BUCKET_COUNT 64
|
||||
|
||||
#define EBPF_NS_PER_FILETIME 100
|
||||
|
||||
// Macro locally suppresses "Unreferenced variable" warning, which in 'Release' builds is treated as an error.
|
||||
|
@ -106,13 +103,6 @@ extern "C"
|
|||
|
||||
extern bool ebpf_fuzzing_enabled;
|
||||
|
||||
typedef enum _ebpf_hash_table_operations
|
||||
{
|
||||
EBPF_HASH_TABLE_OPERATION_ANY = 0,
|
||||
EBPF_HASH_TABLE_OPERATION_INSERT = 1,
|
||||
EBPF_HASH_TABLE_OPERATION_REPLACE = 2,
|
||||
} ebpf_hash_table_operations_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the eBPF platform abstraction layer.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
|
@ -558,170 +548,6 @@ extern "C"
|
|||
void
|
||||
ebpf_free_timer_work_item(_Frees_ptr_opt_ ebpf_timer_work_item_t* timer);
|
||||
|
||||
typedef struct _ebpf_hash_table ebpf_hash_table_t;
|
||||
|
||||
typedef enum _ebpf_hash_table_notification_type
|
||||
{
|
||||
EBPF_HASH_TABLE_NOTIFICATION_TYPE_ALLOCATE, //< A key + value have been allocated.
|
||||
EBPF_HASH_TABLE_NOTIFICATION_TYPE_FREE, //< A key + value have been freed.
|
||||
EBPF_HASH_TABLE_NOTIFICATION_TYPE_USE, //< A key + value have been used.
|
||||
} ebpf_hash_table_notification_type_t;
|
||||
|
||||
typedef void (*ebpf_hash_table_notification_function)(
|
||||
_Inout_ void* context,
|
||||
_In_ ebpf_hash_table_notification_type_t type,
|
||||
_In_ const uint8_t* key,
|
||||
_Inout_ uint8_t* value);
|
||||
|
||||
/**
|
||||
* @brief Options to pass to ebpf_hash_table_create.
|
||||
*
|
||||
* Some fields are required, others are optional. If an optional field is
|
||||
* not specified, a default value will be used.
|
||||
*/
|
||||
typedef struct _ebpf_hash_table_creation_options
|
||||
{
|
||||
// Required fields.
|
||||
size_t key_size; //< Size of key in bytes.
|
||||
size_t value_size; //< Size of value in bytes.
|
||||
// Optional fields.
|
||||
void (*extract_function)(
|
||||
_In_ const uint8_t* value,
|
||||
_Outptr_result_buffer_((*length_in_bits + 7) / 8) const uint8_t** data,
|
||||
_Out_ size_t* length_in_bits); //< Function to extract key from stored value.
|
||||
void* (*allocate)(size_t size); //< Function to allocate memory - defaults to ebpf_epoch_allocate.
|
||||
void (*free)(void* memory); //< Function to free memory - defaults to ebpf_epoch_free.
|
||||
size_t bucket_count; //< Number of buckets to use - defaults to EBPF_HASH_TABLE_DEFAULT_BUCKET_COUNT.
|
||||
size_t max_entries; //< Maximum number of entries in the hash table - defaults to EBPF_HASH_TABLE_NO_LIMIT.
|
||||
size_t supplemental_value_size; //< Size of supplemental value to store in each entry - defaults to 0.
|
||||
void* notification_context; //< Context to pass to notification functions.
|
||||
ebpf_hash_table_notification_function
|
||||
notification_callback; //< Function to call when value storage is allocated or freed.
|
||||
} ebpf_hash_table_creation_options_t;
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize a hash table.
|
||||
*
|
||||
* @param[out] hash_table Pointer to memory that will contain hash table on
|
||||
* success.
|
||||
* @param[in] options Options to control hash table creation.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
|
||||
* hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_create(
|
||||
_Out_ ebpf_hash_table_t** hash_table, _In_ const ebpf_hash_table_creation_options_t* options);
|
||||
|
||||
/**
|
||||
* @brief Remove all items from the hash table and release memory.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to release.
|
||||
*/
|
||||
void
|
||||
ebpf_hash_table_destroy(_In_opt_ _Post_ptr_invalid_ ebpf_hash_table_t* hash_table);
|
||||
|
||||
/**
|
||||
* @brief Find an element in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to search.
|
||||
* @param[in] key Key to find in hash table.
|
||||
* @param[out] value Pointer to value if found.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NOT_FOUND Key not found in hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_find(_In_ const ebpf_hash_table_t* hash_table, _In_ const uint8_t* key, _Outptr_ uint8_t** value);
|
||||
|
||||
/**
|
||||
* @brief Insert or update an entry in the hash table.
|
||||
*
|
||||
* @param[in, out] hash_table Hash-table to update.
|
||||
* @param[in] key Key to find and insert or update.
|
||||
* @param[in] value Value to insert into hash table or NULL to insert zero entry.
|
||||
* @param[in] operation One of ebpf_hash_table_operations_t operations.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MEMORY Unable to allocate memory for this
|
||||
* entry in the hash table.
|
||||
* @retval EBPF_OUT_OF_SPACE Unable to insert this entry in the hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_update(
|
||||
_Inout_ ebpf_hash_table_t* hash_table,
|
||||
_In_ const uint8_t* key,
|
||||
_In_opt_ const uint8_t* value,
|
||||
ebpf_hash_table_operations_t operation);
|
||||
|
||||
/**
|
||||
* @brief Remove an entry from the hash table.
|
||||
*
|
||||
* @param[in, out] hash_table Hash-table to update.
|
||||
* @param[in] key Key to find and remove.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NOT_FOUND Key not found in hash table.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_delete(_Inout_ ebpf_hash_table_t* hash_table, _In_ const uint8_t* key);
|
||||
|
||||
/**
|
||||
* @brief Find the next key in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @param[in] previous_key Previous key or NULL to restart.
|
||||
* @param[out] next_key Next key if it exists.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MORE_KEYS No keys exist in the hash table that
|
||||
* are lexicographically after the specified key.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_next_key(
|
||||
_In_ const ebpf_hash_table_t* hash_table, _In_opt_ const uint8_t* previous_key, _Out_ uint8_t* next_key);
|
||||
|
||||
/**
|
||||
* @brief Returns the next (key, value) pair in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @param[in] previous_key Previous key or NULL to restart.
|
||||
* @param[out] next_key Next key if it exists.
|
||||
* @param[out] next_value If non-NULL, returns the next value if it exists.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MORE_KEYS No keys exist in the hash table that
|
||||
* are lexicographically after the specified key.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_next_key_and_value(
|
||||
_In_ const ebpf_hash_table_t* hash_table,
|
||||
_In_opt_ const uint8_t* previous_key,
|
||||
_Out_ uint8_t* next_key,
|
||||
_Inout_opt_ uint8_t** next_value);
|
||||
|
||||
/**
|
||||
* @brief Returns the next (key, value) pair in the hash table.
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @param[in] previous_key Previous key or NULL to restart.
|
||||
* @param[out] next_key_pointer Pointer to next key if one exists.
|
||||
* @param[out] next_value If non-NULL, returns the next value if it exists.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MORE_KEYS No keys exist in the hash table that
|
||||
* are lexicographically after the specified key.
|
||||
*/
|
||||
_Must_inspect_result_ ebpf_result_t
|
||||
ebpf_hash_table_next_key_pointer_and_value(
|
||||
_In_ const ebpf_hash_table_t* hash_table,
|
||||
_In_opt_ const uint8_t* previous_key,
|
||||
_Outptr_ uint8_t** next_key_pointer,
|
||||
_Outptr_opt_ uint8_t** next_value);
|
||||
|
||||
/**
|
||||
* @brief Get the number of keys in the hash table
|
||||
*
|
||||
* @param[in] hash_table Hash-table to query.
|
||||
* @return Count of entries in the hash table.
|
||||
*/
|
||||
size_t
|
||||
ebpf_hash_table_key_count(_In_ const ebpf_hash_table_t* hash_table);
|
||||
|
||||
/**
|
||||
* @brief Atomically increase the value of addend by 1 and return the new
|
||||
* value.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "ebpf_epoch.h"
|
||||
#include "ebpf_hash_table.h"
|
||||
#include "ebpf_state.h"
|
||||
#include "ebpf_tracelog.h"
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "ebpf_async.h"
|
||||
#include "ebpf_bitmap.h"
|
||||
#include "ebpf_epoch.h"
|
||||
#include "ebpf_hash_table.h"
|
||||
#include "ebpf_nethooks.h"
|
||||
#include "ebpf_pinning_table.h"
|
||||
#include "ebpf_platform.h"
|
||||
|
@ -151,6 +152,43 @@ TEST_CASE("hash_table_test", "[platform]")
|
|||
REQUIRE(ebpf_hash_table_update(table, key_3.data(), data_3.data(), EBPF_HASH_TABLE_OPERATION_ANY) == EBPF_SUCCESS);
|
||||
REQUIRE(ebpf_hash_table_key_count(table) == 3);
|
||||
|
||||
// Iterate through all keys.
|
||||
uint64_t cookie = 0;
|
||||
uint8_t keys_found = 0;
|
||||
std::vector<const uint8_t*> keys;
|
||||
std::vector<const uint8_t*> values;
|
||||
size_t count = 2;
|
||||
keys.resize(count);
|
||||
values.resize(count);
|
||||
// Bucket contains 3 keys, but we only have space for 2.
|
||||
// Should fail with insufficient buffer.
|
||||
REQUIRE(ebpf_hash_table_iterate(table, &cookie, &count, keys.data(), values.data()) == EBPF_INSUFFICIENT_BUFFER);
|
||||
REQUIRE(count == 3);
|
||||
keys.resize(count);
|
||||
values.resize(count);
|
||||
// Bucket contains 3 keys, and we have space for 3.
|
||||
// Should succeed.
|
||||
REQUIRE(ebpf_hash_table_iterate(table, &cookie, &count, keys.data(), values.data()) == EBPF_SUCCESS);
|
||||
|
||||
// Verify that all keys are found.
|
||||
for (size_t index = 0; index < 3; index++) {
|
||||
if (memcmp(keys[index], key_1.data(), key_1.size()) == 0) {
|
||||
REQUIRE(memcmp(values[index], data_1.data(), data_1.size()) == 0);
|
||||
keys_found |= 1 << 0;
|
||||
} else if (memcmp(keys[index], key_2.data(), key_2.size()) == 0) {
|
||||
REQUIRE(memcmp(values[index], data_2.data(), data_2.size()) == 0);
|
||||
keys_found |= 1 << 1;
|
||||
} else if (memcmp(keys[index], key_3.data(), key_3.size()) == 0) {
|
||||
REQUIRE(memcmp(values[index], data_3.data(), data_3.size()) == 0);
|
||||
keys_found |= 1 << 2;
|
||||
} else {
|
||||
REQUIRE(false);
|
||||
}
|
||||
}
|
||||
// Verify that there are no more keys.
|
||||
REQUIRE(ebpf_hash_table_iterate(table, &cookie, &count, keys.data(), values.data()) == EBPF_NO_MORE_KEYS);
|
||||
REQUIRE(keys_found == 0x7);
|
||||
|
||||
// Find the first
|
||||
REQUIRE(ebpf_hash_table_find(table, key_1.data(), &returned_value) == EBPF_SUCCESS);
|
||||
REQUIRE(memcmp(returned_value, data_1.data(), data_1.size()) == 0);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#define TEST_AREA "platform"
|
||||
#include "ebpf_hash_table.h"
|
||||
#include "performance.h"
|
||||
|
||||
static void
|
||||
|
|
Загрузка…
Ссылка в новой задаче