std.bpf — eBPF Maps und Programme

import std.bpf;

Wrapper um sys_bpf(321). eBPF (extended Berkeley Packet Filter) ist ein Kernel-Subsystem für sichere, vom Kernel-Verifier geprüfte Programme. Haupteinsatz: Netzwerk-Filterung, Tracing, Performance-Monitoring, XDP.

Achtung: Auf Produktionssystemen erfordert BPF meist CAP_BPF oder CAP_SYS_ADMIN. Bei unprivileged_bpf_disabled=1 (Ubuntu-Standard) schlägt selbst das Anlegen einfacher Maps mit EPERM fehl.

std.debug · std.net.socket · std.security_ext


BPF-Kommando-Konstanten

Konstante Wert Beschreibung
BPF_MAP_CREATE 0 Neue Map anlegen
BPF_MAP_LOOKUP_ELEM 1 Element lesen
BPF_MAP_UPDATE_ELEM 2 Element schreiben/aktualisieren
BPF_MAP_DELETE_ELEM 3 Element löschen
BPF_MAP_GET_NEXT_KEY 4 Iteration: nächster Schlüssel
BPF_PROG_LOAD 5 Programm laden

Map-Typ-Konstanten

Konstante Wert Beschreibung
BPF_MAP_TYPE_HASH 1 Hash-Tabelle (allgemein)
BPF_MAP_TYPE_ARRAY 2 Array mit int-Index
BPF_MAP_TYPE_PROG_ARRAY 3 Tail-Call-Array
BPF_MAP_TYPE_PERF_EVENT_ARRAY 4 Perf-Event-Ringpuffer
BPF_MAP_TYPE_PERCPU_HASH 5 Hash, per-CPU
BPF_MAP_TYPE_PERCPU_ARRAY 6 Array, per-CPU
BPF_MAP_TYPE_STACK_TRACE 7 Stack-Traces
BPF_MAP_TYPE_QUEUE 18 FIFO-Queue
BPF_MAP_TYPE_STACK 19 LIFO-Stack
BPF_MAP_TYPE_RINGBUF 27 Ring-Buffer (Kernel 5.8+)

Update-Flags

Konstante Bedeutung
BPF_ANY Anlegen oder ersetzen
BPF_NOEXIST Nur anlegen wenn nicht vorhanden
BPF_EXIST Nur ersetzen wenn vorhanden

Programm-Typen

Konstante Beschreibung
BPF_PROG_TYPE_SOCKET_FILTER Socket-Filter
BPF_PROG_TYPE_KPROBE Kernel-Probe
BPF_PROG_TYPE_SCHED_CLS TC-Classifier
BPF_PROG_TYPE_TRACEPOINT Tracepoint
BPF_PROG_TYPE_XDP XDP (eXpress Data Path)
BPF_PROG_TYPE_PERF_EVENT Perf-Event

Instruktions-Encoding

Jede BPF-Instruktion ist 8 Bytes:

Offset Typ Feld
+0 uint8 opcode
+1 uint8 dst_reg (Bits 0-3) \ src_reg (Bits 4-7)
+2 int16 offset
+4 int32 immediate

Häufige Opcodes:

Konstante Wert Beschreibung
BPF_OP_MOV64_IMM 0xB7 r[dst] = imm
BPF_OP_MOV64_REG 0xBF r[dst] = r[src]
BPF_OP_ADD64_IMM 0x07 r[dst] += imm
BPF_OP_EXIT 0x95 Programm beenden
BPF_OP_CALL 0x85 Helper-Funktion aufrufen
BPF_OP_JEQ_IMM 0x15 Jump wenn r[dst] == imm

Register: BPF_R0 (Rückgabe) bis BPF_R10 (Frame-Pointer, nur-lesen).


Funktionen

Map-Operationen

