Add DETACH operation to detach a program from a hook. (#352)
* add UNLINK operation * Some fixes: 1. Added attach_lock to synchronize multiple detach calls on same link object. 2. ebpf_extension_unload() should be called from ebpf_link_detach_program() 3. Changed return type of ebpf_program_get_properties to void. * Update libs/execution_context/ebpf_program.c Co-authored-by: Dave Thaler <dthaler@microsoft.com>
This commit is contained in:
Родитель
8006f181e0
Коммит
14248601d3
|
@ -354,6 +354,17 @@ extern "C"
|
|||
uint32_t
|
||||
ebpf_api_link_program(ebpf_handle_t program_handle, ebpf_attach_type_t attach_type, ebpf_handle_t* link_handle);
|
||||
|
||||
/**
|
||||
* @brief Detach the eBPF program from the link.
|
||||
*
|
||||
* @param[in] link_handle Handle to the link.
|
||||
*
|
||||
* @retval ERROR_SUCCESS The operations succeeded.
|
||||
* @retval ERROR_INVALID_PARAMETER The link handle is invalid.
|
||||
*/
|
||||
uint32_t
|
||||
ebpf_api_unlink_program(ebpf_handle_t link_handle);
|
||||
|
||||
/**
|
||||
* @brief Close an eBPF handle.
|
||||
*
|
||||
|
|
|
@ -556,6 +556,15 @@ ebpf_api_link_program(ebpf_handle_t program_handle, ebpf_attach_type_t attach_ty
|
|||
return retval;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ebpf_api_unlink_program(ebpf_handle_t link_handle)
|
||||
{
|
||||
ebpf_operation_unlink_program_request_t request = {
|
||||
sizeof(request), EBPF_OPERATION_UNLINK_PROGRAM, reinterpret_cast<uint64_t>(link_handle)};
|
||||
|
||||
return invoke_ioctl(request);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ebpf_api_close_handle(ebpf_handle_t handle)
|
||||
{
|
||||
|
|
|
@ -552,9 +552,7 @@ _ebpf_core_protocol_query_program_info(
|
|||
if (retval != EBPF_SUCCESS)
|
||||
goto Done;
|
||||
|
||||
retval = ebpf_program_get_properties(program, ¶meters);
|
||||
if (retval != EBPF_SUCCESS)
|
||||
goto Done;
|
||||
ebpf_program_get_properties(program, ¶meters);
|
||||
|
||||
required_reply_length = EBPF_OFFSET_OF(struct _ebpf_operation_query_program_info_reply, data) +
|
||||
parameters.program_name.length + parameters.section_name.length;
|
||||
|
@ -665,11 +663,32 @@ _ebpf_core_protocol_link_program(
|
|||
goto Done;
|
||||
|
||||
Done:
|
||||
if (retval != EBPF_SUCCESS) {
|
||||
ebpf_link_detach_program(link);
|
||||
}
|
||||
ebpf_object_release_reference((ebpf_object_t*)program);
|
||||
ebpf_object_release_reference((ebpf_object_t*)link);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
_ebpf_core_protocol_unlink_program(_In_ const ebpf_operation_unlink_program_request_t* request)
|
||||
{
|
||||
ebpf_result_t retval;
|
||||
ebpf_link_t* link = NULL;
|
||||
|
||||
retval = ebpf_reference_object_by_handle(request->link_handle, EBPF_OBJECT_LINK, (ebpf_object_t**)&link);
|
||||
if (retval != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ebpf_link_detach_program(link);
|
||||
|
||||
Done:
|
||||
ebpf_object_release_reference((ebpf_object_t*)link);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
_ebpf_core_protocol_close_handle(_In_ const ebpf_operation_close_handle_request_t* request)
|
||||
{
|
||||
|
@ -966,6 +985,11 @@ static ebpf_protocol_handler_t _ebpf_protocol_handlers[] = {
|
|||
sizeof(ebpf_operation_link_program_request_t),
|
||||
sizeof(ebpf_operation_link_program_reply_t)},
|
||||
|
||||
// EBPF_OPERATION_UNLINK_PROGRAM
|
||||
{(ebpf_result_t(__cdecl*)(const void*))_ebpf_core_protocol_unlink_program,
|
||||
sizeof(ebpf_operation_unlink_program_request_t),
|
||||
0},
|
||||
|
||||
// EBPF_OPERATION_CLOSE_HANDLE
|
||||
{(ebpf_result_t(__cdecl*)(const void*))_ebpf_core_protocol_close_handle,
|
||||
sizeof(ebpf_operation_close_handle_request_t),
|
||||
|
|
|
@ -16,6 +16,7 @@ typedef struct _ebpf_link
|
|||
ebpf_program_type_t program_type;
|
||||
ebpf_extension_data_t client_data;
|
||||
ebpf_extension_client_t* extension_client_context;
|
||||
ebpf_lock_t attach_lock;
|
||||
|
||||
void* provider_binding_context;
|
||||
} ebpf_link_t;
|
||||
|
@ -34,9 +35,7 @@ static void
|
|||
_ebpf_link_free(ebpf_object_t* object)
|
||||
{
|
||||
ebpf_link_t* link = (ebpf_link_t*)object;
|
||||
ebpf_extension_unload(link->extension_client_context);
|
||||
ebpf_link_detach_program(link);
|
||||
ebpf_free(link->client_data.data);
|
||||
ebpf_lock_destroy(&link->attach_lock);
|
||||
ebpf_epoch_free(link);
|
||||
}
|
||||
|
||||
|
@ -50,6 +49,7 @@ ebpf_link_create(ebpf_link_t** link)
|
|||
memset(*link, 0, sizeof(ebpf_link_t));
|
||||
|
||||
ebpf_object_initialize(&(*link)->object, EBPF_OBJECT_LINK, _ebpf_link_free);
|
||||
ebpf_lock_create(&(*link)->attach_lock);
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -106,42 +106,46 @@ ebpf_link_attach_program(ebpf_link_t* link, ebpf_program_t* program)
|
|||
{
|
||||
ebpf_result_t return_value = EBPF_SUCCESS;
|
||||
ebpf_program_parameters_t program_parameters;
|
||||
ebpf_lock_state_t state;
|
||||
state = ebpf_lock_lock(&link->attach_lock);
|
||||
if (link->program) {
|
||||
return_value = EBPF_INVALID_ARGUMENT;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
link->program = program;
|
||||
ebpf_object_acquire_reference((ebpf_object_t*)program);
|
||||
|
||||
return_value = ebpf_program_get_properties(program, &program_parameters);
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
goto Done;
|
||||
}
|
||||
|
||||
ebpf_program_get_properties(program, &program_parameters);
|
||||
if (memcmp(&program_parameters.program_type, &link->program_type, sizeof(link->program_type)) != 0) {
|
||||
return_value = EBPF_INVALID_ARGUMENT;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
link->program = program;
|
||||
ebpf_program_attach_link(program, link);
|
||||
|
||||
Done:
|
||||
if (return_value != EBPF_SUCCESS) {
|
||||
if (link->program == program) {
|
||||
ebpf_object_release_reference((ebpf_object_t*)program);
|
||||
link->program = NULL;
|
||||
}
|
||||
}
|
||||
ebpf_lock_unlock(&link->attach_lock, state);
|
||||
return return_value;
|
||||
}
|
||||
|
||||
void
|
||||
ebpf_link_detach_program(ebpf_link_t* link)
|
||||
{
|
||||
if (!link->program)
|
||||
ebpf_lock_state_t state;
|
||||
ebpf_program_t* program;
|
||||
state = ebpf_lock_lock(&link->attach_lock);
|
||||
if (!link->program) {
|
||||
ebpf_lock_unlock(&link->attach_lock, state);
|
||||
return;
|
||||
}
|
||||
|
||||
ebpf_object_release_reference((ebpf_object_t*)link->program);
|
||||
program = link->program;
|
||||
link->program = NULL;
|
||||
ebpf_lock_unlock(&link->attach_lock, state);
|
||||
|
||||
ebpf_program_detach_link(program, link);
|
||||
|
||||
ebpf_extension_unload(link->extension_client_context);
|
||||
ebpf_free(link->client_data.data);
|
||||
}
|
||||
|
||||
static ebpf_result_t
|
||||
|
|
|
@ -47,8 +47,21 @@ typedef struct _ebpf_program
|
|||
ebpf_trampoline_table_t* trampoline_table;
|
||||
|
||||
ebpf_epoch_work_item_t* cleanup_work_item;
|
||||
|
||||
ebpf_list_entry_t links;
|
||||
ebpf_lock_t links_lock;
|
||||
} ebpf_program_t;
|
||||
|
||||
static void
|
||||
_ebpf_program_detach_links(_Inout_ ebpf_program_t* program)
|
||||
{
|
||||
while (!ebpf_list_is_empty(&program->links)) {
|
||||
ebpf_list_entry_t* entry = program->links.Flink;
|
||||
ebpf_object_t* object = CONTAINING_RECORD(entry, ebpf_object_t, object_list_entry);
|
||||
ebpf_link_detach_program((ebpf_link_t*)object);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_ebpf_program_program_info_provider_changed(
|
||||
_In_ void* client_binding_context,
|
||||
|
@ -110,8 +123,13 @@ static void
|
|||
_ebpf_program_free(ebpf_object_t* object)
|
||||
{
|
||||
ebpf_program_t* program = (ebpf_program_t*)object;
|
||||
if (!program)
|
||||
if (!program) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Detach from all the attach points.
|
||||
_ebpf_program_detach_links(program);
|
||||
ebpf_assert(ebpf_list_is_empty(&program->links));
|
||||
|
||||
ebpf_epoch_schedule_work_item(program->cleanup_work_item);
|
||||
}
|
||||
|
@ -129,6 +147,8 @@ _ebpf_program_epoch_free(void* context)
|
|||
ebpf_program_t* program = (ebpf_program_t*)context;
|
||||
size_t index;
|
||||
|
||||
ebpf_lock_destroy(&program->links_lock);
|
||||
|
||||
ebpf_extension_unload(program->general_helper_extension_client);
|
||||
ebpf_extension_unload(program->program_info_client);
|
||||
|
||||
|
@ -275,6 +295,9 @@ ebpf_program_initialize(ebpf_program_t* program, const ebpf_program_parameters_t
|
|||
goto Done;
|
||||
}
|
||||
|
||||
ebpf_list_initialize(&program->links);
|
||||
ebpf_lock_create(&program->links_lock);
|
||||
|
||||
return_value = EBPF_SUCCESS;
|
||||
|
||||
Done:
|
||||
|
@ -283,11 +306,10 @@ Done:
|
|||
return return_value;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
void
|
||||
ebpf_program_get_properties(ebpf_program_t* program, ebpf_program_parameters_t* program_parameters)
|
||||
{
|
||||
*program_parameters = program->parameters;
|
||||
return EBPF_SUCCESS;
|
||||
}
|
||||
|
||||
ebpf_result_t
|
||||
|
@ -550,3 +572,29 @@ ebpf_program_free_program_info(_In_opt_ _Post_invalid_ ebpf_program_info_t* prog
|
|||
ebpf_free(program_info);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ebpf_program_attach_link(_Inout_ ebpf_program_t* program, _Inout_ ebpf_link_t* link)
|
||||
{
|
||||
// Acquire "attach" reference on the link object.
|
||||
ebpf_object_acquire_reference((ebpf_object_t*)link);
|
||||
|
||||
// Insert the link in the attach list.
|
||||
ebpf_lock_state_t state;
|
||||
state = ebpf_lock_lock(&program->links_lock);
|
||||
ebpf_list_insert_tail(&program->links, &((ebpf_object_t*)link)->object_list_entry);
|
||||
ebpf_lock_unlock(&program->links_lock, state);
|
||||
}
|
||||
|
||||
void
|
||||
ebpf_program_detach_link(_Inout_ ebpf_program_t* program, _Inout_ ebpf_link_t* link)
|
||||
{
|
||||
// Remove the link from the attach list.
|
||||
ebpf_lock_state_t state;
|
||||
state = ebpf_lock_lock(&program->links_lock);
|
||||
ebpf_list_remove_entry(&((ebpf_object_t*)link)->object_list_entry);
|
||||
ebpf_lock_unlock(&program->links_lock, state);
|
||||
|
||||
// Release the "attach" reference.
|
||||
ebpf_object_release_reference((ebpf_object_t*)link);
|
||||
}
|
||||
|
|
|
@ -64,11 +64,8 @@ extern "C"
|
|||
*
|
||||
* @param[in] program Program instance to query.
|
||||
* @param[in] program_parameters Parameters of the program.
|
||||
* @retval EBPF_SUCCESS The operation was successful.
|
||||
* @retval EBPF_NO_MEMORY Unable to allocate resources for this
|
||||
* program instance.
|
||||
*/
|
||||
ebpf_result_t
|
||||
void
|
||||
ebpf_program_get_properties(ebpf_program_t* program, ebpf_program_parameters_t* program_parameters);
|
||||
|
||||
/**
|
||||
|
@ -158,6 +155,24 @@ extern "C"
|
|||
ebpf_program_get_helper_function_address(
|
||||
const ebpf_program_t* program, uint32_t helper_function_id, uint64_t* address);
|
||||
|
||||
/**
|
||||
* @brief Attach a link object to an eBPF program.
|
||||
*
|
||||
* @param[in] program Program to attach to the link object.
|
||||
* @param[in] link The link object.
|
||||
*/
|
||||
void
|
||||
ebpf_program_attach_link(_Inout_ ebpf_program_t* program, _Inout_ ebpf_link_t* link);
|
||||
|
||||
/**
|
||||
* @brief Detach a link object from the eBPF program it is attached to.
|
||||
*
|
||||
* @param[in] program Program to detach to the link object from.
|
||||
* @param[in] link The link object.
|
||||
*/
|
||||
void
|
||||
ebpf_program_detach_link(_Inout_ ebpf_program_t* program, _Inout_ ebpf_link_t* link);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@ typedef enum _ebpf_operation_id
|
|||
EBPF_OPERATION_UPDATE_PINNING,
|
||||
EBPF_OPERATION_GET_PINNING,
|
||||
EBPF_OPERATION_LINK_PROGRAM,
|
||||
EBPF_OPERATION_UNLINK_PROGRAM,
|
||||
EBPF_OPERATION_CLOSE_HANDLE,
|
||||
EBPF_OPERATION_GET_EC_FUNCTION,
|
||||
EBPF_OPERATION_GET_PROGRAM_INFO,
|
||||
|
@ -233,6 +234,12 @@ typedef struct _ebpf_operation_link_program_reply
|
|||
uint64_t link_handle;
|
||||
} ebpf_operation_link_program_reply_t;
|
||||
|
||||
typedef struct _ebpf_operation_unlink_program_request
|
||||
{
|
||||
struct _ebpf_operation_header header;
|
||||
uint64_t link_handle;
|
||||
} ebpf_operation_unlink_program_request_t;
|
||||
|
||||
typedef struct _ebpf_operation_close_handle_request
|
||||
{
|
||||
struct _ebpf_operation_header header;
|
||||
|
|
|
@ -136,7 +136,7 @@ TEST_CASE("program", "[execution_context]")
|
|||
|
||||
REQUIRE(ebpf_program_initialize(program.get(), &program_parameters) == EBPF_SUCCESS);
|
||||
|
||||
REQUIRE(ebpf_program_get_properties(program.get(), &returned_program_parameters) == EBPF_SUCCESS);
|
||||
ebpf_program_get_properties(program.get(), &returned_program_parameters);
|
||||
REQUIRE(
|
||||
memcmp(
|
||||
&program_parameters.program_type,
|
||||
|
|
|
@ -34,7 +34,7 @@ _ebpf_object_tracking_list_insert(ebpf_object_t* object)
|
|||
{
|
||||
ebpf_lock_state_t state;
|
||||
state = ebpf_lock_lock(&_ebpf_object_tracking_list_lock);
|
||||
ebpf_list_insert_tail(&_ebpf_object_tracking_list, &object->entry);
|
||||
ebpf_list_insert_tail(&_ebpf_object_tracking_list, &object->global_list_entry);
|
||||
ebpf_lock_unlock(&_ebpf_object_tracking_list_lock, state);
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ _ebpf_object_tracking_list_remove(ebpf_object_t* object)
|
|||
{
|
||||
ebpf_lock_state_t state;
|
||||
state = ebpf_lock_lock(&_ebpf_object_tracking_list_lock);
|
||||
ebpf_list_remove_entry(&object->entry);
|
||||
ebpf_list_remove_entry(&object->global_list_entry);
|
||||
ebpf_lock_unlock(&_ebpf_object_tracking_list_lock, state);
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,8 @@ ebpf_object_initialize(ebpf_object_t* object, ebpf_object_type_t object_type, eb
|
|||
object->reference_count = 1;
|
||||
object->type = object_type;
|
||||
object->free_function = free_function;
|
||||
ebpf_list_initialize(&object->entry);
|
||||
ebpf_list_initialize(&object->global_list_entry);
|
||||
ebpf_list_initialize(&object->object_list_entry);
|
||||
_ebpf_object_tracking_list_insert(object);
|
||||
}
|
||||
|
||||
|
@ -133,10 +134,10 @@ ebpf_object_reference_next_object(ebpf_object_t* previous_object, ebpf_object_ty
|
|||
if (previous_object == NULL)
|
||||
entry = _ebpf_object_tracking_list.Flink;
|
||||
else
|
||||
entry = previous_object->entry.Flink;
|
||||
entry = previous_object->global_list_entry.Flink;
|
||||
|
||||
for (; entry != &_ebpf_object_tracking_list; entry = entry->Flink) {
|
||||
ebpf_object_t* object = EBPF_FROM_FIELD(ebpf_object_t, entry, entry);
|
||||
ebpf_object_t* object = EBPF_FROM_FIELD(ebpf_object_t, global_list_entry, entry);
|
||||
if (object->type == type) {
|
||||
*next_object = object;
|
||||
ebpf_object_acquire_reference(object);
|
||||
|
|
|
@ -28,7 +28,10 @@ extern "C"
|
|||
volatile int32_t reference_count;
|
||||
ebpf_object_type_t type;
|
||||
ebpf_free_object_t free_function;
|
||||
ebpf_list_entry_t entry;
|
||||
// Used to insert object in the global tracking list.
|
||||
ebpf_list_entry_t global_list_entry;
|
||||
// Used to insert object in an object specific list.
|
||||
ebpf_list_entry_t object_list_entry;
|
||||
} ebpf_object_t;
|
||||
|
||||
/**
|
||||
|
|
|
@ -160,7 +160,7 @@ droppacket_test(ebpf_execution_type_t execution_type)
|
|||
ebpf_handle_t map_handle;
|
||||
uint32_t count_of_map_handle = 1;
|
||||
uint32_t result = 0;
|
||||
const char* error_message = NULL;
|
||||
const char* error_message = nullptr;
|
||||
|
||||
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
|
||||
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
|
||||
|
@ -230,7 +230,7 @@ divide_by_zero_test(ebpf_execution_type_t execution_type)
|
|||
ebpf_handle_t map_handle;
|
||||
uint32_t count_of_map_handle = 1;
|
||||
uint32_t result = 0;
|
||||
const char* error_message = NULL;
|
||||
const char* error_message = nullptr;
|
||||
|
||||
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
|
||||
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
|
||||
|
@ -318,7 +318,7 @@ bindmonitor_test(ebpf_execution_type_t execution_type)
|
|||
_test_helper_end_to_end test_helper;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
const char* error_message = NULL;
|
||||
const char* error_message = nullptr;
|
||||
ebpf_handle_t map_handles[2];
|
||||
uint32_t count_of_map_handles = 2;
|
||||
uint64_t fake_pid = 12345;
|
||||
|
@ -461,7 +461,7 @@ TEST_CASE("map_pinning_test", "[end_to_end]")
|
|||
_test_helper_end_to_end test_helper;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
const char* error_message = NULL;
|
||||
const char* error_message = nullptr;
|
||||
ebpf_handle_t map_handles[4] = {0};
|
||||
uint32_t count_of_map_handles = 2;
|
||||
uint32_t result;
|
||||
|
@ -542,7 +542,7 @@ TEST_CASE("enumerate_and_query_maps", "[end_to_end]")
|
|||
_test_helper_end_to_end test_helper;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
const char* error_message = NULL;
|
||||
const char* error_message = nullptr;
|
||||
ebpf_handle_t map_handles[4];
|
||||
uint32_t count_of_map_handles = 2;
|
||||
uint32_t result;
|
||||
|
@ -607,7 +607,7 @@ TEST_CASE("enumerate_and_query_programs", "[end_to_end]")
|
|||
ebpf_handle_t program_handle;
|
||||
ebpf_handle_t map_handles[3];
|
||||
uint32_t count_of_map_handle = 1;
|
||||
const char* error_message = NULL;
|
||||
const char* error_message = nullptr;
|
||||
uint32_t result;
|
||||
const char* file_name = nullptr;
|
||||
const char* section_name = nullptr;
|
||||
|
@ -674,3 +674,148 @@ TEST_CASE("pinned_map_enum", "[end_to_end]")
|
|||
|
||||
ebpf_test_pinned_map_enum();
|
||||
}
|
||||
|
||||
TEST_CASE("implicit_detach", "[end_to_end]")
|
||||
{
|
||||
// This test case does the following:
|
||||
// 1. Close program handle. An implicit detach should happen and program
|
||||
// object should be deleted.
|
||||
// 2. Close link handle. The link object should be deleted.
|
||||
|
||||
_test_helper_end_to_end test_helper;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
ebpf_handle_t map_handle;
|
||||
uint32_t count_of_map_handle = 1;
|
||||
uint32_t result = 0;
|
||||
const char* error_message = nullptr;
|
||||
|
||||
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
|
||||
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
|
||||
|
||||
result = ebpf_api_load_program(
|
||||
SAMPLE_PATH "droppacket.o",
|
||||
"xdp",
|
||||
EBPF_EXECUTION_INTERPRET,
|
||||
&program_handle,
|
||||
&count_of_map_handle,
|
||||
&map_handle,
|
||||
&error_message);
|
||||
|
||||
if (error_message) {
|
||||
printf("ebpf_api_load_program failed with %s\n", error_message);
|
||||
ebpf_free_string(error_message);
|
||||
error_message = nullptr;
|
||||
}
|
||||
REQUIRE(result == EBPF_SUCCESS);
|
||||
|
||||
REQUIRE(hook.attach(program_handle) == EBPF_SUCCESS);
|
||||
|
||||
// Close program handle. That should detach the program from the hook
|
||||
// and unload the program.
|
||||
ebpf_api_close_handle(program_handle);
|
||||
program_handle = INVALID_HANDLE_VALUE;
|
||||
REQUIRE(ebpf_api_get_next_program(program_handle, &program_handle) == EBPF_SUCCESS);
|
||||
REQUIRE(program_handle == INVALID_HANDLE_VALUE);
|
||||
|
||||
// Close link handle. This should delete the link object.
|
||||
// ebpf_object_tracking_terminate() which is called when the test
|
||||
// exits checks if all the objects in EC have been deleted.
|
||||
hook.close_handle();
|
||||
}
|
||||
|
||||
TEST_CASE("explicit_detach", "[end_to_end]")
|
||||
{
|
||||
// This test case does the following:
|
||||
// 1. Call detach API and then close the link handle. The link onject
|
||||
// should be deleted.
|
||||
// 2. Close program handle. The program object should be deleted.
|
||||
|
||||
_test_helper_end_to_end test_helper;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
ebpf_handle_t map_handle;
|
||||
uint32_t count_of_map_handle = 1;
|
||||
uint32_t result = 0;
|
||||
const char* error_message = nullptr;
|
||||
|
||||
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
|
||||
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
|
||||
|
||||
result = ebpf_api_load_program(
|
||||
SAMPLE_PATH "droppacket.o",
|
||||
"xdp",
|
||||
EBPF_EXECUTION_INTERPRET,
|
||||
&program_handle,
|
||||
&count_of_map_handle,
|
||||
&map_handle,
|
||||
&error_message);
|
||||
|
||||
if (error_message) {
|
||||
printf("ebpf_api_load_program failed with %s\n", error_message);
|
||||
ebpf_free_string(error_message);
|
||||
error_message = nullptr;
|
||||
}
|
||||
REQUIRE(result == EBPF_SUCCESS);
|
||||
|
||||
REQUIRE(hook.attach(program_handle) == EBPF_SUCCESS);
|
||||
|
||||
// Detach and close link handle.
|
||||
// ebpf_object_tracking_terminate() which is called when the test
|
||||
// exits checks if all the objects in EC have been deleted.
|
||||
hook.detach();
|
||||
|
||||
// Close program handle.
|
||||
ebpf_api_close_handle(program_handle);
|
||||
program_handle = INVALID_HANDLE_VALUE;
|
||||
REQUIRE(ebpf_api_get_next_program(program_handle, &program_handle) == EBPF_SUCCESS);
|
||||
REQUIRE(program_handle == INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
TEST_CASE("implicit_explicit_detach", "[end_to_end]")
|
||||
{
|
||||
// This test case does the following:
|
||||
// 1. Close the program handle so that an implicit detach happens.
|
||||
// 2. Explicitly call detach and then close the link handle. Explicit
|
||||
// detach in this step should be a no-op.
|
||||
|
||||
_test_helper_end_to_end test_helper;
|
||||
|
||||
ebpf_handle_t program_handle;
|
||||
ebpf_handle_t map_handle;
|
||||
uint32_t count_of_map_handle = 1;
|
||||
uint32_t result = 0;
|
||||
const char* error_message = nullptr;
|
||||
|
||||
single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
|
||||
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
|
||||
|
||||
result = ebpf_api_load_program(
|
||||
SAMPLE_PATH "droppacket.o",
|
||||
"xdp",
|
||||
EBPF_EXECUTION_INTERPRET,
|
||||
&program_handle,
|
||||
&count_of_map_handle,
|
||||
&map_handle,
|
||||
&error_message);
|
||||
|
||||
if (error_message) {
|
||||
printf("ebpf_api_load_program failed with %s\n", error_message);
|
||||
ebpf_free_string(error_message);
|
||||
error_message = nullptr;
|
||||
}
|
||||
REQUIRE(result == EBPF_SUCCESS);
|
||||
|
||||
REQUIRE(hook.attach(program_handle) == EBPF_SUCCESS);
|
||||
// Close program handle. That should detach the program from the hook
|
||||
// and unload the program.
|
||||
ebpf_api_close_handle(program_handle);
|
||||
program_handle = INVALID_HANDLE_VALUE;
|
||||
REQUIRE(ebpf_api_get_next_program(program_handle, &program_handle) == EBPF_SUCCESS);
|
||||
REQUIRE(program_handle == INVALID_HANDLE_VALUE);
|
||||
|
||||
// Detach and close link handle.
|
||||
// ebpf_object_tracking_terminate() which is called when the test
|
||||
// exits checks if all the objects in EC have been deleted.
|
||||
hook.detach();
|
||||
}
|
|
@ -51,6 +51,13 @@ typedef class _single_instance_hook
|
|||
|
||||
void
|
||||
detach()
|
||||
{
|
||||
ebpf_api_unlink_program(link_handle);
|
||||
ebpf_api_close_handle(link_handle);
|
||||
}
|
||||
|
||||
void
|
||||
close_handle()
|
||||
{
|
||||
ebpf_api_close_handle(link_handle);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче