Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add unit tests from kernel #354

Merged
merged 26 commits into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/test-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ jobs:
enable: false
examples:
path: tailcall_minimal
- privilege_options:
enable: false
examples:
path: malloc
privilege_options:
- options: "--privileged -v /sys/kernel/debug/:/sys/kernel/debug:rw -v /sys/kernel/tracing:/sys/kernel/tracing:rw"
enable: true
Expand Down Expand Up @@ -208,3 +212,9 @@ jobs:
ROOT=$(pwd)
cd example/${{matrix.examples.path}}
python3 $ROOT/.github/script/run_example.py "${{matrix.examples.executable}}" "${{matrix.examples.victim}}" "${{matrix.examples.expected_str}}" "/github/home/.bpftime/bpftime -i /github/home/.bpftime" 0
- name: Setup tmate session
# Setup SSH when manually triggered and failing, so we can debug CI more conveniently
if: "${{ failure() && github.event_name == 'workflow_dispatch' }}"
uses: mxschmitt/action-tmate@v3
with:
limit-access-to-actor: true
6 changes: 6 additions & 0 deletions .github/workflows/test-runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ jobs:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Remount shm dev
# The size of /dev/shm defaults to be 64M, but boost won't detect this at all, leaving bus error to us..
# So we remount it to make it larger
run: |
mount -o remount,size=1G /dev/shm
- name: Install lcov
if: "matrix.container == 'ubuntu-2204'"
run: |
Expand All @@ -39,6 +44,7 @@ jobs:
cmake --build build --config Debug --target bpftime_runtime_tests -j$(nproc)
- name: Test Runtime
run: ./build/runtime/unit-test/bpftime_runtime_tests

- name: Generate runtime coverage (Ubuntu)
if: "matrix.container == 'ubuntu-2204'"
run: |
Expand Down
2 changes: 1 addition & 1 deletion attach/frida_uprobe_attach_impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ option(TEST_LCOV "option for lcov" OFF)
add_executable(bpftime_frida_uprobe_attach_tests ${TEST_SOURCES})

if (${TEST_LCOV})
target_compile_options(bpftime_frida_uprobe_attach_tests PRIVATE -fprofile-arcs -ftest-coverage)
target_compile_options(bpftime_frida_uprobe_attach_tests PRIVATE -fprofile-arcs -ftest-coverage -fprofile-update=atomic)
endif()

if(${ENABLE_EBPF_VERIFIER} AND NOT TARGET Catch2)
Expand Down
2 changes: 1 addition & 1 deletion attach/syscall_trace_attach_impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ option(TEST_LCOV "option for lcov" OFF)
add_executable(bpftime_syscall_trace_attach_tests ${TEST_SOURCES})

if (${TEST_LCOV})
target_compile_options(bpftime_syscall_trace_attach_tests PRIVATE -fprofile-arcs -ftest-coverage)
target_compile_options(bpftime_syscall_trace_attach_tests PRIVATE -fprofile-arcs -ftest-coverage -fprofile-update=atomic)
endif()

if(${ENABLE_EBPF_VERIFIER} AND NOT TARGET Catch2)
Expand Down
2 changes: 1 addition & 1 deletion bpftime-verifier/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ option(TEST_LCOV "option for lcov" OFF)
add_executable(bpftime_verifier_tests ${TEST_SOURCES})

if (${TEST_LCOV})
target_compile_options(bpftime_verifier_tests PRIVATE -fprofile-arcs -ftest-coverage)
target_compile_options(bpftime_verifier_tests PRIVATE -fprofile-arcs -ftest-coverage -fprofile-update=atomic)
endif()

add_dependencies(bpftime_verifier_tests bpftime-verifier)
Expand Down
10 changes: 10 additions & 0 deletions runtime/src/bpf_map/map_common_def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,16 @@ struct bytes_vec_hasher {
return seed;
}
};

static inline bool check_update_flags(uint64_t flags)
{
if (flags != 0 /*BPF_ANY*/ && flags != 1 /*BPF_NOEXIST*/ &&
flags != 2 /*BPF_EXIST*/) {
errno = EINVAL;
return false;
}
return true;
}
} // namespace bpftime

