====== 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.
→ [[lyx_-_programmiersprache:units:debug|std.debug]] · [[lyx_-_programmiersprache:units:net:socket|std.net.socket]] · [[lyx_-_programmiersprache:units:security_ext|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