From 14248601d332ef6336047ff916aa9f5cb4dfd890 Mon Sep 17 00:00:00 2001 From: saxena-anurag <43585259+saxena-anurag@users.noreply.github.com> Date: Fri, 30 Jul 2021 17:17:16 -0700 Subject: [PATCH] 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 --- include/ebpf_api.h | 11 ++ libs/api/ebpf_api.cpp | 9 + libs/execution_context/ebpf_core.c | 30 +++- libs/execution_context/ebpf_link.c | 42 ++--- libs/execution_context/ebpf_program.c | 54 +++++- libs/execution_context/ebpf_program.h | 23 ++- libs/execution_context/ebpf_protocol.h | 7 + .../unit/execution_context_unit_test.cpp | 2 +- libs/platform/ebpf_object.c | 11 +- libs/platform/ebpf_object.h | 5 +- tests/end_to_end/end_to_end.cpp | 157 +++++++++++++++++- tests/end_to_end/helpers.h | 7 + 12 files changed, 316 insertions(+), 42 deletions(-) diff --git a/include/ebpf_api.h b/include/ebpf_api.h index d286bcf36..f5ce30be6 100644 --- a/include/ebpf_api.h +++ b/include/ebpf_api.h @@ -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. * diff --git a/libs/api/ebpf_api.cpp b/libs/api/ebpf_api.cpp index 3198a2eba..a781411c1 100644 --- a/libs/api/ebpf_api.cpp +++ b/libs/api/ebpf_api.cpp @@ -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(link_handle)}; + + return invoke_ioctl(request); +} + uint32_t ebpf_api_close_handle(ebpf_handle_t handle) { diff --git a/libs/execution_context/ebpf_core.c b/libs/execution_context/ebpf_core.c index f5385f90d..521bc2c4d 100644 --- a/libs/execution_context/ebpf_core.c +++ b/libs/execution_context/ebpf_core.c @@ -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), diff --git a/libs/execution_context/ebpf_link.c b/libs/execution_context/ebpf_link.c index b1e6fe7f6..ae9d04c53 100644 --- a/libs/execution_context/ebpf_link.c +++ b/libs/execution_context/ebpf_link.c @@ -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 diff --git a/libs/execution_context/ebpf_program.c b/libs/execution_context/ebpf_program.c index db5d287a6..e2ffbf8fd 100644 --- a/libs/execution_context/ebpf_program.c +++ b/libs/execution_context/ebpf_program.c @@ -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); +} diff --git a/libs/execution_context/ebpf_program.h b/libs/execution_context/ebpf_program.h index a55f352f8..0f964d0f4 100644 --- a/libs/execution_context/ebpf_program.h +++ b/libs/execution_context/ebpf_program.h @@ -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 diff --git a/libs/execution_context/ebpf_protocol.h b/libs/execution_context/ebpf_protocol.h index 45f3bf070..930437f04 100644 --- a/libs/execution_context/ebpf_protocol.h +++ b/libs/execution_context/ebpf_protocol.h @@ -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; diff --git a/libs/execution_context/unit/execution_context_unit_test.cpp b/libs/execution_context/unit/execution_context_unit_test.cpp index 80a38fdff..dbbd32699 100644 --- a/libs/execution_context/unit/execution_context_unit_test.cpp +++ b/libs/execution_context/unit/execution_context_unit_test.cpp @@ -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, diff --git a/libs/platform/ebpf_object.c b/libs/platform/ebpf_object.c index ad7fe38a8..15520faa1 100644 --- a/libs/platform/ebpf_object.c +++ b/libs/platform/ebpf_object.c @@ -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); diff --git a/libs/platform/ebpf_object.h b/libs/platform/ebpf_object.h index 6e95a224b..60940dc42 100644 --- a/libs/platform/ebpf_object.h +++ b/libs/platform/ebpf_object.h @@ -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; /** diff --git a/tests/end_to_end/end_to_end.cpp b/tests/end_to_end/end_to_end.cpp index 17742281a..803b25b7f 100644 --- a/tests/end_to_end/end_to_end.cpp +++ b/tests/end_to_end/end_to_end.cpp @@ -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(); +} \ No newline at end of file diff --git a/tests/end_to_end/helpers.h b/tests/end_to_end/helpers.h index d96d4c9b2..1484f0bb4 100644 --- a/tests/end_to_end/helpers.h +++ b/tests/end_to_end/helpers.h @@ -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); }