321 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3/* Basic per-epoll context busy poll test.4 *5 * Only tests the ioctls, but should be expanded to test two connected hosts in6 * the future7 */8 9#define _GNU_SOURCE10 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 0x8A40#define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params)41#define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params)42#endif43 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 kernel129 *130 * the default should be default and all fields should be zero'd by the131 * 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 the223 * params with a busy_poll_budget > NAPI_POLL_WEIGHT should succeed224 */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_MAIN321