Add more libbpf APIs needed by bpftool (#576)

* Add more libbpf APIs needed by bpftool

* Add missing export for existing bpf_map__name API
* Add bpf_object__load
* Add bpf_object__load_xattr
* Add bpf_object__open_file
* Add bpf_object__unload() API
* Add bpf_program__get_type
* Add bpf_program__set_type
* Add bpf_program__unload() API
* Add libbpf_get_error
* Add libbpf_num_possible_cpus
* Rename BPF_MAP_TYPE_UNSPECIFIED to BPF_MAP_TYPE_UNSPEC for libbpf
  compat
* Rename BPF_PROG_TYPE_UNKNOWN to BPF_PROG_TYPE_UNSPEC for libbpf compat
* Add attach_type to bpf_link_info
* Add map_flags to bpf_map_info (but currently always 0)

Fixes #575

Signed-off-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Dave Thaler 2021-09-23 19:32:09 -07:00 коммит произвёл GitHub
Родитель 6a1c193b5b
Коммит 20d7a6565e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
34 изменённых файлов: 675 добавлений и 143 удалений

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

@ -19,6 +19,7 @@ EXPORTS
bpf_map__is_pinned
bpf_map__key_size
bpf_map__max_entries
bpf_map__name
bpf_map__next
bpf_map__pin
bpf_map__prev
@ -38,11 +39,15 @@ EXPORTS
bpf_object__find_map_by_name
bpf_object__find_map_fd_by_name
bpf_object__find_program_by_name
bpf_object__load
bpf_object__load_xattr
bpf_object__name
bpf_object__next
bpf_object__open_file
bpf_object__pin
bpf_object__pin_maps
bpf_object__pin_programs
bpf_object__unload
bpf_object__unpin_maps
bpf_object__unpin_programs
bpf_prog_get_fd_by_id
@ -52,12 +57,15 @@ EXPORTS
bpf_program__attach_xdp
bpf_program__fd
bpf_program__get_expected_attach_type
bpf_program__get_type
bpf_program__name
bpf_program__next
bpf_program__pin
bpf_program__prev
bpf_program__section_name
bpf_program__set_expected_attach_type
bpf_program__set_type
bpf_program__unload
bpf_program__unpin
ebpf_api_initiate
ebpf_api_terminate
@ -84,4 +92,6 @@ EXPORTS
ebpf_program_attach_by_fd
ebpf_program_load
ebpf_program_query_info
libbpf_get_error
libbpf_num_possible_cpus
libbpf_prog_type_by_name

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

@ -199,7 +199,7 @@ bpf_map_update_elem(int fd, const void* key, const void* value, __u64 flags);
/**
* @brief Get a file descriptor for a pinned object by pin path.
* @param[in] path Pin path for the object.
* @param[in] pathname Pin path for the object.
*
* @return file descriptor for the pinned object, or -1 if not found.
*/

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

@ -267,6 +267,58 @@ bpf_object__find_map_fd_by_name(const struct bpf_object* obj, const char* name);
struct bpf_program*
bpf_object__find_program_by_name(const struct bpf_object* obj, const char* name);
/**
* @brief Load all the programs in a given object.
*
* @param[in] obj Object from which to load programs.
*
* @retval 0 The operation was successful.
* @retval <0 An error occured, and errno was set.
*
* @exception EINVAL An invalid argument was provided.
* @exception ENOMEM Out of memory.
*
* @sa bpf_object__load_xattr
* @sa bpf_object__open
* @sa bpf_object__unload
* @sa bpf_prog_load
*/
int
bpf_object__load(struct bpf_object* obj);
/**
* @brief Unload all the programs in a given object.
*
* @param[in] obj Object in which to unload programs.
*
* @retval 0 The operation was successful.
* @retval <0 An error occured, and errno was set.
*
* @sa bpf_object__load
* @sa bpf_object__load_xattr
* @sa bpf_prog_load
*/
int
bpf_object__unload(struct bpf_object* obj);
/**
* @brief Load all the programs in a given object.
*
* @param[in] attr Structure with load attributes.
*
* @retval 0 The operation was successful.
* @retval <0 An error occured, and errno was set.
*
* @exception EINVAL An invalid argument was provided.
* @exception ENOMEM Out of memory.
*
* @sa bpf_object__open
* @sa bpf_object__load_xattr
* @sa bpf_prog_load
*/
int
bpf_object__load_xattr(struct bpf_object_load_attr* attr);
/**
* @brief Get the name of an eBPF object.
*
@ -287,6 +339,17 @@ bpf_object__name(const struct bpf_object* obj);
struct bpf_object*
bpf_object__next(struct bpf_object* prev);
/**
* @brief Open a file without loading the programs.
*
* @param[in] path File name to open.
* @param[opts] opts Options to use when opening the object.
*
* @returns Pointer to an eBPF object, or NULL on failure.
*/
struct bpf_object*
bpf_object__open_file(const char* path, const struct bpf_object_open_opts* opts);
/**
* @brief Pin an eBPF object to a specified path.
*
@ -468,6 +531,18 @@ bpf_program__fd(const struct bpf_program* prog);
enum bpf_attach_type
bpf_program__get_expected_attach_type(const struct bpf_program* prog);
/**
* @brief Get the program type for an eBPF program.
*
* @param[in] prog Program to check.
*
* @returns Program type.
*
* @sa bpf_program__get_expected_attach_type
*/
enum bpf_prog_type
bpf_program__get_type(const struct bpf_program* prog);
/**
* @brief Get the function name of an eBPF program.
*
@ -550,6 +625,28 @@ bpf_program__section_name(const struct bpf_program* prog);
void
bpf_program__set_expected_attach_type(struct bpf_program* prog, enum bpf_attach_type type);
/**
* @brief Set the program type for an eBPF program.
*
* @param[in] prog Program to update.
* @param[in] type Program type to set.
*
* @sa bpf_program__set_expected_attach_type
*/
void
bpf_program__set_type(struct bpf_program* prog, enum bpf_prog_type type);
/**
* @brief Unload a program.
*
* @param[in] prog Program to unload.
*
* @sa bpf_object__unload
* @sa bpf_prog_load
*/
void
bpf_program__unload(struct bpf_program* prog);
/**
* @brief Unpin a program.
*
@ -583,6 +680,31 @@ libbpf_prog_type_by_name(const char* name, enum bpf_prog_type* prog_type, enum b
/** @} */
/**
* @name System-related functions
* @{
*/
/**
* @brief Get a negative error code based on errno and a possibly null pointer.
*
* @param[in] ptr Pointer that may be NULL.
*
* @returns Negative error code.
*/
long
libbpf_get_error(const void* ptr);
/**
* @brief Get the number of processors on the current system.
*
* @returns Number of processors.
*/
int
libbpf_num_possible_cpus(void);
/** @} */
#else
#pragma warning(push)
#pragma warning(disable : 4200) // Zero-sized array in struct/union

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

@ -33,7 +33,7 @@ extern "C"
__declspec(selectany) ebpf_attach_type_t EBPF_ATTACH_TYPE_SAMPLE = {
0xf788ef4b, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
__declspec(selectany) ebpf_attach_type_t EBPF_PROGRAM_TYPE_UNSPECIFIED = {0};
__declspec(selectany) ebpf_program_type_t EBPF_PROGRAM_TYPE_UNSPECIFIED = {0};
/** @brief Program type for handling incoming packets as early as possible.
*
@ -61,7 +61,7 @@ extern "C"
0xf788ef4a, 0x207d, 0x4dc3, {0x85, 0xcf, 0x0f, 0x2e, 0xa1, 0x07, 0x21, 0x3c}};
typedef int32_t fd_t;
const fd_t ebpf_fd_invalid = -1;
extern __declspec(selectany) const fd_t ebpf_fd_invalid = -1;
typedef intptr_t ebpf_handle_t;
typedef struct _tlv_type_length_value tlv_type_length_value_t;
@ -366,10 +366,10 @@ extern "C"
* EBPF_EXECUTION_ANY is specified, execution type will be decided by a
* system-wide policy.
* @param[out] object Returns pointer to ebpf_object object. The caller
is expected to call ebpf_object_close() at the end.
is expected to call bpf_object__close() at the end.
* @param[out] program_fd Returns a file descriptor for the first program.
* The caller should not call _close() on the fd, but should instead use
* ebpf_object_close() to close this (and other) file descriptors.
* bpf_object__close() to close this (and other) file descriptors.
* @param[out] log_buffer Returns a pointer to a null-terminated log buffer.
* The caller is responsible for freeing the returned log_buffer pointer
* by calling ebpf_free_string().
@ -479,7 +479,7 @@ extern "C"
* @brief Get a program type and expected attach type by name.
*
* @param[in] name Name, as if it were a section name in an ELF file.
* @param[out] prog_type Program type.
* @param[out] program_type Program type.
* @param[out] expected_attach_type Expected attach type.
*
* @retval EBPF_SUCCESS The operation was successful.

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

@ -12,9 +12,9 @@
typedef enum bpf_map_type
{
BPF_MAP_TYPE_UNSPECIFIED = 0, ///< Unspecified map type.
BPF_MAP_TYPE_HASH = 1, ///< Hash table.
BPF_MAP_TYPE_ARRAY = 2, ///< Array, where the map key is the array index.
BPF_MAP_TYPE_UNSPEC = 0, ///< Unspecified map type.
BPF_MAP_TYPE_HASH = 1, ///< Hash table.
BPF_MAP_TYPE_ARRAY = 2, ///< Array, where the map key is the array index.
BPF_MAP_TYPE_PROG_ARRAY =
3, ///< Array of program fds usable with bpf_tail_call, where the map key is the array index.
BPF_MAP_TYPE_PERCPU_HASH = 4,
@ -84,20 +84,47 @@ typedef enum
// Cross-platform BPF program types.
enum bpf_prog_type
{
BPF_PROG_TYPE_UNKNOWN,
BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_XDP,
BPF_PROG_TYPE_BIND, // TODO(#333): replace with cross-platform program type
};
// The link type is used to tell which union member is present
// in the bpf_link_info struct. There is exactly one non-zero value
// per union member.
enum bpf_link_type
{
BPF_LINK_TYPE_UNSPEC,
BPF_LINK_TYPE_PLAIN,
};
enum bpf_attach_type
{
BPF_ATTACH_TYPE_UNSPEC,
BPF_ATTACH_TYPE_XDP,
__MAX_BPF_ATTACH_TYPE,
};
// Libbpf itself requires the following structs to be defined, but doesn't
// care what fields they have. Applications such as bpftool on the other
// hand depend on fields of specific names and types.
#pragma warning(push)
#pragma warning(disable : 4201) /* nameless struct/union */
struct bpf_link_info
{
ebpf_id_t id; ///< Link ID.
ebpf_id_t prog_id; ///< Program ID.
ebpf_id_t id; ///< Link ID.
ebpf_id_t prog_id; ///< Program ID.
enum bpf_link_type type; ///< Link type.
union
{
struct
{
int attach_type; ///< Attach type integer.
};
};
};
#pragma warning(pop)
#define BPF_OBJ_NAME_LEN 64
@ -110,12 +137,17 @@ struct bpf_map_info
uint32_t value_size; ///< Size in bytes of a map value.
uint32_t max_entries; ///< Maximum number of entries allowed in the map.
char name[BPF_OBJ_NAME_LEN]; ///< Null-terminated map name.
uint32_t map_flags; ///< Map flags.
// Windows-specific fields.
ebpf_id_t inner_map_id; ///< ID of inner map template.
uint32_t pinned_path_count; ///< Number of pinned paths.
};
#define BPF_ANY 0x0
#define BPF_NOEXIST 0x1
#define BPF_EXIST 0x2
struct bpf_prog_info
{
// Cross-platform fields.

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

@ -13,17 +13,13 @@
#undef LIBBPF_DEPRECATED
#define LIBBPF_DEPRECATED(x)
typedef int32_t __s32;
typedef uint8_t __u8;
typedef uint32_t __u32;
typedef uint64_t __u64;
typedef uint32_t pid_t;
enum bpf_attach_type
{
BPF_ATTACH_TYPE_UNSPEC,
BPF_ATTACH_TYPE_XDP,
};
enum bpf_func_id
{
BPF_FUNC_ID_UNKNOWN

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

@ -178,6 +178,7 @@
<ClCompile Include="libbpf_object.cpp" />
<ClCompile Include="libbpf_program.cpp" />
<ClCompile Include="libbpf_map.cpp" />
<ClCompile Include="libbpf_system.cpp" />
<ClCompile Include="Verifier.cpp" />
<ClCompile Include="windows_platform.cpp" />
</ItemGroup>

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

@ -37,6 +37,9 @@
<ClCompile Include="libbpf_link.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libbpf_system.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">

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

@ -61,9 +61,10 @@ typedef struct bpf_link
typedef struct bpf_object
{
char* file_name = nullptr;
char* object_name = nullptr;
std::vector<ebpf_program_t*> programs;
std::vector<ebpf_map_t*> maps;
bool loaded = false;
} ebpf_object_t;
ebpf_result_t
@ -120,6 +121,17 @@ ebpf_program_next(_In_opt_ const struct bpf_program* previous, _In_ const struct
_Ret_maybenull_ struct bpf_program*
ebpf_program_previous(_In_opt_ const struct bpf_program* next, _In_ const struct bpf_object* object);
/**
* @brief Unload an eBPF program.
*
* @param[in] program Program to unload.
*
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_ARGUMENT One or more parameters are wrong.
*/
ebpf_result_t
ebpf_program_unload(_In_ struct bpf_program* program);
/**
* @brief Get next map in ebpf_object object.
*
@ -179,7 +191,7 @@ ebpf_map_get_fd(_In_ const struct bpf_map* map);
* @param[in] object Pointer to ebpf_object.
*/
void
ebpf_object_close(_In_ _Post_invalid_ struct bpf_object* object);
ebpf_object_close(_In_opt_ _Post_invalid_ struct bpf_object* object);
void
initialize_map(_Out_ ebpf_map_t* map, _In_ const map_cache_t& map_cache);
@ -391,3 +403,59 @@ ebpf_object_pin(fd_t fd, _In_z_ const char* path);
*/
fd_t
ebpf_object_get(_In_z_ const char* path);
/**
* @brief Open a file without loading the programs.
*
* @param[in] path File name to open.
* @param[in] object_name Optional object name to override file name
* as the object name.
* @param[in] program_type Optional program type for all programs.
* If NULL, the program type is derived from the section names.
* @param[in] attach_type Default attach type for all programs.
* If NULL, the attach type is derived from the section names.
* @param[out] object Returns a pointer to the object created.
* @param[out] error_message Error message string, which
* the caller must free using ebpf_free_string().
*
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_ARGUMENT One or more parameters are wrong.
* @retval EBPF_NO_MEMORY Out of memory.
*/
ebpf_result_t
ebpf_object_open(
_In_z_ const char* path,
_In_opt_z_ const char* object_name,
_In_opt_ const ebpf_program_type_t* program_type,
_In_opt_ const ebpf_attach_type_t* attach_type,
_Outptr_ struct bpf_object** object,
_Outptr_result_maybenull_z_ const char** error_message) noexcept;
/**
* @brief Load all the programs in a given object.
*
* @param[in] object Object from which to load programs.
* @param[in] execution_type Execution type.
* @param[out] error_message Error message string, which
* the caller must free using ebpf_free_string().
*
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_ARGUMENT One or more parameters are wrong.
* @retval EBPF_NO_MEMORY Out of memory.
*/
ebpf_result_t
ebpf_object_load(
_Inout_ struct bpf_object* object,
ebpf_execution_type_t execution_type,
_Outptr_result_maybenull_z_ const char** error_message);
/**
* @brief Unload all the programs in a given object.
*
* @param[in] object Object in which to unload programs.
*
* @retval EBPF_SUCCESS The operation was successful.
* @retval EBPF_INVALID_ARGUMENT One or more parameters are wrong.
*/
ebpf_result_t
ebpf_object_unload(_In_ struct bpf_object* object);

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

@ -287,7 +287,7 @@ _get_map_descriptor_properties(
ebpf_result_t result = EBPF_SUCCESS;
ebpf_map_t* map;
*type = BPF_MAP_TYPE_UNSPECIFIED;
*type = BPF_MAP_TYPE_UNSPEC;
*key_size = 0;
*value_size = 0;
@ -1101,7 +1101,10 @@ ebpf_program_attach(
} else {
program_attach_type = &program->attach_type;
}
assert(program->handle != ebpf_handle_invalid);
if (program->handle == ebpf_handle_invalid) {
result = EBPF_INVALID_ARGUMENT;
goto Exit;
}
result =
_link_ebpf_program(program->handle, program_attach_type, link, (uint8_t*)attach_parameters, attach_params_size);
@ -1285,12 +1288,8 @@ clean_up_ebpf_program(_In_ _Post_invalid_ ebpf_program_t* program)
if (program == nullptr) {
return;
}
if (program->fd != ebpf_fd_invalid) {
Platform::_close(program->fd);
}
if (program->handle != ebpf_handle_invalid) {
_ebpf_programs.erase(program->handle);
}
ebpf_program_unload(program);
free(program->byte_code);
free(program->program_name);
free(program->section_name);
@ -1313,7 +1312,7 @@ clean_up_ebpf_map(_In_ _Post_invalid_ ebpf_map_t* map)
if (map == nullptr) {
return;
}
if (map->map_fd != 0) {
if (map->map_fd > 0) {
Platform::_close(map->map_fd);
}
if (map->map_handle != ebpf_handle_invalid) {
@ -1392,6 +1391,7 @@ initialize_map(_Out_ ebpf_map_t* map, _In_ const map_cache_t& map_cache)
static ebpf_result_t
_initialize_ebpf_object_from_elf(
_In_z_ const char* file_name,
_In_opt_z_ const char* object_name,
_In_opt_ const ebpf_program_type_t* expected_program_type,
_In_opt_ const ebpf_attach_type_t* expected_attach_type,
_Out_ ebpf_object_t& object,
@ -1406,16 +1406,18 @@ _initialize_ebpf_object_from_elf(
goto Exit;
}
object.file_name = _strdup(file_name);
if (object.file_name == nullptr) {
object.object_name = _strdup(object_name ? object_name : file_name);
if (object.object_name == nullptr) {
result = EBPF_NO_MEMORY;
goto Exit;
}
for (auto& program : object.programs) {
program->fd = ebpf_fd_invalid;
program->object = &object;
}
for (auto& map : object.maps) {
map->map_fd = ebpf_fd_invalid;
map->object = &object;
}
@ -1475,6 +1477,214 @@ _get_next_map_to_create(std::vector<ebpf_map_t*>& maps)
return nullptr;
}
ebpf_result_t
ebpf_object_open(
_In_z_ const char* path,
_In_opt_z_ const char* object_name,
_In_opt_ const ebpf_program_type_t* program_type,
_In_opt_ const ebpf_attach_type_t* attach_type,
_Outptr_ struct bpf_object** object,
_Outptr_result_maybenull_z_ const char** error_message) noexcept
{
*error_message = nullptr;
ebpf_object_t* new_object = new (std::nothrow) ebpf_object_t();
if (new_object == nullptr) {
return EBPF_NO_MEMORY;
}
ebpf_result_t result =
_initialize_ebpf_object_from_elf(path, object_name, program_type, attach_type, *new_object, error_message);
if (result != EBPF_SUCCESS) {
goto Done;
}
*object = new_object;
_ebpf_objects.emplace_back(*object);
Done:
clear_map_descriptors();
if (result != EBPF_SUCCESS) {
_clean_up_ebpf_object(new_object);
}
return result;
}
static ebpf_result_t
_ebpf_object_create_maps(_Inout_ ebpf_object_t* object)
{
ebpf_result_t result = EBPF_SUCCESS;
clear_map_descriptors();
// TODO: update ebpf_map_definition_t structure so that it contains flag and pinning information.
for (int count = 0; count < object->maps.size(); count++) {
ebpf_map_t* map = _get_next_map_to_create(object->maps);
if (map == nullptr) {
// Any remaining maps cannot be created.
result = EBPF_INVALID_OBJECT;
break;
}
ebpf_handle_t inner_map_handle = (map->inner_map) ? map->inner_map->map_handle : ebpf_handle_invalid;
result = _create_map(map->name, &map->map_definition, inner_map_handle, &map->map_handle);
if (result != EBPF_SUCCESS) {
break;
}
map->map_fd = _create_file_descriptor_for_handle(map->map_handle);
}
if (result != EBPF_SUCCESS) {
clean_up_ebpf_maps(object->maps);
} else {
for (auto& map : object->maps) {
_ebpf_maps.insert(std::pair<ebpf_handle_t, ebpf_map_t*>(map->map_handle, map));
}
}
clear_map_descriptors();
return result;
}
static ebpf_result_t
_ebpf_object_load_programs(
_Inout_ struct bpf_object* object,
_In_ ebpf_execution_type_t execution_type,
_Outptr_result_maybenull_z_ const char** log_buffer)
{
ebpf_result_t result = EBPF_SUCCESS;
std::vector<original_fd_handle_map_t> handle_map;
uint32_t error_message_size = 0;
*log_buffer = nullptr;
for (auto& program : object->programs) {
result = _create_program(
program->program_type, object->object_name, program->section_name, program->program_name, &program->handle);
if (result != EBPF_SUCCESS) {
break;
}
program->fd = _create_file_descriptor_for_handle(program->handle);
// Populate load_info.
ebpf_program_load_info load_info = {0};
load_info.object_name = const_cast<char*>(object->object_name);
load_info.section_name = const_cast<char*>(program->section_name);
load_info.program_name = const_cast<char*>(program->program_name);
load_info.program_type = program->program_type;
load_info.program_handle = reinterpret_cast<file_handle_t>(program->handle);
load_info.execution_type = execution_type;
load_info.byte_code = program->byte_code;
load_info.byte_code_size = program->byte_code_size;
load_info.execution_context = execution_context_kernel_mode;
load_info.map_count = (uint32_t)object->maps.size();
if (load_info.map_count > 0) {
for (auto& map : object->maps) {
fd_t inner_map_original_fd = (map->inner_map) ? map->inner_map->original_fd : ebpf_fd_invalid;
handle_map.emplace_back(
map->original_fd, inner_map_original_fd, reinterpret_cast<file_handle_t>(map->map_handle));
}
load_info.handle_map = handle_map.data();
}
result = ebpf_rpc_load_program(&load_info, log_buffer, &error_message_size);
if (result != EBPF_SUCCESS) {
break;
}
}
if (result == EBPF_SUCCESS) {
for (auto& program : object->programs) {
_ebpf_programs.insert(std::pair<ebpf_handle_t, ebpf_program_t*>(program->handle, program));
}
}
return result;
}
// This logic is intended to be similar to libbpf's bpf_object__load_xattr().
ebpf_result_t
ebpf_object_load(
_Inout_ struct bpf_object* object,
ebpf_execution_type_t execution_type,
_Outptr_result_maybenull_z_ const char** log_buffer)
{
if (!object)
return EBPF_INVALID_ARGUMENT;
if (object->loaded) {
return EBPF_INVALID_ARGUMENT;
}
ebpf_result_t result = EBPF_SUCCESS;
try {
result = _ebpf_object_create_maps(object);
if (result != EBPF_SUCCESS) {
goto Done;
}
result = _ebpf_object_load_programs(object, execution_type, log_buffer);
} catch (const std::bad_alloc&) {
result = EBPF_NO_MEMORY;
goto Done;
} catch (...) {
result = EBPF_FAILED;
goto Done;
}
object->loaded = true; /* doesn't matter if successfully loaded or not */
Done:
if (result != EBPF_SUCCESS) {
ebpf_object_unload(object);
}
return result;
}
// This function is intended to work like libbpf's bpf_object__unload().
ebpf_result_t
ebpf_object_unload(_In_ struct bpf_object* object)
{
if (!object)
return EBPF_INVALID_ARGUMENT;
for (auto& map : object->maps) {
if (map->map_fd > 0) {
Platform::_close(map->map_fd);
map->map_fd = ebpf_fd_invalid;
}
if (map->map_handle != ebpf_handle_invalid) {
_ebpf_maps.erase(map->map_handle);
map->map_handle = ebpf_handle_invalid;
}
}
for (auto& program : object->programs) {
ebpf_program_unload(program);
}
return EBPF_SUCCESS;
}
// This function is intended to work like libbpf's bpf_program__unload().
ebpf_result_t
ebpf_program_unload(_In_ struct bpf_program* program)
{
if (!program)
return EBPF_INVALID_ARGUMENT;
if (program->fd != ebpf_fd_invalid) {
Platform::_close(program->fd);
program->fd = ebpf_fd_invalid;
}
if (program->handle != ebpf_handle_invalid) {
_ebpf_programs.erase(program->handle);
program->handle = ebpf_handle_invalid;
}
return EBPF_SUCCESS;
}
ebpf_result_t
ebpf_program_load(
_In_z_ const char* file_name,
@ -1487,11 +1697,8 @@ ebpf_program_load(
{
ebpf_object_t* new_object = nullptr;
ebpf_protocol_buffer_t request_buffer;
uint32_t error_message_size = 0;
std::vector<uintptr_t> handles;
ebpf_result_t result = EBPF_SUCCESS;
ebpf_program_load_info load_info = {0};
std::vector<original_fd_handle_map_t> handle_map;
if (file_name == nullptr || object == nullptr || program_fd == nullptr || log_buffer == nullptr) {
result = EBPF_INVALID_ARGUMENT;
@ -1506,85 +1713,19 @@ ebpf_program_load(
}
clear_map_descriptors();
*log_buffer = nullptr;
*object = nullptr;
try {
new_object = new ebpf_object_t();
if (new_object == nullptr) {
result = EBPF_NO_MEMORY;
goto Done;
}
result = _initialize_ebpf_object_from_elf(file_name, program_type, attach_type, *new_object, log_buffer);
result = ebpf_object_open(file_name, nullptr, program_type, attach_type, &new_object, log_buffer);
if (result != EBPF_SUCCESS) {
goto Done;
}
// Create all maps.
// TODO: update ebpf_map_definition_t structure so that it contains flag and pinning information.
for (int count = 0; count < new_object->maps.size(); count++) {
ebpf_map_t* map = _get_next_map_to_create(new_object->maps);
if (map == nullptr) {
// Any remaining maps cannot be created.
result = EBPF_INVALID_OBJECT;
goto Done;
}
ebpf_handle_t inner_map_handle = (map->inner_map) ? map->inner_map->map_handle : ebpf_handle_invalid;
result = _create_map(map->name, &map->map_definition, inner_map_handle, &map->map_handle);
if (result != EBPF_SUCCESS) {
goto Done;
}
map->map_fd = _create_file_descriptor_for_handle(map->map_handle);
}
for (auto& program : new_object->programs) {
result = _create_program(
program->program_type, file_name, program->section_name, program->program_name, &program->handle);
if (result != EBPF_SUCCESS) {
goto Done;
}
program->fd = _create_file_descriptor_for_handle(program->handle);
// populate load_info.
load_info.file_name = const_cast<char*>(file_name);
load_info.section_name = const_cast<char*>(program->section_name);
load_info.program_name = const_cast<char*>(program->program_name);
load_info.program_type = program->program_type;
load_info.program_handle = reinterpret_cast<file_handle_t>(program->handle);
load_info.execution_type = execution_type;
load_info.byte_code = program->byte_code;
load_info.byte_code_size = program->byte_code_size;
load_info.execution_context = execution_context_kernel_mode;
load_info.map_count = (uint32_t)new_object->maps.size();
if (load_info.map_count > 0) {
for (auto& map : new_object->maps) {
fd_t inner_map_original_fd = (map->inner_map) ? map->inner_map->original_fd : ebpf_fd_invalid;
handle_map.emplace_back(
map->original_fd, inner_map_original_fd, reinterpret_cast<file_handle_t>(map->map_handle));
}
load_info.handle_map = handle_map.data();
}
result = ebpf_rpc_load_program(&load_info, log_buffer, &error_message_size);
if (result != EBPF_SUCCESS) {
goto Done;
}
}
for (auto& program : new_object->programs) {
_ebpf_programs.insert(std::pair<ebpf_handle_t, ebpf_program_t*>(program->handle, program));
}
for (auto& map : new_object->maps) {
_ebpf_maps.insert(std::pair<ebpf_handle_t, ebpf_map_t*>(map->map_handle, map));
result = ebpf_object_load(new_object, execution_type, log_buffer);
if (result != EBPF_SUCCESS) {
goto Done;
}
*object = new_object;
_ebpf_objects.emplace_back(*object);
*program_fd = new_object->programs[0]->fd;
} catch (const std::bad_alloc&) {
result = EBPF_NO_MEMORY;
@ -1596,7 +1737,7 @@ ebpf_program_load(
Done:
if (result != EBPF_SUCCESS) {
_clean_up_ebpf_object(new_object);
ebpf_object_close(new_object);
}
clear_map_descriptors();
return result;
@ -1745,7 +1886,7 @@ ebpf_map_get_fd(_In_ const struct bpf_map* map)
}
void
ebpf_object_close(_In_ _Post_invalid_ struct bpf_object* object)
ebpf_object_close(_In_opt_ _Post_invalid_ struct bpf_object* object)
{
if (object == nullptr) {
return;

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

@ -18,3 +18,10 @@ libbpf_result_err(ebpf_result_t result)
{
return libbpf_err(-ebpf_result_to_errno(result));
}
static inline void*
libbpf_err_ptr(int err)
{
errno = -err;
return NULL;
}

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

@ -17,7 +17,7 @@
const char*
bpf_object__name(const struct bpf_object* object)
{
return object->file_name;
return object->object_name;
}
int
@ -54,8 +54,7 @@ bpf_object__find_program_by_name(const struct bpf_object* obj, const char* name)
if (!strcmp(prog->program_name, name))
return prog;
}
errno = ENOENT;
return nullptr;
return (struct bpf_program*)libbpf_err_ptr(-ENOENT);
}
struct bpf_object*
@ -83,3 +82,43 @@ bpf_obj_get(const char* pathname)
{
return (int)ebpf_object_get(pathname);
}
struct bpf_object*
bpf_object__open_file(const char* path, const struct bpf_object_open_opts* opts)
{
if (!path) {
return (struct bpf_object*)libbpf_err_ptr(-EINVAL);
}
struct bpf_object* object;
const char* error_message;
ebpf_result_t result = ebpf_object_open(path, opts->object_name, nullptr, nullptr, &object, &error_message);
ebpf_free_string(error_message);
libbpf_result_err(result); // Set errno.
return object;
}
int
bpf_object__load_xattr(struct bpf_object_load_attr* attr)
{
const char* error_message;
ebpf_result result = ebpf_object_load(attr->obj, EBPF_EXECUTION_ANY, &error_message);
ebpf_free_string(error_message);
return libbpf_result_err(result);
}
int
bpf_object__load(struct bpf_object* object)
{
struct bpf_object_load_attr attr = {
.obj = object,
};
return bpf_object__load_xattr(&attr);
}
int
bpf_object__unload(struct bpf_object* obj)
{
return libbpf_result_err(ebpf_object_unload(obj));
}

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

@ -27,6 +27,19 @@ _get_ebpf_program_type(enum bpf_prog_type type)
return nullptr;
}
static enum bpf_prog_type
_get_bpf_program_type(const ebpf_program_type_t* type)
{
// TODO(issue #223): read this mapping from the registry
if (memcmp(type, &EBPF_PROGRAM_TYPE_XDP, sizeof(*type)) == 0) {
return BPF_PROG_TYPE_XDP;
}
if (memcmp(type, &EBPF_PROGRAM_TYPE_BIND, sizeof(*type)) == 0) {
return BPF_PROG_TYPE_BIND;
}
return BPF_PROG_TYPE_UNSPEC;
}
static const ebpf_attach_type_t*
_get_ebpf_attach_type(enum bpf_attach_type type)
{
@ -271,6 +284,19 @@ bpf_program__set_expected_attach_type(struct bpf_program* program, enum bpf_atta
program->attach_type = *_get_ebpf_attach_type(type);
}
enum bpf_prog_type
bpf_program__get_type(const struct bpf_program* program)
{
return _get_bpf_program_type(&program->program_type);
}
void
bpf_program__set_type(struct bpf_program* program, enum bpf_prog_type type)
{
const ebpf_program_type_t* program_type = _get_ebpf_program_type(type);
program->program_type = (program_type != nullptr) ? *program_type : EBPF_PROGRAM_TYPE_UNSPECIFIED;
}
int
bpf_prog_get_fd_by_id(uint32_t id)
{
@ -318,3 +344,12 @@ libbpf_prog_type_by_name(const char* name, enum bpf_prog_type* prog_type, enum b
errno = ESRCH;
return -1;
}
void
bpf_program__unload(struct bpf_program* prog)
{
ebpf_result_t result = ebpf_program_unload(prog);
if (result != EBPF_SUCCESS) {
errno = ebpf_result_to_errno(result);
}
}

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

@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#include <windows.h>
#pragma warning(push)
#pragma warning(disable : 4200)
#include "libbpf.h"
#pragma warning(pop)
long
libbpf_get_error(const void* ptr)
{
/* Older versions of Linux encode error numbers in a
* void* in some cases, so libbpf has to deal with both
* that case and the simple case of using errno, so
* exposes this API to be agnostic. But we always use
* errno, so don't need to look at the ptr value.
*/
UNREFERENCED_PARAMETER(ptr);
return -errno;
}
int
libbpf_num_possible_cpus(void)
{
SYSTEM_INFO info;
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
}

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

@ -120,7 +120,7 @@ get_program_type_windows(const std::string& section, const std::string&)
#define BPF_MAP_TYPE(x) BPF_MAP_TYPE_##x, #x
static const EbpfMapType windows_map_types[] = {
{BPF_MAP_TYPE(UNSPECIFIED)},
{BPF_MAP_TYPE(UNSPEC)},
{BPF_MAP_TYPE(HASH)},
{BPF_MAP_TYPE(ARRAY), true},
{BPF_MAP_TYPE(PROG_ARRAY), true, EbpfMapValueType::PROGRAM},

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

@ -9,7 +9,7 @@
#include <netsh.h>
#include <string>
#include <vector>
#include "bpf.h"
#include "bpf/bpf.h"
#include "ebpf_api.h"
#include "ebpf_windows.h"
#include "platform.h"

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

@ -9,7 +9,7 @@
#include <netsh.h>
#include <string>
#include <vector>
#include "bpf.h"
#include "bpf/bpf.h"
#include "ebpf_api.h"
#include "ebpf_windows.h"
#include "platform.h"

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

@ -10,7 +10,7 @@
#include <set>
#include <string>
#include <vector>
#include "bpf.h"
#include "bpf/bpf.h"
#include "ebpf_api.h"
#include "ebpf_windows.h"
#include "pins.h"

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

@ -9,9 +9,9 @@
#include <windows.h>
#include <combaseapi.h>
#include <netsh.h>
#include "bpf.h"
#include "bpf/bpf.h"
#include "bpf/libbpf.h"
#include "ebpf_api.h"
#include "libbpf.h"
#include "platform.h"
#include "programs.h"
#include "tokens.h"

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

@ -188,6 +188,8 @@ ebpf_link_get_info(
info->id = link->object.id;
info->prog_id = (link->program) ? ((ebpf_object_t*)link->program)->id : EBPF_ID_NONE;
info->type = BPF_LINK_TYPE_PLAIN;
info->attach_type = BPF_ATTACH_TYPE_UNSPEC; // TODO(#223): get actual integer, and also return attach_type_uuid
*info_size = sizeof(*info);
return EBPF_SUCCESS;

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

@ -872,7 +872,7 @@ ebpf_program_get_info(
(char*)program->parameters.program_name.value,
program->parameters.program_name.length);
info->nr_map_ids = program->count_of_maps;
info->type = BPF_PROG_TYPE_UNKNOWN; // TODO(issue #223): get integer if any.
info->type = BPF_PROG_TYPE_UNSPEC; // TODO(issue #223): get integer if any.
info->type_uuid = *ebpf_program_type(program);
info->pinned_path_count = program->object.pinned_path_count;
info->link_count = program->link_count;

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

@ -45,8 +45,8 @@ import "wtypes.idl";
typedef struct _ebpf_program_load_info
{
// Optional file name.
[string] char* file_name;
// Object name.
[string] char* object_name;
// Optional section name.
[string] char* section_name;
// Optional program name.

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

@ -7,11 +7,11 @@
#include <mutex>
#include <thread>
#include "api_test.h"
#include "bpf/libbpf.h"
#include "catch_wrapper.hpp"
#include "common_tests.h"
#include <io.h>
#include "service_helper.h"
#include "libbpf.h"
#define SAMPLE_PATH ""
#define EBPF_CORE_DRIVER_BINARY_NAME L"ebpfcore.sys"

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

@ -10,14 +10,14 @@
#include <WinSock2.h>
#include <in6addr.h> // Must come after Winsock2.h
#include "bpf.h"
#include "bpf/bpf.h"
#include "bpf/libbpf.h"
#include "catch_wrapper.hpp"
#include "common_tests.h"
#include "ebpf_bind_program_data.h"
#include "ebpf_core.h"
#include "ebpf_xdp_program_data.h"
#include "helpers.h"
#include "libbpf.h"
#include "mock.h"
#include "platform.h"
#include "program_helper.h"

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

@ -4,14 +4,14 @@
#include <windows.h>
#include <netsh.h> // Must be included after windows.h
#include <string.h>
#include "ebpf_epoch.h"
#include "bpf/bpf.h"
#pragma warning(push)
#pragma warning(disable : 4200)
#include "libbpf.h"
#include "bpf/libbpf.h"
#pragma warning(pop)
#include "ebpf_epoch.h"
#include "netsh_test_helper.h"
#include "platform.h"
#include "programs.h"
#include "test_helper.hpp"
TEST_CASE("show disassembly bpf.o", "[netsh][disassembly]")

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

@ -6,7 +6,7 @@
#include <windows.h>
#include <netsh.h> // Must be included after windows.h
#include <string.h>
#include "bpf.h"
#include "bpf/bpf.h"
#include "capture_helper.hpp"
#include "catch_wrapper.hpp"
#include "elf.h"

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

@ -6,10 +6,10 @@
#pragma once
#include <windows.h>
#include "bpf.h"
#include "bpf/bpf.h"
#include "bpf/libbpf.h"
#include "ebpf_api.h"
#include "ebpf_result.h"
#include "libbpf.h"
void
ebpf_test_pinned_map_enum();

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

@ -4,7 +4,7 @@
#include <windows.h>
#include <netsh.h> // Must be included after windows.h
#include <string.h>
#include "bpf.h"
#include "bpf/bpf.h"
#include "capture_helper.hpp"
#include "catch_wrapper.hpp"
#include "elf.h"
@ -129,4 +129,4 @@ _run_netsh_command(
*result = NO_ERROR;
return capture.get_stdout_contents();
}
}

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

@ -5,9 +5,9 @@
* @brief Utility functions for loading and attaching test eBPF programs.
*/
#include "bpf.h"
#include "bpf/bpf.h"
#include "bpf/libbpf.h"
#include "helpers.h"
#include "libbpf.h"
typedef class _program_load_attach_helper
{

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

@ -169,8 +169,8 @@ static const char*
_ebpf_map_type_t_to_string(ebpf_map_type_t type)
{
switch (type) {
case BPF_MAP_TYPE_UNSPECIFIED:
return "BPF_MAP_TYPE_UNSPECIFIED";
case BPF_MAP_TYPE_UNSPEC:
return "BPF_MAP_TYPE_UNSPEC";
case BPF_MAP_TYPE_HASH:
return "BPF_MAP_TYPE_HASH";
case BPF_MAP_TYPE_ARRAY:

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

@ -10,7 +10,7 @@
#include "ebpf_object.h"
#include "ebpf_program.h"
#include "helpers.h"
#include "libbpf.h"
#include "bpf/libbpf.h"
#include "performance_measure.h"
#define PERF_TEST(FUNCTION) \

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

@ -7,10 +7,10 @@
#include <mutex>
#include <thread>
#include "bpf.h"
#include "bpf/bpf.h"
#include "bpf/libbpf.h"
#include "catch_wrapper.hpp"
#include "common_tests.h"
#include "libbpf.h"
#include "netsh_test_helper.h"
#include "program_helper.h"
#include "service_helper.h"
@ -161,4 +161,4 @@ TEST_CASE("netsh_add_program_test_sample_ebpf", "[sample_ext_test]")
_run_netsh_command(handle_ebpf_add_program, L"test_sample_ebpf.o", L"pinned=none", nullptr, &result);
REQUIRE(result == NO_ERROR);
REQUIRE(output.starts_with("Loaded with"));
}
}

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

@ -3,13 +3,13 @@
#include <io.h>
#include <WinSock2.h>
#include "bpf.h"
#include "catch_wrapper.hpp"
#include "helpers.h"
#include "bpf/bpf.h"
#pragma warning(push)
#pragma warning(disable : 4200)
#include "libbpf.h"
#include "bpf/libbpf.h"
#pragma warning(pop)
#include "catch_wrapper.hpp"
#include "helpers.h"
#include "platform.h"
#include "program_helper.h"
#include "test_helper.hpp"
@ -875,3 +875,49 @@ TEST_CASE("libbpf_prog_type_by_name", "[libbpf]")
REQUIRE(prog_type == BPF_PROG_TYPE_XDP);
REQUIRE(expected_attach_type == BPF_ATTACH_TYPE_XDP);
}
TEST_CASE("libbpf_get_error", "[libbpf]")
{
errno = 123;
REQUIRE(libbpf_get_error(nullptr) == -123);
}
TEST_CASE("bpf_object__load", "[libbpf]")
{
_test_helper_libbpf test_helper;
const char* my_object_name = "my_object_name";
struct bpf_object_open_opts opts = {0};
opts.object_name = my_object_name;
struct bpf_object* object = bpf_object__open_file("droppacket.o", &opts);
REQUIRE(object != nullptr);
REQUIRE(strcmp(bpf_object__name(object), my_object_name) == 0);
struct bpf_program* program = bpf_object__find_program_by_name(object, "DropPacket");
REQUIRE(program != nullptr);
REQUIRE(bpf_program__fd(program) == ebpf_fd_invalid);
REQUIRE(bpf_program__get_type(program) == BPF_PROG_TYPE_XDP);
// Make sure we can override the program type if desired.
bpf_program__set_type(program, BPF_PROG_TYPE_BIND);
REQUIRE(bpf_program__get_type(program) == BPF_PROG_TYPE_BIND);
bpf_program__set_type(program, BPF_PROG_TYPE_XDP);
// Trying to attach the program should fail since it's not loaded yet.
bpf_link* link = bpf_program__attach(program);
REQUIRE(link == nullptr);
REQUIRE(libbpf_get_error(link) == -EINVAL);
// Load the program.
REQUIRE(bpf_object__load(object) == 0);
// Attach should now succeed.
link = bpf_program__attach(program);
REQUIRE(link != nullptr);
REQUIRE(bpf_link__destroy(link) == 0);
bpf_object__close(object);
}

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

@ -5,9 +5,9 @@
#include <iostream>
#include <string>
#include <windows.h>
#include "bpf.h"
#include "bpf/bpf.h"
#include "bpf/libbpf.h"
#include "ebpf_api.h"
#include "libbpf.h"
const char* process_map = "port_quota::process_map";
const char* limits_map = "port_quota::limits_map";