Create bpf_map structures from bpf_object__open() on a native file (#1160)

* Create bpf_map structures from bpf_object__open() on a native file

Fixes #1140

Signed-off-by: Dave Thaler <dthaler@microsoft.com>

* Fix map update when loading native object

Signed-off-by: Dave Thaler <dthaler@microsoft.com>

* Update tests

Signed-off-by: Dave Thaler <dthaler@microsoft.com>

* Fix for test

Signed-off-by: Dave Thaler <dthaler@microsoft.com>

* More test fixes

Signed-off-by: Dave Thaler <dthaler@microsoft.com>

* More test fixes

Signed-off-by: Dave Thaler <dthaler@microsoft.com>

* PR feedback

Signed-off-by: Dave Thaler <dthaler@microsoft.com>

* PR feedback

Signed-off-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Dave Thaler 2022-06-07 19:28:52 -07:00 коммит произвёл GitHub
Родитель e54d049866
Коммит f863a02469
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
9 изменённых файлов: 322 добавлений и 74 удалений

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

@ -102,7 +102,6 @@ extern "C"
_Field_z_ const char* section_name;
_Field_z_ const char* program_type_name;
_Field_z_ const char* program_name;
size_t map_count;
size_t raw_data_size;
_Field_size_(raw_data_size) char* raw_data;
ebpf_stat_t* stats;

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

@ -404,7 +404,6 @@ ebpf_api_elf_enumerate_sections(
info->section_name = _strdup(raw_program.section.c_str());
info->program_type_name = _strdup(raw_program.info.type.name.c_str());
info->map_count = raw_program.info.map_descriptors.size();
std::vector<uint8_t> raw_data = convert_ebpf_program_to_bytes(raw_program.prog);
info->raw_data_size = raw_data.size();

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

@ -66,6 +66,13 @@ _ebpf_program_load_native(
_Inout_ struct bpf_object* object,
_Out_ fd_t* program_fd);
static const char*
_ebpf_get_section_string(
_In_ const struct _ebpf_pe_context* pe_context,
uintptr_t address,
_In_ const image_section_header& section_header,
_In_ const bounded_buffer* buffer);
static fd_t
_create_file_descriptor_for_handle(ebpf_handle_t handle) noexcept
{
@ -1422,16 +1429,15 @@ _initialize_ebpf_maps_native(
goto Exit;
}
map = (ebpf_map_t*)calloc(1, sizeof(ebpf_map_t));
if (map == nullptr) {
result = EBPF_NO_MEMORY;
goto Exit;
}
map = maps[i];
// Note that the map name need not match, if the map was reused
// based on a pin path. Other fields ought to match however.
ebpf_assert(map->map_definition.type == info.type);
ebpf_assert(map->map_definition.key_size == info.key_size);
ebpf_assert(map->map_definition.value_size == info.value_size);
ebpf_assert(map->map_definition.max_entries == info.max_entries);
map->map_definition.type = info.type;
map->map_definition.key_size = info.key_size;
map->map_definition.value_size = info.value_size;
map->map_definition.max_entries = info.max_entries;
map->map_definition.inner_map_id = info.inner_map_id;
map->map_fd = _create_file_descriptor_for_handle(map_handles[i]);
if (map->map_fd == ebpf_fd_invalid) {
@ -1440,14 +1446,6 @@ _initialize_ebpf_maps_native(
}
map->map_handle = map_handles[i];
map_handles[i] = ebpf_handle_invalid;
map->name = _strdup(info.name);
if (map->name == nullptr) {
result = EBPF_NO_MEMORY;
goto Exit;
}
maps.emplace_back(map);
map = nullptr;
}
Exit:
@ -1531,7 +1529,6 @@ _initialize_ebpf_object_native(
ebpf_assert(object.file_name != nullptr);
ebpf_assert(object.object_name != nullptr);
// TODO(issue #1140): populate maps at open time
for (auto& map : object.maps) {
map->object = &object;
}
@ -1547,6 +1544,8 @@ Exit:
static ebpf_result_t
_ebpf_enumerate_native_sections(
_In_z_ const char* file,
_Inout_opt_ ebpf_object_t* object,
_In_opt_z_ const char* pin_root_path,
_Outptr_result_maybenull_ ebpf_section_info_t** infos,
_Outptr_result_maybenull_z_ const char** error_message);
@ -1554,7 +1553,7 @@ static ebpf_result_t
_initialize_ebpf_object_from_native_file(
_In_z_ const char* file_name,
_In_opt_z_ const char* pin_root_path,
_Out_ ebpf_object_t& object,
_Inout_ ebpf_object_t& object,
_Outptr_result_maybenull_z_ const char** error_message) noexcept
{
ebpf_program_t* program = nullptr;
@ -1564,7 +1563,7 @@ _initialize_ebpf_object_from_native_file(
ebpf_assert(error_message);
ebpf_section_info_t* infos = nullptr;
ebpf_result_t result = _ebpf_enumerate_native_sections(file_name, &infos, error_message);
ebpf_result_t result = _ebpf_enumerate_native_sections(file_name, &object, pin_root_path, &infos, error_message);
if (result != EBPF_SUCCESS) {
goto Exit;
}
@ -1609,9 +1608,6 @@ _initialize_ebpf_object_from_native_file(
program = nullptr;
}
// TODO(issue #1140): populate object.maps
UNREFERENCED_PARAMETER(pin_root_path);
Exit:
free(program);
if (result != EBPF_SUCCESS) {
@ -1626,7 +1622,7 @@ static ebpf_result_t
_initialize_ebpf_object_from_elf(
_In_z_ const char* file_name,
_In_opt_z_ const char* pin_root_path,
_Out_ ebpf_object_t& object,
_Inout_ ebpf_object_t& object,
_Outptr_result_maybenull_z_ const char** error_message) noexcept
{
EBPF_LOG_ENTRY();
@ -1784,12 +1780,14 @@ ebpf_free_sections(_In_opt_ ebpf_section_info_t* infos)
typedef struct _ebpf_pe_context
{
ebpf_result_t result;
ebpf_object_t* object;
const char* pin_root_path;
uintptr_t image_base;
ebpf_section_info_t* infos;
std::map<std::string, std::string> section_names;
std::map<std::string, std::string> program_names;
std::map<std::string, GUID> section_program_types;
int map_count;
uintptr_t rdata_base;
size_t rdata_size;
const bounded_buffer* rdata_buffer;
@ -1799,7 +1797,7 @@ typedef struct _ebpf_pe_context
} ebpf_pe_context_t;
static int
_ebpf_pe_get_map_count(
_ebpf_pe_get_map_definitions(
void* context,
const VA& va,
const std::string& section_name,
@ -1810,18 +1808,73 @@ _ebpf_pe_get_map_count(
UNREFERENCED_PARAMETER(va);
UNREFERENCED_PARAMETER(buffer);
ebpf_map_t* map = nullptr;
ebpf_pe_context_t* pe_context = (ebpf_pe_context_t*)context;
if (section_name == "maps") {
// bpf2c generates a section that has map names as strings at the
// start of the section. Skip over them looking for the map_entry_t
// which starts with a 16-byte-aligned NULL pointer.
// which starts with an 8-byte-aligned NULL pointer where the previous
// byte (if any) is also 00, and the following 8 bytes are non-NULL.
uint32_t map_offset = 0;
uint64_t zero = 0;
while (map_offset < section_header.Misc.VirtualSize &&
memcmp(buffer->buf + map_offset, &zero, sizeof(zero)) != 0) {
map_offset += 16;
while (map_offset + 16 < section_header.Misc.VirtualSize &&
(memcmp(buffer->buf + map_offset, &zero, sizeof(zero)) != 0 ||
(map_offset > 0 && buffer->buf[map_offset - 1] != 0) ||
memcmp(buffer->buf + map_offset + 8, &zero, sizeof(zero)) == 0)) {
map_offset += 8;
}
if (pe_context->object != nullptr) {
for (int map_index = 0; map_offset + sizeof(map_entry_t) <= section_header.Misc.VirtualSize;
map_offset += sizeof(map_entry_t), map_index++) {
map_entry_t* entry = (map_entry_t*)(buffer->buf + map_offset);
map = (ebpf_map_t*)calloc(1, sizeof(ebpf_map_t));
if (map == nullptr) {
goto Error;
}
map->map_handle = ebpf_handle_invalid;
map->original_fd = (fd_t)map_index;
map->map_definition.type = entry->definition.type;
map->map_definition.key_size = entry->definition.key_size;
map->map_definition.value_size = entry->definition.value_size;
map->map_definition.max_entries = entry->definition.max_entries;
map->map_definition.pinning = entry->definition.pinning;
map->map_definition.inner_map_id = entry->definition.inner_id;
map->inner_map_original_fd = entry->definition.inner_map_idx;
map->pinned = false;
map->reused = false;
map->pin_path = nullptr;
const char* map_name =
_ebpf_get_section_string(pe_context, (uintptr_t)entry->name, section_header, buffer);
map->name = _strdup(map_name);
if (map->name == nullptr) {
pe_context->result = EBPF_NO_MEMORY;
goto Error;
}
if (map->map_definition.pinning == PIN_GLOBAL_NS) {
char pin_path_buffer[EBPF_MAX_PIN_PATH_LENGTH];
int len = snprintf(
pin_path_buffer,
EBPF_MAX_PIN_PATH_LENGTH,
"%s/%s",
pe_context->pin_root_path ? pe_context->pin_root_path : DEFAULT_PIN_ROOT_PATH,
map->name);
if (len < 0 || len >= EBPF_MAX_PIN_PATH_LENGTH) {
pe_context->result = EBPF_INVALID_ARGUMENT;
goto Error;
}
map->pin_path = _strdup(pin_path_buffer);
if (map->pin_path == nullptr) {
pe_context->result = EBPF_NO_MEMORY;
goto Error;
}
}
pe_context->object->maps.emplace_back(map);
map = nullptr;
}
}
pe_context->map_count = (section_header.Misc.VirtualSize - map_offset) / sizeof(map_entry_t);
} else if (section_name == ".rdata") {
pe_context->rdata_base = pe_context->image_base + section_header.VirtualAddress;
pe_context->rdata_size = section_header.Misc.VirtualSize;
@ -1832,11 +1885,18 @@ _ebpf_pe_get_map_count(
pe_context->data_buffer = buffer;
}
EBPF_LOG_EXIT();
EBPF_LOG_FUNCTION_SUCCESS();
return 0;
Error:
if (map) {
clean_up_ebpf_map(map);
}
EBPF_LOG_FUNCTION_ERROR(pe_context->result);
return 1;
}
const char*
static const char*
_ebpf_get_section_string(
_In_ const ebpf_pe_context_t* pe_context,
uintptr_t address,
@ -1876,7 +1936,7 @@ _ebpf_pe_get_section_names(
// byte (if any) is also 00.
uint32_t program_offset = 0;
uint64_t zero = 0;
while (program_offset < section_header.Misc.VirtualSize &&
while (program_offset + sizeof(zero) <= section_header.Misc.VirtualSize &&
(memcmp(buffer->buf + program_offset, &zero, sizeof(zero)) != 0 ||
(program_offset > 0 && buffer->buf[program_offset - 1] != 0))) {
program_offset += 16;
@ -1946,7 +2006,6 @@ _ebpf_pe_add_section(
_strdup(get_program_type_windows(pe_context->section_program_types[pe_section_name]).name.c_str());
info->raw_data_size = section_header.Misc.VirtualSize;
info->raw_data = (char*)malloc(section_header.Misc.VirtualSize);
info->map_count = pe_context->map_count;
if (info->raw_data == nullptr || info->program_type_name == nullptr || info->section_name == nullptr) {
_ebpf_free_section_info(info);
EBPF_LOG_EXIT();
@ -1968,6 +2027,8 @@ _ebpf_pe_add_section(
static ebpf_result_t
_ebpf_enumerate_native_sections(
_In_z_ const char* file,
_Inout_opt_ ebpf_object_t* object,
_In_opt_z_ const char* pin_root_path,
_Outptr_result_maybenull_ ebpf_section_info_t** infos,
_Outptr_result_maybenull_z_ const char** error_message)
{
@ -1980,15 +2041,19 @@ _ebpf_enumerate_native_sections(
EBPF_RETURN_RESULT(EBPF_FILE_NOT_FOUND);
}
ebpf_pe_context_t context = {.image_base = pe->peHeader.nt.OptionalHeader64.ImageBase};
IterSec(pe, _ebpf_pe_get_map_count, &context);
ebpf_pe_context_t context = {
.result = EBPF_SUCCESS,
.object = object,
.pin_root_path = pin_root_path,
.image_base = pe->peHeader.nt.OptionalHeader64.ImageBase};
IterSec(pe, _ebpf_pe_get_map_definitions, &context);
IterSec(pe, _ebpf_pe_get_section_names, &context);
IterSec(pe, _ebpf_pe_add_section, &context);
DestructParsedPE(pe);
*infos = context.infos;
EBPF_RETURN_RESULT(EBPF_SUCCESS);
EBPF_RETURN_RESULT(context.result);
}
ebpf_result_t
@ -2003,7 +2068,7 @@ ebpf_enumerate_sections(
std::string file_extension = file_name_string.substr(file_name_string.find_last_of(".") + 1);
if (file_extension == "dll" || file_extension == "sys") {
// Verbose is currently unused.
EBPF_RETURN_RESULT(_ebpf_enumerate_native_sections(file, infos, error_message));
EBPF_RETURN_RESULT(_ebpf_enumerate_native_sections(file, nullptr, nullptr, infos, error_message));
} else {
EBPF_RETURN_RESULT(
ebpf_api_elf_enumerate_sections(file, nullptr, verbose, infos, error_message) ? EBPF_FAILED : EBPF_SUCCESS);
@ -2925,7 +2990,7 @@ ebpf_map_next(_In_opt_ const struct bpf_map* previous, _In_ const struct bpf_obj
goto Exit;
}
if (previous == nullptr) {
map = object->maps[0];
map = (object->maps.size() > 0) ? object->maps[0] : nullptr;
} else {
size_t maps_count = object->maps.size();
for (size_t i = 0; i < maps_count; i++) {

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

@ -6,6 +6,7 @@
#include <iomanip>
#include <locale>
#include <netsh.h>
#include "bpf/libbpf.h"
#include "elf.h"
#include "tokens.h"
#include "utilities.h"
@ -69,6 +70,13 @@ handle_ebpf_show_disassembly(
}
}
static PCSTR
_get_map_type_name(ebpf_map_type_t type)
{
int index = (type >= _countof(_ebpf_map_display_names)) ? 0 : type;
return _ebpf_map_display_names[index];
}
DWORD
handle_ebpf_show_sections(
LPCWSTR machine, LPWSTR* argv, DWORD current_index, DWORD argc, DWORD flags, LPCVOID data, BOOL* done)
@ -126,7 +134,6 @@ handle_ebpf_show_sections(
}
ebpf_section_info_t* section_data = nullptr;
const char* error_message = nullptr;
if (ebpf_enumerate_sections(filename.c_str(), level == VL_VERBOSE, &section_data, &error_message) != 0) {
std::cerr << error_message << std::endl;
@ -137,8 +144,9 @@ handle_ebpf_show_sections(
if (level == VL_NORMAL) {
std::cout << "\n";
std::cout << " Section Type # Maps Size\n";
std::cout << "==================== ========= ====== ======\n";
std::cout << " Size\n";
std::cout << " Section Type (bytes)\n";
std::cout << "==================== ========= =======\n";
}
for (auto current_section = section_data; current_section != nullptr; current_section = current_section->next) {
if (!section.empty() && strcmp(current_section->section_name, section.c_str()) != 0) {
@ -146,22 +154,43 @@ handle_ebpf_show_sections(
}
if (level == VL_NORMAL) {
std::cout << std::setw(20) << std::right << current_section->section_name << " " << std::setw(9)
<< current_section->program_type_name << " " << std::setw(6) << current_section->map_count
<< " " << std::setw(6) << current_section->raw_data_size << "\n";
<< current_section->program_type_name << " " << std::setw(7) << current_section->raw_data_size
<< "\n";
} else {
std::cout << "\n";
std::cout << "Section : " << current_section->section_name << "\n";
std::cout << "Program Type : " << current_section->program_type_name << "\n";
std::cout << "# Maps : " << current_section->map_count << "\n";
std::cout << "Size : " << current_section->raw_data_size << " bytes\n";
for (auto stat = current_section->stats; stat != nullptr; stat = stat->next) {
std::cout << std::setw(13) << std::left << stat->key << ": " << stat->value << "\n";
}
}
}
ebpf_free_sections(section_data);
ebpf_free_string(error_message);
// Show maps.
std::cout << "\n";
std::cout << " Key Value Max\n";
std::cout << " Map Type Size Size Entries Name\n";
std::cout << "================== ==== ===== ======= ========\n";
bpf_object* object = bpf_object__open(filename.c_str());
if (object == nullptr) {
std::cout << "Couldn't get maps from " << filename << "\n";
return ERROR_SUPPRESS_OUTPUT;
}
bpf_map* map;
bpf_object__for_each_map(map, object)
{
printf(
"%18s%6u%7u%9u %s\n",
_get_map_type_name(bpf_map__type(map)),
bpf_map__key_size(map),
bpf_map__value_size(map),
bpf_map__max_entries(map),
bpf_map__name(map));
}
bpf_object__close(object);
return NO_ERROR;
}

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

@ -115,7 +115,7 @@ _is_native_program(_In_z_ const char* file_name)
{
std::string file_name_string(file_name);
std::string file_extension = file_name_string.substr(file_name_string.find_last_of(".") + 1);
if (file_extension == "dll") {
if (file_extension == "dll" || file_extension == "sys") {
return true;
}

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

@ -1713,6 +1713,12 @@ _map_reuse_test(ebpf_execution_type_t execution_type)
error = bpf_obj_pin(outer_map_fd, "/ebpf/global/outer_map");
REQUIRE(error == 0);
// The outer map name created above should not have a name.
bpf_map_info info;
uint32_t info_size = sizeof(info);
REQUIRE(bpf_obj_get_info_by_fd(outer_map_fd, &info, &info_size) == 0);
REQUIRE(info.name[0] == 0);
int port_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32), sizeof(__u32), 1, 0);
REQUIRE(port_map_fd > 0);
@ -1730,6 +1736,11 @@ _map_reuse_test(ebpf_execution_type_t execution_type)
program_load_attach_helper_t program_helper(
file_name, BPF_PROG_TYPE_XDP, "lookup_update", EBPF_EXECUTION_ANY, &ifindex, sizeof(ifindex), hook);
// The outer map we created earlier should still not have a name even though there is a name in the file,
// since the unnamed map was reused.
REQUIRE(bpf_obj_get_info_by_fd(outer_map_fd, &info, &info_size) == 0);
REQUIRE(info.name[0] == 0);
auto packet = prepare_udp_packet(10, ETHERNET_TYPE_IPV4);
xdp_md_t ctx{packet.data(), packet.data() + packet.size(), 0, TEST_IFINDEX};
int hook_result;
@ -1754,6 +1765,53 @@ _map_reuse_test(ebpf_execution_type_t execution_type)
DECLARE_JIT_TEST_CASES("map_reuse", "[end_to_end]", _map_reuse_test);
// Try to reuse a map of the wrong type.
static void
_wrong_map_reuse_test(ebpf_execution_type_t execution_type)
{
_test_helper_end_to_end test_helper;
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
const char* file_name = (execution_type == EBPF_EXECUTION_NATIVE ? "map_reuse_um.dll" : "map_reuse.o");
// First create and pin the maps manually.
int inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32), sizeof(__u32), 1, 0);
REQUIRE(inner_map_fd > 0);
int outer_map_fd = bpf_create_map_in_map(BPF_MAP_TYPE_HASH_OF_MAPS, nullptr, sizeof(__u32), inner_map_fd, 1, 0);
REQUIRE(outer_map_fd > 0);
// Pin the outer map and port map to the wrong paths so they won't match what is in the ebpf program.
REQUIRE(bpf_obj_pin(outer_map_fd, "/ebpf/global/port_map") == 0);
int port_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32), sizeof(__u32), 1, 0);
REQUIRE(port_map_fd > 0);
// Pin port map.
REQUIRE(bpf_obj_pin(port_map_fd, "/ebpf/global/outer_map") == 0);
// Open eBPF program file.
bpf_object* object = bpf_object__open(file_name);
REQUIRE(object != nullptr);
bpf_program* program = bpf_object__next_program(object, nullptr);
REQUIRE(program != nullptr);
// Try to load the program. This should fail because the maps can't be reused.
REQUIRE(bpf_object__load(object) == -EINVAL);
bpf_object__close(object);
Platform::_close(outer_map_fd);
Platform::_close(inner_map_fd);
Platform::_close(port_map_fd);
REQUIRE(ebpf_object_unpin("/ebpf/global/outer_map") == EBPF_SUCCESS);
REQUIRE(ebpf_object_unpin("/ebpf/global/port_map") == EBPF_SUCCESS);
}
DECLARE_JIT_TEST_CASES("wrong_map_reuse", "[end_to_end]", _wrong_map_reuse_test);
static void
_auto_pinned_maps_test(ebpf_execution_type_t execution_type)
{
@ -2213,6 +2271,25 @@ TEST_CASE("load_native_program_negative4", "[end-to-end]")
Platform::_delete_service(service_handle);
}
// Try to load a .sys in user mode.
TEST_CASE("load_native_program_negative5", "[end_to_end]")
{
_test_helper_end_to_end test_helper;
int result;
const char* error_message = nullptr;
bpf_object* object = nullptr;
fd_t program_fd;
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
set_native_module_failures(true);
result =
ebpf_program_load("map.sys", BPF_PROG_TYPE_UNSPEC, EBPF_EXECUTION_ANY, &object, &program_fd, &error_message);
REQUIRE(result == -ENOENT);
}
// The below tests try to load native drivers for invalid programs (that will fail verification).
// Since verification can be skipped in bpf2c for only Debug builds, these tests are applicable
// only for Debug build.

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

@ -94,9 +94,14 @@ TEST_CASE("show sections bpf.o", "[netsh][sections]")
REQUIRE(result == NO_ERROR);
REQUIRE(
output == "\n"
" Section Type # Maps Size\n"
"==================== ========= ====== ======\n"
" .text xdp 0 16\n");
" Size\n"
" Section Type (bytes)\n"
"==================== ========= =======\n"
" .text xdp 16\n"
"\n"
" Key Value Max\n"
" Map Type Size Size Entries Name\n"
"================== ==== ===== ======= ========\n");
}
// Test specifying a section name.
@ -109,7 +114,6 @@ TEST_CASE("show sections bpf.o .text", "[netsh][sections]")
output == "\n"
"Section : .text\n"
"Program Type : xdp\n"
"# Maps : 0\n"
"Size : 16 bytes\n"
"Instructions : 2\n"
"adjust_head : 0\n"
@ -128,7 +132,11 @@ TEST_CASE("show sections bpf.o .text", "[netsh][sections]")
"map_in_map : 0\n"
"other : 2\n"
"packet_access: 0\n"
"store : 0\n");
"store : 0\n"
"\n"
" Key Value Max\n"
" Map Type Size Size Entries Name\n"
"================== ==== ===== ======= ========\n");
}
// Test a .sys file.
@ -140,9 +148,14 @@ TEST_CASE("show sections bpf.sys", "[netsh][sections]")
REQUIRE(
output == "\n"
" Section Type # Maps Size\n"
"==================== ========= ====== ======\n"
" .text xdp 0 1752\n");
" Size\n"
" Section Type (bytes)\n"
"==================== ========= =======\n"
" .text xdp 1752\n"
"\n"
" Key Value Max\n"
" Map Type Size Size Entries Name\n"
"================== ==== ===== ======= ========\n");
}
// Test a DLL with multiple maps in the map section.
@ -153,9 +166,17 @@ TEST_CASE("show sections map_reuse_um.dll", "[netsh][sections]")
REQUIRE(result == NO_ERROR);
REQUIRE(
output == "\n"
" Section Type # Maps Size\n"
"==================== ========= ====== ======\n"
" xdp_prog xdp 3 1087\n");
" Size\n"
" Section Type (bytes)\n"
"==================== ========= =======\n"
" xdp_prog xdp 1087\n"
"\n"
" Key Value Max\n"
" Map Type Size Size Entries Name\n"
"================== ==== ===== ======= ========\n"
" Hash of maps 4 4 1 outer_map\n"
" Array 4 4 1 inner_map\n"
" Array 4 4 1 port_map\n");
}
// Test a .dll file with multiple programs.
@ -167,11 +188,17 @@ TEST_CASE("show sections tail_call_multiple_um.dll", "[netsh][sections]")
REQUIRE(result == NO_ERROR);
REQUIRE(
output == "\n"
" Section Type # Maps Size\n"
"==================== ========= ====== ======\n"
" xdp_prog xdp 0 413\n"
" xdp_prog/0 xdp 0 413\n"
" xdp_prog/1 xdp 0 190\n");
" Size\n"
" Section Type (bytes)\n"
"==================== ========= =======\n"
" xdp_prog xdp 413\n"
" xdp_prog/0 xdp 413\n"
" xdp_prog/1 xdp 190\n"
"\n"
" Key Value Max\n"
" Map Type Size Size Entries Name\n"
"================== ==== ===== ======= ========\n"
" Program array 4 4 10 map\n");
}
// Test a .sys file with multiple programs, including ones with long names.
@ -183,12 +210,19 @@ TEST_CASE("show sections cgroup_sock_addr.sys", "[netsh][sections]")
REQUIRE(result == NO_ERROR);
REQUIRE(
output == "\n"
" Section Type # Maps Size\n"
"==================== ========= ====== ======\n"
" cgroup/connect4 sock_addr 2 594\n"
" cgroup/connect6 sock_addr 2 728\n"
" cgroup/recv_accept4 sock_addr 2 594\n"
" cgroup/recv_accept6 sock_addr 2 728\n");
" Size\n"
" Section Type (bytes)\n"
"==================== ========= =======\n"
" cgroup/connect4 sock_addr 594\n"
" cgroup/connect6 sock_addr 728\n"
" cgroup/recv_accept4 sock_addr 594\n"
" cgroup/recv_accept6 sock_addr 728\n"
"\n"
" Key Value Max\n"
" Map Type Size Size Entries Name\n"
"================== ==== ===== ======= ========\n"
" Hash 44 4 1 ingress_connection_policy_map\n"
" Hash 44 4 1 egress_connection_policy_map\n");
}
TEST_CASE("show verification nosuchfile.o", "[netsh][verification]")

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

@ -257,7 +257,10 @@ _preprocess_load_native_module(_Inout_ service_context_t* context)
auto get_function =
reinterpret_cast<decltype(&get_metadata_table)>(GetProcAddress(context->dll, "get_metadata_table"));
REQUIRE(get_function != nullptr);
if (get_function == nullptr) {
REQUIRE(_expect_native_module_load_failures);
return;
}
metadata_table_t* table = get_function();
REQUIRE(table != nullptr);
@ -479,8 +482,8 @@ Glue_delete_service(SC_HANDLE handle)
// Delete the service if it has not been loaded yet. Otherwise
// mark it pending for delete.
if (!context->loaded) {
_service_path_to_context_map.erase(path);
ebpf_free(context);
_service_path_to_context_map.erase(path);
} else {
context->delete_pending = true;
}

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

@ -1981,6 +1981,16 @@ TEST_CASE("bpf_object__open_file with .dll", "[libbpf]")
REQUIRE(bpf_object__next_program(object, program) == nullptr);
struct bpf_map* map = bpf_object__next_map(object, nullptr);
REQUIRE(map != nullptr);
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(map == nullptr);
// Trying to attach the program should fail since it's not loaded yet.
bpf_link* link = bpf_program__attach(program);
REQUIRE(link == nullptr);
@ -1989,6 +1999,17 @@ TEST_CASE("bpf_object__open_file with .dll", "[libbpf]")
// Load the program.
REQUIRE(bpf_object__load(object) == 0);
// The maps should now have FDs.
map = bpf_object__next_map(object, nullptr);
REQUIRE(map != nullptr);
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(map == nullptr);
// Attach should now succeed.
link = bpf_program__attach(program);
REQUIRE(link != nullptr);
@ -2022,6 +2043,16 @@ TEST_CASE("bpf_object__load with .o", "[libbpf]")
REQUIRE(bpf_program__set_type(program, BPF_PROG_TYPE_XDP) == 0);
struct bpf_map* map = bpf_object__next_map(object, nullptr);
REQUIRE(map != nullptr);
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
REQUIRE(bpf_map__fd(map) == ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(map == nullptr);
// Trying to attach the program should fail since it's not loaded yet.
bpf_link* link = bpf_program__attach(program);
REQUIRE(link == nullptr);
@ -2034,6 +2065,17 @@ TEST_CASE("bpf_object__load with .o", "[libbpf]")
link = bpf_program__attach(program);
REQUIRE(link != nullptr);
// The maps should now have FDs.
map = bpf_object__next_map(object, nullptr);
REQUIRE(map != nullptr);
REQUIRE(strcmp(bpf_map__name(map), "dropped_packet_map") == 0);
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(strcmp(bpf_map__name(map), "interface_index_map") == 0);
REQUIRE(bpf_map__fd(map) != ebpf_fd_invalid);
map = bpf_object__next_map(object, map);
REQUIRE(map == nullptr);
REQUIRE(bpf_link__destroy(link) == 0);
bpf_object__close(object);
}