From 094cc5550159f5dabdbb0f6911a691de904554ad Mon Sep 17 00:00:00 2001 From: Alan Jowett Date: Mon, 29 Jan 2024 16:02:10 -0800 Subject: [PATCH 1/3] Add support for statically initializing BPF_MAP_TYPE_HASH_OF_MAPS Signed-off-by: Alan Jowett --- libs/execution_context/ebpf_native.c | 2 +- tests/sample/undocked/hash_of_map.c | 48 ++++++++++++++++++++++ tests/unit/libbpf_test.cpp | 61 ++++++++++++++++++++++++++++ tools/bpf2c/bpf_code_generator.cpp | 5 +++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 tests/sample/undocked/hash_of_map.c diff --git a/libs/execution_context/ebpf_native.c b/libs/execution_context/ebpf_native.c index e7311ecd97..3df669dca5 100644 --- a/libs/execution_context/ebpf_native.c +++ b/libs/execution_context/ebpf_native.c @@ -923,7 +923,7 @@ _ebpf_native_set_initial_map_values(_Inout_ ebpf_native_module_t* module) ebpf_handle_t handle_to_insert = ebpf_handle_invalid; - if (native_map_to_update->entry->definition.type == BPF_MAP_TYPE_ARRAY_OF_MAPS) { + if (_ebpf_native_is_map_in_map(native_map_to_update)) { ebpf_native_map_t* native_map_to_insert = _ebpf_native_find_map_by_name(module, map_initial_values[i].values[j]); if (native_map_to_update == NULL) { diff --git a/tests/sample/undocked/hash_of_map.c b/tests/sample/undocked/hash_of_map.c new file mode 100644 index 0000000000..83bd6ba465 --- /dev/null +++ b/tests/sample/undocked/hash_of_map.c @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +// Whenever this sample program changes, bpf2c_tests will fail unless the +// expected files in tests\bpf2c_tests\expected are updated. The following +// script can be used to regenerate the expected files: +// generate_expected_bpf2c_output.ps1 +// +// Usage: +// .\scripts\generate_expected_bpf2c_output.ps1 +// Example: +// .\scripts\generate_expected_bpf2c_output.ps1 .\x64\Debug\ + +#include "bpf_helpers.h" +#include "sample_ext_helpers.h" + +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, uint32_t); + __type(value, uint32_t); + __uint(max_entries, 1); +} inner_map SEC(".maps"); + +struct +{ + __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); + __type(key, uint32_t); + __type(value, uint32_t); + __uint(max_entries, 1); + __array(values, inner_map); +} outer_map SEC(".maps") = { + .values = {&inner_map}, +}; + +SEC("sample_ext") int lookup(sample_program_context_t* ctx) +{ + uint32_t outer_key = 0; + void* inner_map = bpf_map_lookup_elem(&outer_map, &outer_key); + if (inner_map) { + uint32_t inner_key = 0; + uint32_t* value = (uint32_t*)bpf_map_lookup_elem(inner_map, &inner_key); + if (value) { + return *(uint32_t*)value; + } + } + return 0; +} diff --git a/tests/unit/libbpf_test.cpp b/tests/unit/libbpf_test.cpp index e2ef202ea6..1f1269bf84 100644 --- a/tests/unit/libbpf_test.cpp +++ b/tests/unit/libbpf_test.cpp @@ -8,6 +8,7 @@ #pragma warning(pop) #include "capture_helper.hpp" #include "catch_wrapper.hpp" +#include "common_tests.h" #include "ebpf_platform.h" #include "ebpf_tracelog.h" #include "ebpf_vm_isa.hpp" @@ -3293,4 +3294,64 @@ TEST_CASE("libbpf map batch", "[libbpf]") delete_batch_size = batch_size; REQUIRE(bpf_map_delete_batch(invalid_map_fd, keys.data(), &delete_batch_size, &opts) == -EBADF); +} + +void +_hash_of_map_initial_value_test(ebpf_execution_type_t execution_type) +{ + _test_helper_libbpf test_helper; + test_helper.initialize(); + + std::string file_name = std::format("hash_of_map{}", execution_type == EBPF_EXECUTION_NATIVE ? "_um.dll" : ".o"); + + bpf_object_ptr object(bpf_object__open(file_name.c_str())); + REQUIRE(object != nullptr); + + REQUIRE(ebpf_object_set_execution_type(object.get(), execution_type) == EBPF_SUCCESS); + + // Load the BPF program. + REQUIRE(bpf_object__load(object.get()) == 0); + + // Get the outer map. + bpf_map* outer_map = bpf_object__find_map_by_name(object.get(), "outer_map"); + REQUIRE(outer_map != nullptr); + + bpf_map* inner_map = bpf_object__find_map_by_name(object.get(), "inner_map"); + REQUIRE(inner_map != nullptr); + + fd_t outer_map_fd = bpf_map__fd(outer_map); + REQUIRE(outer_map_fd > 0); + + fd_t inner_map_fd = bpf_map__fd(inner_map); + REQUIRE(inner_map_fd > 0); + + // Issue: https://github.com/microsoft/ebpf-for-windows/issues/3210 + // Only native execution supports map of maps with static initializers. + if (execution_type != EBPF_EXECUTION_NATIVE) { + return; + } + + uint32_t key = 0; + uint32_t inner_map_id = 0; + + // Get the map at index 0. + REQUIRE(bpf_map_lookup_elem(outer_map_fd, &key, &inner_map_id) == 0); + + // Get id of the inner map. + bpf_map_info info; + uint32_t info_length = sizeof(info); + memset(&info, 0, sizeof(info)); + REQUIRE(bpf_obj_get_info_by_fd(inner_map_fd, &info, &info_length) == 0); + + // Verify that the id of the inner map matches the id in the outer map. + REQUIRE(inner_map_id == info.id); +} + +TEST_CASE("hash_of_map", "[libbpf]") +{ +#if !defined(CONFIG_BPF_JIT_DISABLED) + _hash_of_map_initial_value_test(EBPF_EXECUTION_JIT); + +#endif + _hash_of_map_initial_value_test(EBPF_EXECUTION_NATIVE); } \ No newline at end of file diff --git a/tools/bpf2c/bpf_code_generator.cpp b/tools/bpf2c/bpf_code_generator.cpp index 049d7c761d..61ef448e15 100644 --- a/tools/bpf2c/bpf_code_generator.cpp +++ b/tools/bpf2c/bpf_code_generator.cpp @@ -529,6 +529,11 @@ bpf_code_generator::parse_btf_maps_section(const unsafe_string& name) // Compute the offset of the values array and resize the vector // to hold the initial values. if (member.name == "values") { + // If the map is statically initialized, then the keys must be uint32_t. + if (map_definition.key_size != sizeof(uint32_t)) { + throw bpf_code_generator_exception("map keys must be uint32_t for static initialization"); + } + map_names_to_values_offset[unsafe_symbol_name] = member.offset_from_start_in_bits / 8; if (map_names_to_values_offset[unsafe_symbol_name] > (range.second - range.first)) { throw bpf_code_generator_exception("map values offset is outside of map range"); From 7632c2dec7341bdc8c1e38fc6b022818623e79e9 Mon Sep 17 00:00:00 2001 From: Alan Jowett Date: Tue, 30 Jan 2024 09:48:46 -0800 Subject: [PATCH 2/3] Update installer and add code gen tests Signed-off-by: Alan Jowett --- installer/Product.wxs | 12 + tests/bpf2c_tests/elf_bpf.cpp | 1 + tests/bpf2c_tests/expected/hash_of_map_dll.c | 251 ++++++++++++ tests/bpf2c_tests/expected/hash_of_map_raw.c | 225 +++++++++++ tests/bpf2c_tests/expected/hash_of_map_sys.c | 386 +++++++++++++++++++ 5 files changed, 875 insertions(+) create mode 100644 tests/bpf2c_tests/expected/hash_of_map_dll.c create mode 100644 tests/bpf2c_tests/expected/hash_of_map_raw.c create mode 100644 tests/bpf2c_tests/expected/hash_of_map_sys.c diff --git a/installer/Product.wxs b/installer/Product.wxs index 811589a972..390f908c3e 100644 --- a/installer/Product.wxs +++ b/installer/Product.wxs @@ -826,6 +826,18 @@ SPDX-License-Identifier: MIT + + + + + + + + + + + + diff --git a/tests/bpf2c_tests/elf_bpf.cpp b/tests/bpf2c_tests/elf_bpf.cpp index adc1856267..32f01ef093 100644 --- a/tests/bpf2c_tests/elf_bpf.cpp +++ b/tests/bpf2c_tests/elf_bpf.cpp @@ -219,6 +219,7 @@ DECLARE_TEST("droppacket", _test_mode::Verify) DECLARE_TEST("droppacket_unsafe", _test_mode::NoVerify) DECLARE_TEST("empty", _test_mode::NoVerify) DECLARE_TEST("encap_reflect_packet", _test_mode::Verify) +DECLARE_TEST("hash_of_map", _test_mode::Verify) DECLARE_TEST("inner_map", _test_mode::Verify) DECLARE_TEST("invalid_helpers", _test_mode::NoVerify); DECLARE_TEST("invalid_maps1", _test_mode::NoVerify); diff --git a/tests/bpf2c_tests/expected/hash_of_map_dll.c b/tests/bpf2c_tests/expected/hash_of_map_dll.c new file mode 100644 index 0000000000..55c4a24ab3 --- /dev/null +++ b/tests/bpf2c_tests/expected/hash_of_map_dll.c @@ -0,0 +1,251 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +// Do not alter this generated file. +// This file was generated from hash_of_map.o + +#include "bpf2c.h" + +#include +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#include + +#define metadata_table hash_of_map##_metadata_table +extern metadata_table_t metadata_table; + +bool APIENTRY +DllMain(_In_ HMODULE hModule, unsigned int ul_reason_for_call, _In_ void* lpReserved) +{ + UNREFERENCED_PARAMETER(hModule); + UNREFERENCED_PARAMETER(lpReserved); + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +__declspec(dllexport) metadata_table_t* get_metadata_table() { return &metadata_table; } + +#include "bpf2c.h" + +static void +_get_hash(_Outptr_result_buffer_maybenull_(*size) const uint8_t** hash, _Out_ size_t* size) +{ + *hash = NULL; + *size = 0; +} +#pragma data_seg(push, "maps") +static map_entry_t _maps[] = { + {NULL, + { + BPF_MAP_TYPE_HASH, // Type of map. + 4, // Size in bytes of a map key. + 4, // Size in bytes of a map value. + 1, // Maximum number of entries allowed in the map. + 0, // Inner map index. + LIBBPF_PIN_NONE, // Pinning type for the map. + 8, // Identifier for a map template. + 0, // The id of the inner map template. + }, + "inner_map"}, + {NULL, + { + BPF_MAP_TYPE_HASH_OF_MAPS, // Type of map. + 4, // Size in bytes of a map key. + 4, // Size in bytes of a map value. + 1, // Maximum number of entries allowed in the map. + 0, // Inner map index. + LIBBPF_PIN_NONE, // Pinning type for the map. + 14, // Identifier for a map template. + 8, // The id of the inner map template. + }, + "outer_map"}, +}; +#pragma data_seg(pop) + +static void +_get_maps(_Outptr_result_buffer_maybenull_(*count) map_entry_t** maps, _Out_ size_t* count) +{ + *maps = _maps; + *count = 2; +} + +static helper_function_entry_t lookup_helpers[] = { + {NULL, 1, "helper_id_1"}, +}; + +static GUID lookup_program_type_guid = {0xf788ef4a, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}}; +static GUID lookup_attach_type_guid = {0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}}; +static uint16_t lookup_maps[] = { + 1, +}; + +#pragma code_seg(push, "sample~1") +static uint64_t +lookup(void* context) +#line 36 "sample/undocked/hash_of_map.c" +{ +#line 36 "sample/undocked/hash_of_map.c" + // Prologue +#line 36 "sample/undocked/hash_of_map.c" + uint64_t stack[(UBPF_STACK_SIZE + 7) / 8]; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r0 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r1 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r2 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r3 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r4 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r5 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r6 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r10 = 0; + +#line 36 "sample/undocked/hash_of_map.c" + r1 = (uintptr_t)context; +#line 36 "sample/undocked/hash_of_map.c" + r10 = (uintptr_t)((uint8_t*)stack + sizeof(stack)); + + // EBPF_OP_MOV64_IMM pc=0 dst=r6 src=r0 offset=0 imm=0 +#line 36 "sample/undocked/hash_of_map.c" + r6 = IMMEDIATE(0); + // EBPF_OP_STXW pc=1 dst=r10 src=r6 offset=-4 imm=0 +#line 38 "sample/undocked/hash_of_map.c" + *(uint32_t*)(uintptr_t)(r10 + OFFSET(-4)) = (uint32_t)r6; + // EBPF_OP_MOV64_REG pc=2 dst=r2 src=r10 offset=0 imm=0 +#line 38 "sample/undocked/hash_of_map.c" + r2 = r10; + // EBPF_OP_ADD64_IMM pc=3 dst=r2 src=r0 offset=0 imm=-4 +#line 38 "sample/undocked/hash_of_map.c" + r2 += IMMEDIATE(-4); + // EBPF_OP_LDDW pc=4 dst=r1 src=r0 offset=0 imm=0 +#line 39 "sample/undocked/hash_of_map.c" + r1 = POINTER(_maps[1].address); + // EBPF_OP_CALL pc=6 dst=r0 src=r0 offset=0 imm=1 +#line 39 "sample/undocked/hash_of_map.c" + r0 = lookup_helpers[0].address +#line 39 "sample/undocked/hash_of_map.c" + (r1, r2, r3, r4, r5); +#line 39 "sample/undocked/hash_of_map.c" + if ((lookup_helpers[0].tail_call) && (r0 == 0)) +#line 39 "sample/undocked/hash_of_map.c" + return 0; + // EBPF_OP_JEQ_IMM pc=7 dst=r0 src=r0 offset=9 imm=0 +#line 40 "sample/undocked/hash_of_map.c" + if (r0 == IMMEDIATE(0)) +#line 40 "sample/undocked/hash_of_map.c" + goto label_2; + // EBPF_OP_MOV64_IMM pc=8 dst=r6 src=r0 offset=0 imm=0 +#line 40 "sample/undocked/hash_of_map.c" + r6 = IMMEDIATE(0); + // EBPF_OP_STXW pc=9 dst=r10 src=r6 offset=-8 imm=0 +#line 41 "sample/undocked/hash_of_map.c" + *(uint32_t*)(uintptr_t)(r10 + OFFSET(-8)) = (uint32_t)r6; + // EBPF_OP_MOV64_REG pc=10 dst=r2 src=r10 offset=0 imm=0 +#line 41 "sample/undocked/hash_of_map.c" + r2 = r10; + // EBPF_OP_ADD64_IMM pc=11 dst=r2 src=r0 offset=0 imm=-8 +#line 41 "sample/undocked/hash_of_map.c" + r2 += IMMEDIATE(-8); + // EBPF_OP_MOV64_REG pc=12 dst=r1 src=r0 offset=0 imm=0 +#line 42 "sample/undocked/hash_of_map.c" + r1 = r0; + // EBPF_OP_CALL pc=13 dst=r0 src=r0 offset=0 imm=1 +#line 42 "sample/undocked/hash_of_map.c" + r0 = lookup_helpers[0].address +#line 42 "sample/undocked/hash_of_map.c" + (r1, r2, r3, r4, r5); +#line 42 "sample/undocked/hash_of_map.c" + if ((lookup_helpers[0].tail_call) && (r0 == 0)) +#line 42 "sample/undocked/hash_of_map.c" + return 0; + // EBPF_OP_JNE_IMM pc=14 dst=r0 src=r0 offset=1 imm=0 +#line 43 "sample/undocked/hash_of_map.c" + if (r0 != IMMEDIATE(0)) +#line 43 "sample/undocked/hash_of_map.c" + goto label_1; + // EBPF_OP_JA pc=15 dst=r0 src=r0 offset=1 imm=0 +#line 43 "sample/undocked/hash_of_map.c" + goto label_2; +label_1: + // EBPF_OP_LDXW pc=16 dst=r6 src=r0 offset=0 imm=0 +#line 44 "sample/undocked/hash_of_map.c" + r6 = *(uint32_t*)(uintptr_t)(r0 + OFFSET(0)); +label_2: + // EBPF_OP_MOV64_REG pc=17 dst=r0 src=r6 offset=0 imm=0 +#line 48 "sample/undocked/hash_of_map.c" + r0 = r6; + // EBPF_OP_EXIT pc=18 dst=r0 src=r0 offset=0 imm=0 +#line 48 "sample/undocked/hash_of_map.c" + return r0; +#line 48 "sample/undocked/hash_of_map.c" +} +#pragma code_seg(pop) +#line __LINE__ __FILE__ + +#pragma data_seg(push, "programs") +static program_entry_t _programs[] = { + { + 0, + lookup, + "sample~1", + "sample_ext", + "lookup", + lookup_maps, + 1, + lookup_helpers, + 1, + 19, + &lookup_program_type_guid, + &lookup_attach_type_guid, + }, +}; +#pragma data_seg(pop) + +static void +_get_programs(_Outptr_result_buffer_(*count) program_entry_t** programs, _Out_ size_t* count) +{ + *programs = _programs; + *count = 1; +} + +static void +_get_version(_Out_ bpf2c_version_t* version) +{ + version->major = 0; + version->minor = 13; + version->revision = 0; +} + +#pragma data_seg(push, "map_initial_values") +static const char* _outer_map_initial_string_table[] = { + "inner_map", +}; + +static map_initial_values_t _map_initial_values_array[] = { + { + .name = "outer_map", + .count = 1, + .values = _outer_map_initial_string_table, + }, +}; +#pragma data_seg(pop) + +static void +_get_map_initial_values(_Outptr_result_buffer_(*count) map_initial_values_t** map_initial_values, _Out_ size_t* count) +{ + *map_initial_values = _map_initial_values_array; + *count = 1; +} + +metadata_table_t hash_of_map_metadata_table = { + sizeof(metadata_table_t), _get_programs, _get_maps, _get_hash, _get_version, _get_map_initial_values}; diff --git a/tests/bpf2c_tests/expected/hash_of_map_raw.c b/tests/bpf2c_tests/expected/hash_of_map_raw.c new file mode 100644 index 0000000000..561c42e2f9 --- /dev/null +++ b/tests/bpf2c_tests/expected/hash_of_map_raw.c @@ -0,0 +1,225 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +// Do not alter this generated file. +// This file was generated from hash_of_map.o + +#include "bpf2c.h" + +static void +_get_hash(_Outptr_result_buffer_maybenull_(*size) const uint8_t** hash, _Out_ size_t* size) +{ + *hash = NULL; + *size = 0; +} +#pragma data_seg(push, "maps") +static map_entry_t _maps[] = { + {NULL, + { + BPF_MAP_TYPE_HASH, // Type of map. + 4, // Size in bytes of a map key. + 4, // Size in bytes of a map value. + 1, // Maximum number of entries allowed in the map. + 0, // Inner map index. + LIBBPF_PIN_NONE, // Pinning type for the map. + 8, // Identifier for a map template. + 0, // The id of the inner map template. + }, + "inner_map"}, + {NULL, + { + BPF_MAP_TYPE_HASH_OF_MAPS, // Type of map. + 4, // Size in bytes of a map key. + 4, // Size in bytes of a map value. + 1, // Maximum number of entries allowed in the map. + 0, // Inner map index. + LIBBPF_PIN_NONE, // Pinning type for the map. + 14, // Identifier for a map template. + 8, // The id of the inner map template. + }, + "outer_map"}, +}; +#pragma data_seg(pop) + +static void +_get_maps(_Outptr_result_buffer_maybenull_(*count) map_entry_t** maps, _Out_ size_t* count) +{ + *maps = _maps; + *count = 2; +} + +static helper_function_entry_t lookup_helpers[] = { + {NULL, 1, "helper_id_1"}, +}; + +static GUID lookup_program_type_guid = {0xf788ef4a, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}}; +static GUID lookup_attach_type_guid = {0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}}; +static uint16_t lookup_maps[] = { + 1, +}; + +#pragma code_seg(push, "sample~1") +static uint64_t +lookup(void* context) +#line 36 "sample/undocked/hash_of_map.c" +{ +#line 36 "sample/undocked/hash_of_map.c" + // Prologue +#line 36 "sample/undocked/hash_of_map.c" + uint64_t stack[(UBPF_STACK_SIZE + 7) / 8]; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r0 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r1 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r2 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r3 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r4 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r5 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r6 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r10 = 0; + +#line 36 "sample/undocked/hash_of_map.c" + r1 = (uintptr_t)context; +#line 36 "sample/undocked/hash_of_map.c" + r10 = (uintptr_t)((uint8_t*)stack + sizeof(stack)); + + // EBPF_OP_MOV64_IMM pc=0 dst=r6 src=r0 offset=0 imm=0 +#line 36 "sample/undocked/hash_of_map.c" + r6 = IMMEDIATE(0); + // EBPF_OP_STXW pc=1 dst=r10 src=r6 offset=-4 imm=0 +#line 38 "sample/undocked/hash_of_map.c" + *(uint32_t*)(uintptr_t)(r10 + OFFSET(-4)) = (uint32_t)r6; + // EBPF_OP_MOV64_REG pc=2 dst=r2 src=r10 offset=0 imm=0 +#line 38 "sample/undocked/hash_of_map.c" + r2 = r10; + // EBPF_OP_ADD64_IMM pc=3 dst=r2 src=r0 offset=0 imm=-4 +#line 38 "sample/undocked/hash_of_map.c" + r2 += IMMEDIATE(-4); + // EBPF_OP_LDDW pc=4 dst=r1 src=r0 offset=0 imm=0 +#line 39 "sample/undocked/hash_of_map.c" + r1 = POINTER(_maps[1].address); + // EBPF_OP_CALL pc=6 dst=r0 src=r0 offset=0 imm=1 +#line 39 "sample/undocked/hash_of_map.c" + r0 = lookup_helpers[0].address +#line 39 "sample/undocked/hash_of_map.c" + (r1, r2, r3, r4, r5); +#line 39 "sample/undocked/hash_of_map.c" + if ((lookup_helpers[0].tail_call) && (r0 == 0)) +#line 39 "sample/undocked/hash_of_map.c" + return 0; + // EBPF_OP_JEQ_IMM pc=7 dst=r0 src=r0 offset=9 imm=0 +#line 40 "sample/undocked/hash_of_map.c" + if (r0 == IMMEDIATE(0)) +#line 40 "sample/undocked/hash_of_map.c" + goto label_2; + // EBPF_OP_MOV64_IMM pc=8 dst=r6 src=r0 offset=0 imm=0 +#line 40 "sample/undocked/hash_of_map.c" + r6 = IMMEDIATE(0); + // EBPF_OP_STXW pc=9 dst=r10 src=r6 offset=-8 imm=0 +#line 41 "sample/undocked/hash_of_map.c" + *(uint32_t*)(uintptr_t)(r10 + OFFSET(-8)) = (uint32_t)r6; + // EBPF_OP_MOV64_REG pc=10 dst=r2 src=r10 offset=0 imm=0 +#line 41 "sample/undocked/hash_of_map.c" + r2 = r10; + // EBPF_OP_ADD64_IMM pc=11 dst=r2 src=r0 offset=0 imm=-8 +#line 41 "sample/undocked/hash_of_map.c" + r2 += IMMEDIATE(-8); + // EBPF_OP_MOV64_REG pc=12 dst=r1 src=r0 offset=0 imm=0 +#line 42 "sample/undocked/hash_of_map.c" + r1 = r0; + // EBPF_OP_CALL pc=13 dst=r0 src=r0 offset=0 imm=1 +#line 42 "sample/undocked/hash_of_map.c" + r0 = lookup_helpers[0].address +#line 42 "sample/undocked/hash_of_map.c" + (r1, r2, r3, r4, r5); +#line 42 "sample/undocked/hash_of_map.c" + if ((lookup_helpers[0].tail_call) && (r0 == 0)) +#line 42 "sample/undocked/hash_of_map.c" + return 0; + // EBPF_OP_JNE_IMM pc=14 dst=r0 src=r0 offset=1 imm=0 +#line 43 "sample/undocked/hash_of_map.c" + if (r0 != IMMEDIATE(0)) +#line 43 "sample/undocked/hash_of_map.c" + goto label_1; + // EBPF_OP_JA pc=15 dst=r0 src=r0 offset=1 imm=0 +#line 43 "sample/undocked/hash_of_map.c" + goto label_2; +label_1: + // EBPF_OP_LDXW pc=16 dst=r6 src=r0 offset=0 imm=0 +#line 44 "sample/undocked/hash_of_map.c" + r6 = *(uint32_t*)(uintptr_t)(r0 + OFFSET(0)); +label_2: + // EBPF_OP_MOV64_REG pc=17 dst=r0 src=r6 offset=0 imm=0 +#line 48 "sample/undocked/hash_of_map.c" + r0 = r6; + // EBPF_OP_EXIT pc=18 dst=r0 src=r0 offset=0 imm=0 +#line 48 "sample/undocked/hash_of_map.c" + return r0; +#line 48 "sample/undocked/hash_of_map.c" +} +#pragma code_seg(pop) +#line __LINE__ __FILE__ + +#pragma data_seg(push, "programs") +static program_entry_t _programs[] = { + { + 0, + lookup, + "sample~1", + "sample_ext", + "lookup", + lookup_maps, + 1, + lookup_helpers, + 1, + 19, + &lookup_program_type_guid, + &lookup_attach_type_guid, + }, +}; +#pragma data_seg(pop) + +static void +_get_programs(_Outptr_result_buffer_(*count) program_entry_t** programs, _Out_ size_t* count) +{ + *programs = _programs; + *count = 1; +} + +static void +_get_version(_Out_ bpf2c_version_t* version) +{ + version->major = 0; + version->minor = 13; + version->revision = 0; +} + +#pragma data_seg(push, "map_initial_values") +static const char* _outer_map_initial_string_table[] = { + "inner_map", +}; + +static map_initial_values_t _map_initial_values_array[] = { + { + .name = "outer_map", + .count = 1, + .values = _outer_map_initial_string_table, + }, +}; +#pragma data_seg(pop) + +static void +_get_map_initial_values(_Outptr_result_buffer_(*count) map_initial_values_t** map_initial_values, _Out_ size_t* count) +{ + *map_initial_values = _map_initial_values_array; + *count = 1; +} + +metadata_table_t hash_of_map_metadata_table = { + sizeof(metadata_table_t), _get_programs, _get_maps, _get_hash, _get_version, _get_map_initial_values}; diff --git a/tests/bpf2c_tests/expected/hash_of_map_sys.c b/tests/bpf2c_tests/expected/hash_of_map_sys.c new file mode 100644 index 0000000000..92a0d3a921 --- /dev/null +++ b/tests/bpf2c_tests/expected/hash_of_map_sys.c @@ -0,0 +1,386 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +// Do not alter this generated file. +// This file was generated from hash_of_map.o + +#define NO_CRT +#include "bpf2c.h" + +#include +#include +#include + +DRIVER_INITIALIZE DriverEntry; +DRIVER_UNLOAD DriverUnload; +RTL_QUERY_REGISTRY_ROUTINE static _bpf2c_query_registry_routine; + +#define metadata_table hash_of_map##_metadata_table + +static GUID _bpf2c_npi_id = {/* c847aac8-a6f2-4b53-aea3-f4a94b9a80cb */ + 0xc847aac8, + 0xa6f2, + 0x4b53, + {0xae, 0xa3, 0xf4, 0xa9, 0x4b, 0x9a, 0x80, 0xcb}}; +static NPI_MODULEID _bpf2c_module_id = {sizeof(_bpf2c_module_id), MIT_GUID, {0}}; +static HANDLE _bpf2c_nmr_client_handle; +static HANDLE _bpf2c_nmr_provider_handle; +extern metadata_table_t metadata_table; + +static NTSTATUS +_bpf2c_npi_client_attach_provider( + _In_ HANDLE nmr_binding_handle, + _In_ void* client_context, + _In_ const NPI_REGISTRATION_INSTANCE* provider_registration_instance); + +static NTSTATUS +_bpf2c_npi_client_detach_provider(_In_ void* client_binding_context); + +static const NPI_CLIENT_CHARACTERISTICS _bpf2c_npi_client_characteristics = { + 0, // Version + sizeof(NPI_CLIENT_CHARACTERISTICS), // Length + _bpf2c_npi_client_attach_provider, + _bpf2c_npi_client_detach_provider, + NULL, + {0, // Version + sizeof(NPI_REGISTRATION_INSTANCE), // Length + &_bpf2c_npi_id, + &_bpf2c_module_id, + 0, + &metadata_table}}; + +static NTSTATUS +_bpf2c_query_npi_module_id( + _In_ const wchar_t* value_name, + unsigned long value_type, + _In_ const void* value_data, + unsigned long value_length, + _Inout_ void* context, + _Inout_ void* entry_context) +{ + UNREFERENCED_PARAMETER(value_name); + UNREFERENCED_PARAMETER(context); + UNREFERENCED_PARAMETER(entry_context); + + if (value_type != REG_BINARY) { + return STATUS_INVALID_PARAMETER; + } + if (value_length != sizeof(_bpf2c_module_id.Guid)) { + return STATUS_INVALID_PARAMETER; + } + + memcpy(&_bpf2c_module_id.Guid, value_data, value_length); + return STATUS_SUCCESS; +} + +NTSTATUS +DriverEntry(_In_ DRIVER_OBJECT* driver_object, _In_ UNICODE_STRING* registry_path) +{ + NTSTATUS status; + RTL_QUERY_REGISTRY_TABLE query_table[] = { + { + NULL, // Query routine + RTL_QUERY_REGISTRY_SUBKEY, // Flags + L"Parameters", // Name + NULL, // Entry context + REG_NONE, // Default type + NULL, // Default data + 0, // Default length + }, + { + _bpf2c_query_npi_module_id, // Query routine + RTL_QUERY_REGISTRY_REQUIRED, // Flags + L"NpiModuleId", // Name + NULL, // Entry context + REG_NONE, // Default type + NULL, // Default data + 0, // Default length + }, + {0}}; + + status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, registry_path->Buffer, query_table, NULL, NULL); + if (!NT_SUCCESS(status)) { + goto Exit; + } + + status = NmrRegisterClient(&_bpf2c_npi_client_characteristics, NULL, &_bpf2c_nmr_client_handle); + +Exit: + if (NT_SUCCESS(status)) { + driver_object->DriverUnload = DriverUnload; + } + + return status; +} + +void +DriverUnload(_In_ DRIVER_OBJECT* driver_object) +{ + NTSTATUS status = NmrDeregisterClient(_bpf2c_nmr_client_handle); + if (status == STATUS_PENDING) { + NmrWaitForClientDeregisterComplete(_bpf2c_nmr_client_handle); + } + UNREFERENCED_PARAMETER(driver_object); +} + +static NTSTATUS +_bpf2c_npi_client_attach_provider( + _In_ HANDLE nmr_binding_handle, + _In_ void* client_context, + _In_ const NPI_REGISTRATION_INSTANCE* provider_registration_instance) +{ + NTSTATUS status = STATUS_SUCCESS; + void* provider_binding_context = NULL; + void* provider_dispatch_table = NULL; + + UNREFERENCED_PARAMETER(client_context); + UNREFERENCED_PARAMETER(provider_registration_instance); + + if (_bpf2c_nmr_provider_handle != NULL) { + return STATUS_INVALID_PARAMETER; + } + +#pragma warning(push) +#pragma warning( \ + disable : 6387) // Param 3 does not adhere to the specification for the function 'NmrClientAttachProvider' + // As per MSDN, client dispatch can be NULL, but SAL does not allow it. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/netioddk/nf-netioddk-nmrclientattachprovider + status = NmrClientAttachProvider( + nmr_binding_handle, client_context, NULL, &provider_binding_context, &provider_dispatch_table); + if (status != STATUS_SUCCESS) { + goto Done; + } +#pragma warning(pop) + _bpf2c_nmr_provider_handle = nmr_binding_handle; + +Done: + return status; +} + +static NTSTATUS +_bpf2c_npi_client_detach_provider(_In_ void* client_binding_context) +{ + _bpf2c_nmr_provider_handle = NULL; + UNREFERENCED_PARAMETER(client_binding_context); + return STATUS_SUCCESS; +} + +#include "bpf2c.h" + +static void +_get_hash(_Outptr_result_buffer_maybenull_(*size) const uint8_t** hash, _Out_ size_t* size) +{ + *hash = NULL; + *size = 0; +} +#pragma data_seg(push, "maps") +static map_entry_t _maps[] = { + {NULL, + { + BPF_MAP_TYPE_HASH, // Type of map. + 4, // Size in bytes of a map key. + 4, // Size in bytes of a map value. + 1, // Maximum number of entries allowed in the map. + 0, // Inner map index. + LIBBPF_PIN_NONE, // Pinning type for the map. + 8, // Identifier for a map template. + 0, // The id of the inner map template. + }, + "inner_map"}, + {NULL, + { + BPF_MAP_TYPE_HASH_OF_MAPS, // Type of map. + 4, // Size in bytes of a map key. + 4, // Size in bytes of a map value. + 1, // Maximum number of entries allowed in the map. + 0, // Inner map index. + LIBBPF_PIN_NONE, // Pinning type for the map. + 14, // Identifier for a map template. + 8, // The id of the inner map template. + }, + "outer_map"}, +}; +#pragma data_seg(pop) + +static void +_get_maps(_Outptr_result_buffer_maybenull_(*count) map_entry_t** maps, _Out_ size_t* count) +{ + *maps = _maps; + *count = 2; +} + +static helper_function_entry_t lookup_helpers[] = { + {NULL, 1, "helper_id_1"}, +}; + +static GUID lookup_program_type_guid = {0xf788ef4a, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}}; +static GUID lookup_attach_type_guid = {0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}}; +static uint16_t lookup_maps[] = { + 1, +}; + +#pragma code_seg(push, "sample~1") +static uint64_t +lookup(void* context) +#line 36 "sample/undocked/hash_of_map.c" +{ +#line 36 "sample/undocked/hash_of_map.c" + // Prologue +#line 36 "sample/undocked/hash_of_map.c" + uint64_t stack[(UBPF_STACK_SIZE + 7) / 8]; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r0 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r1 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r2 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r3 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r4 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r5 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r6 = 0; +#line 36 "sample/undocked/hash_of_map.c" + register uint64_t r10 = 0; + +#line 36 "sample/undocked/hash_of_map.c" + r1 = (uintptr_t)context; +#line 36 "sample/undocked/hash_of_map.c" + r10 = (uintptr_t)((uint8_t*)stack + sizeof(stack)); + + // EBPF_OP_MOV64_IMM pc=0 dst=r6 src=r0 offset=0 imm=0 +#line 36 "sample/undocked/hash_of_map.c" + r6 = IMMEDIATE(0); + // EBPF_OP_STXW pc=1 dst=r10 src=r6 offset=-4 imm=0 +#line 38 "sample/undocked/hash_of_map.c" + *(uint32_t*)(uintptr_t)(r10 + OFFSET(-4)) = (uint32_t)r6; + // EBPF_OP_MOV64_REG pc=2 dst=r2 src=r10 offset=0 imm=0 +#line 38 "sample/undocked/hash_of_map.c" + r2 = r10; + // EBPF_OP_ADD64_IMM pc=3 dst=r2 src=r0 offset=0 imm=-4 +#line 38 "sample/undocked/hash_of_map.c" + r2 += IMMEDIATE(-4); + // EBPF_OP_LDDW pc=4 dst=r1 src=r0 offset=0 imm=0 +#line 39 "sample/undocked/hash_of_map.c" + r1 = POINTER(_maps[1].address); + // EBPF_OP_CALL pc=6 dst=r0 src=r0 offset=0 imm=1 +#line 39 "sample/undocked/hash_of_map.c" + r0 = lookup_helpers[0].address +#line 39 "sample/undocked/hash_of_map.c" + (r1, r2, r3, r4, r5); +#line 39 "sample/undocked/hash_of_map.c" + if ((lookup_helpers[0].tail_call) && (r0 == 0)) +#line 39 "sample/undocked/hash_of_map.c" + return 0; + // EBPF_OP_JEQ_IMM pc=7 dst=r0 src=r0 offset=9 imm=0 +#line 40 "sample/undocked/hash_of_map.c" + if (r0 == IMMEDIATE(0)) +#line 40 "sample/undocked/hash_of_map.c" + goto label_2; + // EBPF_OP_MOV64_IMM pc=8 dst=r6 src=r0 offset=0 imm=0 +#line 40 "sample/undocked/hash_of_map.c" + r6 = IMMEDIATE(0); + // EBPF_OP_STXW pc=9 dst=r10 src=r6 offset=-8 imm=0 +#line 41 "sample/undocked/hash_of_map.c" + *(uint32_t*)(uintptr_t)(r10 + OFFSET(-8)) = (uint32_t)r6; + // EBPF_OP_MOV64_REG pc=10 dst=r2 src=r10 offset=0 imm=0 +#line 41 "sample/undocked/hash_of_map.c" + r2 = r10; + // EBPF_OP_ADD64_IMM pc=11 dst=r2 src=r0 offset=0 imm=-8 +#line 41 "sample/undocked/hash_of_map.c" + r2 += IMMEDIATE(-8); + // EBPF_OP_MOV64_REG pc=12 dst=r1 src=r0 offset=0 imm=0 +#line 42 "sample/undocked/hash_of_map.c" + r1 = r0; + // EBPF_OP_CALL pc=13 dst=r0 src=r0 offset=0 imm=1 +#line 42 "sample/undocked/hash_of_map.c" + r0 = lookup_helpers[0].address +#line 42 "sample/undocked/hash_of_map.c" + (r1, r2, r3, r4, r5); +#line 42 "sample/undocked/hash_of_map.c" + if ((lookup_helpers[0].tail_call) && (r0 == 0)) +#line 42 "sample/undocked/hash_of_map.c" + return 0; + // EBPF_OP_JNE_IMM pc=14 dst=r0 src=r0 offset=1 imm=0 +#line 43 "sample/undocked/hash_of_map.c" + if (r0 != IMMEDIATE(0)) +#line 43 "sample/undocked/hash_of_map.c" + goto label_1; + // EBPF_OP_JA pc=15 dst=r0 src=r0 offset=1 imm=0 +#line 43 "sample/undocked/hash_of_map.c" + goto label_2; +label_1: + // EBPF_OP_LDXW pc=16 dst=r6 src=r0 offset=0 imm=0 +#line 44 "sample/undocked/hash_of_map.c" + r6 = *(uint32_t*)(uintptr_t)(r0 + OFFSET(0)); +label_2: + // EBPF_OP_MOV64_REG pc=17 dst=r0 src=r6 offset=0 imm=0 +#line 48 "sample/undocked/hash_of_map.c" + r0 = r6; + // EBPF_OP_EXIT pc=18 dst=r0 src=r0 offset=0 imm=0 +#line 48 "sample/undocked/hash_of_map.c" + return r0; +#line 48 "sample/undocked/hash_of_map.c" +} +#pragma code_seg(pop) +#line __LINE__ __FILE__ + +#pragma data_seg(push, "programs") +static program_entry_t _programs[] = { + { + 0, + lookup, + "sample~1", + "sample_ext", + "lookup", + lookup_maps, + 1, + lookup_helpers, + 1, + 19, + &lookup_program_type_guid, + &lookup_attach_type_guid, + }, +}; +#pragma data_seg(pop) + +static void +_get_programs(_Outptr_result_buffer_(*count) program_entry_t** programs, _Out_ size_t* count) +{ + *programs = _programs; + *count = 1; +} + +static void +_get_version(_Out_ bpf2c_version_t* version) +{ + version->major = 0; + version->minor = 13; + version->revision = 0; +} + +#pragma data_seg(push, "map_initial_values") +static const char* _outer_map_initial_string_table[] = { + "inner_map", +}; + +static map_initial_values_t _map_initial_values_array[] = { + { + .name = "outer_map", + .count = 1, + .values = _outer_map_initial_string_table, + }, +}; +#pragma data_seg(pop) + +static void +_get_map_initial_values(_Outptr_result_buffer_(*count) map_initial_values_t** map_initial_values, _Out_ size_t* count) +{ + *map_initial_values = _map_initial_values_array; + *count = 1; +} + +metadata_table_t hash_of_map_metadata_table = { + sizeof(metadata_table_t), _get_programs, _get_maps, _get_hash, _get_version, _get_map_initial_values}; From e541e32fad445e5100d9aeda6213d9b828e26a92 Mon Sep 17 00:00:00 2001 From: Alan Jowett Date: Tue, 30 Jan 2024 11:08:34 -0800 Subject: [PATCH 3/3] Add files to expected install list Signed-off-by: Alan Jowett --- scripts/check_msi_installation_files_regular_debug.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/check_msi_installation_files_regular_debug.txt b/scripts/check_msi_installation_files_regular_debug.txt index 434067f768..5ce90d0496 100644 --- a/scripts/check_msi_installation_files_regular_debug.txt +++ b/scripts/check_msi_installation_files_regular_debug.txt @@ -172,6 +172,10 @@ C:\Program Files\ebpf-for-windows\testing\empty_um.dll C:\Program Files\ebpf-for-windows\testing\empty_um.pdb C:\Program Files\ebpf-for-windows\testing\encap_reflect_packet.o C:\Program Files\ebpf-for-windows\testing\encap_reflect_packet.sys +C:\Program Files\ebpf-for-windows\testing\hash_of_map_um.dll +C:\Program Files\ebpf-for-windows\testing\hash_of_map_um.pdb +C:\Program Files\ebpf-for-windows\testing\hash_of_map.o +C:\Program Files\ebpf-for-windows\testing\hash_of_map.sys C:\Program Files\ebpf-for-windows\testing\invalid_helpers_um.dll C:\Program Files\ebpf-for-windows\testing\invalid_helpers_um.pdb C:\Program Files\ebpf-for-windows\testing\invalid_maps1_um.dll