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