diff --git a/include/bpf_helper_defs.h b/include/bpf_helper_defs.h index 7d1c0e1c8..64ee5be18 100644 --- a/include/bpf_helper_defs.h +++ b/include/bpf_helper_defs.h @@ -48,6 +48,18 @@ EBPF_HELPER(int64_t, bpf_map_delete_elem, (struct bpf_map * map, void* key)); #define bpf_map_delete_elem ((bpf_map_delete_elem_t)BPF_FUNC_map_delete_elem) #endif +/** + * @brief Get a pointer to an entry in the map and erase that element. + * + * @param[in] map Map to search. + * @param[in] key Key to use when searching map. + * @return Pointer to the value if found or NULL. + */ +EBPF_HELPER(void*, bpf_map_lookup_and_delete_elem, (struct bpf_map * map, void* key)); +#ifndef __doxygen +#define bpf_map_lookup_and_delete_elem ((bpf_map_lookup_and_delete_elem_t)BPF_FUNC_map_lookup_and_delete_elem) +#endif + /** * @brief Perform a tail call into another eBPF program. * @@ -103,13 +115,18 @@ EBPF_HELPER(uint64_t, bpf_ktime_get_ns, ()); #endif /** - * @brief Get a pointer to an entry in the map and erase that element. + * @brief Computes difference of checksum values for two input raw buffers using 1's complement arithmetic. * - * @param[in] map Map to search. - * @param[in] key Key to use when searching map. - * @return Pointer to the value if found or NULL. + * @param[in] from Pointer to first raw buffer. + * @param[in] from_size Length of the "from" buffer. Must be a multiple of 4. + * @param[in] to Pointer to the second raw buffer, whose checksum will be subtracted from that of the "from" buffer. + * @param[in] to_size Length of the "to" buffer. Must be a multiple of 4. + * @param[in] seed An optional integer that can be added to the value, which can be used to carry result of a previous + * csum_diff operation. + * + * @returns The checksum delta on success, or <0 on failure. */ -EBPF_HELPER(void*, bpf_map_lookup_and_delete_elem, (struct bpf_map * map, void* key)); +EBPF_HELPER(int, bpf_csum_diff, (void* from, int from_size, void* to, int to_size, int seed)); #ifndef __doxygen -#define bpf_map_lookup_and_delete_elem ((bpf_map_lookup_and_delete_elem_t)BPF_FUNC_map_lookup_and_delete_elem) -#endif +#define bpf_csum_diff ((bpf_csum_diff_t)BPF_FUNC_csum_diff) +#endif \ No newline at end of file diff --git a/include/ebpf_nethooks.h b/include/ebpf_nethooks.h index b518322a6..7052b6308 100644 --- a/include/ebpf_nethooks.h +++ b/include/ebpf_nethooks.h @@ -47,7 +47,6 @@ xdp_hook_t(xdp_md_t* context); typedef enum { BPF_FUNC_xdp_adjust_head = XDP_EXT_HELPER_FN_BASE + 1, - BPF_FUNC_csum_diff = XDP_EXT_HELPER_FN_BASE + 2, } ebpf_nethook_helper_id_t; /** @@ -64,21 +63,6 @@ EBPF_HELPER(int, bpf_xdp_adjust_head, (xdp_md_t * ctx, int delta)); #define bpf_xdp_adjust_head ((bpf_xdp_adjust_head_t)BPF_FUNC_xdp_adjust_head) #endif -/** - * @brief Compute checksum difference for replacing parts of a network packet buffer. - * - * @param[in] from Pointer to raw buffer that will be replaced. - * @param[in] from_size Length of the "from" buffer. Must be a multiple of 4. - * @param[in] to Pointer to the raw buffer that will replace the previous buffer. - * @param[in] to_size Length of the "to" buffer. Must be a multiple of 4. - * - * @returns The checksum delta on success, or <0 on failure. - */ -EBPF_HELPER(int, bpf_csum_diff, (void* from, int from_size, void* to, int to_size, int seed)); -#ifndef __doxygen -#define bpf_csum_diff ((bpf_csum_diff_t)BPF_FUNC_csum_diff) -#endif - // BIND hook typedef enum _bind_operation diff --git a/include/ebpf_structs.h b/include/ebpf_structs.h index 2b86a6534..83a75b255 100644 --- a/include/ebpf_structs.h +++ b/include/ebpf_structs.h @@ -93,12 +93,13 @@ typedef enum BPF_FUNC_map_lookup_elem = 1, BPF_FUNC_map_update_elem = 2, BPF_FUNC_map_delete_elem = 3, - BPF_FUNC_tail_call = 4, - BPF_FUNC_get_prandom_u32 = 5, - BPF_FUNC_ktime_get_boot_ns = 6, - BPF_FUNC_get_smp_processor_id = 7, - BPF_FUNC_ktime_get_ns = 8, - BPF_FUNC_map_lookup_and_delete_elem = 9, + BPF_FUNC_map_lookup_and_delete_elem = 4, + BPF_FUNC_tail_call = 5, + BPF_FUNC_get_prandom_u32 = 6, + BPF_FUNC_ktime_get_boot_ns = 7, + BPF_FUNC_get_smp_processor_id = 8, + BPF_FUNC_ktime_get_ns = 9, + BPF_FUNC_csum_diff = 10 } ebpf_helper_id_t; // Cross-platform BPF program types. diff --git a/libs/execution_context/ebpf_core.c b/libs/execution_context/ebpf_core.c index fd0be3315..6b93813a3 100644 --- a/libs/execution_context/ebpf_core.c +++ b/libs/execution_context/ebpf_core.c @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation // SPDX-License-Identifier: MIT +#include #include "ebpf_core.h" #include "ebpf_epoch.h" #include "ebpf_handle.h" @@ -29,6 +30,8 @@ static int64_t _ebpf_core_map_update_element(ebpf_map_t* map, const uint8_t* key, const uint8_t* data, uint64_t flags); static int64_t _ebpf_core_map_delete_element(ebpf_map_t* map, const uint8_t* key); +static void* +_ebpf_core_map_find_and_delete_element(_Inout_ ebpf_map_t* map, _In_ const uint8_t* key); // Tail call. static int64_t @@ -44,9 +47,6 @@ _ebpf_core_get_time_ns(); static uint32_t _ebpf_core_get_current_cpu(); -static void* -_ebpf_core_map_find_and_delete_element(_Inout_ ebpf_map_t* map, _In_ const uint8_t* key); - #define EBPF_CORE_GLOBAL_HELPER_EXTENSION_VERSION 0 static ebpf_program_info_t _ebpf_global_helper_program_info = {{"global_helper", NULL, {0}}, 0, NULL}; @@ -56,13 +56,13 @@ static const void* _ebpf_general_helpers[] = { (void*)&_ebpf_core_map_find_element, (void*)&_ebpf_core_map_update_element, (void*)&_ebpf_core_map_delete_element, + (void*)&_ebpf_core_map_find_and_delete_element, (void*)&_ebpf_core_tail_call, (void*)&_ebpf_core_random_uint32, (void*)&_ebpf_core_get_time_since_boot_ns, - (void*)_ebpf_core_get_current_cpu, + (void*)&_ebpf_core_get_current_cpu, (void*)&_ebpf_core_get_time_ns, - (void*)&_ebpf_core_map_find_and_delete_element, -}; + (void*)&ebpf_core_csum_diff}; static ebpf_extension_provider_t* _ebpf_global_helper_function_provider_context = NULL; static ebpf_helper_function_addresses_t _ebpf_global_helper_function_dispatch_table = { @@ -1194,6 +1194,19 @@ _ebpf_core_map_delete_element(ebpf_map_t* map, const uint8_t* key) return -ebpf_map_delete_entry(map, 0, key, EBPF_MAP_FLAG_HELPER); } +static void* +_ebpf_core_map_find_and_delete_element(_Inout_ ebpf_map_t* map, _In_ const uint8_t* key) +{ + ebpf_result_t retval; + uint8_t* value; + retval = ebpf_map_find_entry( + map, 0, key, sizeof(&value), (uint8_t*)&value, EBPF_MAP_FLAG_HELPER | EPBF_MAP_FIND_FLAG_DELETE); + if (retval != EBPF_SUCCESS) + return NULL; + else + return value; +} + static int64_t _ebpf_core_tail_call(void* context, ebpf_map_t* map, uint32_t index) { @@ -1235,17 +1248,35 @@ _ebpf_core_get_current_cpu() return ebpf_get_current_cpu(); } -static void* -_ebpf_core_map_find_and_delete_element(_Inout_ ebpf_map_t* map, _In_ const uint8_t* key) +int +ebpf_core_csum_diff( + _In_reads_bytes_opt_(from_size) const void* from, + int from_size, + _In_reads_bytes_opt_(to_size) const void* to, + int to_size, + int seed) { - ebpf_result_t retval; - uint8_t* value; - retval = ebpf_map_find_entry( - map, 0, key, sizeof(&value), (uint8_t*)&value, EBPF_MAP_FLAG_HELPER | EPBF_MAP_FIND_FLAG_DELETE); - if (retval != EBPF_SUCCESS) - return NULL; - else - return value; + int csum_diff = -EINVAL; + + if ((from_size % 4 != 0) || (to_size % 4 != 0)) + // size of buffers should be a multiple of 4. + goto Exit; + + csum_diff = seed; + if (to != NULL) + for (int i = 0; i < to_size / 2; i++) + csum_diff += (uint16_t)(*((uint16_t*)to + i)); + if (from != NULL) + for (int i = 0; i < from_size / 2; i++) + csum_diff += (uint16_t)(~*((uint16_t*)from + i)); + + // Adding 16-bit unsigned integers or their one's complement will produce a positive 32-bit integer, + // unless the length of the buffers is so long, that the signed 32 bit output overflows and produces a negative + // result. + if (csum_diff < 0) + csum_diff = -EINVAL; +Exit: + return csum_diff; } typedef struct _ebpf_protocol_handler @@ -1461,4 +1492,4 @@ ebpf_core_invoke_protocol_handler( ebpf_restore_current_thread_affinity(old_affinity_mask); return retval; -} +} \ No newline at end of file diff --git a/libs/execution_context/ebpf_core.h b/libs/execution_context/ebpf_core.h index 906b2ad69..692448548 100644 --- a/libs/execution_context/ebpf_core.h +++ b/libs/execution_context/ebpf_core.h @@ -73,6 +73,26 @@ extern "C" ebpf_core_get_protocol_handler_properties( ebpf_operation_id_t operation_id, _Out_ size_t* minimum_request_size, _Out_ size_t* minimum_reply_size); + /** + * @brief Computes difference of checksum values for two input raw buffers using 1's complement arithmetic. + * + * @param[in] from Pointer to first raw buffer. + * @param[in] from_size Length of the "from" buffer. Must be a multiple of 4. + * @param[in] to Pointer to the second raw buffer, whose checksum will be subtracted from that of the "from" buffer. + * @param[in] to_size Length of the "to" buffer. Must be a multiple of 4. + * @param[in] seed An optional integer that can be added to the value, which can be used to carry result of a + * previous csum_diff operation. + * + * @returns The checksum delta on success, or <0 on failure. + */ + int + ebpf_core_csum_diff( + _In_reads_bytes_opt_(from_size) const void* from, + int from_size, + _In_reads_bytes_opt_(to_size) const void* to, + int to_size, + int seed); + #ifdef __cplusplus } #endif diff --git a/libs/execution_context/ebpf_general_helpers.c b/libs/execution_context/ebpf_general_helpers.c index 702a0f14f..157b44875 100644 --- a/libs/execution_context/ebpf_general_helpers.c +++ b/libs/execution_context/ebpf_general_helpers.c @@ -2,7 +2,8 @@ // SPDX-License-Identifier: MIT /** - * @brief Prototypes for general helper functions (aka global functions) implemented by eBPF core Execution Context. + * @brief Defines prototype structures for program information for general helper functions (aka global functions) + * implemented by the eBPF core Execution Context. */ #include "ebpf_platform.h" @@ -22,6 +23,10 @@ ebpf_helper_function_prototype_t ebpf_core_helper_function_prototype_array[] = { "bpf_map_delete_elem", EBPF_RETURN_TYPE_INTEGER, {EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}}, + {BPF_FUNC_map_lookup_and_delete_elem, + "bpf_map_lookup_and_delete_elem", + EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL, + {EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}}, {BPF_FUNC_tail_call, "bpf_tail_call", EBPF_RETURN_TYPE_INTEGER_OR_NO_RETURN_IF_SUCCEED, @@ -30,12 +35,14 @@ ebpf_helper_function_prototype_t ebpf_core_helper_function_prototype_array[] = { {BPF_FUNC_ktime_get_boot_ns, "bpf_ktime_get_boot_ns", EBPF_RETURN_TYPE_INTEGER, {0}}, {BPF_FUNC_get_smp_processor_id, "bpf_get_smp_processor_id", EBPF_RETURN_TYPE_INTEGER, {0}}, {BPF_FUNC_ktime_get_ns, "bpf_ktime_get_ns", EBPF_RETURN_TYPE_INTEGER, {0}}, - {BPF_FUNC_map_lookup_and_delete_elem, - "bpf_map_lookup_and_delete_elem", - EBPF_RETURN_TYPE_PTR_TO_MAP_VALUE_OR_NULL, - {EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}}, - -}; + {BPF_FUNC_csum_diff, + "bpf_csum_diff", + EBPF_RETURN_TYPE_INTEGER, + {EBPF_ARGUMENT_TYPE_PTR_TO_MEM_OR_NULL, + EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO, + EBPF_ARGUMENT_TYPE_PTR_TO_MEM_OR_NULL, + EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO, + EBPF_ARGUMENT_TYPE_ANYTHING}}}; #ifdef __cplusplus extern "C" diff --git a/libs/execution_context/unit/execution_context_unit_test.cpp b/libs/execution_context/unit/execution_context_unit_test.cpp index 97e6c75c6..1cac38317 100644 --- a/libs/execution_context/unit/execution_context_unit_test.cpp +++ b/libs/execution_context/unit/execution_context_unit_test.cpp @@ -572,3 +572,25 @@ TEST_CASE("name size", "[execution_context]") ebpf_map_create(&oversize_name, &map_definition, (uintptr_t)ebpf_handle_invalid, &local_map) == EBPF_INVALID_ARGUMENT); } + +const uint16_t from_buffer[] = {0x4500, 0x0073, 0x0000, 0x4000, 0x4011, 0x0000, 0x2000, 0x0001, 0x2000, 0x000a}; +const uint16_t to_buffer[] = {0x4500, 0x0073, 0x0000, 0x4000, 0x4011, 0x0000, 0xc0a8, 0x0001, 0xc0a8, 0x00c7}; + +TEST_CASE("test-csum-diff", "[execution_context]") +{ + int csum = ebpf_core_csum_diff( + from_buffer, + sizeof(from_buffer), + to_buffer, + sizeof(to_buffer), + ebpf_core_csum_diff(nullptr, 0, from_buffer, sizeof(from_buffer), 0)); + REQUIRE(csum > 0); + + // Fold checksum. + csum = (csum >> 16) + (csum & 0xFFFF); + csum = (csum >> 16) + (csum & 0xFFFF); + csum = (uint16_t)~csum; + + // See: https://en.wikipedia.org/wiki/IPv4_header_checksum#Calculating_the_IPv4_header_checksum + REQUIRE(csum == 0xb861); +} \ No newline at end of file diff --git a/netebpfext/net_ebpf_ext_helpers.h b/netebpfext/net_ebpf_ext_helpers.h deleted file mode 100644 index 536f0c854..000000000 --- a/netebpfext/net_ebpf_ext_helpers.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft Corporation -// SPDX-License-Identifier: MIT - -/** - * @file Prototypes and implementations for helper functions that are common to various programs types implemented in - * netebpfext. - */ - -#pragma once - -#include -#include "ebpf_platform.h" - -static inline int -_net_ebpf_ext_csum_diff( - _In_reads_bytes_opt_(from_size) const void* from, - int from_size, - _In_reads_bytes_opt_(to_size) const void* to, - int to_size, - int seed) -{ - int csum_diff = -EINVAL; - - if ((from_size % 4 != 0) || (to_size % 4 != 0)) - // size of buffers should be a multiple of 4. - goto Exit; - - csum_diff = seed; - if (to != NULL) - for (int i = 0; i < to_size / 2; i++) - csum_diff += (uint16_t)(*((uint16_t*)to + i)); - if (from != NULL) - for (int i = 0; i < from_size / 2; i++) - csum_diff += (uint16_t)(~*((uint16_t*)from + i)); - - // Adding 16-bit unsigned integers or their one's complement will produce a positive 32-bit integer, - // unless the length of the buffers is so long, that the signed 32 bit output overflows and produces a negative - // result. - if (csum_diff < 0) - csum_diff = -EINVAL; -Exit: - return csum_diff; -} \ No newline at end of file diff --git a/netebpfext/net_ebpf_ext_program_info.h b/netebpfext/net_ebpf_ext_program_info.h index 76dbee3da..87e973730 100644 --- a/netebpfext/net_ebpf_ext_program_info.h +++ b/netebpfext/net_ebpf_ext_program_info.h @@ -14,15 +14,7 @@ static ebpf_helper_function_prototype_t _xdp_ebpf_extension_helper_function_prot {XDP_EXT_HELPER_FUNCTION_START + 1, "bpf_xdp_adjust_head", EBPF_RETURN_TYPE_INTEGER, - {EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_ANYTHING}}, - {XDP_EXT_HELPER_FUNCTION_START + 2, - "bpf_csum_diff", - EBPF_RETURN_TYPE_INTEGER, - {EBPF_ARGUMENT_TYPE_PTR_TO_MEM_OR_NULL, - EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO, - EBPF_ARGUMENT_TYPE_PTR_TO_MEM_OR_NULL, - EBPF_ARGUMENT_TYPE_CONST_SIZE_OR_ZERO, - EBPF_ARGUMENT_TYPE_ANYTHING}}}; + {EBPF_ARGUMENT_TYPE_PTR_TO_CTX, EBPF_ARGUMENT_TYPE_ANYTHING}}}; // XDP Extension program information. static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = { diff --git a/netebpfext/net_ebpf_ext_xdp.c b/netebpfext/net_ebpf_ext_xdp.c index 620cdc316..5461c5d95 100644 --- a/netebpfext/net_ebpf_ext_xdp.c +++ b/netebpfext/net_ebpf_ext_xdp.c @@ -16,7 +16,6 @@ #include "ebpf_xdp_program_data.h" #include "net_ebpf_ext.h" -#include "net_ebpf_ext_helpers.h" static ebpf_ext_attach_hook_provider_registration_t* _ebpf_xdp_hook_provider_registration = NULL; static ebpf_extension_provider_t* _ebpf_xdp_program_info_provider = NULL; @@ -24,7 +23,7 @@ static ebpf_extension_provider_t* _ebpf_xdp_program_info_provider = NULL; static int _net_ebpf_xdp_adjust_head(_Inout_ xdp_md_t* ctx, int delta); -static const void* _ebpf_xdp_helper_functions[] = {(void*)&_net_ebpf_xdp_adjust_head, (void*)&_net_ebpf_ext_csum_diff}; +static const void* _ebpf_xdp_helper_functions[] = {(void*)&_net_ebpf_xdp_adjust_head}; static ebpf_helper_function_addresses_t _ebpf_xdp_helper_function_address_table = { EBPF_COUNT_OF(_ebpf_xdp_helper_functions), (uint64_t*)_ebpf_xdp_helper_functions}; diff --git a/tests/end_to_end/end_to_end.cpp b/tests/end_to_end/end_to_end.cpp index c837d4141..da83a446f 100644 --- a/tests/end_to_end/end_to_end.cpp +++ b/tests/end_to_end/end_to_end.cpp @@ -1039,28 +1039,6 @@ _xdp_encap_reflect_packet_test(ebpf_execution_type_t execution_type, ADDRESS_FAM } } -const uint16_t from_buffer[] = {0x4500, 0x0073, 0x0000, 0x4000, 0x4011, 0x0000, 0x2000, 0x0001, 0x2000, 0x000a}; -const uint16_t to_buffer[] = {0x4500, 0x0073, 0x0000, 0x4000, 0x4011, 0x0000, 0xc0a8, 0x0001, 0xc0a8, 0x00c7}; - -TEST_CASE("test-csum-diff", "[end_to_end]") -{ - int csum = test_xdp_helper_t::csum_diff( - from_buffer, - sizeof(from_buffer), - to_buffer, - sizeof(to_buffer), - test_xdp_helper_t::csum_diff(nullptr, 0, from_buffer, sizeof(from_buffer), 0)); - REQUIRE(csum > 0); - - // Fold checksum. - csum = (csum >> 16) + (csum & 0xFFFF); - csum = (csum >> 16) + (csum & 0xFFFF); - csum = (uint16_t)~csum; - - // See: https://en.wikipedia.org/wiki/IPv4_header_checksum#Calculating_the_IPv4_header_checksum - REQUIRE(csum == 0xb861); -} - TEST_CASE("xdp-reflect-v4-jit", "[xdp_tests]") { _xdp_reflect_packet_test(EBPF_EXECUTION_JIT, AF_INET); } TEST_CASE("xdp-reflect-v6-jit", "[xdp_tests]") { _xdp_reflect_packet_test(EBPF_EXECUTION_JIT, AF_INET6); } TEST_CASE("xdp-reflect-v4-interpret", "[xdp_tests]") { _xdp_reflect_packet_test(EBPF_EXECUTION_INTERPRET, AF_INET); } diff --git a/tests/end_to_end/helpers.h b/tests/end_to_end/helpers.h index 5000b313d..14681ec07 100644 --- a/tests/end_to_end/helpers.h +++ b/tests/end_to_end/helpers.h @@ -9,7 +9,6 @@ #include "ebpf_platform.h" #include "ebpf_program_types.h" #include "net_ebpf_ext_program_info.h" -#include "net_ebpf_ext_helpers.h" #include "sample_ext_program_info.h" typedef struct _ebpf_free_memory @@ -247,23 +246,11 @@ typedef class _test_xdp_helper ((xdp_md_helper_t*)ctx)->adjust_head(delta); return 0; } - - static int - csum_diff( - _In_reads_bytes_opt_(from_size) const void* from, - int from_size, - _In_reads_bytes_opt_(to_size) const void* to, - int to_size, - int seed) - { - return _net_ebpf_ext_csum_diff(from, from_size, to, to_size, seed); - } } test_xdp_helper_t; #define TEST_NET_EBPF_EXTENSION_NPI_PROVIDER_VERSION 0 -static const void* _test_ebpf_xdp_helper_functions[] = { - (void*)&test_xdp_helper_t::adjust_head, (void*)&test_xdp_helper_t::csum_diff}; +static const void* _test_ebpf_xdp_helper_functions[] = {(void*)&test_xdp_helper_t::adjust_head}; static ebpf_helper_function_addresses_t _test_ebpf_xdp_helper_function_address_table = { EBPF_COUNT_OF(_test_ebpf_xdp_helper_functions), (uint64_t*)_test_ebpf_xdp_helper_functions};