Add netsh command to show maps (#476)

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

Co-authored-by: saxena-anurag <43585259+saxena-anurag@users.noreply.github.com>
This commit is contained in:
Dave Thaler 2021-09-01 08:10:39 -07:00 коммит произвёл GitHub
Родитель 2aaa711f7d
Коммит d5c275acb3
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 167 добавлений и 6 удалений

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

@ -164,10 +164,12 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="elf.cpp" />
<ClCompile Include="maps.cpp" />
<ClCompile Include="programs.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="elf.h" />
<ClInclude Include="maps.h" />
<ClInclude Include="programs.h" />
<ClInclude Include="tokens.h" />
</ItemGroup>

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

@ -25,6 +25,9 @@
<ClCompile Include="programs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="maps.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="elf.h">
@ -36,5 +39,8 @@
<ClInclude Include="tokens.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="maps.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>

82
libs/ebpfnetsh/maps.cpp Normal file
Просмотреть файл

@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <netsh.h>
#include <string>
#include <vector>
#include "ebpf_api.h"
#include "ebpf_windows.h"
#include "maps.h"
#include "tokens.h"
static std::string _map_type_names[] = {
"Other", "Hash", "Array", "Program array", "Per-CPU hash table", "Per-CPU array", "Hash of maps", "Array of maps"};
static std::string
_get_map_type_name(ebpf_map_type_t type)
{
int index = (type >= _countof(_map_type_names)) ? 0 : type;
return _map_type_names[index];
}
DWORD
handle_ebpf_show_maps(
LPCWSTR machine, LPWSTR* argv, DWORD current_index, DWORD argc, DWORD flags, LPCVOID data, BOOL* done)
{
ebpf_result_t result;
UNREFERENCED_PARAMETER(machine);
UNREFERENCED_PARAMETER(flags);
UNREFERENCED_PARAMETER(data);
UNREFERENCED_PARAMETER(done);
std::cout << "\n";
std::cout << " Key Value Max Inner\n";
std::cout << " Map Type Size Size Entries Index\n";
std::cout << "================== ==== ===== ======= =====\n";
fd_t map_fd = ebpf_fd_invalid;
for (;;) {
fd_t next_map_fd;
result = ebpf_get_next_map(map_fd, &next_map_fd);
if (result != EBPF_SUCCESS) {
break;
}
if (map_fd != ebpf_fd_invalid) {
ebpf_close_fd(map_fd);
}
map_fd = next_map_fd;
if (map_fd == ebpf_fd_invalid) {
break;
}
ebpf_map_definition_in_file_t map_definition;
result = ebpf_map_query_definition(
map_fd,
&map_definition.size,
(uint32_t*)&map_definition.type,
&map_definition.key_size,
&map_definition.value_size,
&map_definition.max_entries,
&map_definition.inner_map_idx);
if (result != EBPF_SUCCESS) {
break;
}
std::cout << std::setw(18) << std::right << _get_map_type_name(map_definition.type) << std::setw(6)
<< std::right << map_definition.key_size << std::setw(7) << std::right << map_definition.value_size
<< std::setw(9) << std::right << map_definition.max_entries << std::setw(7) << std::right
<< map_definition.inner_map_idx << "\n";
}
if (map_fd != ebpf_fd_invalid) {
ebpf_close_fd(map_fd);
}
return result;
}

14
libs/ebpfnetsh/maps.h Normal file
Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
FN_HANDLE_CMD handle_ebpf_show_maps;
#ifdef __cplusplus
}
#endif

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

