Support TraceLoggingBinary for map find, update and delete. (#3781)

* Initial commit

* Initial commit

* Added _DEBUG around tail call display

* Renamed key to data

* Removed _DEBUG

* Added SAL annotation, as per the comments

* Added SAL annotation, as per the comments

* Fix crash

* make data non-optional

* Added the check for .key_size != 0

* Removed additional tracing in EBPF_LOG_MESSAGE_BINARY macro

* Merged with main

* Trying 16KB of stack size

* Addressed PR comment

* Added macro with combined traces

* Increased stack size to 32K for DEBUG image

* Fix the string concatenation in macro

* Increase the stack size to 64, and added some logs to check the crashdumps during hangs

* Added retry when the dump file cannot be compressed because it is used by another process

* Expanded stack size for all netebpf wfp callouts

* Addressed PR comments

* Added _DEBUG back

* Increased stack size to 20K for DEBUG

* Add optimatization

* With 4K stack expansion size

* Final commit
This commit is contained in:
Sharmi 2024-10-04 13:20:47 -07:00 коммит произвёл GitHub
Родитель 504ed9a032
Коммит f23ab7def5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
9 изменённых файлов: 165 добавлений и 13 удалений

Просмотреть файл

@ -140,6 +140,18 @@ typedef uint8_t* ebpf_lru_entry_t;
#define EBPF_LRU_ENTRY_KEY_PTR(map, entry) \
((uint8_t*)(((uint8_t*)entry) + EBPF_LRU_ENTRY_KEY_OFFSET(map->partition_count)))
#define EBPF_LOG_MAP_OPERATION(flags, operation, map, key) \
if (((flags) & EBPF_MAP_FLAG_HELPER) && (map)->ebpf_map_definition.key_size != 0) { \
EBPF_LOG_MESSAGE_UTF8_STRING( \
EBPF_TRACELOG_LEVEL_VERBOSE, EBPF_TRACELOG_KEYWORD_MAP, "Map "##operation, &(map)->name); \
EBPF_LOG_MESSAGE_BINARY( \
EBPF_TRACELOG_LEVEL_VERBOSE, \
EBPF_TRACELOG_KEYWORD_MAP, \
"Key", \
(key), \
(map)->ebpf_map_definition.key_size); \
}
/**
* @brief The partition of the LRU map key history.
*/
@ -2447,6 +2459,7 @@ ebpf_map_find_entry(
{
// High volume call - Skip entry/exit logging.
uint8_t* return_value = NULL;
if (!(flags & EBPF_MAP_FLAG_HELPER) && (key_size != map->ebpf_map_definition.key_size)) {
EBPF_LOG_MESSAGE_UINT64_UINT64(
EBPF_TRACELOG_LEVEL_ERROR,
@ -2486,6 +2499,8 @@ ebpf_map_find_entry(
return EBPF_INVALID_ARGUMENT;
}
EBPF_LOG_MAP_OPERATION(flags, "lookup", map, key);
ebpf_core_object_t* object = ebpf_map_metadata_tables[type].get_object_from_entry(map, key);
if (object) {
return_value = (uint8_t*)object;
@ -2605,6 +2620,8 @@ ebpf_map_update_entry(
return EBPF_OPERATION_NOT_SUPPORTED;
}
EBPF_LOG_MAP_OPERATION(flags, "update", map, key);
if ((flags & EBPF_MAP_FLAG_HELPER) &&
ebpf_map_metadata_tables[map->ebpf_map_definition.type].update_entry_per_cpu) {
result = ebpf_map_metadata_tables[map->ebpf_map_definition.type].update_entry_per_cpu(map, key, value, option);
@ -2668,6 +2685,8 @@ ebpf_map_delete_entry(_In_ ebpf_map_t* map, size_t key_size, _In_reads_(key_size
return EBPF_OPERATION_NOT_SUPPORTED;
}
EBPF_LOG_MAP_OPERATION(flags, "delete", map, key);
ebpf_result_t result = ebpf_map_metadata_tables[map->ebpf_map_definition.type].delete_entry(map, key);
return result;
}

Просмотреть файл

@ -1556,6 +1556,11 @@ ebpf_program_invoke(
if (current_program->parameters.code_type == EBPF_CODE_JIT ||
current_program->parameters.code_type == EBPF_CODE_NATIVE) {
EBPF_LOG_MESSAGE_UTF8_STRING(
EBPF_TRACELOG_LEVEL_VERBOSE,
EBPF_TRACELOG_KEYWORD_PROGRAM,
"Tail call program",
&current_program->parameters.program_name);
ebpf_program_entry_point_t function_pointer;
function_pointer = (ebpf_program_entry_point_t)(current_program->code_or_vm.code.code_pointer);
*result = (function_pointer)(context);

Просмотреть файл

@ -303,6 +303,18 @@ extern "C"
ebpf_log_message_uint64_uint64(_##trace_level##, _##keyword##, message, value1, value2); \
}
void
ebpf_log_message_binary(
ebpf_tracelog_level_t trace_level,
ebpf_tracelog_keyword_t keyword,
_In_z_ const char* message,
_In_reads_bytes_(data_size) const void* data,
uint32_t data_size);
#define EBPF_LOG_MESSAGE_BINARY(trace_level, keyword, message, data, data_size) \
if (TraceLoggingProviderEnabled(ebpf_tracelog_provider, trace_level, keyword)) { \
ebpf_log_message_binary(_##trace_level##, _##keyword##, message, data, data_size); \
}
void
ebpf_log_message_error(
ebpf_tracelog_level_t trace_level,

Просмотреть файл

@ -7,7 +7,11 @@
<ItemGroup>
<ClCompile Include="..\ebpf_serialize.c" />
<ClCompile Include="..\shared_common.c" />
<ClCompile Include="..\tracelog.c" />
<ClCompile Include="..\tracelog.c" >
<Optimization>Full</Optimization>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<WholeProgramOptimization>true</WholeProgramOptimization>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\ebpf_ring_buffer.h" />

Просмотреть файл

@ -976,6 +976,85 @@ __declspec(noinline) void ebpf_log_message_uint64_uint64(
}
}
#define _EBPF_LOG_MESSAGE_BINARY(trace_level, keyword, message, data, data_size) \
TraceLoggingWrite( \
ebpf_tracelog_provider, \
EBPF_TRACELOG_EVENT_GENERIC_MESSAGE, \
TraceLoggingLevel((trace_level)), \
TraceLoggingKeyword((keyword)), \
TraceLoggingString((message), "Message"), \
TraceLoggingBinary((data), (data_size)));
#define EBPF_LOG_MESSAGE_BINARY_KEYWORD_SWITCH(trace_level, message, data, data_size) \
switch (keyword) { \
CASE_FUNCTION_ENTRY_EXIT: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_FUNCTION_ENTRY_EXIT, message, data, data_size); \
break; \
CASE_BASE: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_BASE, message, data, data_size); \
break; \
CASE_ERROR: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_ERROR, message, data, data_size); \
break; \
CASE_EPOCH: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_EPOCH, message, data, data_size); \
break; \
CASE_CORE: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_CORE, message, data, data_size); \
break; \
CASE_LINK: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_LINK, message, data, data_size); \
break; \
CASE_MAP: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_MAP, message, data, data_size); \
break; \
CASE_PROGRAM: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_PROGRAM, message, data, data_size); \
break; \
CASE_API: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_API, message, data, data_size); \
break; \
CASE_PRINTK: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_PRINTK, message, data, data_size); \
break; \
CASE_NATIVE: \
_EBPF_LOG_MESSAGE_BINARY(trace_level, KEYWORD_NATIVE, message, data, data_size); \
break; \
default: \
ebpf_assert(!"Invalid keyword"); \
break; \
}
__declspec(noinline) void ebpf_log_message_binary(
ebpf_tracelog_level_t trace_level,
ebpf_tracelog_keyword_t keyword,
_In_z_ const char* message,
_In_reads_bytes_(data_size) const void* data,
uint32_t data_size)
{
switch (trace_level) {
CASE_LOG_ALWAYS:
EBPF_LOG_MESSAGE_BINARY_KEYWORD_SWITCH(LEVEL_LOG_ALWAYS, message, data, data_size);
break;
CASE_CRITICAL:
EBPF_LOG_MESSAGE_BINARY_KEYWORD_SWITCH(LEVEL_CRITICAL, message, data, data_size);
break;
CASE_LEVEL_ERROR:
EBPF_LOG_MESSAGE_BINARY_KEYWORD_SWITCH(LEVEL_ERROR, message, data, data_size);
break;
CASE_WARNING:
EBPF_LOG_MESSAGE_BINARY_KEYWORD_SWITCH(LEVEL_WARNING, message, data, data_size);
break;
CASE_INFO:
EBPF_LOG_MESSAGE_BINARY_KEYWORD_SWITCH(LEVEL_INFO, message, data, data_size);
break;
CASE_VERBOSE:
EBPF_LOG_MESSAGE_BINARY_KEYWORD_SWITCH(LEVEL_VERBOSE, message, data, data_size);
break;
default:
ebpf_assert(!"Invalid trace level");
break;
}
}
#define _EBPF_LOG_MESSAGE_ERROR(trace_level, keyword, message, error) \
TraceLoggingWrite( \
ebpf_tracelog_provider, \

Просмотреть файл

@ -4,7 +4,7 @@
#include "ebpf_extension_uuids.h"
#include "net_ebpf_ext_hook_provider.h"
#define NET_EBPF_EXT_STACK_EXPANSION_SIZE 1024 * 10
#define NET_EBPF_EXT_STACK_EXPANSION_SIZE 1024 * 4
typedef struct _net_ebpf_ext_hook_client_rundown
{
@ -315,7 +315,7 @@ net_ebpf_extension_hook_expand_stack_and_invoke_programs(
#pragma warning(disable : 28160) // Error annotation: DISPATCH_LEVEL is only supported on Windows 7 or later.
// Expand the stack and call the program.
status = KeExpandKernelStackAndCalloutEx(
(PEXPAND_STACK_CALLOUT)_net_ebpf_extension_invoke_programs_callout,
_net_ebpf_extension_invoke_programs_callout,
&invoke_parameters,
NET_EBPF_EXT_STACK_EXPANSION_SIZE,
FALSE,

Просмотреть файл

@ -1570,7 +1570,8 @@ net_ebpf_extension_sock_addr_authorize_recv_accept_classify(
goto Exit;
}
program_result = net_ebpf_extension_hook_invoke_programs(sock_addr_ctx, &filter_context->base, &result);
program_result =
net_ebpf_extension_hook_expand_stack_and_invoke_programs(sock_addr_ctx, &filter_context->base, &result);
if (program_result == EBPF_OBJECT_NOT_FOUND) {
// No eBPF program is attached to this filter.
goto Exit;

Просмотреть файл

@ -65,7 +65,11 @@ function GetDriveFreeSpaceGB
# Convert drive to single letter (eg. "C:" to "C") for Get-Volume.
$DriveSpecification = $DriveSpecification -replace ".$"
$FreeSpaceGB = (((Get-Volume $DriveSpecification).SizeRemaining) / 1GB).ToString("F2")
$Volume = Get-Volume $DriveSpecification
if ($Volume -eq $Null) {
ThrowWithErrorMessage -ErrorMessage "*** ERROR *** Drive $DriveSpecification not found."
}
$FreeSpaceGB = (($Volume.SizeRemaining) / 1GB).ToString("F2")
return $FreeSpaceGB
}
@ -136,13 +140,19 @@ if ($VerbosePreference -eq 'Continue') {
}
# Get the available free space before test start (useful in investigating dump file creation failures)
$BeforeTestFreeSpaceGB = GetDriveFreeSpaceGB -DriveSpecification $Env:SystemDrive
try {
$BeforeTestFreeSpaceGB = GetDriveFreeSpaceGB -DriveSpecification $Env:SystemDrive
} catch {
Write-Log "Error getting available disk space: $_"
$BeforeTestFreeSpaceGB = "Unknown"
# Continue with the test.
}
Write-Log "Available System disk space (Before test start): $BeforeTestFreeSpaceGB GB"
# Start the test process using the provided command and arguments.
$FullTestCommandSpec = Join-Path $Pwd $TestCommand
Write-Log "`n`n"
Write-Log "Staring Test command: $FullTestCommandSpec $TestArguments"
Write-Log "Starting Test command: $FullTestCommandSpec $TestArguments"
Write-Log "Test hang timeout: $TestHangTimeout (seconds)"
Write-Log "`n"
@ -175,7 +185,13 @@ if (-not $WaitResult) {
# Get the available free space at this point in case the test creates its own files.
# (useful in investigating user and/or kernel dump file creation failures).
$DriveFreeSpaceGB = GetDriveFreeSpaceGB -DriveSpecification $Env:SystemDrive
try {
$DriveFreeSpaceGB = GetDriveFreeSpaceGB -DriveSpecification $Env:SystemDrive
} catch {
Write-Log "Error getting available disk space: $_"
$DriveFreeSpaceGB = "Unknown"
# Continue with the test.
}
Write-Log "Current available disk space: $DriveFreeSpaceGB GB`n"
# $TestProcess refers to 'cmd.exe' which ends up running the real test application.

Просмотреть файл

@ -324,11 +324,27 @@ function ArchiveKernelModeDumpOnVM
Write-Output `
"Compressing kernel dump files: $KernelModeDumpFileSourcePath -> $KernelModeDumpFileDestinationPath"
Compress-Archive `
-Path $KernelModeDumpFileSourcePath\*.dmp `
-DestinationPath $KernelModeDumpFileDestinationPath\km_dumps.zip `
-CompressionLevel Fastest `
-Force
# Retry 3 times to ensure compression operation succeeds.
# To mitigate error message: "The process cannot access the file 'C:\Windows\MEMORY.DMP' because it is being used by another process."
$retryCount = 1
while ($retryCount -lt 4) {
$error.clear()
Compress-Archive `
-Path "$KernelModeDumpFileSourcePath\*.dmp" `
-DestinationPath "$KernelModeDumpFileDestinationPath\km_dumps.zip" `
-CompressionLevel Fastest `
-Force
if ($error[0] -ne $null) {
$ErrorMessage = "*** ERROR *** Failed to compress kernel mode dump files: $error. Retrying $retryCount"
Write-Output $ErrorMessage
Start-Sleep -seconds (5 * $retryCount)
$retryCount++
} else {
# Compression succeeded.
break;
}
}
if (Test-Path $KernelModeDumpFileDestinationPath\km_dumps.zip -PathType Leaf) {
$CompressedDumpFile = get-childitem -Path $KernelModeDumpFileDestinationPath\km_dumps.zip