Skip to content

Commit

Permalink
add: ubpf jit (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
Officeyutong authored Jun 8, 2024
1 parent 933b3f8 commit 1289c18
Show file tree
Hide file tree
Showing 16 changed files with 1,638 additions and 40 deletions.
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

0 comments on commit 1289c18

Please sign in to comment.