VM Interface Definition in bpftime: Header Location and API Reference

The core VM interface definition in bpftime is located in vm/vm-core/include/ebpf-vm.h, which declares the opaque struct ebpf_vm type and all API functions for creating, configuring, and executing eBPF programs across pluggable backends.

The bpftime project provides a high-performance userspace eBPF runtime with pluggable VM backends. Understanding the VM interface definition in bpftime is essential for developers integrating custom VM implementations or extending the runtime functionality. This guide identifies the exact header location and explains the stable C API contract used by LLVM-JIT, ubpf, and other backends.

Location of the VM Interface Header and Implementation Files

The primary VM interface definition resides in the public header file vm/vm-core/include/ebpf-vm.h within the eunomia-bpf/bpftime repository. This header defines the opaque struct ebpf_vm type and serves as the stable contract between VM implementations and the rest of the system.

The corresponding implementation is found in vm/vm-core/src/ebpf-vm.cpp, which contains the concrete logic for VM lifecycle management, bytecode loading, and execution. For legacy code compatibility, a thin wrapper is provided in vm/compat/include/bpftime_vm_compat.hpp. Additional reference material is available in vm/README.md, and a minimal working example is located at vm/example/main.c.

Core API Functions and Data Structures

The header exposes a C-based API that abstracts different VM backends. All functions operate on the opaque struct ebpf_vm pointer, allowing the runtime to switch between implementations like the LLVM-JIT or ubpf without changing calling code.

VM Lifecycle Management

  • struct ebpf_vm *ebpf_create(const char *vm_name); — Allocates a new VM instance. Pass "llvm" for the LLVM-JIT backend or "ubpf" for the interpreter.
  • void ebpf_destroy(struct ebpf_vm *vm); — Releases all resources associated with a VM instance.

Program Loading and Execution

  • int ebpf_load(struct ebpf_vm *vm, const void *code, uint32_t code_len, char **errmsg); — Loads raw eBPF bytecode into the VM.
  • int ebpf_exec(const struct ebpf_vm *vm, void *mem, size_t mem_len, uint64_t *bpf_return_value); — Interprets and executes the loaded program against the provided memory region.

JIT Compilation and Helper Registration

  • ebpf_jit_fn ebpf_compile(struct ebpf_vm *vm, char **errmsg); — JIT-compiles the loaded program to native machine code, returning a function pointer of type ebpf_jit_fn.
  • int ebpf_register(struct ebpf_vm *vm, unsigned int index, const char *name, void *fn); — Registers external helper functions accessible from eBPF programs.
  • int ebpf_load_aot_object(struct ebpf_vm *vm, const void *buf, size_t buf_len); — Loads ahead-of-time compiled objects.
  • void ebpf_set_lddw_helpers(...); — Attaches helpers required for the lddw instruction.
  • int ebpf_set_pointer_secret(struct ebpf_vm *vm, uint64_t secret); — Sets an optional secret for return-oriented programming mitigation.

Practical Code Examples

The following examples demonstrate how to use the VM interface definition in bpftime to create a VM, load bytecode, and execute programs.

Interpreter Mode Execution

#include "vm/vm-core/include/ebpf-vm.h"

int main() {
    /* Create a VM instance using the LLVM-JIT backend */
    struct ebpf_vm *vm = ebpf_create("llvm");
    if (!vm) return 1;

    /* Register helper functions */
    ebpf_register(vm, 1, "my_print", (void *)my_print);

    /* Load raw eBPF bytecode */
    const void *code = ...;          /* pointer to bytecode buffer */
    uint32_t code_len = ...;         /* length in bytes */
    char *errmsg = NULL;
    if (ebpf_load(vm, code, code_len, &errmsg) < 0) {
        fprintf(stderr, "load error: %s\n", errmsg);
        free(errmsg);
        ebpf_destroy(vm);
        return 1;
    }

    /* Execute with a memory region */
    uint8_t mem[EBPF_STACK_SIZE] = {0};
    uint64_t ret_val;
    if (ebpf_exec(vm, mem, sizeof(mem), &ret_val) < 0) {
        fprintf(stderr, "execution failed\n");
    } else {
        printf("program returned: %llu\n", (unsigned long long)ret_val);
    }

    ebpf_destroy(vm);
    return 0;
}

JIT Compilation and Native Execution

#include "vm/vm-core/include/ebpf-vm.h"

int main() {
    struct ebpf_vm *vm = ebpf_create("llvm");
    
    /* Load bytecode as shown in previous example */
    /* ... loading code ... */
    
    char *errmsg = NULL;
    ebpf_jit_fn fn = ebpf_compile(vm, &errmsg);
    if (!fn) {
        fprintf(stderr, "jit compile error: %s\n", errmsg);
        free(errmsg);
        ebpf_destroy(vm);
        return 1;
    }

    /* Call the JIT-compiled function directly */
    uint8_t mem[EBPF_STACK_SIZE] = {0};
    uint64_t result = fn(mem, sizeof(mem));
    printf("JIT result = %llu\n", (unsigned long long)result);

    ebpf_destroy(vm);
    return 0;
}

Summary

Frequently Asked Questions

Where is the VM interface definition located in bpftime?

The core definition is in vm/vm-core/include/ebpf-vm.h. This header declares the struct ebpf_vm type and all public API functions. The implementation resides in vm/vm-core/src/ebpf-vm.cpp, while vm/compat/include/bpftime_vm_compat.hpp provides backward compatibility.

What functions are defined in the bpftime VM interface?

The interface defines lifecycle functions (ebpf_create, ebpf_destroy), loading functions (ebpf_load, ebpf_load_aot_object), execution functions (ebpf_exec, ebpf_compile), and helper management (ebpf_register, ebpf_set_lddw_helpers).

How do I JIT compile an eBPF program using bpftime?

First create a VM with ebpf_create(), load bytecode with ebpf_load(), then call ebpf_compile() to obtain an ebpf_jit_fn function pointer. You can then call this pointer directly with your memory buffer to execute native code.

Is there a compatibility layer for older bpftime VM APIs?

Yes. The file vm/compat/include/bpftime_vm_compat.hpp provides a thin wrapper that exposes the modern ebpf-vm.h interface to legacy code written against older bpftime VM APIs, ensuring backward compatibility during migrations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →