// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (c) 2022 Hengqi Chen */ #include "compat.h" #include "trace_helpers.h" #include #include #include #define PERF_BUFFER_PAGES 64 struct bpf_buffer { struct bpf_map *events; void *inner; bpf_buffer_sample_fn fn; void *ctx; int type; }; static void perfbuf_sample_fn(void *ctx, int cpu, void *data, __u32 size) { struct bpf_buffer *buffer = ctx; bpf_buffer_sample_fn fn; fn = buffer->fn; if (!fn) return; (void)fn(buffer->ctx, data, size); } struct bpf_buffer *bpf_buffer__new(struct bpf_map *events, struct bpf_map *heap) { struct bpf_buffer *buffer; bool use_ringbuf; int type; use_ringbuf = probe_ringbuf(); if (use_ringbuf) { bpf_map__set_autocreate(heap, false); type = BPF_MAP_TYPE_RINGBUF; } else { bpf_map__set_type(events, BPF_MAP_TYPE_PERF_EVENT_ARRAY); bpf_map__set_key_size(events, sizeof(int)); bpf_map__set_value_size(events, sizeof(int)); type = BPF_MAP_TYPE_PERF_EVENT_ARRAY; } buffer = calloc(1, sizeof(*buffer)); if (!buffer) { errno = ENOMEM; return NULL; } buffer->events = events; buffer->type = type; return buffer; } int bpf_buffer__open(struct bpf_buffer *buffer, bpf_buffer_sample_fn sample_cb, bpf_buffer_lost_fn lost_cb, void *ctx) { int fd, type; void *inner; fd = bpf_map__fd(buffer->events); type = buffer->type; switch (type) { case BPF_MAP_TYPE_PERF_EVENT_ARRAY: buffer->fn = sample_cb; buffer->ctx = ctx; inner = perf_buffer__new(fd, PERF_BUFFER_PAGES, perfbuf_sample_fn, lost_cb, buffer, NULL); break; case BPF_MAP_TYPE_RINGBUF: inner = ring_buffer__new(fd, sample_cb, ctx, NULL); break; default: return 0; } if (!inner) return -errno; buffer->inner = inner; return 0; } int bpf_buffer__poll(struct bpf_buffer *buffer, int timeout_ms) { switch (buffer->type) { case BPF_MAP_TYPE_PERF_EVENT_ARRAY: return perf_buffer__poll(buffer->inner, timeout_ms); case BPF_MAP_TYPE_RINGBUF: return ring_buffer__poll(buffer->inner, timeout_ms); default: return -EINVAL; } } void bpf_buffer__free(struct bpf_buffer *buffer) { if (!buffer) return; switch (buffer->type) { case BPF_MAP_TYPE_PERF_EVENT_ARRAY: perf_buffer__free(buffer->inner); break; case BPF_MAP_TYPE_RINGBUF: ring_buffer__free(buffer->inner); break; } free(buffer); }