Skip to content

Cheat Sheet — Java ↔ Kernel / C

Quick reference for every mapping the hello-ebpf compiler plugin understands.

Program skeleton

Java Kernel / C meaning
@BPF(license="GPL") abstract class Foo extends BPFProgram Defines a BPF program; license string embedded in ELF
@BPFFunction void myFn(...) A C function compiled into the BPF program
@BPFFunction(section = "xdp/foo") Override the ELF section name

Pointer operations

Java Kernel / C
Ptr<X> p X *p
Ptr.of(x) &x
p.val() *p (dereference)
p.set(v) *p = v
p.val().field p->field
Ptr.of(p.val().field).set(v) p->field = v
Ptr.<X>cast(p) (X *)p — safe cast between pointer types
Ptr.voidPointer() (void *)0 / null void pointer

Types and structs

Java Kernel / C
@Type record Foo(int a, int b) struct Foo { int a; int b; };
@Size(16) String s char s[16] — fixed-length char array field
BPFJ.charBuf(16) char buf[16] = {} — stack buffer initialisation
@Unsigned int n u32 n — treat the Java int as unsigned
@Unsigned long n u64 n
final static int N = 4 on a @BPF class static const int N = 4 in generated C

Global variables

Java Meaning
GlobalVariable<Long> ctr = new GlobalVariable<>(0L) BPF array map of size 1 (kernel) + Java accessor
ctr.get() Java-side read (mmap'd)
ctr.set(v) Java-side write (mmap'd)
ctr.get() inside @BPFFunction ctr dereference in C
ctr.incrementAndGet() Atomic fetch-and-add on the Java side
ctr.addAndGet(delta) Atomic add-delta on the Java side
ctr.compareAndSet(expect, update) CAS on the Java side

Map types

Java declaration BPF map type
BPFHashMap<K,V> BPF_MAP_TYPE_HASH
BPFLRUHashMap<K,V> BPF_MAP_TYPE_LRU_HASH
BPFArray<V> BPF_MAP_TYPE_ARRAY
BPFRingBuffer<E> BPF_MAP_TYPE_RINGBUF
BPFPerCpuArray<V> BPF_MAP_TYPE_PERCPU_ARRAY
BPFBloomFilter<V> BPF_MAP_TYPE_BLOOM_FILTER
BPFQueue<V> BPF_MAP_TYPE_QUEUE
BPFStack<V> BPF_MAP_TYPE_STACK
BPFProgArray BPF_MAP_TYPE_PROG_ARRAY (tail calls)
BPFTaskStorage<V> BPF_MAP_TYPE_TASK_STORAGE (per-task state, sched_ext)

All maps are annotated with @BPFMapDefinition(maxEntries = N).

Scheduler abstractions (sched_ext)

DispatchQueue

Java Meaning
new DispatchQueue(id) Create a custom DSQ; scx_bpf_create_dsq(id,-1) lifted to init()
DispatchQueue.attach(id) Wrap an already-existing DSQ — no create emitted
DispatchQueue.local() SCX_DSQ_LOCAL — current CPU's local queue
DispatchQueue.localOn(cpu) SCX_DSQ_LOCAL_ON \| cpu
DispatchQueue.global() SCX_DSQ_GLOBAL
dsq.insert(p, slice, flags) FIFO insert with explicit slice
dsq.insertScaled(p, flags) FIFO insert; slice scaled by queue depth
dsq.insertVtime(p, slice, vtime, flags) Vtime-ordered insert
dsq.insertVtimeClamped(p, vtimeNow, flags) Vtime insert with idle-budget clamping (WFQ)
DispatchQueue.insertToLocalIfIdle(p, isIdle, slice) Fast-path from selectCPU
dsq.moveToLocal() Move one task to the local CPU queue; returns true if moved
dsq.nonEmpty() true when tasks are waiting
dsq.nrQueued() Count of waiting tasks
DispatchQueue.now() Monotonic time in ns (scx_bpf_now())
DispatchQueue.kickCpu(cpu, flags) Wake a remote CPU
DispatchQueue.yieldNow(p) Zero the running task's slice — immediate reschedule
dsq.destroy() Destroy a custom DSQ

EnqFlags

Java Meaning
EnqFlags.passThrough(enq_flags) Wrap the raw enq_flags parameter from enqueue()
EnqFlags.empty() No flags
EnqFlags.of(flag, ...) Compose scx_enq_flags constants
f.isWakeup() SCX_ENQ_WAKEUP set?
f.isLast() Last runnable task on this CPU?
f.or(other) Combine two EnqFlags

KickFlags

Java Meaning
KickFlags.idle() SCX_KICK_IDLE — wake only if the CPU is idle
KickFlags.preempt() SCX_KICK_PREEMPT — preempt whatever is running
KickFlags.waitForKick() SCX_KICK_WAIT — wait for the kick to be processed
KickFlags.none() No flags
f.or(other) Combine two KickFlags

CpuMask

CpuMask wraps a read-only const struct cpumask *. Must be used as a local variable inside a @BPFFunction (never as a field). Always release borrowed masks.

Java Meaning
CpuMask.idle() Borrow the global idle CPU mask; release with releaseIdle()
CpuMask.idleSmt() Idle mask, one logical CPU per physical core
CpuMask.idleOnNode(n) Idle mask restricted to NUMA node n
CpuMask.online() Online CPU mask; release with release()
CpuMask.possible() Possible CPU mask; release with release()
CpuMask.ofTask(p) Read-only view of p->cpus_ptr; no release needed
mask.test(cpu) true if cpu is set
mask.weight() Number of CPUs set
mask.first() Lowest-numbered CPU set (or >= nr_cpu_ids if empty)
mask.isEmpty() true if no CPUs set
mask.intersects(other) true if the two masks share at least one CPU
mask.pickIdle(0) Pick and claim an idle CPU; returns CPU or -EBUSY
mask.pickAny(0) Pick any CPU, preferring idle ones
mask.releaseIdle() Release masks from idle() / idleSmt() / idleOnNode()
mask.release() Release masks from online() / possible()

Hook interfaces

Java BPF hook
implements XDPHook XDP program (express data path)
implements TCHook TC classifier (traffic control)
implements Scheduler sched_ext scheduler
implements LSMHook BPF LSM (requires CONFIG_BPF_LSM=y)
implements CGroupHook cgroup ingress/egress
@Kprobe("do_sys_openat2") on method kprobe at function entry, auto-attach
@Kretprobe("do_sys_openat2") on method kretprobe at function return
@Fentry("do_sys_openat2") on method fentry (BTF-based), auto-attach
@Fexit("do_sys_openat2") on method fexit (BTF-based)
@Tracepoint(category="syscalls", name="sys_enter_openat") tracepoint section
@RawTracepoint("sys_enter") raw_tracepoint section
@Ksyscall("openat") ksyscall (arch-portable kprobe on syscall)

BPFJ helper methods (BPF side)

Java call Expands to in C
BPFJ.bpf_trace_printk(fmt, args) bpf_trace_printk(fmt, sizeof(fmt), args)
BPFJ.currentPid() (u32)(bpf_get_current_pid_tgid())
BPFJ.currentTgid() (u32)(bpf_get_current_pid_tgid() >> 32)
BPFJ.currentNs() bpf_ktime_get_ns()
BPFJ.getCurrentComm(buf) bpf_get_current_comm(buf, sizeof(buf))
BPFJ.bpf_loop(n, callback, ctx, flags) bpf_loop(n, callback, ctx, flags)
BPFJ.bpf_probe_read_user(dst, src) bpf_probe_read_user(&dst, sizeof(*&dst), src)
BPFJ.bpf_probe_read_kernel(dest, src) bpf_probe_read_kernel(&dest, sizeof(dest), src)
BPFHelpers.bpf_skb_store_bytes(skb, off, from, len, flags) bpf_skb_store_bytes(...)

Pointer pattern examples

// Read a struct field through a pointer
Ptr<xdp_md> ctx = ...;
int data = ctx.val().data;

// Write through a nested pointer
Ptr<sock_common> sk = ...;
Ptr.of(sk.val().skc_daddr).set(newAddr);

// Cast void pointer
Ptr<ethhdr> eth = Ptr.cast(Ptr.of(ctx.val().data));

Byte-order note

Network protocols use big-endian (network byte order). x86 hosts are little-endian. Always convert:

// In @BPFFunction — use kernel helpers
int proto = BPFJ.bpf_ntohs(eth.val().h_proto);

// Or use the raw macros via Lib constants
if (eth.val().h_proto == bpf_htons(ETH_P_IP)) { ... }

On the Java side, use Short.reverseBytes(), Integer.reverseBytes(), or java.nio.ByteOrder.


Further reading