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:
Родитель
504ed9a032
Коммит
f23ab7def5
|
@ -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",
|
||||
¤t_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
|
||||
|
|
Загрузка…
Ссылка в новой задаче