An open API service indexing awesome lists of open source software.

https://github.com/platformatic/node-epbf


https://github.com/platformatic/node-epbf

Last synced: 14 days ago
JSON representation

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