#endif
28 changes: 20 additions & 8 deletions runtime/src/bpf_map/userspace/array_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <bpf_map/userspace/array_map.hpp>
#include <cerrno>

Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand Down
26 changes: 19 additions & 7 deletions runtime/src/bpf_map/userspace/per_cpu_array_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* All rights reserved.
*/
#include "bpf_map/map_common_def.hpp"
#include "linux/bpf.h"
#include "spdlog/spdlog.h"
#include <algorithm>
#include <bpf_map/userspace/per_cpu_array_map.hpp>
Expand Down Expand Up @@ -39,7 +40,7 @@ void *per_cpu_array_map_impl::elem_lookup(const void *key)
}
uint32_t key_val = *(uint32_t *)key;
if (key_val >= max_ent) {
errno = E2BIG;
errno = ENOENT;
return nullptr;
}
return data_at(key_val, cpu);
Expand All @@ -49,13 +50,19 @@ void *per_cpu_array_map_impl::elem_lookup(const void *key)
long per_cpu_array_map_impl::elem_update(const void *key, const void *value,
uint64_t flags)
{
if (!check_update_flags(flags))
return -1;
return ensure_on_current_cpu<long>([&](int cpu) -> long {
// return impl[cpu].elem_update(key, value, flags);
if (key == nullptr) {
errno = ENOENT;
return -1;
}
uint32_t key_val = *(uint32_t *)key;
if (key_val < max_ent && flags == BPF_NOEXIST) {
errno = EEXIST;
return -1;
}
if (key_val >= max_ent) {
errno = E2BIG;
return -1;
Expand All @@ -68,13 +75,12 @@ long per_cpu_array_map_impl::elem_update(const void *key, const void *value,

long per_cpu_array_map_impl::elem_delete(const void *key)
{
errno = ENOTSUP;
errno = EINVAL;
SPDLOG_DEBUG("Deleting of per cpu array is not supported");
return -1;
}

int per_cpu_array_map_impl::map_get_next_key(const void *key,
void *next_key)
int per_cpu_array_map_impl::map_get_next_key(const void *key, void *next_key)
{
// Not found
if (key == nullptr || *(uint32_t *)key >= max_ent) {
Expand All @@ -100,7 +106,7 @@ void *per_cpu_array_map_impl::elem_lookup_userspace(const void *key)
}
uint32_t key_val = *(uint32_t *)key;
if (key_val >= max_ent) {
errno = E2BIG;
errno = ENOENT;
return nullptr;
}
return data_at(key_val, 0);
Expand All @@ -110,11 +116,17 @@ long per_cpu_array_map_impl::elem_update_userspace(const void *key,
const void *value,
uint64_t flags)
{
if (!check_update_flags(flags))
return -1;
if (key == nullptr) {
errno = ENOENT;
return -1;
}
uint32_t key_val = *(uint32_t *)key;
if (key_val < max_ent && flags == BPF_NOEXIST) {
errno = EEXIST;
return -1;
}
if (key_val >= max_ent) {
errno = E2BIG;
return -1;
Expand All @@ -126,8 +138,8 @@ long per_cpu_array_map_impl::elem_update_userspace(const void *key,

long per_cpu_array_map_impl::elem_delete_userspace(const void *key)
{
errno = ENOTSUP;
SPDLOG_ERROR("Element delete is not supported by per cpu array");
errno = EINVAL;
SPDLOG_WARN("Element delete is not supported by per cpu array");
return -1;
}

Expand Down
64 changes: 50 additions & 14 deletions runtime/src/bpf_map/userspace/per_cpu_hash_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,32 @@
* All rights reserved.
*/
#include "bpf_map/map_common_def.hpp"
#include "linux/bpf.h"
#include "spdlog/fmt/bin_to_hex.h"
#include "spdlog/spdlog.h"
#include <algorithm>
#include <bpf_map/userspace/per_cpu_hash_map.hpp>
#include <cerrno>
#include <cstring>
#include <unistd.h>
#include "platform_utils.hpp"


namespace bpftime
{
per_cpu_hash_map_impl::per_cpu_hash_map_impl(
boost::interprocess::managed_shared_memory &memory, uint32_t key_size,
uint32_t value_size)
: per_cpu_hash_map_impl(memory, key_size, value_size,
uint32_t value_size, uint32_t max_entries)
: per_cpu_hash_map_impl(memory, key_size, value_size, max_entries,
sysconf(_SC_NPROCESSORS_ONLN))
{
}

per_cpu_hash_map_impl::per_cpu_hash_map_impl(
boost::interprocess::managed_shared_memory &memory, uint32_t key_size,
uint32_t value_size, int ncpu)
uint32_t value_size, uint32_t max_entries, int ncpu)
: impl(memory.get_segment_manager()), key_size(key_size),
value_size(value_size), ncpu(ncpu),
value_size(value_size), ncpu(ncpu), _max_entries(max_entries),
value_template(value_size * ncpu, memory.get_segment_manager()),
key_templates(memory.get_segment_manager()),
single_value_templates(memory.get_segment_manager())
Expand Down Expand Up @@ -64,6 +68,8 @@ void *per_cpu_hash_map_impl::elem_lookup(const void *key)
long per_cpu_hash_map_impl::elem_update(const void *key, const void *value,
uint64_t flags)
{
if (!check_update_flags(flags))
return -1;
int cpu = my_sched_getcpu();
SPDLOG_DEBUG("Per cpu update, key {}, value {}", (const char *)key,
*(long *)value);
Expand Down Expand Up @@ -115,7 +121,7 @@ int per_cpu_hash_map_impl::map_get_next_key(const void *key, void *next_key)
}
// No need to be allocated at shm. Allocate as a local variable to make
// it thread safe, since we use sharable lock
bytes_vec key_vec = this->key_templates[0];
bytes_vec &key_vec = this->key_templates[0];
key_vec.assign((uint8_t *)key, (uint8_t *)key + key_size);

auto itr = impl.find(key_vec);
Expand All @@ -139,7 +145,7 @@ void *per_cpu_hash_map_impl::elem_lookup_userspace(const void *key)
errno = ENOENT;
return nullptr;
}
bytes_vec key_vec = this->key_templates[0];
bytes_vec &key_vec = this->key_templates[0];
key_vec.assign((uint8_t *)key, (uint8_t *)key + key_size);
if (auto itr = impl.find(key_vec); itr != impl.end()) {
SPDLOG_TRACE("Exit elem lookup of hash map: {}",
Expand All @@ -157,24 +163,54 @@ long per_cpu_hash_map_impl::elem_update_userspace(const void *key,
const void *value,
uint64_t flags)
{
bytes_vec key_vec = this->key_templates[0];
if (!check_update_flags(flags))
return -1;
bytes_vec &key_vec = this->key_templates[0];
bytes_vec value_vec = this->value_template;
key_vec.assign((uint8_t *)key, (uint8_t *)key + key_size);
value_vec.assign((uint8_t *)value,
(uint8_t *)value + value_size * ncpu);

if (auto itr = impl.find(key_vec); itr != impl.end()) {
itr->second = value_vec;
} else {
impl.insert(bi_map_value_ty(key_vec, value_vec));
bool elem_exists = impl.find(key_vec) != impl.end();
if (flags == BPF_NOEXIST && elem_exists) {
errno = EEXIST;
return -1;
}
if (flags == BPF_EXIST && !elem_exists) {
errno = ENOENT;
return -1;
}
if (elem_exists == false && impl.size() == _max_entries) {
errno = E2BIG;
return -1;
}
impl.insert_or_assign(key_vec, value_vec);
return 0;
}
long per_cpu_hash_map_impl::elem_delete_userspace(const void *key)
{
bytes_vec key_vec = this->key_templates[0];
bytes_vec &key_vec = this->key_templates[0];
key_vec.assign((uint8_t *)key, (uint8_t *)key + key_size);
auto itr = impl.find(key_vec);
if (itr == impl.end()) {
errno = ENOENT;
return -1;
}
impl.erase(itr);
return 0;
}

long per_cpu_hash_map_impl::lookup_and_delete_userspace(const void *key,
void *value)
{
bytes_vec &key_vec = this->key_templates[0];
key_vec.assign((uint8_t *)key, (uint8_t *)key + key_size);
impl.erase(key_vec);
auto itr = this->impl.find(key_vec);
if (itr == impl.end()) {
errno = ENOENT;
return -1;
}
memcpy(value, itr->second.data(), ncpu * value_size);
impl.erase(itr);
return 0;
}
} // namespace bpftime
Loading
Loading