====== 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