https://github.com/platformatic/node-epbf
https://github.com/platformatic/node-epbf
Last synced: 14 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/platformatic/node-epbf
- Owner: platformatic
- License: apache-2.0
- Created: 2026-01-07T08:53:36.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-03-01T09:27:00.000Z (3 months ago)
- Last Synced: 2026-05-03T12:02:31.057Z (27 days ago)
- Language: C
- Size: 54.7 KB
- Stars: 6
- Watchers: 0
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
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
```bash
npm install node-ebpf
```
## Getting Started
### 1. Write a BPF Program
Create a simple BPF program in C (e.g., `hello.bpf.c`):
```c
#include
#include
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
```bash
clang -O2 -target bpf -c hello.bpf.c -o hello.bpf.o
```
### 3. Load and Attach from Node.js
```typescript
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
```bash
sudo node hello.ts
# or grant CAP_BPF
sudo setcap cap_bpf,cap_perfmon+ep $(which node)
node hello.ts
```
## API 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 `.o` BPF object file
- **Returns** - A new BpfObject instance
- **Throws** - Error if the file cannot be opened
```typescript
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
```typescript
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.
```typescript
obj.load();
```
##### `close(): void`
Close the BPF object and release all resources. Programs and maps become invalid after this call.
```typescript
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
```typescript
const prog = obj.program('trace_execve');
```
##### `programs(): BpfProgram[]`
Get all programs in the object.
```typescript
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
```typescript
const map = obj.map('events');
```
##### `maps(): BpfMap[]`
Get all maps in the object.
```typescript
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/...`).
```typescript
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)
```typescript
const link = prog.attachKprobe('do_sys_open');
const retLink = prog.attachKprobe('do_sys_open', true); // kretprobe
```
##### `attachTracepoint(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`)
```typescript
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
```typescript
const link = prog.attachXdp('eth0');
```
##### `attachRawTracepoint(name: string): BpfLink`
Attach to a raw tracepoint.
- **name** - Raw tracepoint name (e.g., `sched_switch`)
```typescript
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 program
- `name: string` - Program function name
- `type: ProgType` - Program type (KPROBE, TRACEPOINT, XDP, etc.)
- `sectionName: string` - ELF section name
- `autoload: 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 `keySize` bytes)
- **Returns** - Value buffer or null if not found
```typescript
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 `keySize` bytes)
- **value** - Value buffer (must match `valueSize` bytes)
- **flags** - Update flags: `UpdateFlags.ANY` (default), `NOEXIST`, `EXIST`
```typescript
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
```typescript
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`
Iterate over all keys.
```typescript
for (const key of map.keys()) {
console.log(key);
}
```
##### `entries(): Generator<[Buffer, Buffer]>`
Iterate over all key-value pairs.
```typescript
for (const [key, value] of map.entries()) {
console.log(key, value);
}
```
##### `values(): Generator`
Iterate over all values.
#### Properties
- `fd: number` - File descriptor
- `name: string` - Map variable name
- `type: MapType` - Map type (HASH, ARRAY, RINGBUF, etc.)
- `keySize: number` - Key size in bytes
- `valueSize: number` - Value size in bytes
- `maxEntries: 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.
```typescript
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 descriptor
- `isValid: 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
```typescript
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.
```typescript
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 integration
- `watching: boolean` - Whether automatic polling is active
- `closed: 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.
```typescript
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
```typescript
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 more
```
#### ProgType
```typescript
import { ProgType } from 'node-ebpf';
ProgType.KPROBE
ProgType.TRACEPOINT
ProgType.XDP
ProgType.RAW_TRACEPOINT
ProgType.SOCKET_FILTER
// ... and more
```
#### UpdateFlags
```typescript
import { UpdateFlags } from 'node-ebpf';
UpdateFlags.ANY // Create or update
UpdateFlags.NOEXIST // Create only if doesn't exist
UpdateFlags.EXIST // Update only if exists
```
## Examples
See the [examples](./examples) directory for complete working examples.
## License
Apache-2.0