Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libbpf: Expose API to consume one ring at a time #5401

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tools/lib/bpf/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,7 @@ LIBBPF_API int ring_buffer__add(struct ring_buffer *rb, int map_fd,
ring_buffer_sample_fn sample_cb, void *ctx);
LIBBPF_API int ring_buffer__poll(struct ring_buffer *rb, int timeout_ms);
LIBBPF_API int ring_buffer__consume(struct ring_buffer *rb);
LIBBPF_API int ring_buffer__consume_ring(struct ring_buffer *rb, uint32_t ring_id);
LIBBPF_API int ring_buffer__epoll_fd(const struct ring_buffer *rb);

struct user_ring_buffer_opts {
Expand Down
1 change: 1 addition & 0 deletions tools/lib/bpf/libbpf.map
Original file line number Diff line number Diff line change
Expand Up @@ -398,4 +398,5 @@ LIBBPF_1.3.0 {
bpf_prog_detach_opts;
bpf_program__attach_netfilter;
bpf_program__attach_tcx;
ring_buffer__consume_ring;
} LIBBPF_1.2.0;
22 changes: 22 additions & 0 deletions tools/lib/bpf/ringbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,28 @@ int ring_buffer__consume(struct ring_buffer *rb)
return res;
}

/* Consume available data from a single RINGBUF map identified by its ID.
* The ring ID is returned in epoll_data by epoll_wait when called with
* ring_buffer__epoll_fd.
*/
int ring_buffer__consume_ring(struct ring_buffer *rb, uint32_t ring_id)
{
struct ring *ring;
int64_t res;

if (ring_id >= rb->ring_cnt)
return libbpf_err(-EINVAL);

ring = &rb->rings[ring_id];
res = ringbuf_process_ring(ring);
if (res < 0)
return libbpf_err(res);

if (res > INT_MAX)
return INT_MAX;
return res;
}

/* Poll for available data and consume records, if any are available.
* Returns number of records consumed (or INT_MAX, whichever is less), or
* negative number, if any of the registered callbacks returned error.
Expand Down
26 changes: 26 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/ringbuf_multi.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ static int process_sample(void *ctx, void *data, size_t len)
CHECK(s->value != 777, "sample2_value", "exp %ld, got %ld\n",
777L, s->value);
break;
case 2:
CHECK(ring != 2, "sample3_ring", "exp %d, got %d\n", 2, ring);
CHECK(s->value != 1337, "sample3_value", "exp %ld, got %ld\n",
1337L, s->value);
break;
default:
CHECK(true, "extra_sample", "unexpected sample seq %d, val %ld\n",
s->seq, s->value);
Expand All @@ -45,6 +50,8 @@ void test_ringbuf_multi(void)
int err;
int page_size = getpagesize();
int proto_fd = -1;
int epoll_fd;
struct epoll_event events[2];

skel = test_ringbuf_multi__open();
if (CHECK(!skel, "skel_open", "skeleton open failed\n"))
Expand Down Expand Up @@ -124,6 +131,25 @@ void test_ringbuf_multi(void)
CHECK(skel->bss->total != 2, "err_total", "exp %ld, got %ld\n",
2L, skel->bss->total);

/* validate APIs to support external polling */
epoll_fd = ring_buffer__epoll_fd(ringbuf);

/* expect events on either ring to trigger through the epoll_fd */
skel->bss->target_ring = 2;
skel->bss->value = 1337;
syscall(__NR_getpgid);

err = epoll_wait(epoll_fd, events, sizeof(events) / sizeof(struct epoll_event), -1);
if (CHECK(err != 1, "epoll_wait", "epoll_wait exp %d, got %d\n", 1, err))
goto cleanup;
if (CHECK(!(events[0].events & EPOLLIN), "epoll_event", "expected EPOLLIN\n"))
goto cleanup;

/* epoll data can be used to consume only the affected ring */
err = ring_buffer__consume_ring(ringbuf, events[0].data.u32);
CHECK(err != 1, "consume_ring", "consume_ring %u exp %d, got %d\n",
events[0].data.u32, 1, err);

cleanup:
if (proto_fd >= 0)
close(proto_fd);
Expand Down
Loading