diff --git a/runtime/src/bpf_map/map_common_def.hpp b/runtime/src/bpf_map/map_common_def.hpp index 5fbce558..3948692a 100644 --- a/runtime/src/bpf_map/map_common_def.hpp +++ b/runtime/src/bpf_map/map_common_def.hpp @@ -5,6 +5,7 @@ */ #ifndef _MAP_COMMON_DEF_HPP #define _MAP_COMMON_DEF_HPP +#include "linux/bpf.h" #include "spdlog/spdlog.h" #include #include @@ -68,6 +69,14 @@ struct bytes_vec_hasher { return seed; } }; +static inline bool check_update_flags(uint64_t flags) +{ + if (flags != BPF_ANY && flags != BPF_NOEXIST && flags != BPF_EXIST) { + errno = EINVAL; + return false; + } + return true; +} } // namespace bpftime #endif diff --git a/runtime/src/bpf_map/userspace/array_map.cpp b/runtime/src/bpf_map/userspace/array_map.cpp index abfd4896..30143990 100644 --- a/runtime/src/bpf_map/userspace/array_map.cpp +++ b/runtime/src/bpf_map/userspace/array_map.cpp @@ -3,6 +3,8 @@ * Copyright (c) 2022, eunomia-bpf org * All rights reserved. */ +#include "bpf_map/map_common_def.hpp" +#include "linux/bpf.h" #include #include @@ -34,9 +36,16 @@ void *array_map_impl::elem_lookup(const void *key) long array_map_impl::elem_update(const void *key, const void *value, uint64_t flags) { + if (!check_update_flags(flags)) + return -1; auto key_val = *(uint32_t *)key; + if (key_val < _max_entries && flags == BPF_NOEXIST) { + errno = EEXIST; + return -1; + } + if (key_val >= _max_entries) { - errno = ENOENT; + errno = E2BIG; return -1; } std::copy((uint8_t *)value, (uint8_t *)value + _value_size, @@ -47,13 +56,16 @@ long array_map_impl::elem_update(const void *key, const void *value, long array_map_impl::elem_delete(const void *key) { auto key_val = *(uint32_t *)key; - if (key_val >= _max_entries) { - errno = ENOENT; - return -1; - } - std::fill(&data[key_val * _value_size], - &data[key_val * _value_size] + _value_size, 0); - return 0; + // kernel tests says element in an array map can't be deleted... + errno = EINVAL; + return -1; + // if (key_val >= _max_entries) { + // errno = ENOENT; + // return -1; + // } + // std::fill(&data[key_val * _value_size], + // &data[key_val * _value_size] + _value_size, 0); + // return 0; } int array_map_impl::map_get_next_key(const void *key, void *next_key) diff --git a/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp b/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp index ade89d92..a08197b6 100644 --- a/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp +++ b/runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp @@ -14,14 +14,6 @@ #include #include "platform_utils.hpp" -static inline bool check_update_flags(uint64_t flags) -{ - if (flags != BPF_ANY && flags != BPF_NOEXIST && flags != BPF_EXIST) { - errno = EINVAL; - return false; - } - return true; -} namespace bpftime { diff --git a/runtime/unit-test/maps/kernel_unit_tests.cpp b/runtime/unit-test/maps/kernel_unit_tests.cpp index 316524c5..9c010438 100644 --- a/runtime/unit-test/maps/kernel_unit_tests.cpp +++ b/runtime/unit-test/maps/kernel_unit_tests.cpp @@ -1,3 +1,4 @@ +#include "bpf_map/userspace/array_map.hpp" #include "bpf_map/userspace/per_cpu_hash_map.hpp" #include "catch2/catch_test_macros.hpp" #include "linux/bpf.h" @@ -318,3 +319,59 @@ TEST_CASE("test_hashmap_walk (kernel)") REQUIRE(i == max_entries); } + +TEST_CASE("test_arraymap (kernel)") +{ + shm_remove remover(SHM_NAME); + managed_shared_memory mem(boost::interprocess::create_only, SHM_NAME, + 20 << 20); + int key, next_key; + long long value; + auto value_size = sizeof(value); + array_map_impl map(mem, sizeof(value), 2); + const auto lookup_helper = [&](const void *key, void *value) -> long { + auto returned_value = map.elem_lookup(key); + if (!returned_value) + return -1; + memcpy(value, returned_value, sizeof(value_size)); + return 0; + }; + + key = 1; + value = 1234; + /* Insert key=1 element. */ + REQUIRE(map.elem_update(&key, &value, BPF_ANY) == 0); + + value = 0; + REQUIRE((map.elem_update(&key, &value, BPF_NOEXIST) < 0 && + errno == EEXIST)); + + /* Check that key=1 can be found. */ + REQUIRE((lookup_helper(&key, &value) == 0 && value == 1234)); + + key = 0; + /* Check that key=0 is also found and zero initialized. */ + REQUIRE((lookup_helper(&key, &value) == 0 && value == 0)); + + /* key=0 and key=1 were inserted, check that key=2 cannot be inserted + * due to max_entries limit. + */ + key = 2; + REQUIRE((map.elem_update(&key, &value, BPF_EXIST) < 0 && + errno == E2BIG)); + + /* Check that key = 2 doesn't exist. */ + REQUIRE((lookup_helper(&key, &value) < 0 && errno == ENOENT)); + + /* Iterate over two elements. */ + REQUIRE((map.map_get_next_key(NULL, &next_key) == 0 && next_key == 0)); + REQUIRE((map.map_get_next_key(&key, &next_key) == 0 && next_key == 0)); + REQUIRE((map.map_get_next_key(&next_key, &next_key) == 0 && + next_key == 1)); + REQUIRE((map.map_get_next_key(&next_key, &next_key) < 0 && + errno == ENOENT)); + + /* Delete shouldn't succeed. */ + key = 1; + REQUIRE((map.elem_delete(&key) < 0 && errno == EINVAL)); +}