Skip to content

Commit

Permalink
feat: add unit tests from kernel (#354)
Browse files Browse the repository at this point in the history
* Update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

* update

---------

Co-authored-by: Officeyutong <[email protected]>
  • Loading branch information
kenlig and Officeyutong authored Oct 20, 2024
1 parent da6ba42 commit 327ba8d
Show file tree
Hide file tree
Showing 17 changed files with 1,177 additions and 187 deletions.
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

0 comments on commit 327ba8d

Please sign in to comment.