Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Top-Level Declarations

A Whistler source file consists of top-level declarations: defmap, defprog, defstruct, and defunion. Every other construct lives inside the body of a defprog.

defmap

defmap declares a BPF map -- a kernel-side data structure shared between BPF programs and userspace. You choose a map type (hash table, array, ring buffer, etc.), specify key and value sizes, and set capacity. The compiler emits the corresponding ELF map section and generates accessor forms you can use inside defprog bodies.

defprog

defprog defines a BPF program. Each defprog produces one program section in the output ELF. You specify the program type (XDP, kprobe, tracepoint, and so on), write the body using Whistler forms, and the compiler handles register allocation, stack layout, and bytecode emission. Multiple defprog forms in the same source file compile into a single ELF object.

defstruct

defstruct declares a C-compatible struct layout used on both the BPF side and the Common Lisp userspace side. On the BPF side the compiler generates constructors, field accessors, and sizeof. On the CL side it generates a corresponding CL struct with encode and decode functions, so you can pack and unpack data exchanged through maps or ring buffers without manual byte wrangling.

defunion

defunion declares a union of existing struct types. It allocates the size of the largest member; the returned pointer can be used with any member's field accessors (all members share offset 0). This is useful for packet parsing where the same stack buffer is reused for different header types:

(defstruct ip-hdr  ...)
(defstruct udp-hdr ...)
(defunion packet-buf ip-hdr udp-hdr)

(let ((pkt (make-packet-buf)))
  (skb-load-bytes (ctx-ptr) 0 pkt (sizeof ip-hdr))
  (ip-hdr-protocol pkt))    ; access through any member's accessors