018.Ringbuffer相关API

下面把 eBPF Ring Buffer(BPF_MAP_TYPE_RINGBUF) 相关的 核心 API内核侧(BPF 程序)用户态(libbpf) 系统列出来,并标注典型用法与注意点

注意:Ringbuffer写满了就不会再写入数据


一、内核侧(eBPF 程序)API

头文件:#include <bpf/bpf_helpers.h>

1️⃣ 预留空间(reserve)

void *bpf_ringbuf_reserve(void *ringbuf, u64 size, u64 flags);
  • 作用:从 ring buffer 预留一块 size 字节的空间
  • 返回:成功返回指向这块空间的指针;失败返回 NULL
  • flags
    • 0(常用)
    • BPF_RB_NO_WAKEUP(提交时不唤醒用户态)

注意:失败一定要判空,不能写 NULL 指针


2️⃣ 提交事件(submit)

void bpf_ringbuf_submit(void *data, u64 flags);
  • 作用:提交已写好的事件,让用户态可见
  • flags
    • 0
    • BPF_RB_NO_WAKEUP

语义:一旦 submit,数据就“不可回滚”。


3️⃣ 丢弃事件(discard)

void bpf_ringbuf_discard(void *data, u64 flags);
  • 作用:放弃这次预留(常用于过滤后不想输出)
  • flags
    • 0
    • BPF_RB_NO_WAKEUP

常见场景
条件不满足 / PID 不匹配 / 采样被丢弃。


4️⃣ 一步到位输出(output,快捷但不推荐)

long bpf_ringbuf_output(void *ringbuf, void *data, u64 size, u64 flags);
  • 作用:不 reserve,直接拷贝一份数据进 ringbuf
  • 缺点:一次额外拷贝、不可变长结构友好度差
  • 建议新代码优先用 reserve/submit

5️⃣ 查询剩余空间(可选)

u64 bpf_ringbuf_query(void *ringbuf, u64 query);
  • query
    • BPF_RB_AVAIL_DATA
    • BPF_RB_RING_SIZE
    • BPF_RB_CONS_POS
    • BPF_RB_PROD_POS

用途:自适应采样、限流(较少用)


二、用户态(libbpf)API

头文件:#include <bpf/libbpf.h>

1️⃣ 创建 ring buffer 消费者

struct ring_buffer *ring_buffer__new(
    int map_fd,
    ring_buffer_sample_fn sample_cb,
    void *ctx,
    const struct ring_buffer_opts *opts
);
  • map_fd:ringbuf map 的 fd
  • sample_cb:事件回调
  • ctx:回调上下文
  • opts:可选(通常为 NULL)

2️⃣ 轮询事件(poll)

int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms);
  • 作用:阻塞/轮询等待事件
  • timeout_ms
    • -1:一直阻塞
    • 0:非阻塞
    • >0:超时毫秒

返回值

  • >0:处理的事件数
  • 0:超时
  • <0:错误

3️⃣ 释放 ring buffer

void ring_buffer__free(struct ring_buffer *rb);
  • 作用:释放用户态资源
  • 注意:不会影响内核侧 map

4️⃣ 回调函数签名

int sample_cb(void *ctx, void *data, size_t size);
  • data:事件数据
  • size:事件长度
  • 返回0(继续),<0(停止)

三、Map 定义(BPF 侧)

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 1 << 24); // 16MB
} events SEC(".maps");
  • max_entries:ring buffer 总大小(字节)
  • 建议:按峰值事件速率 × 单条大小 × 容忍延迟估算

四、典型内核侧使用范式(推荐)

struct event *e;

e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e)
    return 0;

e->pid = bpf_get_current_pid_tgid() >> 32;
e->size = size;

bpf_ringbuf_submit(e, 0);

或带过滤:

e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e)
    return 0;

if (!need_output) {
    bpf_ringbuf_discard(e, 0);
    return 0;
}

bpf_ringbuf_submit(e, 0);

五、快速对照:Ring Buffer vs Perf Buffer

能力 Ring Buffer Perf Buffer
内核版本 ≥ 5.8 较老也支持
变长事件
API 简洁
性能
新项目 首选 不推荐
posted @ 2026-06-02 00:37  BlackSnow  阅读(16)  评论(0)    收藏  举报