😉
Язык, который упрощает разработку eBPF-программПисать eBPF на чистом C с libbpf больно. Нужно разбираться в ограничениях верификатора, вручную управлять tail calls, настраивать загрузчики, собирать отдельно userspace и kernel-код. А если добавить kfunc, то ещё и писать модуль ядра с BTF-регистрацией. Для одной задачи приходится жонглировать тремя парадигмами программирования одновременно.
KernelScript — это DSL для eBPF, который позволяет описывать userspace, eBPF и kernelspace код в одном файле. Компилятор сам разберётся, что куда отправить. На выходе — готовый проект с C-кодом, Makefile и загрузчиком. Проект написан на OCaml, распространяется под Apache 2.0.
Что именно он делаетВы пишете
.ks файл. Компилятор по атрибутам:
@xdp,
@tc,
@kfunc,
@helper; определяет, какая функция относится к какому домену, и генерирует соответствующий C-код. XDP-функции уходят в eBPF-бинарник, обычные функции становятся userspace-кодом,
@kfunc превращается в модуль ядра.
Вот минимальный пример XDP-программы на KernelScript:
@xdp fn packet_filter(ctx: *xdp_md) -> xdp_action {
var packet_size = ctx->data_end - ctx->data
if (packet_size > 1500) {
return XDP_DROP
}
return XDP_PASS
}Для сравнения — та же логика на чистом C заняла бы раза в три больше строк, включая boilerplate для секций, лицензии и привязки к хукам.
Что решаетГлавная проблема eBPF-разработки — это количество ручной работы. KernelScript автоматизирует несколько вещей, которые обычно приходится делать руками.
Tail calls. Вместо ручной настройки program arrays и вызовов
bpf_tail_call() достаточно написать
return other_xdp_func(ctx). Компилятор сам сгенерирует нужный код.
Разделяемые map-ы. Объявляете map один раз, и он доступен во всех программах как обычная переменная:
pin var shared_counter : hash<u32, u32>(1024)
@xdp fn counter(ctx: *xdp_md) -> xdp_action {
shared_counter[1] = shared_counter[1] + 1
return XDP_PASS
}
Lifecycle программ. Тип программы проверяется на этапе компиляции — нельзя вызвать
attach() до
load().
Генерация kfunc-модулей. Достаточно пометить функцию
@kfunc, и компилятор создаст
.mod.c файл с модулем ядра и регистрацией BTF-символов.
Как запуститьЗависимости для Debian/Ubuntu:
sudo apt install libbpf-dev libelf-dev zlib1g-dev opam bpftool
Установка:
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
Создание проекта:
kernelscript init xdp my_filter
Это сгенерирует каталог
my_filter/ с файлом
my_filter.ks и README.
После редактирования
.ks файла — компиляция и сборка:
kernelscript compile my_filter/my_filter.ks
cd my_filter/
make
sudo ./my_filter
На выходе получится структура:
my_filter/
├── my_filter.ks # исходник KernelScript
├── my_filter.c # userspace-программа
├── my_filter.ebpf.c # eBPF C-код
├── my_filter.mod.c # модуль ядра (если есть @kfunc)
├── Makefile
└── README.md
Поддерживаемые типы программKernelScript поддерживает основные типы eBPF-программ:
@xdp для обработки пакетов,
@tc для traffic control,
@probe для трассировки функций ядра,
@tracepoint для точек трассировки. Отдельно поддерживается
struct_ops для TCP congestion control.
Система типов включает type aliases, структуры, enum-ы, фиксированные массивы (
u8[64]) и указатели на функции. Всё это спроектировано с учётом ограничений верификатора eBPF, то есть нет сложных дженериков, которые могут сломать верификацию.
ИтогоKernelScript не заменяет знание eBPF. Вам всё ещё нужно понимать, что такое XDP, как работают map-ы и зачем нужен bpf_probe_read. Но он убирает рутину и позволяет сосредоточиться на логике, а не на boilerplate. Проект пока в бете, API может меняться. Но если вы работаете с eBPF и устали от связки из трёх языков и пяти make-файлов, попробовать стоит.
➡️
Репозиторий📍 Навигация:
Вакансии •
Задачи •
Собесы🐸 Библиотека devops'a#арсенал_инженера