Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
  3
  4#include <linux/bpf.h>
  5#include <bpf/bpf_helpers.h>
  6#include "bpf_misc.h"
  7#include "test_user_ringbuf.h"
  8
  9char _license[] SEC("license") = "GPL";
 10
 11struct {
 12	__uint(type, BPF_MAP_TYPE_USER_RINGBUF);
 13} user_ringbuf SEC(".maps");
 14
 15struct {
 16	__uint(type, BPF_MAP_TYPE_RINGBUF);
 17} kernel_ringbuf SEC(".maps");
 18
 19/* inputs */
 20int pid, err, val;
 21
 22int read = 0;
 23
 24/* Counter used for end-to-end protocol test */
 25__u64 kern_mutated = 0;
 26__u64 user_mutated = 0;
 27__u64 expected_user_mutated = 0;
 28
 29static int
 30is_test_process(void)
 31{
 32	int cur_pid = bpf_get_current_pid_tgid() >> 32;
 33
 34	return cur_pid == pid;
 35}
 36
 37static long
 38record_sample(struct bpf_dynptr *dynptr, void *context)
 39{
 40	const struct sample *sample = NULL;
 41	struct sample stack_sample;
 42	int status;
 43	static int num_calls;
 44
 45	if (num_calls++ % 2 == 0) {
 46		status = bpf_dynptr_read(&stack_sample, sizeof(stack_sample), dynptr, 0, 0);
 47		if (status) {
 48			bpf_printk("bpf_dynptr_read() failed: %d\n", status);
 49			err = 1;
 50			return 1;
 51		}
 52	} else {
 53		sample = bpf_dynptr_data(dynptr, 0, sizeof(*sample));
 54		if (!sample) {
 55			bpf_printk("Unexpectedly failed to get sample\n");
 56			err = 2;
 57			return 1;
 58		}
 59		stack_sample = *sample;
 60	}
 61
 62	__sync_fetch_and_add(&read, 1);
 63	return 0;
 64}
 65
 66static void
 67handle_sample_msg(const struct test_msg *msg)
 68{
 69	switch (msg->msg_op) {
 70	case TEST_MSG_OP_INC64:
 71		kern_mutated += msg->operand_64;
 72		break;
 73	case TEST_MSG_OP_INC32:
 74		kern_mutated += msg->operand_32;
 75		break;
 76	case TEST_MSG_OP_MUL64:
 77		kern_mutated *= msg->operand_64;
 78		break;
 79	case TEST_MSG_OP_MUL32:
 80		kern_mutated *= msg->operand_32;
 81		break;
 82	default:
 83		bpf_printk("Unrecognized op %d\n", msg->msg_op);
 84		err = 2;
 85	}
 86}
 87
 88static long
 89read_protocol_msg(struct bpf_dynptr *dynptr, void *context)
 90{
 91	const struct test_msg *msg = NULL;
 92
 93	msg = bpf_dynptr_data(dynptr, 0, sizeof(*msg));
 94	if (!msg) {
 95		err = 1;
 96		bpf_printk("Unexpectedly failed to get msg\n");
 97		return 0;
 98	}
 99
100	handle_sample_msg(msg);
101
102	return 0;
103}
104
105static int publish_next_kern_msg(__u32 index, void *context)
106{
107	struct test_msg *msg = NULL;
108	int operand_64 = TEST_OP_64;
109	int operand_32 = TEST_OP_32;
110
111	msg = bpf_ringbuf_reserve(&kernel_ringbuf, sizeof(*msg), 0);
112	if (!msg) {
113		err = 4;
114		return 1;
115	}
116
117	switch (index % TEST_MSG_OP_NUM_OPS) {
118	case TEST_MSG_OP_INC64:
119		msg->operand_64 = operand_64;
120		msg->msg_op = TEST_MSG_OP_INC64;
121		expected_user_mutated += operand_64;
122		break;
123	case TEST_MSG_OP_INC32:
124		msg->operand_32 = operand_32;
125		msg->msg_op = TEST_MSG_OP_INC32;
126		expected_user_mutated += operand_32;
127		break;
128	case TEST_MSG_OP_MUL64:
129		msg->operand_64 = operand_64;
130		msg->msg_op = TEST_MSG_OP_MUL64;
131		expected_user_mutated *= operand_64;
132		break;
133	case TEST_MSG_OP_MUL32:
134		msg->operand_32 = operand_32;
135		msg->msg_op = TEST_MSG_OP_MUL32;
136		expected_user_mutated *= operand_32;
137		break;
138	default:
139		bpf_ringbuf_discard(msg, 0);
140		err = 5;
141		return 1;
142	}
143
144	bpf_ringbuf_submit(msg, 0);
145
146	return 0;
147}
148
149static void
150publish_kern_messages(void)
151{
152	if (expected_user_mutated != user_mutated) {
153		bpf_printk("%lu != %lu\n", expected_user_mutated, user_mutated);
154		err = 3;
155		return;
156	}
157
158	bpf_loop(8, publish_next_kern_msg, NULL, 0);
159}
160
161SEC("fentry/" SYS_PREFIX "sys_prctl")
162int test_user_ringbuf_protocol(void *ctx)
163{
164	long status = 0;
165
166	if (!is_test_process())
167		return 0;
168
169	status = bpf_user_ringbuf_drain(&user_ringbuf, read_protocol_msg, NULL, 0);
170	if (status < 0) {
171		bpf_printk("Drain returned: %ld\n", status);
172		err = 1;
173		return 0;
174	}
175
176	publish_kern_messages();
177
178	return 0;
179}
180
181SEC("fentry/" SYS_PREFIX "sys_getpgid")
182int test_user_ringbuf(void *ctx)
183{
184	if (!is_test_process())
185		return 0;
186
187	err = bpf_user_ringbuf_drain(&user_ringbuf, record_sample, NULL, 0);
188
189	return 0;
190}
191
192static long
193do_nothing_cb(struct bpf_dynptr *dynptr, void *context)
194{
195	__sync_fetch_and_add(&read, 1);
196	return 0;
197}
198
199SEC("fentry/" SYS_PREFIX "sys_prlimit64")
200int test_user_ringbuf_epoll(void *ctx)
201{
202	long num_samples;
203
204	if (!is_test_process())
205		return 0;
206
207	num_samples = bpf_user_ringbuf_drain(&user_ringbuf, do_nothing_cb, NULL, 0);
208	if (num_samples <= 0)
209		err = 1;
210
211	return 0;
212}