File Index
Files and directories
Sign in
FILE

epoll_busy_poll.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/net/epoll_busy_poll.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2
  3/* Basic per-epoll context busy poll test.
  4 *
  5 * Only tests the ioctls, but should be expanded to test two connected hosts in
  6 * the future
  7 */
  8
  9#define _GNU_SOURCE
 10
 11#include <error.h>
 12#include <errno.h>
 13#include <inttypes.h>
 14#include <limits.h>
 15#include <stdio.h>
 16#include <stdlib.h>
 17#include <string.h>
 18#include <unistd.h>
 19
 20#include <sys/capability.h>
 21
 22#include <sys/epoll.h>
 23#include <sys/ioctl.h>
 24#include <sys/socket.h>
 25
 26#include "kselftest_harness.h"
 27
 28/* if the headers haven't been updated, we need to define some things */
 29#if !defined(EPOLL_IOC_TYPE)
 30struct epoll_params {
 31	uint32_t busy_poll_usecs;
 32	uint16_t busy_poll_budget;
 33	uint8_t prefer_busy_poll;
 34
 35	/* pad the struct to a multiple of 64bits */
 36	uint8_t __pad;
 37};
 38
 39#define EPOLL_IOC_TYPE 0x8A
 40#define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params)
 41#define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params)
 42#endif
 43
 44FIXTURE(invalid_fd)
 45{
 46	int invalid_fd;
 47	struct epoll_params params;
 48};
 49
 50FIXTURE_SETUP(invalid_fd)
 51{
 52	int ret;
 53
 54	ret = socket(AF_UNIX, SOCK_DGRAM, 0);
 55	EXPECT_NE(-1, ret)
 56		TH_LOG("error creating unix socket");
 57
 58	self->invalid_fd = ret;
 59}
 60
 61FIXTURE_TEARDOWN(invalid_fd)
 62{
 63	int ret;
 64
 65	ret = close(self->invalid_fd);
 66	EXPECT_EQ(0, ret);
 67}
 68
 69TEST_F(invalid_fd, test_invalid_fd)
 70{
 71	int ret;
 72
 73	ret = ioctl(self->invalid_fd, EPIOCGPARAMS, &self->params);
 74
 75	EXPECT_EQ(-1, ret)
 76		TH_LOG("EPIOCGPARAMS on invalid epoll FD should error");
 77
 78	EXPECT_EQ(ENOTTY, errno)
 79		TH_LOG("EPIOCGPARAMS on invalid epoll FD should set errno to ENOTTY");
 80
 81	memset(&self->params, 0, sizeof(struct epoll_params));
 82
 83	ret = ioctl(self->invalid_fd, EPIOCSPARAMS, &self->params);
 84
 85	EXPECT_EQ(-1, ret)
 86		TH_LOG("EPIOCSPARAMS on invalid epoll FD should error");
 87
 88	EXPECT_EQ(ENOTTY, errno)
 89		TH_LOG("EPIOCSPARAMS on invalid epoll FD should set errno to ENOTTY");
 90}
 91
 92FIXTURE(epoll_busy_poll)
 93{
 94	int fd;
 95	struct epoll_params params;
 96	struct epoll_params *invalid_params;
 97	cap_t caps;
 98};
 99
