KernelScript is a modern, type-safe, domain-specific programming language for eBPF-centric kernel customization
505
stars
544
commits
OCaml
primary language
Jun 26, 2026
updated

⚠️ Beta Version Notice KernelScript is currently in beta development. The language syntax, APIs, and features are subject to change at any time without backward compatibility guarantees. This software is intended for experimental use and early feedback. Production use is not recommended at this time.
A Domain-Specific Programming Language for eBPF-Centric Development
KernelScript is a modern, type-safe, domain-specific programming language that unifies eBPF, userspace, and kernelspace development in a single codebase. Built with an eBPF-centric approach, it provides a clean, readable syntax while generating efficient C code for eBPF programs, coordinated userspace programs, and seamless kernel module (kfunc) integration.
KernelScript aims to become the programming language for Linux kernel customization and application-specific optimization. By leveraging kfunc and eBPF capabilities, it provides a modern alternative to traditional kernel module interfaces such as procfs and debugfs.
Writing eBPF programs today is challenging and error-prone:
bpf_tail_call() invocation, and error handling for failed tail callsbpf_ringbuf_reserve_dynptr(), bpf_dynptr_data(), bpf_dynptr_write(), and proper cleanup sequencesWhy not Rust?
@xdp, @tc, and regular functions compile to different targets automaticallyattach() before load() succeedsu8[64]) and simplified types designed for verifier compatibilityResult<T,E> model doesn't align with eBPF's C-style integer error codes. KernelScript's throw/catch works seamlessly in both userspace and eBPF contexts@kfunc attributes - features that require deep compiler integrationWhy not bpftrace?
Why not Python/Go eBPF libraries?
KernelScript addresses these problems through revolutionary language features:
✅ Single-file multi-target compilation - Write userspace, eBPF, and kernel module code in one file. The compiler automatically targets each function correctly based on attributes (@xdp, @helper, @kfunc, and regular userspace functions)
✅ Automatic tail call orchestration - Simply write return other_xdp_func(ctx) and the compiler handles program arrays, bpf_tail_call() generation, and error handling automatically
✅ Transparent dynptr integration - Use simple pointer operations (ringbuffer.reserve(), some_map[key]) while the compiler automatically uses complex dynptr APIs (bpf_ringbuf_reserve_dynptr, bpf_dynptr_write) behind the scenes
✅ First-class program lifecycle safety - Programs are typed values with compile-time guarantees that prevent calling attach() before load() succeeds
✅ Zero-boilerplate shared state - Maps are automatically accessible across all programs as regular global variables in a programming language
✅ Ergonomic map idioms - Declaration-as-condition (if (var s = m[k]) { s.field = ... }) and compound assignment on map indices (m[k].count += 1) compile down to a single presence-checked lookup with in-place mutation, no manual write-back
✅ Builtin kfunc support - Define full-privilege kernel functions that eBPF programs can call directly, automatically generating kernel modules and BTF registrations
✅ Unified error handling - C-style integer throw/catch works seamlessly in both eBPF and userspace contexts, unlike complex Result types
✅ Verifier-optimized type system - Fixed-size arrays (u8[64]), simple type aliases, and no complex generics that confuse the eBPF verifier
✅ Complete automated toolchain - Generate ready-to-use projects with Makefiles, userspace loaders, kernel modules (if kfunc is defined) and build systems from a single source file
✅ Automatic BTF extraction - Seamlessly extract available kfuncs and kernel struct definitions from specified BTF files during project initialization
| Feature | Raw C + libbpf | Rust eBPF | bpftrace | KernelScript |
|---|---|---|---|---|
| Syntax | Complex C | Complex Rust | Simple but limited | Clean & readable |
| Type Safety | Manual | Yes | Limited | Yes |
| Multi-program | Manual | Manual | No | Automatic |
| Build System | Manual Makefiles | Cargo complexity | N/A | Generated |
| Userspace Code | Manual | Manual | N/A | Generated |
| Learning Curve | Steep | Steep | Easy but limited | Moderate |
| Program Types | All | Most | Tracing only | All |
KernelScript combines the power of low-level eBPF programming with the productivity of modern programming languages, making eBPF development accessible to a broader audience while maintaining the performance and flexibility that makes eBPF powerful.
KernelScript supports all major eBPF program types with typed contexts:
// XDP program for packet processing
@xdp fn packet_filter(ctx: *xdp_md) -> xdp_action {
var packet_size = ctx->data_end - ctx->data
var timestamp = get_current_timestamp() // Call our custom kfunc
if (packet_size > 1500) {
return XDP_DROP
}
return XDP_PASS
}
// TC program for traffic control
@tc("ingress")
fn traffic_shaper(ctx: *__sk_buff) -> i32 {
if (ctx->len > 1000) {
return TC_ACT_SHOT // Drop large packets
}
return TC_ACT_OK
}
// Probe for kernel function tracing
@probe fn trace_syscall(ctx: *pt_regs) -> i32 {
// Trace system call entry
return 0
}
// Perf event program for hardware counter sampling
@perf_event
fn on_branch_miss(ctx: *bpf_perf_event_data) -> i32 {
// Runs on every hardware branch-miss event
return 0
}
KernelScript has a rich type system designed for systems programming:
// Type aliases for clarity
type IpAddress = u32
type Counter = u64
type PacketSize = u16
// Struct definitions
struct PacketInfo {
src_ip: IpAddress,
dst_ip: IpAddress,
protocol: u8,
size: PacketSize
}
// Enums for constants
enum FilterAction {
ALLOW = 0,
BLOCK = 1,
LOG = 2
}
Built-in support for all eBPF map types:
// Pinned maps persist across program restarts
pin var connection_count : hash<IpAddress, Counter>(1024)
// Per-CPU maps for better performance
var cpu_stats : percpu_array<u32, u64>(256)
// LRU maps for automatic eviction
var recent_packets : lru_hash<IpAddress, PacketInfo>(1000)
Clean function syntax with helper function support:
// Custom kernel function - runs in kernel space with full privileges
@kfunc
fn get_current_timestamp() -> u64 {
// Access kernel-only functionality using kernel APIs
return ktime_get_ns() // Direct kernel API call
}
// Helper functions for eBPF programs
@helper
fn extract_src_ip(ctx: *xdp_md) -> IpAddress {
// Packet parsing logic
return 0x7f000001 // 127.0.0.1
}
// Regular userspace functions
fn update_stats(ip: IpAddress, size: PacketSize) {
connection_count[ip] = connection_count[ip] + 1
}
// Function pointers for callbacks
type PacketHandler = fn(PacketInfo) -> FilterAction
fn process_packet(info: PacketInfo, handler: PacketHandler) -> FilterAction {
return handler(info)
}
Modern control flow with pattern matching:
// Pattern matching on enums
fn handle_action(action: FilterAction) -> xdp_action {
return match (action) {
ALLOW: XDP_PASS,
BLOCK: XDP_DROP,
LOG: {
// Log and allow
event_log[0] = 1
XDP_PASS
}
}
}
// Map lookup and update patterns — declaration-as-condition binds
// `count` only inside the truthy branch; one map lookup, no extra
// presence-check variable.
fn lookup_or_create(ip: IpAddress) -> Counter {
if (var count = connection_count[ip]) {
return count // Entry exists
} else {
connection_count[ip] = 1 // Create new entry
return 1
}
}
// Declaration-as-condition: bind only inside the truthy branch.
// For struct-valued maps, the bound name is the lookup pointer, so
// field access auto-derefs and the generated eBPF performs in-place
// mutation against the underlying entry — no write-back needed.
pin var ip_stats : hash<IpAddress, PacketInfo>(1024)
@helper
fn record_packet(ip: IpAddress, size: PacketSize) {
if (var stats = ip_stats[ip]) {
stats.size = size
} else {
ip_stats[ip] = PacketInfo { src_ip: ip, dst_ip: 0, protocol: 0, size: size }
}
}
// Compound assignment indexes into struct-valued maps directly:
@helper
fn bump_size(ip: IpAddress, delta: PacketSize) {
ip_stats[ip].size += delta // emits a presence-checked ptr->size += delta
}
Cordination between multiple eBPF programs is just natural:
// Shared map between programs
pin var shared_counter : hash<u32, u32>(1024)
// XDP program increments counter
@xdp fn packet_counter(ctx: *xdp_md) -> xdp_action {
shared_counter[1] = shared_counter[1] + 1
return XDP_PASS
}
// TC program reads counter
@tc("ingress")
fn packet_reader(ctx: *__sk_buff) -> int {
var count = shared_counter[1]
if (count > 1000) {
return TC_ACT_SHOT // Rate limiting
}
return TC_ACT_OK
}
// Userspace coordination
fn main() -> i32 {
var xdp_prog = load(packet_counter)
var tc_prog = load(packet_reader)
attach(xdp_prog, "eth0", 0)
attach(tc_prog, "eth0", 0)
return 0
}
Use @perf_event to attach eBPF programs to hardware or software performance counters. Only event is required; perf attaches return a first-class attachment whose count you read with read(att).scaled. Event grouping, the full event constant list, and the perf_options / perf_read field reference are in SPEC.md.
// eBPF program fires on every hardware branch-miss sample
@perf_event
fn on_branch_miss(ctx: *bpf_perf_event_data) -> i32 {
return 0
}
fn main() -> i32 {
var prog = load(on_branch_miss)
// Minimal form — defaults: pid=-1 (all procs), cpu=0, no group,
// period=1_000_000, wakeup=1; perf attach flags must be 0
var att = attach(prog, perf_options { event: branch_misses }, 0)
var count = read(att).scaled
print("branch misses: %lld", count)
detach(att) // disables counter, destroys BPF link, closes fd
detach(prog) // safe cleanup for the loaded program handle
return 0
}
📖 For detailed language specification, syntax reference, and advanced features, please read SPEC.md.
🔧 For complete builtin functions reference, see BUILTINS.md.
Create a new KernelScript project with template code:
# Create XDP project
kernelscript init xdp my_packet_filter
# Create TC project
kernelscript init tc/egress my_traffic_shaper
# Create probe project
kernelscript init probe/sys_read my_tracer
# Create project with custom BTF path
kernelscript init --btf-vmlinux-path /custom/path/vmlinux xdp my_project
# Create XDP project with kfuncs extracted
kernelscript init --kfuncs xdp my_packet_filter
# Create struct_ops project
kernelscript init tcp_congestion_ops my_congestion_control
After initialization, you get:
my_project/
├── my_project.ks # Generated KernelScript source without user code
└── README.md # Usage instructions
Available program types:
xdp - XDP programs for packet processingtc - Traffic control programsprobe - Kernel function probingtracepoint - Kernel tracepoint programsperf_event - Hardware/software performance counter programsAvailable struct_ops:
tcp_congestion_ops - TCP congestion controlCompile .ks files to eBPF C code and userspace programs:
# Basic compilation
kernelscript compile my_project/my_project.ks
# Specify output directory
kernelscript compile my_project/my_project.ks -o my_output_dir
kernelscript compile my_project/my_project.ks --output my_output_dir
# Verbose compilation
kernelscript compile my_project/my_project.ks -v
kernelscript compile my_project/my_project.ks --verbose
# Don't generate Makefile
kernelscript compile my_project/my_project.ks --no-makefile
# Also generates tests and only @test functions become main
kernelscript compile --test my_project/my_project.ks
# Custom BTF path
kernelscript compile my_project/my_project.ks --btf-vmlinux-path /custom/path/vmlinux
After compilation, you get a complete project:
my_project/
├── my_project.ks # KernelScript source
├── my_project.c # Generated userspace program
├── my_project.ebpf.c # Generated eBPF C code
├── my_project.mod.c # Generated kernel module (when any kfunc exists)
├── my_project.test.c # Generated test run code (when using --test mode)
├── Makefile # Build system
└── README.md # Usage instructions
cd my_project/
make # Build both eBPF and userspace programs
sudo ./my_project # Run the program
Install system dependencies (Debian/Ubuntu):
sudo apt update
sudo apt install libbpf-dev libelf-dev zlib1g-dev opam bpftool
Install KernelScript:
git clone https://github.com/multikernel/kernelscript.git
cd kernelscript
opam init
opam install . --deps-only --with-test
eval $(opam env) && dune build && dune install
Create your first project:
kernelscript init xdp hello_world
cd hello_world/
Edit the generated code:
# Edit hello_world.ks with your logic
vim hello_world.ks
Compile and run:
kernelscript compile hello_world/hello_world.ks
cd hello_world/
make
sudo ./hello_world
The examples/ directory contains comprehensive examples:
packet_filter.ks - Basic XDP packet filteringmulti_programs.ks - Multiple coordinated programsmaps_demo.ks - All map types and operationsfunctions.ks - Function definitions and callstypes_demo.ks - Type system featureserror_handling_demo.ks - Error handling patternsCopyright 2025 Multikernel Technologies, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
By contributing to this project, you agree that your contributions will be licensed under the Apache License 2.0.
OCaml
98.8%
KernelScript is a modern, type-safe, domain-specific programming language for eBPF-centric kernel customization
505
stars
544
commits
OCaml
primary language
Jun 26, 2026
updated

