Add support for handling anonymous inner maps (#3169)

Signed-off-by: Alan Jowett <alan.jowett@microsoft.com>
Co-authored-by: Alan Jowett <alan.jowett@microsoft.com>
This commit is contained in:
Alan Jowett 2024-01-19 08:33:51 -08:00 коммит произвёл GitHub
Родитель 08d9ee561f
Коммит efb6656b4c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
8 изменённых файлов: 982 добавлений и 2 удалений

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

@ -182,6 +182,31 @@ _parse_btf_map_info_and_populate_cache(const ELFIO::elfio& reader, const vector<
pin_type);
}
// Cache unnamed maps.
for (auto& map : map_data) {
if (map.name.empty()) {
uint32_t idx = (uint32_t)btf_map_name_to_index[map.name];
auto& btf_map_descriptor = btf_map_descriptors[idx];
// We temporarily stored BTF type ids in the descriptor's fd fields.
int btf_type_id = btf_map_descriptor.original_fd;
int btf_inner_type_id = btf_map_descriptor.inner_map_fd;
auto pin_type = _get_pin_type_for_btf_map(btf_data.value(), btf_type_id);
cache_map_handle(
ebpf_handle_invalid,
map_idx_to_original_fd(idx),
btf_type_id,
btf_map_descriptor.type,
btf_map_descriptor.key_size,
btf_map_descriptor.value_size,
btf_map_descriptor.max_entries,
(uint32_t)ebpf_fd_invalid,
btf_inner_type_id,
MAXSIZE_T,
pin_type);
}
}
// Resolve inner_map_fd for each map.
btf_map_descriptors.clear();
g_ebpf_platform_windows.resolve_inner_map_references(btf_map_descriptors);
@ -212,8 +237,24 @@ _get_map_names(
_parse_btf_map_info_and_populate_cache(reader, map_names);
}
if (get_map_descriptor_size() != map_names.size()) {
throw std::runtime_error(string("Map name not found for some maps."));
// Verify that returned map descriptors are a superset of map names referenced in the symbol section.
// Get all map descriptors.
auto map_descriptors = get_all_map_descriptors();
// For each map in map_names (from the symbol table), verify that the map is present in map_descriptors (from the
// BTF data).
for (const auto& map_name : map_names) {
bool found = false;
for (const auto& map_descriptor : map_descriptors) {
if (map_name.section_offset == map_descriptor.section_offset) {
found = true;
break;
}
}
if (!found) {
throw std::runtime_error(string("Map ") + map_name.map_name + " not found.");
}
}
}
@ -390,6 +431,7 @@ load_byte_code(
_get_program_and_map_names(file_name, section_to_program_map, map_names);
auto map_descriptors = get_all_map_descriptors();
size_t anonymous_map_count = 0;
for (const auto& descriptor : map_descriptors) {
bool found = false;
int index;
@ -399,6 +441,15 @@ load_byte_code(
break;
}
}
// Handle anonymous maps.
if (descriptor.section_offset == MAXSIZE_T) {
std::string name = "__anonymous_map_" + std::to_string(++anonymous_map_count);
index = static_cast<int>(map_names.size());
map_names.push_back({descriptor.section_offset, name});
found = true;
}
if (!found) {
result = EBPF_ELF_PARSING_FAILED;
goto Exit;

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

@ -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("inner_map", _test_mode::Verify)
DECLARE_TEST("invalid_helpers", _test_mode::NoVerify);
DECLARE_TEST("invalid_maps1", _test_mode::NoVerify);
DECLARE_TEST("invalid_maps2", _test_mode::NoVerify);

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

@ -0,0 +1,243 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
// Do not alter this generated file.
// This file was generated from inner_map.o
#include "bpf2c.h"
#include <stdio.h>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#define metadata_table inner_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_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.
15, // Identifier for a map template.
11, // The id of the inner map template.
},
"outer_map"},
{NULL,
{
BPF_MAP_TYPE_ARRAY, // 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.
11, // Identifier for a map template.
0, // The id of the inner map template.
},
"__anonymous_1"},
};
#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_update_helpers[] = {
{NULL, 1, "helper_id_1"},
};
static GUID lookup_update_program_type_guid = {
0xf788ef4a, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
static GUID lookup_update_attach_type_guid = {
0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
static uint16_t lookup_update_maps[] = {
0,
};
#pragma code_seg(push, "sample~1")
static uint64_t
lookup_update(void* context)
#line 36 "sample/undocked/inner_map.c"
{
#line 36 "sample/undocked/inner_map.c"
// Prologue
#line 36 "sample/undocked/inner_map.c"
uint64_t stack[(UBPF_STACK_SIZE + 7) / 8];
#line 36 "sample/undocked/inner_map.c"
register uint64_t r0 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r1 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r2 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r3 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r4 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r5 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r6 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r7 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r10 = 0;
#line 36 "sample/undocked/inner_map.c"
r1 = (uintptr_t)context;
#line 36 "sample/undocked/inner_map.c"
r10 = (uintptr_t)((uint8_t*)stack + sizeof(stack));
// EBPF_OP_MOV64_IMM pc=0 dst=r7 src=r0 offset=0 imm=0
#line 36 "sample/undocked/inner_map.c"
r7 = IMMEDIATE(0);
// EBPF_OP_STXW pc=1 dst=r10 src=r7 offset=-4 imm=0
#line 38 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r10 + OFFSET(-4)) = (uint32_t)r7;
// EBPF_OP_MOV64_REG pc=2 dst=r2 src=r10 offset=0 imm=0
#line 38 "sample/undocked/inner_map.c"
r2 = r10;
// EBPF_OP_ADD64_IMM pc=3 dst=r2 src=r0 offset=0 imm=-4
#line 38 "sample/undocked/inner_map.c"
r2 += IMMEDIATE(-4);
// EBPF_OP_LDDW pc=4 dst=r1 src=r0 offset=0 imm=0
#line 41 "sample/undocked/inner_map.c"
r1 = POINTER(_maps[0].address);
// EBPF_OP_CALL pc=6 dst=r0 src=r0 offset=0 imm=1
#line 41 "sample/undocked/inner_map.c"
r0 = lookup_update_helpers[0].address
#line 41 "sample/undocked/inner_map.c"
(r1, r2, r3, r4, r5);
#line 41 "sample/undocked/inner_map.c"
if ((lookup_update_helpers[0].tail_call) && (r0 == 0))
#line 41 "sample/undocked/inner_map.c"
return 0;
// EBPF_OP_MOV64_IMM pc=7 dst=r6 src=r0 offset=0 imm=1
#line 41 "sample/undocked/inner_map.c"
r6 = IMMEDIATE(1);
// EBPF_OP_JEQ_IMM pc=8 dst=r0 src=r0 offset=9 imm=0
#line 42 "sample/undocked/inner_map.c"
if (r0 == IMMEDIATE(0))
#line 42 "sample/undocked/inner_map.c"
goto label_1;
// EBPF_OP_STXW pc=9 dst=r10 src=r7 offset=-8 imm=0
#line 43 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r10 + OFFSET(-8)) = (uint32_t)r7;
// EBPF_OP_MOV64_REG pc=10 dst=r2 src=r10 offset=0 imm=0
#line 43 "sample/undocked/inner_map.c"
r2 = r10;
// EBPF_OP_ADD64_IMM pc=11 dst=r2 src=r0 offset=0 imm=-8
#line 43 "sample/undocked/inner_map.c"
r2 += IMMEDIATE(-8);
// EBPF_OP_MOV64_REG pc=12 dst=r1 src=r0 offset=0 imm=0
#line 44 "sample/undocked/inner_map.c"
r1 = r0;
// EBPF_OP_CALL pc=13 dst=r0 src=r0 offset=0 imm=1
#line 44 "sample/undocked/inner_map.c"
r0 = lookup_update_helpers[0].address
#line 44 "sample/undocked/inner_map.c"
(r1, r2, r3, r4, r5);
#line 44 "sample/undocked/inner_map.c"
if ((lookup_update_helpers[0].tail_call) && (r0 == 0))
#line 44 "sample/undocked/inner_map.c"
return 0;
// EBPF_OP_JEQ_IMM pc=14 dst=r0 src=r0 offset=3 imm=0
#line 45 "sample/undocked/inner_map.c"
if (r0 == IMMEDIATE(0))
#line 45 "sample/undocked/inner_map.c"
goto label_1;
// EBPF_OP_MOV64_IMM pc=15 dst=r1 src=r0 offset=0 imm=1
#line 45 "sample/undocked/inner_map.c"
r1 = IMMEDIATE(1);
// EBPF_OP_STXW pc=16 dst=r0 src=r1 offset=0 imm=0
#line 47 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r0 + OFFSET(0)) = (uint32_t)r1;
// EBPF_OP_MOV64_IMM pc=17 dst=r6 src=r0 offset=0 imm=0
#line 47 "sample/undocked/inner_map.c"
r6 = IMMEDIATE(0);
label_1:
// EBPF_OP_MOV64_REG pc=18 dst=r0 src=r6 offset=0 imm=0
#line 52 "sample/undocked/inner_map.c"
r0 = r6;
// EBPF_OP_EXIT pc=19 dst=r0 src=r0 offset=0 imm=0
#line 52 "sample/undocked/inner_map.c"
return r0;
#line 52 "sample/undocked/inner_map.c"
}
#pragma code_seg(pop)
#line __LINE__ __FILE__
#pragma data_seg(push, "programs")
static program_entry_t _programs[] = {
{
0,
lookup_update,
"sample~1",
"sample_ext",
"lookup_update",
lookup_update_maps,
1,
lookup_update_helpers,
1,
20,
&lookup_update_program_type_guid,
&lookup_update_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;
}
static void
_get_map_initial_values(_Outptr_result_buffer_(*count) map_initial_values_t** map_initial_values, _Out_ size_t* count)
{
*map_initial_values = NULL;
*count = 0;
}
metadata_table_t inner_map_metadata_table = {
sizeof(metadata_table_t), _get_programs, _get_maps, _get_hash, _get_version, _get_map_initial_values};

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

@ -0,0 +1,217 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
// Do not alter this generated file.
// This file was generated from inner_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_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.
15, // Identifier for a map template.
11, // The id of the inner map template.
},
"outer_map"},
{NULL,
{
BPF_MAP_TYPE_ARRAY, // 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.
11, // Identifier for a map template.
0, // The id of the inner map template.
},
"__anonymous_1"},
};
#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_update_helpers[] = {
{NULL, 1, "helper_id_1"},
};
static GUID lookup_update_program_type_guid = {
0xf788ef4a, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
static GUID lookup_update_attach_type_guid = {
0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
static uint16_t lookup_update_maps[] = {
0,
};
#pragma code_seg(push, "sample~1")
static uint64_t
lookup_update(void* context)
#line 36 "sample/undocked/inner_map.c"
{
#line 36 "sample/undocked/inner_map.c"
// Prologue
#line 36 "sample/undocked/inner_map.c"
uint64_t stack[(UBPF_STACK_SIZE + 7) / 8];
#line 36 "sample/undocked/inner_map.c"
register uint64_t r0 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r1 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r2 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r3 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r4 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r5 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r6 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r7 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r10 = 0;
#line 36 "sample/undocked/inner_map.c"
r1 = (uintptr_t)context;
#line 36 "sample/undocked/inner_map.c"
r10 = (uintptr_t)((uint8_t*)stack + sizeof(stack));
// EBPF_OP_MOV64_IMM pc=0 dst=r7 src=r0 offset=0 imm=0
#line 36 "sample/undocked/inner_map.c"
r7 = IMMEDIATE(0);
// EBPF_OP_STXW pc=1 dst=r10 src=r7 offset=-4 imm=0
#line 38 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r10 + OFFSET(-4)) = (uint32_t)r7;
// EBPF_OP_MOV64_REG pc=2 dst=r2 src=r10 offset=0 imm=0
#line 38 "sample/undocked/inner_map.c"
r2 = r10;
// EBPF_OP_ADD64_IMM pc=3 dst=r2 src=r0 offset=0 imm=-4
#line 38 "sample/undocked/inner_map.c"
r2 += IMMEDIATE(-4);
// EBPF_OP_LDDW pc=4 dst=r1 src=r0 offset=0 imm=0
#line 41 "sample/undocked/inner_map.c"
r1 = POINTER(_maps[0].address);
// EBPF_OP_CALL pc=6 dst=r0 src=r0 offset=0 imm=1
#line 41 "sample/undocked/inner_map.c"
r0 = lookup_update_helpers[0].address
#line 41 "sample/undocked/inner_map.c"
(r1, r2, r3, r4, r5);
#line 41 "sample/undocked/inner_map.c"
if ((lookup_update_helpers[0].tail_call) && (r0 == 0))
#line 41 "sample/undocked/inner_map.c"
return 0;
// EBPF_OP_MOV64_IMM pc=7 dst=r6 src=r0 offset=0 imm=1
#line 41 "sample/undocked/inner_map.c"
r6 = IMMEDIATE(1);
// EBPF_OP_JEQ_IMM pc=8 dst=r0 src=r0 offset=9 imm=0
#line 42 "sample/undocked/inner_map.c"
if (r0 == IMMEDIATE(0))
#line 42 "sample/undocked/inner_map.c"
goto label_1;
// EBPF_OP_STXW pc=9 dst=r10 src=r7 offset=-8 imm=0
#line 43 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r10 + OFFSET(-8)) = (uint32_t)r7;
// EBPF_OP_MOV64_REG pc=10 dst=r2 src=r10 offset=0 imm=0
#line 43 "sample/undocked/inner_map.c"
r2 = r10;
// EBPF_OP_ADD64_IMM pc=11 dst=r2 src=r0 offset=0 imm=-8
#line 43 "sample/undocked/inner_map.c"
r2 += IMMEDIATE(-8);
// EBPF_OP_MOV64_REG pc=12 dst=r1 src=r0 offset=0 imm=0
#line 44 "sample/undocked/inner_map.c"
r1 = r0;
// EBPF_OP_CALL pc=13 dst=r0 src=r0 offset=0 imm=1
#line 44 "sample/undocked/inner_map.c"
r0 = lookup_update_helpers[0].address
#line 44 "sample/undocked/inner_map.c"
(r1, r2, r3, r4, r5);
#line 44 "sample/undocked/inner_map.c"
if ((lookup_update_helpers[0].tail_call) && (r0 == 0))
#line 44 "sample/undocked/inner_map.c"
return 0;
// EBPF_OP_JEQ_IMM pc=14 dst=r0 src=r0 offset=3 imm=0
#line 45 "sample/undocked/inner_map.c"
if (r0 == IMMEDIATE(0))
#line 45 "sample/undocked/inner_map.c"
goto label_1;
// EBPF_OP_MOV64_IMM pc=15 dst=r1 src=r0 offset=0 imm=1
#line 45 "sample/undocked/inner_map.c"
r1 = IMMEDIATE(1);
// EBPF_OP_STXW pc=16 dst=r0 src=r1 offset=0 imm=0
#line 47 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r0 + OFFSET(0)) = (uint32_t)r1;
// EBPF_OP_MOV64_IMM pc=17 dst=r6 src=r0 offset=0 imm=0
#line 47 "sample/undocked/inner_map.c"
r6 = IMMEDIATE(0);
label_1:
// EBPF_OP_MOV64_REG pc=18 dst=r0 src=r6 offset=0 imm=0
#line 52 "sample/undocked/inner_map.c"
r0 = r6;
// EBPF_OP_EXIT pc=19 dst=r0 src=r0 offset=0 imm=0
#line 52 "sample/undocked/inner_map.c"
return r0;
#line 52 "sample/undocked/inner_map.c"
}
#pragma code_seg(pop)
#line __LINE__ __FILE__
#pragma data_seg(push, "programs")
static program_entry_t _programs[] = {
{
0,
lookup_update,
"sample~1",
"sample_ext",
"lookup_update",
lookup_update_maps,
1,
lookup_update_helpers,
1,
20,
&lookup_update_program_type_guid,
&lookup_update_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;
}
static void
_get_map_initial_values(_Outptr_result_buffer_(*count) map_initial_values_t** map_initial_values, _Out_ size_t* count)
{
*map_initial_values = NULL;
*count = 0;
}
metadata_table_t inner_map_metadata_table = {
sizeof(metadata_table_t), _get_programs, _get_maps, _get_hash, _get_version, _get_map_initial_values};

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

@ -0,0 +1,378 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
// Do not alter this generated file.
// This file was generated from inner_map.o
#define NO_CRT
#include "bpf2c.h"
#include <guiddef.h>
#include <wdm.h>
#include <wsk.h>
DRIVER_INITIALIZE DriverEntry;
DRIVER_UNLOAD DriverUnload;
RTL_QUERY_REGISTRY_ROUTINE static _bpf2c_query_registry_routine;
#define metadata_table inner_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_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.
15, // Identifier for a map template.
11, // The id of the inner map template.
},
"outer_map"},
{NULL,
{
BPF_MAP_TYPE_ARRAY, // 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.
11, // Identifier for a map template.
0, // The id of the inner map template.
},
"__anonymous_1"},
};
#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_update_helpers[] = {
{NULL, 1, "helper_id_1"},
};
static GUID lookup_update_program_type_guid = {
0xf788ef4a, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
static GUID lookup_update_attach_type_guid = {
0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
static uint16_t lookup_update_maps[] = {
0,
};
#pragma code_seg(push, "sample~1")
static uint64_t
lookup_update(void* context)
#line 36 "sample/undocked/inner_map.c"
{
#line 36 "sample/undocked/inner_map.c"
// Prologue
#line 36 "sample/undocked/inner_map.c"
uint64_t stack[(UBPF_STACK_SIZE + 7) / 8];
#line 36 "sample/undocked/inner_map.c"
register uint64_t r0 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r1 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r2 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r3 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r4 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r5 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r6 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r7 = 0;
#line 36 "sample/undocked/inner_map.c"
register uint64_t r10 = 0;
#line 36 "sample/undocked/inner_map.c"
r1 = (uintptr_t)context;
#line 36 "sample/undocked/inner_map.c"
r10 = (uintptr_t)((uint8_t*)stack + sizeof(stack));
// EBPF_OP_MOV64_IMM pc=0 dst=r7 src=r0 offset=0 imm=0
#line 36 "sample/undocked/inner_map.c"
r7 = IMMEDIATE(0);
// EBPF_OP_STXW pc=1 dst=r10 src=r7 offset=-4 imm=0
#line 38 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r10 + OFFSET(-4)) = (uint32_t)r7;
// EBPF_OP_MOV64_REG pc=2 dst=r2 src=r10 offset=0 imm=0
#line 38 "sample/undocked/inner_map.c"
r2 = r10;
// EBPF_OP_ADD64_IMM pc=3 dst=r2 src=r0 offset=0 imm=-4
#line 38 "sample/undocked/inner_map.c"
r2 += IMMEDIATE(-4);
// EBPF_OP_LDDW pc=4 dst=r1 src=r0 offset=0 imm=0
#line 41 "sample/undocked/inner_map.c"
r1 = POINTER(_maps[0].address);
// EBPF_OP_CALL pc=6 dst=r0 src=r0 offset=0 imm=1
#line 41 "sample/undocked/inner_map.c"
r0 = lookup_update_helpers[0].address
#line 41 "sample/undocked/inner_map.c"
(r1, r2, r3, r4, r5);
#line 41 "sample/undocked/inner_map.c"
if ((lookup_update_helpers[0].tail_call) && (r0 == 0))
#line 41 "sample/undocked/inner_map.c"
return 0;
// EBPF_OP_MOV64_IMM pc=7 dst=r6 src=r0 offset=0 imm=1
#line 41 "sample/undocked/inner_map.c"
r6 = IMMEDIATE(1);
// EBPF_OP_JEQ_IMM pc=8 dst=r0 src=r0 offset=9 imm=0
#line 42 "sample/undocked/inner_map.c"
if (r0 == IMMEDIATE(0))
#line 42 "sample/undocked/inner_map.c"
goto label_1;
// EBPF_OP_STXW pc=9 dst=r10 src=r7 offset=-8 imm=0
#line 43 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r10 + OFFSET(-8)) = (uint32_t)r7;
// EBPF_OP_MOV64_REG pc=10 dst=r2 src=r10 offset=0 imm=0
#line 43 "sample/undocked/inner_map.c"
r2 = r10;
// EBPF_OP_ADD64_IMM pc=11 dst=r2 src=r0 offset=0 imm=-8
#line 43 "sample/undocked/inner_map.c"
r2 += IMMEDIATE(-8);
// EBPF_OP_MOV64_REG pc=12 dst=r1 src=r0 offset=0 imm=0
#line 44 "sample/undocked/inner_map.c"
r1 = r0;
// EBPF_OP_CALL pc=13 dst=r0 src=r0 offset=0 imm=1
#line 44 "sample/undocked/inner_map.c"
r0 = lookup_update_helpers[0].address
#line 44 "sample/undocked/inner_map.c"
(r1, r2, r3, r4, r5);
#line 44 "sample/undocked/inner_map.c"
if ((lookup_update_helpers[0].tail_call) && (r0 == 0))
#line 44 "sample/undocked/inner_map.c"
return 0;
// EBPF_OP_JEQ_IMM pc=14 dst=r0 src=r0 offset=3 imm=0
#line 45 "sample/undocked/inner_map.c"
if (r0 == IMMEDIATE(0))
#line 45 "sample/undocked/inner_map.c"
goto label_1;
// EBPF_OP_MOV64_IMM pc=15 dst=r1 src=r0 offset=0 imm=1
#line 45 "sample/undocked/inner_map.c"
r1 = IMMEDIATE(1);
// EBPF_OP_STXW pc=16 dst=r0 src=r1 offset=0 imm=0
#line 47 "sample/undocked/inner_map.c"
*(uint32_t*)(uintptr_t)(r0 + OFFSET(0)) = (uint32_t)r1;
// EBPF_OP_MOV64_IMM pc=17 dst=r6 src=r0 offset=0 imm=0
#line 47 "sample/undocked/inner_map.c"
r6 = IMMEDIATE(0);
label_1:
// EBPF_OP_MOV64_REG pc=18 dst=r0 src=r6 offset=0 imm=0
#line 52 "sample/undocked/inner_map.c"
r0 = r6;
// EBPF_OP_EXIT pc=19 dst=r0 src=r0 offset=0 imm=0
#line 52 "sample/undocked/inner_map.c"
return r0;
#line 52 "sample/undocked/inner_map.c"
}
#pragma code_seg(pop)
#line __LINE__ __FILE__
#pragma data_seg(push, "programs")
static program_entry_t _programs[] = {
{
0,
lookup_update,
"sample~1",
"sample_ext",
"lookup_update",
lookup_update_maps,
1,
lookup_update_helpers,
1,
20,
&lookup_update_program_type_guid,
&lookup_update_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;
}
static void
_get_map_initial_values(_Outptr_result_buffer_(*count) map_initial_values_t** map_initial_values, _Out_ size_t* count)
{
*map_initial_values = NULL;
*count = 0;
}
metadata_table_t inner_map_metadata_table = {
sizeof(metadata_table_t), _get_programs, _get_maps, _get_hash, _get_version, _get_map_initial_values};

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

@ -0,0 +1,52 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
// clang -O2 -Werror -c inner_map.c -o inner_map.o
//
// For bpf code: clang -target bpf -O2 -Werror -c inner_map.c -o inner_map.o
// this passes the checker
// 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 <build_output_path>
// 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_OF_MAPS);
__type(key, uint32_t);
__uint(max_entries, 1);
__array(
values, struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__type(key, uint32_t);
__type(value, uint32_t);
__uint(max_entries, 1);
});
} outer_map SEC(".maps");
SEC("sample_ext") int lookup_update(sample_program_context_t* ctx)
{
uint32_t outer_key = 0;
// Read value from inner map.
void* inner_map = bpf_map_lookup_elem(&outer_map, &outer_key);
if (inner_map) {
uint32_t inner_key = 0;
uint32_t* inner_value = (uint32_t*)bpf_map_lookup_elem(inner_map, &inner_key);
if (inner_value) {
// Update value in inner map.
*inner_value = 1;
return 0;
}
}
return 1;
}

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

@ -1497,6 +1497,30 @@ _test_bind_fd_to_prog_array(ebpf_execution_type_t execution_type)
DECLARE_ALL_TEST_CASES("disallow setting bind fd in sample prog array", "[libbpf]", _test_bind_fd_to_prog_array);
static void
_load_inner_map(ebpf_execution_type_t execution_type)
{
_test_helper_end_to_end test_helper;
test_helper.initialize();
program_info_provider_t sample_program_info;
REQUIRE(sample_program_info.initialize(EBPF_PROGRAM_TYPE_SAMPLE) == EBPF_SUCCESS);
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "inner_map_um.dll" : "inner_map.o");
struct bpf_object* sample_object = bpf_object__open(file_name);
REQUIRE(sample_object != nullptr);
// Load the program(s).
REQUIRE(bpf_object__load(sample_object) == 0);
struct bpf_map* map = bpf_object__find_map_by_name(sample_object, "outer_map");
REQUIRE(map != nullptr);
REQUIRE(bpf_map__type(map) == BPF_MAP_TYPE_HASH_OF_MAPS);
bpf_object__close(sample_object);
}
DECLARE_ALL_TEST_CASES("Test loading BPF program with anonymous inner map", "[libbpf]", _load_inner_map);
#if !defined(CONFIG_BPF_JIT_DISABLED)
TEST_CASE("disallow prog_array mixed program type values", "[libbpf]")
{

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

@ -452,7 +452,11 @@ bpf_code_generator::parse_btf_maps_section(const unsafe_string& name)
auto map_data = libbtf::parse_btf_map_section(btf_data.value());
std::map<std::string, size_t> map_offsets;
size_t anonymous_map_count = 0;
for (auto& map : map_data) {
if (map.name.empty()) {
map.name = "__anonymous_" + std::to_string(++anonymous_map_count);
}
map_offsets.insert({map.name, map_descriptors.size()});
map_descriptors.push_back({
.original_fd = static_cast<int>(map.type_id),
@ -486,6 +490,16 @@ bpf_code_generator::parse_btf_maps_section(const unsafe_string& name)
},
name);
// Add anonymous maps to the end of the map list.
size_t last_map_offset = map_names_by_offset.size() != 0 ? map_names_by_offset.rbegin()->first.second : 1;
for (auto& map : map_data) {
if (!map.name.starts_with("__anonymous")) {
continue;
}
map_names_by_offset[std::make_pair(last_map_offset, last_map_offset)] = map.name;
last_map_offset++;
}
for (const auto& [range, unsafe_symbol_name] : map_names_by_offset) {
if (map_name_to_index.find(unsafe_symbol_name.raw()) == map_name_to_index.end()) {
throw bpf_code_generator_exception("map symbol not found in map section");