100FIXTURE_SETUP(epoll_busy_poll)
101{
102	int ret;
103
104	ret = epoll_create1(0);
105	EXPECT_NE(-1, ret)
106		TH_LOG("epoll_create1 failed?");
107
108	self->fd = ret;
109
110	self->caps = cap_get_proc();
111	EXPECT_NE(NULL, self->caps);
112}
113
114FIXTURE_TEARDOWN(epoll_busy_poll)
115{
116	int ret;
117
118	ret = close(self->fd);
119	EXPECT_EQ(0, ret);
120
121	ret = cap_free(self->caps);
122	EXPECT_NE(-1, ret)
123		TH_LOG("unable to free capabilities");
124}
125
126TEST_F(epoll_busy_poll, test_get_params)
127{
128	/* begin by getting the epoll params from the kernel
129	 *
130	 * the default should be default and all fields should be zero'd by the
131	 * kernel, so set params fields to garbage to test this.
132	 */
133	int ret = 0;
134
135	self->params.busy_poll_usecs = 0xff;
136	self->params.busy_poll_budget = 0xff;
137	self->params.prefer_busy_poll = 1;
138	self->params.__pad = 0xf;
139
140	ret = ioctl(self->fd, EPIOCGPARAMS, &self->params);
141	EXPECT_EQ(0, ret)
142		TH_LOG("ioctl EPIOCGPARAMS should succeed");
143
144	EXPECT_EQ(0, self->params.busy_poll_usecs)
145		TH_LOG("EPIOCGPARAMS busy_poll_usecs should have been 0");
146
147	EXPECT_EQ(0, self->params.busy_poll_budget)
148		TH_LOG("EPIOCGPARAMS busy_poll_budget should have been 0");
149
150	EXPECT_EQ(0, self->params.prefer_busy_poll)
151		TH_LOG("EPIOCGPARAMS prefer_busy_poll should have been 0");
152
153	EXPECT_EQ(0, self->params.__pad)
154		TH_LOG("EPIOCGPARAMS __pad should have been 0");
155
156	self->invalid_params = (struct epoll_params *)0xdeadbeef;
157	ret = ioctl(self->fd, EPIOCGPARAMS, self->invalid_params);
158
159	EXPECT_EQ(-1, ret)
160		TH_LOG("EPIOCGPARAMS should error with invalid params");
161
162	EXPECT_EQ(EFAULT, errno)
163		TH_LOG("EPIOCGPARAMS with invalid params should set errno to EFAULT");
164}
165
166TEST_F(epoll_busy_poll, test_set_invalid)
167{
168	int ret;
169
170	memset(&self->params, 0, sizeof(struct epoll_params));
171
172	self->params.__pad = 1;
173
174	ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
175
176	EXPECT_EQ(-1, ret)
177		TH_LOG("EPIOCSPARAMS non-zero __pad should error");
178
179	EXPECT_EQ(EINVAL, errno)
180		TH_LOG("EPIOCSPARAMS non-zero __pad errno should be EINVAL");
181
182	self->params.__pad = 0;
183	self->params.busy_poll_usecs = (uint32_t)INT_MAX + 1;
184
185	ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
186
187	EXPECT_EQ(-1, ret)
188		TH_LOG("EPIOCSPARAMS should error busy_poll_usecs > S32_MAX");
189
190	EXPECT_EQ(EINVAL, errno)
191		TH_LOG("EPIOCSPARAMS busy_poll_usecs > S32_MAX errno should be EINVAL");
192
193	self->params.__pad = 0;
194	self->params.busy_poll_usecs = 32;
195	self->params.prefer_busy_poll = 2;
196
197	ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
198
199	EXPECT_EQ(-1, ret)
200		TH_LOG("EPIOCSPARAMS should error prefer_busy_poll > 1");
201
202	EXPECT_EQ(EINVAL, errno)
203		TH_LOG("EPIOCSPARAMS prefer_busy_poll > 1 errno should be EINVAL");
204
205	self->params.__pad = 0;
206	self->params.busy_poll_usecs = 32;
207	self->params.prefer_busy_poll = 1;
208
209	/* set budget well above kernel's NAPI_POLL_WEIGHT of 64 */
210	self->params.busy_poll_budget = UINT16_MAX;
211
212	/* test harness should run with CAP_NET_ADMIN, but let's make sure */
213	cap_flag_value_t tmp;
214
215	ret = cap_get_flag(self->caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &tmp);
216	EXPECT_EQ(0, ret)
217		TH_LOG("unable to get CAP_NET_ADMIN cap flag");
218
219	EXPECT_EQ(CAP_SET, tmp)
220		TH_LOG("expecting CAP_NET_ADMIN to be set for the test harness");
221
222	/* at this point we know CAP_NET_ADMIN is available, so setting the
223	 * params with a busy_poll_budget > NAPI_POLL_WEIGHT should succeed
224	 */
225	ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
226
227	EXPECT_EQ(0, ret)
228		TH_LOG("EPIOCSPARAMS should allow busy_poll_budget > NAPI_POLL_WEIGHT");
229
230	/* remove CAP_NET_ADMIN from our effective set */
231	cap_value_t net_admin[] = { CAP_NET_ADMIN };
232
233	ret = cap_set_flag(self->caps, CAP_EFFECTIVE, 1, net_admin, CAP_CLEAR);
234	EXPECT_EQ(0, ret)
235		TH_LOG("couldn't clear CAP_NET_ADMIN");
236
237	ret = cap_set_proc(self->caps);
238	EXPECT_EQ(0, ret)
239		TH_LOG("cap_set_proc should drop CAP_NET_ADMIN");
240
241	/* this is now expected to fail */
242	ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
243
244	EXPECT_EQ(-1, ret)
245		TH_LOG("EPIOCSPARAMS should error busy_poll_budget > NAPI_POLL_WEIGHT");
246
247	EXPECT_EQ(EPERM, errno)
248		TH_LOG("EPIOCSPARAMS errno should be EPERM busy_poll_budget > NAPI_POLL_WEIGHT");
249
250	/* restore CAP_NET_ADMIN to our effective set */
251	ret = cap_set_flag(self->caps, CAP_EFFECTIVE, 1, net_admin, CAP_SET);
252	EXPECT_EQ(0, ret)
253		TH_LOG("couldn't restore CAP_NET_ADMIN");
254
255	ret = cap_set_proc(self->caps);
256	EXPECT_EQ(0, ret)
257		TH_LOG("cap_set_proc should set  CAP_NET_ADMIN");
258
259	self->invalid_params = (struct epoll_params *)0xdeadbeef;
260	ret = ioctl(self->fd, EPIOCSPARAMS, self->invalid_params);
261
262	EXPECT_EQ(-1, ret)
263		TH_LOG("EPIOCSPARAMS should error when epoll_params is invalid");
264
265	EXPECT_EQ(EFAULT, errno)
266		TH_LOG("EPIOCSPARAMS should set errno to EFAULT when epoll_params is invalid");
267}
268
269TEST_F(epoll_busy_poll, test_set_and_get_valid)
270{
271	int ret;
272
273	memset(&self->params, 0, sizeof(struct epoll_params));
274
275	self->params.busy_poll_usecs = 25;
276	self->params.busy_poll_budget = 16;
277	self->params.prefer_busy_poll = 1;
278
279	ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
280
281	EXPECT_EQ(0, ret)
282		TH_LOG("EPIOCSPARAMS with valid params should not error");
283
284	/* check that the kernel returns the same values back */
285
286	memset(&self->params, 0, sizeof(struct epoll_params));
287
288	ret = ioctl(self->fd, EPIOCGPARAMS, &self->params);
289
290	EXPECT_EQ(0, ret)
291		TH_LOG("EPIOCGPARAMS should not error");
292
293	EXPECT_EQ(25, self->params.busy_poll_usecs)
294		TH_LOG("params.busy_poll_usecs incorrect");
295
296	EXPECT_EQ(16, self->params.busy_poll_budget)
297		TH_LOG("params.busy_poll_budget incorrect");
298
299	EXPECT_EQ(1, self->params.prefer_busy_poll)
300		TH_LOG("params.prefer_busy_poll incorrect");
301
302	EXPECT_EQ(0, self->params.__pad)
303		TH_LOG("params.__pad was not 0");
304}
305
306TEST_F(epoll_busy_poll, test_invalid_ioctl)
307{
308	int invalid_ioctl = EPIOCGPARAMS + 10;
309	int ret;
310
311	ret = ioctl(self->fd, invalid_ioctl, &self->params);
312
313	EXPECT_EQ(-1, ret)
314		TH_LOG("invalid ioctl should return error");
315
316	EXPECT_EQ(EINVAL, errno)
317		TH_LOG("invalid ioctl should set errno to EINVAL");
318}
319
320TEST_HARNESS_MAIN
~/ Read-only file preview.