xref: /linux/tools/testing/selftests/net/epoll_busy_poll.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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)
30 struct 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 
44 FIXTURE(invalid_fd)
45 {
46 	int invalid_fd;
47 	struct epoll_params params;
48 };
49 
50 FIXTURE_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 
61 FIXTURE_TEARDOWN(invalid_fd)
62 {
63 	int ret;
64 
65 	ret = close(self->invalid_fd);
66 	EXPECT_EQ(0, ret);
67 }
68 
69 TEST_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 
92 FIXTURE(epoll_busy_poll)
93 {
94 	int fd;
95 	struct epoll_params params;
96 	struct epoll_params *invalid_params;
97 	cap_t caps;
98 };
99 
100 FIXTURE_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 
114 FIXTURE_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 
126 TEST_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 
166 TEST_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 
269 TEST_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 
306 TEST_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 
320 TEST_HARNESS_MAIN
321