@ -3,9 +3,15 @@
#include <windows.h>
#include <netsh.h> // Must be included after windows.h
#include "bpf.h"
#include "capture_helper.hpp"
#include "catch_wrapper.hpp"
#include "elf.h"
#pragma warning(push)
#pragma warning(disable : 4200)
#include "libbpf.h"
#pragma warning(pop)
#include "maps.h"
#include "programs.h"
#include "test_helper.hpp"
@ -65,8 +71,6 @@ static std::string
_run_netsh_command(
_In_ FN_HANDLE_CMD* command, _In_opt_z_ const wchar_t* arg1, _In_opt_z_ const wchar_t* arg2, _Out_ int* result)
{
_test_helper_end_to_end test_helper;
capture_helper_t capture;
errno_t error = capture.begin_capture();
if (error != NO_ERROR) {
@ -193,6 +197,8 @@ TEST_CASE("show verification bpf.o", "[netsh][verification]")
TEST_CASE("show verification droppacket.o", "[netsh][verification]")
{
_test_helper_libbpf test_helper;
int result;
std::string output = _run_netsh_command(handle_ebpf_show_verification, L"droppacket.o", L"xdp", &result);
REQUIRE(result == NO_ERROR);
@ -206,6 +212,8 @@ TEST_CASE("show verification droppacket.o", "[netsh][verification]")
TEST_CASE("show verification droppacket_unsafe.o", "[netsh][verification]")
{
_test_helper_libbpf test_helper;
int result;
std::string output = _run_netsh_command(handle_ebpf_show_verification, L"droppacket_unsafe.o", L"xdp", &result);
REQUIRE(result == ERROR_SUPPRESS_OUTPUT);
@ -225,13 +233,52 @@ TEST_CASE("show verification droppacket_unsafe.o", "[netsh][verification]")
TEST_CASE("show programs", "[netsh][programs]")
{
int result;
_test_helper_libbpf test_helper;
// Load a program to show.
struct bpf_object* object;
int program_fd;
int result = bpf_prog_load("tail_call.o", BPF_PROG_TYPE_XDP, &object, &program_fd);
REQUIRE(result == 0);
REQUIRE(object != nullptr);
REQUIRE(program_fd != -1);
std::string output = _run_netsh_command(handle_ebpf_show_programs, nullptr, nullptr, &result);
REQUIRE(result == NO_ERROR);
// Since we mocked the ioctl, there should be no programs shown.
REQUIRE(
output == "\n"
" File Name Section Requested Execution Type\n"
"==================== =============== ========================\n");
"==================== =============== ========================\n"
" tail_call.o xdp_prog JIT\n"
" tail_call.o xdp_prog/0 JIT\n");
bpf_object__close(object);
}
TEST_CASE("show maps", "[netsh][maps]")
{
_test_helper_end_to_end test_helper;
// Create maps to show.
int outer_map_fd = bpf_create_map(BPF_MAP_TYPE_HASH_OF_MAPS, sizeof(__u32), sizeof(__u32), 2, 0);
REQUIRE(outer_map_fd > 0);
int inner_map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(__u32), sizeof(__u32), 1, 0);
REQUIRE(inner_map_fd > 0);
int result;
std::string output = _run_netsh_command(handle_ebpf_show_maps, nullptr, nullptr, &result);
REQUIRE(result == NO_ERROR);
REQUIRE(
output == "\n"
" Key Value Max Inner\n"
" Map Type Size Size Entries Index\n"
"================== ==== ===== ======= =====\n"
" Hash of maps 4 4 2 0\n"
" Array 4 4 1 0\n");
ebpf_close_fd(inner_map_fd); // TODO(issue #287): change to _close(inner_map_fd);
ebpf_close_fd(outer_map_fd); // TODO(issue #287): change to _close(outer_map_fd);
}

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

@ -211,6 +211,14 @@ BEGIN
\nRemarks: Shows the verifier results of the specified eBPF program.\
\n"
HLP_EBPF_SHOW_MAPS "Shows eBPF maps.\n"
HLP_EBPF_SHOW_MAPS_EX "\
\nUsage: %1!s!\
\n\
\nRemarks: Shows all loaded maps.\
\n"
END
#endif // English (United States) resources

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

@ -16,6 +16,8 @@
#define HLP_EBPF_SHOW_SECTIONS_EX 112
#define HLP_EBPF_SHOW_VERIFICATION 113
#define HLP_EBPF_SHOW_VERIFICATION_EX 114
#define HLP_EBPF_SHOW_MAPS 115
#define HLP_EBPF_SHOW_MAPS_EX 116
// Next default values for new objects
//