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

add: ubpf jit #7

Merged
merged 5 commits into from
Jun 8, 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
4 changes: 3 additions & 1 deletion .github/workflows/run-execution-context-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ on:
branches: "master"
pull_request:
branches: "master"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
build:
test:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/run-vm-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Run ubpf vm tests

on:
push:
branches: "master"
pull_request:
branches: "master"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install cmake make clang-15 ninja-build
- name: Build targets
run: |
CC=clang-15 CXX=clang++-15 cmake -S. -Bbuild -DCMAKE_BUILD_TYPE:STRING=Release -G Ninja
CC=clang-15 CXX=clang++-15 cmake --build ./build --config Release --target libebpf_test_runner
- uses: actions/setup-python@v5
with:
python-version: '3.8'
- run: python --version
- run: |
cd vm-test
python -m venv env
source ./env/bin/activate
pip install -r requirements.txt
pytest
16 changes: 11 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ project(
VERSION 0.1.0
LANGUAGES C CXX
)

add_library(
libebpf_objects
OBJECT
set(LIBEBPF_SOURCE_LIST
src/libebpf.c
src/libebpf_vm.c
src/libebpf_vm_verify.c
Expand All @@ -22,12 +19,21 @@ add_library(
src/libebpf_execution_helpers.c
src/libebpf_ffi_functions.c
src/utils/hashmap.c
src/jit/x86_64/ubpf_jit_x86_64.c
src/jit/x86_64/helper_adaptor.c
)


add_library(
libebpf_objects
OBJECT
${LIBEBPF_SOURCE_LIST}
)
target_compile_definitions(libebpf_objects PRIVATE -D_GNU_SOURCE)
target_include_directories(
libebpf_objects
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src
)

set_target_properties(libebpf_objects PROPERTIES C_STANDARD 11 C_EXTENSIONS TRUE)
Expand Down
20 changes: 18 additions & 2 deletions execution-test/test_with_ebpf.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "catch2/catch_message.hpp"
#include "catch2/internal/catch_stdstreams.hpp"
#include "libebpf.h"
#include "libebpf_insn.h"
Expand All @@ -10,8 +11,7 @@
#include <ostream>

TEST_CASE("Test map operations with ebpf programs") {
std::unique_ptr<ebpf_state_t, decltype(&ebpf_state__destroy)> ctx(ebpf_state__create(),
ebpf_state__destroy);
std::unique_ptr<ebpf_state_t, decltype(&ebpf_state__destroy)> ctx(ebpf_state__create(), ebpf_state__destroy);
REQUIRE(ctx != nullptr);
std::unique_ptr<ebpf_vm_t, decltype(&ebpf_vm_destroy)> vm(ebpf_vm_create(), ebpf_vm_destroy);
REQUIRE(vm != nullptr);
Expand Down Expand Up @@ -75,3 +75,19 @@ TEST_CASE("Test map operations with ebpf programs") {
REQUIRE(ebpf_state__map_elem_lookup(ctx.get(), hash_map_id, &key, &value) == 0);
REQUIRE(value == 233 + 456);
}

TEST_CASE("Test execution with JIT") {
std::unique_ptr<ebpf_state_t, decltype(&ebpf_state__destroy)> ctx(ebpf_state__create(), ebpf_state__destroy);
REQUIRE(ctx != nullptr);
std::unique_ptr<ebpf_vm_t, decltype(&ebpf_vm_destroy)> vm(ebpf_vm_create(), ebpf_vm_destroy);
struct libebpf_insn insns[] = { // r1 += r2
BPF_RAW_INSN(BPF_CLASS_ALU64 | BPF_SOURCE_REG | BPF_ALU_ADD, 1, 2, 0, 0),
// r0 = r1
BPF_RAW_INSN(BPF_CLASS_ALU64 | BPF_SOURCE_REG | BPF_ALU_MOV_MOVSX, 0, 1, 0, 0)
};
REQUIRE(ebpf_vm_load_instructions(vm.get(), insns, std::size(insns)) == 0);
auto func = ebpf_vm_compile(vm.get());
INFO(ebpf_error_string());
REQUIRE(func);
REQUIRE(func((void*)100, (size_t)5000) == 5000 + 100);
}
20 changes: 20 additions & 0 deletions include/libebpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@
extern "C" {
#endif

/**
* @brief Function prototype for allocating a piece of executable memory and copy the given buffer onto it
*
*/
typedef void *(*ebpf_allocate_execuable_memory_and_copy)(void *buffer, size_t bufsize);

/**
* @brief Function prototype for releasing a piece of executable memory
*
*/
typedef int (*ebpf_release_executable_memory)(void *mem, size_t len);

/**
* @brief Function prototype for the global custom memory allocator
*
Expand Down Expand Up @@ -38,6 +50,14 @@ typedef void *(*ebpf_realloc)(void *, size_t);
*/
void ebpf_set_global_memory_allocator(ebpf_malloc malloc, ebpf_free free, ebpf_realloc realloc);

/**
* @brief Set functions which will be used for JIT
*
* @param allocate Function to allocate a piece of executable memory and copy buffer to it
* @param release Function to release a piece of executable memory
*/
void ebpf_set_executable_memory_allocator(ebpf_allocate_execuable_memory_and_copy *allocate, ebpf_release_executable_memory *release);

/**
* @brief Get the global error string
*
Expand Down
17 changes: 17 additions & 0 deletions include/libebpf_insn.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,21 @@ struct libebpf_insn {

#define BPF_RAW_INSN_IMM64(SRC, DST, IMM1, IMM2) BPF_RAW_INSN(0x18, DST, SRC, 0, IMM1), BPF_RAW_INSN(0, 0, 0, 0, IMM2)

enum bpf_register {
BPF_REG_0 = 0,
BPF_REG_1,
BPF_REG_2,
BPF_REG_3,
BPF_REG_4,
BPF_REG_5,
BPF_REG_6,
BPF_REG_7,
BPF_REG_8,
BPF_REG_9,
BPF_REG_10,
_BPF_REG_MAX,
};



#endif
13 changes: 12 additions & 1 deletion include/libebpf_vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern "C" {
#define EBPF_STACK_SIZE ((size_t)512)
#define MAX_LOCAL_FUNCTION_LEVEL 20

#define LIBEBPF_MAX_INSTRUCTION_COUNT 65536


/**
Expand All @@ -27,7 +28,7 @@ typedef struct ebpf_vm ebpf_vm_t;
* @brief Function prototype for a jitted ebpf program
*
*/
typedef int (*ebpf_jit_fn)(void *mem, size_t mem_len, uint64_t *return_value);
typedef uint64_t (*ebpf_jit_fn)(void *mem, size_t mem_len);

/**
* @brief Function prototype for external helper
Expand Down Expand Up @@ -143,6 +144,16 @@ int ebpf_vm_run(ebpf_vm_t *vm, void *mem, size_t mem_len, uint64_t *return_value
*/
ebpf_jit_fn ebpf_vm_compile(ebpf_vm_t *vm);

/**
* @brief Translate the loaded eBPF byte code to native code
*
* @param vm The VM instance
* @param buffer buffer to output. ebpf_translate will allocate it. Use _libebpf_global_free to free it
* @param size size of the generated code, in bytes
* @return int 0 if succeeded
*/
int ebpf_translate(struct ebpf_vm *vm, uint8_t **buffer, size_t *size);


#ifdef __cplusplus
}
Expand Down
11 changes: 11 additions & 0 deletions src/jit/x86_64/helper_adaptor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "libebpf_vm.h"
#include <assert.h>
#include <stdint.h>
#include <libebpf_internal.h>
uint64_t ebpf_ubpf_jit_dispatcher_adaptor(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, unsigned int index,
ebpf_vm_t *vm) {
assert(index < MAX_EXTERNAL_HELPER);
struct ebpf_external_helper_definition *helper_def = &vm->helpers[index];
assert(helper_def->fn);
return helper_def->fn(arg1, arg2, arg3, arg4, arg5);
}
Loading
Loading