node-ebpf
v0.1.0
Published
Node.js bindings for libbpf - load and interact with eBPF programs
Maintainers
Readme
node-ebpf
Node.js bindings for libbpf - load and interact with eBPF programs.
Requirements
- Linux kernel 5.8+
- Node.js 20+
- libbpf-dev (
apt install libbpf-dev) - clang (for compiling BPF programs)
Installation
npm install node-ebpfGetting Started
1. Write a BPF Program
Create a simple BPF program in C (e.g., hello.bpf.c):
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} events SEC(".maps");
SEC("tracepoint/syscalls/sys_enter_execve")
int trace_execve(void *ctx) {
int *e = bpf_ringbuf_reserve(&events, sizeof(int), 0);
if (e) {
*e = 42;
bpf_ringbuf_submit(e, 0);
}
return 0;
}
char LICENSE[] SEC("license") = "GPL";2. Compile the BPF Program
clang -O2 -target bpf -c hello.bpf.c -o hello.bpf.o3. Load and Attach from Node.js
import { BpfObject, RingBuffer } from 'node-ebpf';
// Open and load the BPF object
const obj = BpfObject.open('./hello.bpf.o');
obj.load();
// Get the program and attach it
const prog = obj.program('trace_execve');
const link = prog.attach();
// Get the ring buffer map and consume events
const eventsMap = obj.map('events');
const rb = RingBuffer.create(eventsMap, (data) => {
console.log('Event:', data.readInt32LE(0));
});
// Start event-driven polling
rb.start();
// Cleanup on exit
process.on('SIGINT', () => {
rb.close();
link.destroy();
obj.close();
process.exit();
});4. Run with Privileges
sudo node hello.ts
# or grant CAP_BPF
sudo setcap cap_bpf,cap_perfmon+ep $(which node)
node hello.tsAPI Reference
BpfObject
Represents a compiled BPF object file containing programs and maps.
Static Methods
BpfObject.open(path: string): BpfObject
Open a BPF object from a file path.
- path - Path to the
.oBPF object file - Returns - A new BpfObject instance
- Throws - Error if the file cannot be opened
const obj = BpfObject.open('./program.bpf.o');BpfObject.openBuffer(buffer: Buffer, name?: string): BpfObject
Open a BPF object from a memory buffer.
- buffer - Buffer containing the ELF object data
- name - Optional name for the object (defaults to "buffer")
- Returns - A new BpfObject instance
const data = fs.readFileSync('./program.bpf.o');
const obj = BpfObject.openBuffer(data, 'my_program');Instance Methods
load(): void
Load all BPF programs in the object into the kernel. Must be called before attaching programs.
obj.load();close(): void
Close the BPF object and release all resources. Programs and maps become invalid after this call.
obj.close();program(name: string): BpfProgram | null
Get a program by its function name.
- name - The function name defined in the BPF C code
- Returns - BpfProgram instance or null if not found
const prog = obj.program('trace_execve');programs(): BpfProgram[]
Get all programs in the object.
for (const prog of obj.programs()) {
console.log(prog.name, prog.type);
}map(name: string): BpfMap | null
Get a map by its variable name.
- name - The map variable name defined in the BPF C code
- Returns - BpfMap instance or null if not found
const map = obj.map('events');maps(): BpfMap[]
Get all maps in the object.
for (const map of obj.maps()) {
console.log(map.name, map.type, map.keySize, map.valueSize);
}Properties
name: string- Object name (usually the filename)isLoaded: boolean- Whether load() has been called
BpfProgram
Represents a BPF program that can be attached to kernel hooks.
Instance Methods
attach(): BpfLink
Auto-attach based on the program's section name (e.g., kprobe/func, tracepoint/...).
const link = prog.attach();attachKprobe(funcName: string, retprobe?: boolean): BpfLink
Attach to a kernel probe.
- funcName - Kernel function name (e.g.,
do_sys_open) - retprobe - If true, attach as a return probe (default: false)
const link = prog.attachKprobe('do_sys_open');
const retLink = prog.attachKprobe('do_sys_open', true); // kretprobeattachTracepoint(category: string, name: string): BpfLink
Attach to a kernel tracepoint.
- category - Tracepoint category (e.g.,
syscalls,sched) - name - Tracepoint name (e.g.,
sys_enter_open)
const link = prog.attachTracepoint('syscalls', 'sys_enter_execve');attachXdp(iface: string | number): BpfLink
Attach as an XDP (eXpress Data Path) program.
- iface - Network interface name (e.g.,
eth0) or index
const link = prog.attachXdp('eth0');attachRawTracepoint(name: string): BpfLink
Attach to a raw tracepoint.
- name - Raw tracepoint name (e.g.,
sched_switch)
const link = prog.attachRawTracepoint('sched_switch');pin(path: string): void
Pin the program to the BPF filesystem.
unpin(path: string): void
Unpin the program from the BPF filesystem.
setAutoload(value: boolean): void
Set whether this program should be auto-loaded.
Properties
fd: number- File descriptor of the loaded programname: string- Program function nametype: ProgType- Program type (KPROBE, TRACEPOINT, XDP, etc.)sectionName: string- ELF section nameautoload: boolean- Auto-load setting
BpfMap
Represents a BPF map for kernel/userspace data sharing.
Instance Methods
lookup(key: Buffer): Buffer | null
Look up a value by key.
- key - Key buffer (must match
keySizebytes) - Returns - Value buffer or null if not found
const key = Buffer.alloc(4);
key.writeUInt32LE(123);
const value = map.lookup(key);update(key: Buffer, value: Buffer, flags?: UpdateFlags): void
Update or insert a key-value pair.
- key - Key buffer (must match
keySizebytes) - value - Value buffer (must match
valueSizebytes) - flags - Update flags:
UpdateFlags.ANY(default),NOEXIST,EXIST
const key = Buffer.alloc(4);
const value = Buffer.alloc(8);
key.writeUInt32LE(123);
value.writeBigUInt64LE(456n);
map.update(key, value);delete(key: Buffer): boolean
Delete an entry by key.
- key - Key buffer
- Returns - true if deleted, false if not found
map.delete(key);getNextKey(key?: Buffer | null): Buffer | null
Get the next key in iteration order.
- key - Current key, or null/undefined for the first key
- Returns - Next key or null if at end
keys(): Generator<Buffer>
Iterate over all keys.
for (const key of map.keys()) {
console.log(key);
}entries(): Generator<[Buffer, Buffer]>
Iterate over all key-value pairs.
for (const [key, value] of map.entries()) {
console.log(key, value);
}values(): Generator<Buffer>
Iterate over all values.
Properties
fd: number- File descriptorname: string- Map variable nametype: MapType- Map type (HASH, ARRAY, RINGBUF, etc.)keySize: number- Key size in bytesvalueSize: number- Value size in bytesmaxEntries: number- Maximum number of entries
BpfLink
Represents an attachment of a BPF program to a kernel hook.
Instance Methods
destroy(): void
Destroy the link and detach the program.
link.destroy();detach(): void
Detach the program but keep the link object.
pin(path: string): void
Pin the link to the BPF filesystem.
unpin(): void
Unpin the link from the BPF filesystem.
Properties
fd: number- File descriptorisValid: boolean- Whether the link is still valid
RingBuffer
EventEmitter-based ring buffer consumer for efficient kernel-to-userspace data streaming.
Static Methods
RingBuffer.create(map: BpfMap, callback?: RingBufferCallback): RingBuffer
Create a ring buffer consumer from a BPF map.
- map - BpfMap of type RINGBUF
- callback - Optional callback for each data sample
const rb = RingBuffer.create(map, (data) => {
console.log('Received:', data);
});RingBuffer.fromFd(mapFd: number, callback?: RingBufferCallback): RingBuffer
Create from a map file descriptor.
Instance Methods
start(): void
Start automatic event-driven polling. Integrates with Node's event loop using libuv.
rb.start();
rb.on('data', (data) => console.log(data));stop(): void
Stop automatic polling.
poll(timeoutMs?: number): number
Manually poll for new data.
- timeoutMs - Timeout in ms (0 = non-blocking, -1 = infinite)
- Returns - Number of samples consumed
consume(): number
Consume all available data without blocking.
close(): void
Close the ring buffer and release resources.
Properties
epollFd: number- Epoll file descriptor for custom integrationwatching: boolean- Whether automatic polling is activeclosed: boolean- Whether the ring buffer is closed
Events
data- Emitted for each data sample (Buffer)error- Emitted on errors
Utility Functions
setLogCallback(callback: LogCallback | null): void
Set the libbpf log callback.
import { setLogCallback } from 'node-ebpf';
setLogCallback((level, msg) => {
console.log(`[libbpf:${level}] ${msg}`);
});getLibbpfVersion(): string
Get the libbpf version string.
probeProgType(type: ProgType): boolean
Check if a program type is supported by the kernel.
probeMapType(type: MapType): boolean
Check if a map type is supported by the kernel.
Constants
MapType
import { MapType } from 'node-ebpf';
MapType.HASH // Hash table
MapType.ARRAY // Array
MapType.RINGBUF // Ring buffer
MapType.PERF_EVENT_ARRAY
MapType.PERCPU_HASH
MapType.PERCPU_ARRAY
// ... and moreProgType
import { ProgType } from 'node-ebpf';
ProgType.KPROBE
ProgType.TRACEPOINT
ProgType.XDP
ProgType.RAW_TRACEPOINT
ProgType.SOCKET_FILTER
// ... and moreUpdateFlags
import { UpdateFlags } from 'node-ebpf';
UpdateFlags.ANY // Create or update
UpdateFlags.NOEXIST // Create only if doesn't exist
UpdateFlags.EXIST // Update only if existsExamples
See the examples directory for complete working examples.
License
Apache-2.0