Funktion Signatur Beschreibung
BpfMapCreate (mapType: int64, keySize: int64, valSize: int64, maxEntries: int64): int64 Legt Map an; gibt map_fd oder -errno
BpfMapLookup (mapFd: int64, key: int64, valOut: int64): int64 Liest Wert für Schlüssel
BpfMapUpdate (mapFd: int64, key: int64, val: int64, flags: int64): int64 Schreibt/aktualisiert Eintrag
BpfMapDelete (mapFd: int64, key: int64): int64 Entfernt Eintrag

Programm laden

Funktion Signatur Beschreibung
BpfProgLoad (progType: int64, insns: int64, insnCnt: int64, license: pchar, logBuf: int64, logSize: int64): int64 Lädt BPF-Programm; gibt prog_fd oder -errno

Instruktions-Helfer

Funktion Signatur Beschreibung
BpfInsn (code: int64, dst: int64, src: int64, off: int64, imm: int64): int64 Kodiert eine BPF-Instruktion als int64
BpfEmitRaw (buf: int64, n: int64, insn: int64): int64 Schreibt Instruktion n in den Puffer

Verwendung

Array-Map anlegen und befüllen

import std.bpf;
import std.alloc;

fn main(): int64 {
    // Array-Map: uint32-Key, uint64-Wert, 256 Einträge
    var mapFd: int64 := BpfMapCreate(BPF_MAP_TYPE_ARRAY, 4, 8, 256);
    if (mapFd < 0) { return mapFd; }

    // Eintrag schreiben: Key = 0, Wert = 42
    var key: int64 := alloc(4);
    var val: int64 := alloc(8);
    poke32(key, 0);
    poke64(val, 42);
    BpfMapUpdate(mapFd, key, val, BPF_ANY);

    // Eintrag lesen
    var out: int64 := alloc(8);
    var r: int64 := BpfMapLookup(mapFd, key, out);
    if (r = 0) {
        var v: int64 := peek64(out);  // v = 42
    }

    free(key, 4); free(val, 8); free(out, 8);
    close(mapFd);
    return 0;
}

Minimales BPF-Programm laden

import std.bpf;
import std.alloc;

fn main(): int64 {
    // Minimales Programm: r0 = 0; exit
    var insns: int64 := alloc(2 * BPF_INSN_SIZE);
    BpfEmitRaw(insns, 0, BpfInsn(BPF_OP_MOV64_IMM, BPF_R0, 0, 0, 0));
    BpfEmitRaw(insns, 1, BpfInsn(BPF_OP_EXIT,      0,      0, 0, 0));

    var logBuf: int64 := alloc(4096);
    var fd: int64 := BpfProgLoad(BPF_PROG_TYPE_SOCKET_FILTER,
                                  insns, 2, "GPL", logBuf, 4096);
    if (fd < 0) {
        // logBuf enthält Verifier-Fehlermeldung
        free(insns, 2 * BPF_INSN_SIZE);
        free(logBuf, 4096);
        return fd;
    }

    free(insns, 2 * BPF_INSN_SIZE);
    free(logBuf, 4096);
    close(fd);
    return 0;
}


Hinweise

  • CAP_BPF: Auf modernen Systemen (Kernel 5.8+) reicht CAP_BPF; ältere Kernel benötigen CAP_SYS_ADMIN. Ubuntu sperrt BPF für normale Nutzer standardmäßig.
  • Verifier-Log: Bei BpfProgLoad-Fehler enthält logBuf die genaue Verifier-Fehlermeldung — wichtig für Debugging. logBuf=0 und logSize=0 deaktiviert den Log.
  • Lizenz: Der Lizenz-String beeinflusst welche Kernel-Helper-Funktionen verfügbar sind. GPL-only-Helpers (z.B. bpf_probe_read) benötigen GPL oder kompatible Lizenz.
  • Map-FDs: BPF-Map-FDs sind normale Dateideskriptoren und müssen mit close() freigegeben werden. Maps bleiben solange aktiv wie mindestens ein fd offen ist.
  • bpf_attr Größe: Alle Funktionen allozieren intern einen 128-Byte-Puffer (BPF_ATTR_SIZE) für den Syscall.

Letzte Aktualisierung: 2026-06-06