⚠️ Beta Version Notice KernelScript is currently in beta development. The language syntax, APIs, and features are subject to change at any time without backward compatibility guarantees. This software is intended for experimental use and early feedback. Production use is not recommended at this time.
A Domain-Specific Programming Language for eBPF-Centric Development
KernelScript is a modern, type-safe, domain-specific programming language that unifies eBPF, userspace, and kernelspace development in a single codebase. Built with an eBPF-centric approach, it provides a clean, readable syntax while generating efficient C code for eBPF programs, coordinated userspace programs, and seamless kernel module (kfunc) integration.
KernelScript aims to become the programming language for Linux kernel customization and application-specific optimization. By leveraging kfunc and eBPF capabilities, it provides a modern alternative to traditional kernel module interfaces such as procfs and debugfs.
Writing eBPF programs today is challenging and error-prone:
bpf_tail_call() invocation, and error handling for failed tail callsbpf_ringbuf_reserve_dynptr(), bpf_dynptr_data(), bpf_dynptr_write(), and proper cleanup sequencesWhy not Rust?
@xdp, @tc, and regular functions compile to different targets automaticallyattach() before load() succeedsu8[64]) and simplified types designed for verifier compatibilityResult<T,E> model doesn't align with eBPF's C-style integer error codes. KernelScript's throw/catch works seamlessly in both userspace and eBPF contexts@kfunc attributes - features that require deep compiler integrationWhy not bpftrace?
Why not Python/Go eBPF libraries?
KernelScript addresses these problems through revolutionary language features:
✅ Single-file multi-target compilation - Write userspace, eBPF, and kernel module code in one file. The compiler automatically targets each function correctly based on attributes (@xdp, @helper, @kfunc, and regular userspace functions)
✅ Automatic tail call orchestration - Simply write return other_xdp_func(ctx) and the compiler handles program arrays, bpf_tail_call() generation, and error handling automatically
✅ Transparent dynptr integration - Use simple pointer operations (ringbuffer.reserve(), some_map[key]) while the compiler automatically uses complex dynptr APIs (bpf_ringbuf_reserve_dynptr, bpf_dynptr_write) behind the scenes
✅ First-class program lifecycle safety - Programs are typed values with compile-time guarantees that prevent calling attach() before load() succeeds
✅ Zero-boilerplate shared state - Maps are automatically accessible across all programs as regular global variables in a programming language
✅ Ergonomic map idioms - Declaration-as-condition (if (var s = m[k]) { s.field = ... }) and compound assignment on map indices (m[k].count += 1) compile down to a single presence-checked lookup with in-place mutation, no manual write-back
✅ Builtin kfunc support - Define full-privilege kernel functions that eBPF programs can call directly, automatically generating kernel modules and BTF registrations
✅ Unified error handling - C-style integer throw/catch works seamlessly in both eBPF and userspace contexts, unlike complex Result types
✅ Verifier-optimized type system - Fixed-size arrays (u8[64]), simple type aliases, and no complex generics that confuse the eBPF verifier
✅ Complete automated toolchain - Generate ready-to-use projects with Makefiles, userspace loaders, kernel modules (if kfunc is defined) and build systems from a single source file
✅ Automatic BTF extraction - Seamlessly extract available kfuncs and kernel struct definitions from specified BTF files during project initialization
| Feature | Raw C + libbpf | Rust eBPF | bpftrace | KernelScript |
|---|---|---|---|---|
| Syntax | Complex C | Complex Rust | Simple but limited | Clean & readable |
| Type Safety | Manual | Yes | Limited | Yes |
| Multi-program | Manual | Manual | No | Automatic |
| Build System | Manual Makefiles | Cargo complexity | N/A | Generated |
| Userspace Code | Manual | Manual | N/A | Generated |
| Learning Curve | Steep | Steep | Easy but limited | Moderate |
| Program Types | All | Most | Tracing only | All |
KernelScript combines the power of low-level eBPF programming with the productivity of modern programming languages, making eBPF development accessible to a broader audience while maintaining the performance and flexibility that makes eBPF powerful.
KernelScript supports all major eBPF program types with typed contexts:
// XDP program for packet processing
@xdp fn packet_filter(ctx: *xdp_md) -> xdp_action {
var packet_size = ctx->data_end - ctx->data
var timestamp = get_current_timestamp() // Call our custom kfunc
if (packet_size > 1500) {
return XDP_DROP
}
return XDP_PASS
}
// TC program for traffic control
@tc("ingress")
fn traffic_shaper(ctx: *__sk_buff) -> i32 {
if (ctx->len > 1000) {
return TC_ACT_SHOT // Drop large packets
}
return TC_ACT_OK
}
// Probe for kernel function tracing
@probe fn trace_syscall(ctx: *pt_regs) -> i32 {
// Trace system call entry
return 0
}
// Perf event program for hardware counter sampling
@perf_event
fn on_branch_miss(ctx: *bpf_perf_event_data) -> i32 {
// Runs on every hardware branch-miss event
return 0
}
KernelScript has a rich type system designed for systems programming:
// Type aliases for clarity
type IpAddress = u32
type Counter = u64
type PacketSize = u16
// Struct definitions
struct PacketInfo {
src_ip: IpAddress,
dst_ip: IpAddress,
protocol: u8,
size: PacketSize
}
// Enums for constants
enum FilterAction {
ALLOW = 0,
BLOCK = 1,
LOG = 2
}
Built-in support for all eBPF map types:
// Pinned maps persist across program restarts
pin var connection_count : hash<IpAddress, Counter>(1024)
// Per-CPU maps for better performance
var cpu_stats : percpu_array<u32, u64>(256)
// LRU maps for automatic eviction
var recent_packets : lru_hash<IpAddress, PacketInfo>(1000)
Clean function syntax with helper function support:
// Custom kernel function - runs in kernel space with full privileges
@kfunc
fn get_current_timestamp() -> u64 {
// Access kernel-only functionality using kernel APIs
return ktime_get_ns() // Direct kernel API call
}
// Helper functions for eBPF programs
@helper
fn extract_src_ip(ctx: *xdp_md) -> IpAddress {
// Packet parsing logic
return 0x7f000001 // 127.0.0.1
}
// Regular userspace functions
fn update_stats(ip: IpAddress, size: PacketSize) {
connection_count[ip] = connection_count[ip] + 1
}
// Function pointers for callbacks
type PacketHandler = fn(PacketInfo) -> FilterAction
fn process_packet(info: PacketInfo, handler: PacketHandler) -> FilterAction {
return handler(info)
}
Modern control flow with pattern matching:
// Pattern matching on enums
fn handle_action(action: FilterAction) -> xdp_action {
return match (action) {
ALLOW: XDP_PASS,
BLOCK: XDP_DROP,
LOG: {
// Log and allow
event_log[0] = 1
XDP_PASS
}
}
}
// Map lookup and update patterns — declaration-as-condition binds
// `count` only inside the truthy branch; one map lookup, no extra
// presence-check variable.
fn lookup_or_create(ip: IpAddress) -> Counter {
if (var count = connection_count[ip]) {
return count // Entry exists
} else {
connection_count[ip] = 1 // Create new entry
return 1
}
}
// Declaration-as-condition: bind only inside the truthy branch.
// For struct-valued maps, the bound name is the lookup pointer, so
// field access auto-derefs and the generated eBPF performs in-place
// mutation against the underlying entry — no write-back needed.
pin var ip_stats : hash<IpAddress, PacketInfo>(1024)
@helper
fn record_packet(ip: IpAddress, size: PacketSize) {
if (var stats = ip_stats[ip]) {
stats.size = size
} else {
ip_stats[ip] = PacketInfo { src_ip: ip, dst_ip: 0, protocol: 0, size: size }
}
}
// Compound assignment indexes into struct-valued maps directly:
@helper
fn bump_size(ip: IpAddress, delta: PacketSize) {
ip_stats[ip].size += delta // emits a presence-checked ptr->size += delta
}
Cordination between multiple eBPF programs is just natural:
// Shared map between programs
pin var shared_counter : hash<u32, u32>(1024)
// XDP program increments counter
@xdp fn packet_counter(ctx: *xdp_md) -> xdp_action {
shared_counter[1] = shared_counter[1] + 1
return XDP_PASS
}
// TC program reads counter
@tc("ingress")
fn packet_reader(ctx: *__sk_buff) -> int {
var count = shared_counter[1]
if (count > 1000) {
return TC_ACT_SHOT // Rate limiting
}
return TC_ACT_OK
}
// Userspace coordination
fn main() -> i32 {
var xdp_prog = load(packet_counter)
var tc_prog = load(packet_reader)
attach(xdp_prog, "eth0", 0)
attach(tc_prog, "eth0", 0)
return 0
}
Use @perf_event to attach eBPF programs to hardware or software performance counters. Only event is required; perf attaches return a first-class attachment whose count you read with read(att).scaled. Event grouping, the full event constant list, and the perf_options / perf_read field reference are in SPEC.md.
// eBPF program fires on every hardware branch-miss sample
@perf_event
fn on_branch_miss(ctx: *bpf_perf_event_data) -> i32 {
return 0
}
fn main() -> i32 {
var prog = load(on_branch_miss)
// Minimal form — defaults: pid=-1 (all procs), cpu=0, no group,
// period=1_000_000, wakeup=1; perf attach flags must be 0
var att = attach(prog, perf_options { event: branch_misses }, 0)
var count = read(att).scaled
print("branch misses: %lld", count)
detach(att) // disables counter, destroys BPF link, closes fd
detach(prog) // safe cleanup for the loaded program handle
return 0
}
📖 For detailed language specification, syntax reference, and advanced features, please read SPEC.md.
🔧 For complete builtin functions reference, see BUILTINS.md.
Create a new KernelScript project with template code:
# Create XDP project
kernelscript init xdp my_packet_filter
# Create TC project
kernelscript init tc/egress my_traffic_shaper
# Create probe project
kernelscript init probe/sys_read my_tracer
# Create project with custom BTF path
kernelscript init --btf-vmlinux-path /custom/path/vmlinux xdp my_project
# Create XDP project with kfuncs extracted
kernelscript init --kfuncs xdp my_packet_filter
# Create struct_ops project
kernelscript init tcp_congestion_ops my_congestion_control
After initialization, you get:
my_project/
├── my_project.ks # Generated KernelScript source without user code
└── README.md # Usage instructions
Available program types:
xdp - XDP programs for packet processingtc - Traffic control programsprobe - Kernel function probingtracepoint - Kernel tracepoint programsperf_event - Hardware/software performance counter programsAvailable struct_ops:
tcp_congestion_ops - TCP congestion controlCompile .ks files to eBPF C code and userspace programs:
# Basic compilation
kernelscript compile my_project/my_project.ks
# Specify output directory
kernelscript compile my_project/my_project.ks -o my_output_dir
kernelscript compile my_project/my_project.ks --output my_output_dir
# Verbose compilation
kernelscript compile my_project/my_project.ks -v
kernelscript compile my_project/my_project.ks --verbose
# Don't generate Makefile
kernelscript compile my_project/my_project.ks --no-makefile
# Also generates tests and only @test functions become main
kernelscript compile --test my_project/my_project.ks
# Custom BTF path
kernelscript compile my_project/my_project.ks --btf-vmlinux-path /custom/path/vmlinux
After compilation, you get a complete project:
my_project/
├── my_project.ks # KernelScript source
├── my_project.c # Generated userspace program
├── my_project.ebpf.c # Generated eBPF C code
├── my_project.mod.c # Generated kernel module (when any kfunc exists)
├── my_project.test.c # Generated test run code (when using --test mode)
├── Makefile # Build system
└── README.md # Usage instructions
cd my_project/
make # Build both eBPF and userspace programs
sudo ./my_project # Run the program
Install system dependencies (Debian/Ubuntu):
sudo apt update
sudo apt install libbpf-dev libelf-dev zlib1g-dev opam bpftool
Install KernelScript:
git clone https://github.com/multikernel/kernelscript.git
cd kernelscript
opam init
opam install . --deps-only --with-test
eval $(opam env) && dune build && dune install
Create your first project:
kernelscript init xdp hello_world
cd hello_world/
Edit the generated code:
# Edit hello_world.ks with your logic
vim hello_world.ks
Compile and run:
kernelscript compile hello_world/hello_world.ks
cd hello_world/
make
sudo ./hello_world
The examples/ directory contains comprehensive examples:
packet_filter.ks - Basic XDP packet filteringmulti_programs.ks - Multiple coordinated programsmaps_demo.ks - All map types and operationsfunctions.ks - Function definitions and callstypes_demo.ks - Type system featureserror_handling_demo.ks - Error handling patternsCopyright 2025 Multikernel Technologies, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
By contributing to this project, you agree that your contributions will be licensed under the Apache License 2.0.
OCaml
98.8%