1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
5 #include <linux/compiler.h>
6 #include <linux/ring_buffer.h>
7 #include <linux/build_bug.h>
12 #include <sys/syscall.h>
13 #include <sys/sysinfo.h>
14 #include <test_progs.h>
15 #include <uapi/linux/bpf.h>
18 #include "user_ringbuf_fail.skel.h"
19 #include "user_ringbuf_success.skel.h"
21 #include "../progs/test_user_ringbuf.h"
23 static const long c_sample_size = sizeof(struct sample) + BPF_RINGBUF_HDR_SZ;
24 static const long c_ringbuf_size = 1 << 12; /* 1 small page */
25 static const long c_max_entries = c_ringbuf_size / c_sample_size;
27 static void drain_current_samples(void)
29 syscall(__NR_getpgid);
32 static int write_samples(struct user_ring_buffer *ringbuf, uint32_t num_samples)
36 /* Write some number of samples to the ring buffer. */
37 for (i = 0; i < num_samples; i++) {
41 entry = user_ring_buffer__reserve(ringbuf, sizeof(*entry));
47 entry->pid = getpid();
51 read = snprintf(entry->comm, sizeof(entry->comm), "%u", i);
53 /* Assert on the error path to avoid spamming logs with
54 * mostly success messages.
56 ASSERT_GT(read, 0, "snprintf_comm");
58 user_ring_buffer__discard(ringbuf, entry);
62 user_ring_buffer__submit(ringbuf, entry);
66 drain_current_samples();
71 static struct user_ringbuf_success *open_load_ringbuf_skel(void)
73 struct user_ringbuf_success *skel;
76 skel = user_ringbuf_success__open();
77 if (!ASSERT_OK_PTR(skel, "skel_open"))
80 err = bpf_map__set_max_entries(skel->maps.user_ringbuf, c_ringbuf_size);
81 if (!ASSERT_OK(err, "set_max_entries"))
84 err = bpf_map__set_max_entries(skel->maps.kernel_ringbuf, c_ringbuf_size);
85 if (!ASSERT_OK(err, "set_max_entries"))
88 err = user_ringbuf_success__load(skel);
89 if (!ASSERT_OK(err, "skel_load"))
95 user_ringbuf_success__destroy(skel);
99 static void test_user_ringbuf_mappings(void)
102 int page_size = getpagesize();
104 struct user_ringbuf_success *skel;
106 skel = open_load_ringbuf_skel();
110 rb_fd = bpf_map__fd(skel->maps.user_ringbuf);
111 /* cons_pos can be mapped R/O, can't add +X with mprotect. */
112 mmap_ptr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, rb_fd, 0);
113 ASSERT_OK_PTR(mmap_ptr, "ro_cons_pos");
114 ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_WRITE), "write_cons_pos_protect");
115 ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_EXEC), "exec_cons_pos_protect");
116 ASSERT_ERR_PTR(mremap(mmap_ptr, 0, 4 * page_size, MREMAP_MAYMOVE), "wr_prod_pos");
118 ASSERT_ERR(err, "wr_prod_pos_err");
119 ASSERT_OK(munmap(mmap_ptr, page_size), "unmap_ro_cons");
121 /* prod_pos can be mapped RW, can't add +X with mprotect. */
122 mmap_ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED,
124 ASSERT_OK_PTR(mmap_ptr, "rw_prod_pos");
125 ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_EXEC), "exec_prod_pos_protect");
127 ASSERT_ERR(err, "wr_prod_pos_err");
128 ASSERT_OK(munmap(mmap_ptr, page_size), "unmap_rw_prod");
130 /* data pages can be mapped RW, can't add +X with mprotect. */
131 mmap_ptr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, rb_fd,
133 ASSERT_OK_PTR(mmap_ptr, "rw_data");
134 ASSERT_ERR(mprotect(mmap_ptr, page_size, PROT_EXEC), "exec_data_protect");
136 ASSERT_ERR(err, "exec_data_err");
137 ASSERT_OK(munmap(mmap_ptr, page_size), "unmap_rw_data");
139 user_ringbuf_success__destroy(skel);
142 static int load_skel_create_ringbufs(struct user_ringbuf_success **skel_out,
143 struct ring_buffer **kern_ringbuf_out,
144 ring_buffer_sample_fn callback,
145 struct user_ring_buffer **user_ringbuf_out)
147 struct user_ringbuf_success *skel;
148 struct ring_buffer *kern_ringbuf = NULL;
149 struct user_ring_buffer *user_ringbuf = NULL;
150 int err = -ENOMEM, rb_fd;
152 skel = open_load_ringbuf_skel();
156 /* only trigger BPF program for current process */
157 skel->bss->pid = getpid();
159 if (kern_ringbuf_out) {
160 rb_fd = bpf_map__fd(skel->maps.kernel_ringbuf);
161 kern_ringbuf = ring_buffer__new(rb_fd, callback, skel, NULL);
162 if (!ASSERT_OK_PTR(kern_ringbuf, "kern_ringbuf_create"))
165 *kern_ringbuf_out = kern_ringbuf;
168 if (user_ringbuf_out) {
169 rb_fd = bpf_map__fd(skel->maps.user_ringbuf);
170 user_ringbuf = user_ring_buffer__new(rb_fd, NULL);
171 if (!ASSERT_OK_PTR(user_ringbuf, "user_ringbuf_create"))
174 *user_ringbuf_out = user_ringbuf;
175 ASSERT_EQ(skel->bss->read, 0, "no_reads_after_load");
178 err = user_ringbuf_success__attach(skel);
179 if (!ASSERT_OK(err, "skel_attach"))
186 if (kern_ringbuf_out)
187 *kern_ringbuf_out = NULL;
188 if (user_ringbuf_out)
189 *user_ringbuf_out = NULL;
190 ring_buffer__free(kern_ringbuf);
191 user_ring_buffer__free(user_ringbuf);
192 user_ringbuf_success__destroy(skel);
196 static int load_skel_create_user_ringbuf(struct user_ringbuf_success **skel_out,
197 struct user_ring_buffer **ringbuf_out)
199 return load_skel_create_ringbufs(skel_out, NULL, NULL, ringbuf_out);
202 static void manually_write_test_invalid_sample(struct user_ringbuf_success *skel,
203 __u32 size, __u64 producer_pos, int err)
206 __u64 *producer_pos_ptr;
207 int rb_fd, page_size = getpagesize();
209 rb_fd = bpf_map__fd(skel->maps.user_ringbuf);
211 ASSERT_EQ(skel->bss->read, 0, "num_samples_before_bad_sample");
213 /* Map the producer_pos as RW. */
214 producer_pos_ptr = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
215 MAP_SHARED, rb_fd, page_size);
216 ASSERT_OK_PTR(producer_pos_ptr, "producer_pos_ptr");
218 /* Map the data pages as RW. */
219 data_ptr = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, rb_fd, 2 * page_size);
220 ASSERT_OK_PTR(data_ptr, "rw_data");
222 memset(data_ptr, 0, BPF_RINGBUF_HDR_SZ);
223 *(__u32 *)data_ptr = size;
225 /* Synchronizes with smp_load_acquire() in __bpf_user_ringbuf_peek() in the kernel. */
226 smp_store_release(producer_pos_ptr, producer_pos + BPF_RINGBUF_HDR_SZ);
228 drain_current_samples();
229 ASSERT_EQ(skel->bss->read, 0, "num_samples_after_bad_sample");
230 ASSERT_EQ(skel->bss->err, err, "err_after_bad_sample");
232 ASSERT_OK(munmap(producer_pos_ptr, page_size), "unmap_producer_pos");
233 ASSERT_OK(munmap(data_ptr, page_size), "unmap_data_ptr");
236 static void test_user_ringbuf_post_misaligned(void)
238 struct user_ringbuf_success *skel;
239 struct user_ring_buffer *ringbuf;
241 __u32 size = (1 << 5) + 7;
243 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
244 if (!ASSERT_OK(err, "misaligned_skel"))
247 manually_write_test_invalid_sample(skel, size, size, -EINVAL);
248 user_ring_buffer__free(ringbuf);
249 user_ringbuf_success__destroy(skel);
252 static void test_user_ringbuf_post_producer_wrong_offset(void)
254 struct user_ringbuf_success *skel;
255 struct user_ring_buffer *ringbuf;
257 __u32 size = (1 << 5);
259 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
260 if (!ASSERT_OK(err, "wrong_offset_skel"))
263 manually_write_test_invalid_sample(skel, size, size - 8, -EINVAL);
264 user_ring_buffer__free(ringbuf);
265 user_ringbuf_success__destroy(skel);
268 static void test_user_ringbuf_post_larger_than_ringbuf_sz(void)
270 struct user_ringbuf_success *skel;
271 struct user_ring_buffer *ringbuf;
273 __u32 size = c_ringbuf_size;
275 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
276 if (!ASSERT_OK(err, "huge_sample_skel"))
279 manually_write_test_invalid_sample(skel, size, size, -E2BIG);
280 user_ring_buffer__free(ringbuf);
281 user_ringbuf_success__destroy(skel);
284 static void test_user_ringbuf_basic(void)
286 struct user_ringbuf_success *skel;
287 struct user_ring_buffer *ringbuf;
290 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
291 if (!ASSERT_OK(err, "ringbuf_basic_skel"))
294 ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
296 err = write_samples(ringbuf, 2);
297 if (!ASSERT_OK(err, "write_samples"))
300 ASSERT_EQ(skel->bss->read, 2, "num_samples_read_after");
303 user_ring_buffer__free(ringbuf);
304 user_ringbuf_success__destroy(skel);
307 static void test_user_ringbuf_sample_full_ring_buffer(void)
309 struct user_ringbuf_success *skel;
310 struct user_ring_buffer *ringbuf;
314 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
315 if (!ASSERT_OK(err, "ringbuf_full_sample_skel"))
318 sample = user_ring_buffer__reserve(ringbuf, c_ringbuf_size - BPF_RINGBUF_HDR_SZ);
319 if (!ASSERT_OK_PTR(sample, "full_sample"))
322 user_ring_buffer__submit(ringbuf, sample);
323 ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
324 drain_current_samples();
325 ASSERT_EQ(skel->bss->read, 1, "num_samples_read_after");
328 user_ring_buffer__free(ringbuf);
329 user_ringbuf_success__destroy(skel);
332 static void test_user_ringbuf_post_alignment_autoadjust(void)
334 struct user_ringbuf_success *skel;
335 struct user_ring_buffer *ringbuf;
336 struct sample *sample;
339 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
340 if (!ASSERT_OK(err, "ringbuf_align_autoadjust_skel"))
343 /* libbpf should automatically round any sample up to an 8-byte alignment. */
344 sample = user_ring_buffer__reserve(ringbuf, sizeof(*sample) + 1);
345 ASSERT_OK_PTR(sample, "reserve_autoaligned");
346 user_ring_buffer__submit(ringbuf, sample);
348 ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
349 drain_current_samples();
350 ASSERT_EQ(skel->bss->read, 1, "num_samples_read_after");
352 user_ring_buffer__free(ringbuf);
353 user_ringbuf_success__destroy(skel);
356 static void test_user_ringbuf_overfill(void)
358 struct user_ringbuf_success *skel;
359 struct user_ring_buffer *ringbuf;
362 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
366 err = write_samples(ringbuf, c_max_entries * 5);
367 ASSERT_ERR(err, "write_samples");
368 ASSERT_EQ(skel->bss->read, c_max_entries, "max_entries");
370 user_ring_buffer__free(ringbuf);
371 user_ringbuf_success__destroy(skel);
374 static void test_user_ringbuf_discards_properly_ignored(void)
376 struct user_ringbuf_success *skel;
377 struct user_ring_buffer *ringbuf;
378 int err, num_discarded = 0;
381 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
385 ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
388 /* Write samples until the buffer is full. */
389 token = user_ring_buffer__reserve(ringbuf, sizeof(*token));
393 user_ring_buffer__discard(ringbuf, token);
397 if (!ASSERT_GE(num_discarded, 0, "num_discarded"))
400 /* Should not read any samples, as they are all discarded. */
401 ASSERT_EQ(skel->bss->read, 0, "num_pre_kick");
402 drain_current_samples();
403 ASSERT_EQ(skel->bss->read, 0, "num_post_kick");
405 /* Now that the ring buffer has been drained, we should be able to
406 * reserve another token.
408 token = user_ring_buffer__reserve(ringbuf, sizeof(*token));
410 if (!ASSERT_OK_PTR(token, "new_token"))
413 user_ring_buffer__discard(ringbuf, token);
415 user_ring_buffer__free(ringbuf);
416 user_ringbuf_success__destroy(skel);
419 static void test_user_ringbuf_loop(void)
421 struct user_ringbuf_success *skel;
422 struct user_ring_buffer *ringbuf;
423 uint32_t total_samples = 8192;
424 uint32_t remaining_samples = total_samples;
427 BUILD_BUG_ON(total_samples <= c_max_entries);
428 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
433 uint32_t curr_samples;
435 curr_samples = remaining_samples > c_max_entries
436 ? c_max_entries : remaining_samples;
437 err = write_samples(ringbuf, curr_samples);
439 /* Assert inside of if statement to avoid flooding logs
440 * on the success path.
442 ASSERT_OK(err, "write_samples");
446 remaining_samples -= curr_samples;
447 ASSERT_EQ(skel->bss->read, total_samples - remaining_samples,
448 "current_batched_entries");
449 } while (remaining_samples > 0);
450 ASSERT_EQ(skel->bss->read, total_samples, "total_batched_entries");
453 user_ring_buffer__free(ringbuf);
454 user_ringbuf_success__destroy(skel);
457 static int send_test_message(struct user_ring_buffer *ringbuf,
458 enum test_msg_op op, s64 operand_64,
461 struct test_msg *msg;
463 msg = user_ring_buffer__reserve(ringbuf, sizeof(*msg));
465 /* Assert on the error path to avoid spamming logs with mostly
468 ASSERT_OK_PTR(msg, "reserve_msg");
475 case TEST_MSG_OP_INC64:
476 case TEST_MSG_OP_MUL64:
477 msg->operand_64 = operand_64;
479 case TEST_MSG_OP_INC32:
480 case TEST_MSG_OP_MUL32:
481 msg->operand_32 = operand_32;
484 PRINT_FAIL("Invalid operand %d\n", op);
485 user_ring_buffer__discard(ringbuf, msg);
489 user_ring_buffer__submit(ringbuf, msg);
494 static void kick_kernel_read_messages(void)
499 static int handle_kernel_msg(void *ctx, void *data, size_t len)
501 struct user_ringbuf_success *skel = ctx;
502 struct test_msg *msg = data;
504 switch (msg->msg_op) {
505 case TEST_MSG_OP_INC64:
506 skel->bss->user_mutated += msg->operand_64;
508 case TEST_MSG_OP_INC32:
509 skel->bss->user_mutated += msg->operand_32;
511 case TEST_MSG_OP_MUL64:
512 skel->bss->user_mutated *= msg->operand_64;
514 case TEST_MSG_OP_MUL32:
515 skel->bss->user_mutated *= msg->operand_32;
518 fprintf(stderr, "Invalid operand %d\n", msg->msg_op);
523 static void drain_kernel_messages_buffer(struct ring_buffer *kern_ringbuf,
524 struct user_ringbuf_success *skel)
528 cnt = ring_buffer__consume(kern_ringbuf);
529 ASSERT_EQ(cnt, 8, "consume_kern_ringbuf");
530 ASSERT_OK(skel->bss->err, "consume_kern_ringbuf_err");
533 static void test_user_ringbuf_msg_protocol(void)
535 struct user_ringbuf_success *skel;
536 struct user_ring_buffer *user_ringbuf;
537 struct ring_buffer *kern_ringbuf;
539 __u64 expected_kern = 0;
541 err = load_skel_create_ringbufs(&skel, &kern_ringbuf, handle_kernel_msg, &user_ringbuf);
542 if (!ASSERT_OK(err, "create_ringbufs"))
545 for (i = 0; i < 64; i++) {
546 enum test_msg_op op = i % TEST_MSG_OP_NUM_OPS;
547 __u64 operand_64 = TEST_OP_64;
548 __u32 operand_32 = TEST_OP_32;
550 err = send_test_message(user_ringbuf, op, operand_64, operand_32);
552 /* Only assert on a failure to avoid spamming success logs. */
553 ASSERT_OK(err, "send_test_message");
558 case TEST_MSG_OP_INC64:
559 expected_kern += operand_64;
561 case TEST_MSG_OP_INC32:
562 expected_kern += operand_32;
564 case TEST_MSG_OP_MUL64:
565 expected_kern *= operand_64;
567 case TEST_MSG_OP_MUL32:
568 expected_kern *= operand_32;
571 PRINT_FAIL("Unexpected op %d\n", op);
576 kick_kernel_read_messages();
577 ASSERT_EQ(skel->bss->kern_mutated, expected_kern, "expected_kern");
578 ASSERT_EQ(skel->bss->err, 0, "bpf_prog_err");
579 drain_kernel_messages_buffer(kern_ringbuf, skel);
584 ring_buffer__free(kern_ringbuf);
585 user_ring_buffer__free(user_ringbuf);
586 user_ringbuf_success__destroy(skel);
589 static void *kick_kernel_cb(void *arg)
591 /* Kick the kernel, causing it to drain the ring buffer and then wake
592 * up the test thread waiting on epoll.
594 syscall(__NR_prlimit64);
599 static int spawn_kick_thread_for_poll(void)
603 return pthread_create(&thread, NULL, kick_kernel_cb, NULL);
606 static void test_user_ringbuf_blocking_reserve(void)
608 struct user_ringbuf_success *skel;
609 struct user_ring_buffer *ringbuf;
610 int err, num_written = 0;
613 err = load_skel_create_user_ringbuf(&skel, &ringbuf);
617 ASSERT_EQ(skel->bss->read, 0, "num_samples_read_before");
620 /* Write samples until the buffer is full. */
621 token = user_ring_buffer__reserve(ringbuf, sizeof(*token));
627 user_ring_buffer__submit(ringbuf, token);
631 if (!ASSERT_GE(num_written, 0, "num_written"))
634 /* Should not have read any samples until the kernel is kicked. */
635 ASSERT_EQ(skel->bss->read, 0, "num_pre_kick");
637 /* We correctly time out after 1 second, without a sample. */
638 token = user_ring_buffer__reserve_blocking(ringbuf, sizeof(*token), 1000);
639 if (!ASSERT_EQ(token, NULL, "pre_kick_timeout_token"))
642 err = spawn_kick_thread_for_poll();
643 if (!ASSERT_EQ(err, 0, "deferred_kick_thread\n"))
646 /* After spawning another thread that asynchronously kicks the kernel to
647 * drain the messages, we're able to block and successfully get a
648 * sample once we receive an event notification.
650 token = user_ring_buffer__reserve_blocking(ringbuf, sizeof(*token), 10000);
652 if (!ASSERT_OK_PTR(token, "block_token"))
655 ASSERT_GT(skel->bss->read, 0, "num_post_kill");
656 ASSERT_LE(skel->bss->read, num_written, "num_post_kill");
657 ASSERT_EQ(skel->bss->err, 0, "err_post_poll");
658 user_ring_buffer__discard(ringbuf, token);
661 user_ring_buffer__free(ringbuf);
662 user_ringbuf_success__destroy(skel);
665 #define SUCCESS_TEST(_func) { _func, #_func }
668 void (*test_callback)(void);
669 const char *test_name;
670 } success_tests[] = {
671 SUCCESS_TEST(test_user_ringbuf_mappings),
672 SUCCESS_TEST(test_user_ringbuf_post_misaligned),
673 SUCCESS_TEST(test_user_ringbuf_post_producer_wrong_offset),
674 SUCCESS_TEST(test_user_ringbuf_post_larger_than_ringbuf_sz),
675 SUCCESS_TEST(test_user_ringbuf_basic),
676 SUCCESS_TEST(test_user_ringbuf_sample_full_ring_buffer),
677 SUCCESS_TEST(test_user_ringbuf_post_alignment_autoadjust),
678 SUCCESS_TEST(test_user_ringbuf_overfill),
679 SUCCESS_TEST(test_user_ringbuf_discards_properly_ignored),
680 SUCCESS_TEST(test_user_ringbuf_loop),
681 SUCCESS_TEST(test_user_ringbuf_msg_protocol),
682 SUCCESS_TEST(test_user_ringbuf_blocking_reserve),
685 void test_user_ringbuf(void)
689 for (i = 0; i < ARRAY_SIZE(success_tests); i++) {
690 if (!test__start_subtest(success_tests[i].test_name))
693 success_tests[i].test_callback();
696 RUN_TESTS(user_ringbuf_fail);