160e0f986SJoe Damato // SPDX-License-Identifier: GPL-2.0-or-later
260e0f986SJoe Damato
360e0f986SJoe Damato /* Basic per-epoll context busy poll test.
460e0f986SJoe Damato *
560e0f986SJoe Damato * Only tests the ioctls, but should be expanded to test two connected hosts in
660e0f986SJoe Damato * the future
760e0f986SJoe Damato */
860e0f986SJoe Damato
960e0f986SJoe Damato #define _GNU_SOURCE
1060e0f986SJoe Damato
1160e0f986SJoe Damato #include <error.h>
1260e0f986SJoe Damato #include <errno.h>
1360e0f986SJoe Damato #include <inttypes.h>
1460e0f986SJoe Damato #include <limits.h>
1560e0f986SJoe Damato #include <stdio.h>
1660e0f986SJoe Damato #include <stdlib.h>
1760e0f986SJoe Damato #include <string.h>
1860e0f986SJoe Damato #include <unistd.h>
1960e0f986SJoe Damato
2060e0f986SJoe Damato #include <sys/capability.h>
2160e0f986SJoe Damato
2260e0f986SJoe Damato #include <sys/epoll.h>
2360e0f986SJoe Damato #include <sys/ioctl.h>
2460e0f986SJoe Damato #include <sys/socket.h>
2560e0f986SJoe Damato
2660e0f986SJoe Damato #include "../kselftest_harness.h"
2760e0f986SJoe Damato
2860e0f986SJoe Damato /* if the headers haven't been updated, we need to define some things */
2960e0f986SJoe Damato #if !defined(EPOLL_IOC_TYPE)
3060e0f986SJoe Damato struct epoll_params {
3160e0f986SJoe Damato uint32_t busy_poll_usecs;
3260e0f986SJoe Damato uint16_t busy_poll_budget;
3360e0f986SJoe Damato uint8_t prefer_busy_poll;
3460e0f986SJoe Damato
3560e0f986SJoe Damato /* pad the struct to a multiple of 64bits */
3660e0f986SJoe Damato uint8_t __pad;
3760e0f986SJoe Damato };
3860e0f986SJoe Damato
3960e0f986SJoe Damato #define EPOLL_IOC_TYPE 0x8A
4060e0f986SJoe Damato #define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params)
4160e0f986SJoe Damato #define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params)
4260e0f986SJoe Damato #endif
4360e0f986SJoe Damato
FIXTURE(invalid_fd)4460e0f986SJoe Damato FIXTURE(invalid_fd)
4560e0f986SJoe Damato {
4660e0f986SJoe Damato int invalid_fd;
4760e0f986SJoe Damato struct epoll_params params;
4860e0f986SJoe Damato };
4960e0f986SJoe Damato
FIXTURE_SETUP(invalid_fd)5060e0f986SJoe Damato FIXTURE_SETUP(invalid_fd)
5160e0f986SJoe Damato {
5260e0f986SJoe Damato int ret;
5360e0f986SJoe Damato
5460e0f986SJoe Damato ret = socket(AF_UNIX, SOCK_DGRAM, 0);
5560e0f986SJoe Damato EXPECT_NE(-1, ret)
5660e0f986SJoe Damato TH_LOG("error creating unix socket");
5760e0f986SJoe Damato
5860e0f986SJoe Damato self->invalid_fd = ret;
5960e0f986SJoe Damato }
6060e0f986SJoe Damato
FIXTURE_TEARDOWN(invalid_fd)6160e0f986SJoe Damato FIXTURE_TEARDOWN(invalid_fd)
6260e0f986SJoe Damato {
6360e0f986SJoe Damato int ret;
6460e0f986SJoe Damato
6560e0f986SJoe Damato ret = close(self->invalid_fd);
6660e0f986SJoe Damato EXPECT_EQ(0, ret);
6760e0f986SJoe Damato }
6860e0f986SJoe Damato
TEST_F(invalid_fd,test_invalid_fd)6960e0f986SJoe Damato TEST_F(invalid_fd, test_invalid_fd)
7060e0f986SJoe Damato {
7160e0f986SJoe Damato int ret;
7260e0f986SJoe Damato
7360e0f986SJoe Damato ret = ioctl(self->invalid_fd, EPIOCGPARAMS, &self->params);
7460e0f986SJoe Damato
7560e0f986SJoe Damato EXPECT_EQ(-1, ret)
7660e0f986SJoe Damato TH_LOG("EPIOCGPARAMS on invalid epoll FD should error");
7760e0f986SJoe Damato
7860e0f986SJoe Damato EXPECT_EQ(ENOTTY, errno)
7960e0f986SJoe Damato TH_LOG("EPIOCGPARAMS on invalid epoll FD should set errno to ENOTTY");
8060e0f986SJoe Damato
8160e0f986SJoe Damato memset(&self->params, 0, sizeof(struct epoll_params));
8260e0f986SJoe Damato
8360e0f986SJoe Damato ret = ioctl(self->invalid_fd, EPIOCSPARAMS, &self->params);
8460e0f986SJoe Damato
8560e0f986SJoe Damato EXPECT_EQ(-1, ret)
8660e0f986SJoe Damato TH_LOG("EPIOCSPARAMS on invalid epoll FD should error");
8760e0f986SJoe Damato
8860e0f986SJoe Damato EXPECT_EQ(ENOTTY, errno)
8960e0f986SJoe Damato TH_LOG("EPIOCSPARAMS on invalid epoll FD should set errno to ENOTTY");
9060e0f986SJoe Damato }
9160e0f986SJoe Damato
FIXTURE(epoll_busy_poll)9260e0f986SJoe Damato FIXTURE(epoll_busy_poll)
9360e0f986SJoe Damato {
9460e0f986SJoe Damato int fd;
9560e0f986SJoe Damato struct epoll_params params;
9660e0f986SJoe Damato struct epoll_params *invalid_params;
9760e0f986SJoe Damato cap_t caps;
9860e0f986SJoe Damato };
9960e0f986SJoe Damato
FIXTURE_SETUP(epoll_busy_poll)10060e0f986SJoe Damato FIXTURE_SETUP(epoll_busy_poll)
10160e0f986SJoe Damato {
10260e0f986SJoe Damato int ret;
10360e0f986SJoe Damato
10460e0f986SJoe Damato ret = epoll_create1(0);
10560e0f986SJoe Damato EXPECT_NE(-1, ret)
10660e0f986SJoe Damato TH_LOG("epoll_create1 failed?");
10760e0f986SJoe Damato
10860e0f986SJoe Damato self->fd = ret;
10960e0f986SJoe Damato
11060e0f986SJoe Damato self->caps = cap_get_proc();
11160e0f986SJoe Damato EXPECT_NE(NULL, self->caps);
11260e0f986SJoe Damato }
11360e0f986SJoe Damato
FIXTURE_TEARDOWN(epoll_busy_poll)11460e0f986SJoe Damato FIXTURE_TEARDOWN(epoll_busy_poll)
11560e0f986SJoe Damato {
11660e0f986SJoe Damato int ret;
11760e0f986SJoe Damato
11860e0f986SJoe Damato ret = close(self->fd);
11960e0f986SJoe Damato EXPECT_EQ(0, ret);
12060e0f986SJoe Damato
12160e0f986SJoe Damato ret = cap_free(self->caps);
12260e0f986SJoe Damato EXPECT_NE(-1, ret)
12360e0f986SJoe Damato TH_LOG("unable to free capabilities");
12460e0f986SJoe Damato }
12560e0f986SJoe Damato
TEST_F(epoll_busy_poll,test_get_params)12660e0f986SJoe Damato TEST_F(epoll_busy_poll, test_get_params)
12760e0f986SJoe Damato {
12860e0f986SJoe Damato /* begin by getting the epoll params from the kernel
12960e0f986SJoe Damato *
13060e0f986SJoe Damato * the default should be default and all fields should be zero'd by the
13160e0f986SJoe Damato * kernel, so set params fields to garbage to test this.
13260e0f986SJoe Damato */
13360e0f986SJoe Damato int ret = 0;
13460e0f986SJoe Damato
13560e0f986SJoe Damato self->params.busy_poll_usecs = 0xff;
13660e0f986SJoe Damato self->params.busy_poll_budget = 0xff;
13760e0f986SJoe Damato self->params.prefer_busy_poll = 1;
13860e0f986SJoe Damato self->params.__pad = 0xf;
13960e0f986SJoe Damato
14060e0f986SJoe Damato ret = ioctl(self->fd, EPIOCGPARAMS, &self->params);
14160e0f986SJoe Damato EXPECT_EQ(0, ret)
14260e0f986SJoe Damato TH_LOG("ioctl EPIOCGPARAMS should succeed");
14360e0f986SJoe Damato
14460e0f986SJoe Damato EXPECT_EQ(0, self->params.busy_poll_usecs)
14560e0f986SJoe Damato TH_LOG("EPIOCGPARAMS busy_poll_usecs should have been 0");
14660e0f986SJoe Damato
14760e0f986SJoe Damato EXPECT_EQ(0, self->params.busy_poll_budget)
14860e0f986SJoe Damato TH_LOG("EPIOCGPARAMS busy_poll_budget should have been 0");
14960e0f986SJoe Damato
15060e0f986SJoe Damato EXPECT_EQ(0, self->params.prefer_busy_poll)
15160e0f986SJoe Damato TH_LOG("EPIOCGPARAMS prefer_busy_poll should have been 0");
15260e0f986SJoe Damato
15360e0f986SJoe Damato EXPECT_EQ(0, self->params.__pad)
15460e0f986SJoe Damato TH_LOG("EPIOCGPARAMS __pad should have been 0");
15560e0f986SJoe Damato
15660e0f986SJoe Damato self->invalid_params = (struct epoll_params *)0xdeadbeef;
15760e0f986SJoe Damato ret = ioctl(self->fd, EPIOCGPARAMS, self->invalid_params);
15860e0f986SJoe Damato
15960e0f986SJoe Damato EXPECT_EQ(-1, ret)
16060e0f986SJoe Damato TH_LOG("EPIOCGPARAMS should error with invalid params");
16160e0f986SJoe Damato
16260e0f986SJoe Damato EXPECT_EQ(EFAULT, errno)
16360e0f986SJoe Damato TH_LOG("EPIOCGPARAMS with invalid params should set errno to EFAULT");
16460e0f986SJoe Damato }
16560e0f986SJoe Damato
TEST_F(epoll_busy_poll,test_set_invalid)16660e0f986SJoe Damato TEST_F(epoll_busy_poll, test_set_invalid)
16760e0f986SJoe Damato {
16860e0f986SJoe Damato int ret;
16960e0f986SJoe Damato
17060e0f986SJoe Damato memset(&self->params, 0, sizeof(struct epoll_params));
17160e0f986SJoe Damato
17260e0f986SJoe Damato self->params.__pad = 1;
17360e0f986SJoe Damato
17460e0f986SJoe Damato ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
17560e0f986SJoe Damato
17660e0f986SJoe Damato EXPECT_EQ(-1, ret)
17760e0f986SJoe Damato TH_LOG("EPIOCSPARAMS non-zero __pad should error");
17860e0f986SJoe Damato
17960e0f986SJoe Damato EXPECT_EQ(EINVAL, errno)
18060e0f986SJoe Damato TH_LOG("EPIOCSPARAMS non-zero __pad errno should be EINVAL");
18160e0f986SJoe Damato
18260e0f986SJoe Damato self->params.__pad = 0;
18360e0f986SJoe Damato self->params.busy_poll_usecs = (uint32_t)INT_MAX + 1;
18460e0f986SJoe Damato
18560e0f986SJoe Damato ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
18660e0f986SJoe Damato
18760e0f986SJoe Damato EXPECT_EQ(-1, ret)
18860e0f986SJoe Damato TH_LOG("EPIOCSPARAMS should error busy_poll_usecs > S32_MAX");
18960e0f986SJoe Damato
19060e0f986SJoe Damato EXPECT_EQ(EINVAL, errno)
19160e0f986SJoe Damato TH_LOG("EPIOCSPARAMS busy_poll_usecs > S32_MAX errno should be EINVAL");
19260e0f986SJoe Damato
19360e0f986SJoe Damato self->params.__pad = 0;
19460e0f986SJoe Damato self->params.busy_poll_usecs = 32;
19560e0f986SJoe Damato self->params.prefer_busy_poll = 2;
19660e0f986SJoe Damato
19760e0f986SJoe Damato ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
19860e0f986SJoe Damato
19960e0f986SJoe Damato EXPECT_EQ(-1, ret)
20060e0f986SJoe Damato TH_LOG("EPIOCSPARAMS should error prefer_busy_poll > 1");
20160e0f986SJoe Damato
20260e0f986SJoe Damato EXPECT_EQ(EINVAL, errno)
20360e0f986SJoe Damato TH_LOG("EPIOCSPARAMS prefer_busy_poll > 1 errno should be EINVAL");
20460e0f986SJoe Damato
20560e0f986SJoe Damato self->params.__pad = 0;
20660e0f986SJoe Damato self->params.busy_poll_usecs = 32;
20760e0f986SJoe Damato self->params.prefer_busy_poll = 1;
20860e0f986SJoe Damato
20960e0f986SJoe Damato /* set budget well above kernel's NAPI_POLL_WEIGHT of 64 */
21060e0f986SJoe Damato self->params.busy_poll_budget = UINT16_MAX;
21160e0f986SJoe Damato
21260e0f986SJoe Damato /* test harness should run with CAP_NET_ADMIN, but let's make sure */
21360e0f986SJoe Damato cap_flag_value_t tmp;
21460e0f986SJoe Damato
21560e0f986SJoe Damato ret = cap_get_flag(self->caps, CAP_NET_ADMIN, CAP_EFFECTIVE, &tmp);
21660e0f986SJoe Damato EXPECT_EQ(0, ret)
21760e0f986SJoe Damato TH_LOG("unable to get CAP_NET_ADMIN cap flag");
21860e0f986SJoe Damato
21960e0f986SJoe Damato EXPECT_EQ(CAP_SET, tmp)
22060e0f986SJoe Damato TH_LOG("expecting CAP_NET_ADMIN to be set for the test harness");
22160e0f986SJoe Damato
22260e0f986SJoe Damato /* at this point we know CAP_NET_ADMIN is available, so setting the
22360e0f986SJoe Damato * params with a busy_poll_budget > NAPI_POLL_WEIGHT should succeed
22460e0f986SJoe Damato */
22560e0f986SJoe Damato ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
22660e0f986SJoe Damato
22760e0f986SJoe Damato EXPECT_EQ(0, ret)
22860e0f986SJoe Damato TH_LOG("EPIOCSPARAMS should allow busy_poll_budget > NAPI_POLL_WEIGHT");
22960e0f986SJoe Damato
23060e0f986SJoe Damato /* remove CAP_NET_ADMIN from our effective set */
23160e0f986SJoe Damato cap_value_t net_admin[] = { CAP_NET_ADMIN };
23260e0f986SJoe Damato
23360e0f986SJoe Damato ret = cap_set_flag(self->caps, CAP_EFFECTIVE, 1, net_admin, CAP_CLEAR);
23460e0f986SJoe Damato EXPECT_EQ(0, ret)
235*f37dc28aSColin Ian King TH_LOG("couldn't clear CAP_NET_ADMIN");
23660e0f986SJoe Damato
23760e0f986SJoe Damato ret = cap_set_proc(self->caps);
23860e0f986SJoe Damato EXPECT_EQ(0, ret)
23960e0f986SJoe Damato TH_LOG("cap_set_proc should drop CAP_NET_ADMIN");
24060e0f986SJoe Damato
24160e0f986SJoe Damato /* this is now expected to fail */
24260e0f986SJoe Damato ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
24360e0f986SJoe Damato
24460e0f986SJoe Damato EXPECT_EQ(-1, ret)
24560e0f986SJoe Damato TH_LOG("EPIOCSPARAMS should error busy_poll_budget > NAPI_POLL_WEIGHT");
24660e0f986SJoe Damato
24760e0f986SJoe Damato EXPECT_EQ(EPERM, errno)
24860e0f986SJoe Damato TH_LOG("EPIOCSPARAMS errno should be EPERM busy_poll_budget > NAPI_POLL_WEIGHT");
24960e0f986SJoe Damato
25060e0f986SJoe Damato /* restore CAP_NET_ADMIN to our effective set */
25160e0f986SJoe Damato ret = cap_set_flag(self->caps, CAP_EFFECTIVE, 1, net_admin, CAP_SET);
25260e0f986SJoe Damato EXPECT_EQ(0, ret)
25360e0f986SJoe Damato TH_LOG("couldn't restore CAP_NET_ADMIN");
25460e0f986SJoe Damato
25560e0f986SJoe Damato ret = cap_set_proc(self->caps);
25660e0f986SJoe Damato EXPECT_EQ(0, ret)
25760e0f986SJoe Damato TH_LOG("cap_set_proc should set CAP_NET_ADMIN");
25860e0f986SJoe Damato
25960e0f986SJoe Damato self->invalid_params = (struct epoll_params *)0xdeadbeef;
26060e0f986SJoe Damato ret = ioctl(self->fd, EPIOCSPARAMS, self->invalid_params);
26160e0f986SJoe Damato
26260e0f986SJoe Damato EXPECT_EQ(-1, ret)
26360e0f986SJoe Damato TH_LOG("EPIOCSPARAMS should error when epoll_params is invalid");
26460e0f986SJoe Damato
26560e0f986SJoe Damato EXPECT_EQ(EFAULT, errno)
26660e0f986SJoe Damato TH_LOG("EPIOCSPARAMS should set errno to EFAULT when epoll_params is invalid");
26760e0f986SJoe Damato }
26860e0f986SJoe Damato
TEST_F(epoll_busy_poll,test_set_and_get_valid)26960e0f986SJoe Damato TEST_F(epoll_busy_poll, test_set_and_get_valid)
27060e0f986SJoe Damato {
27160e0f986SJoe Damato int ret;
27260e0f986SJoe Damato
27360e0f986SJoe Damato memset(&self->params, 0, sizeof(struct epoll_params));
27460e0f986SJoe Damato
27560e0f986SJoe Damato self->params.busy_poll_usecs = 25;
27660e0f986SJoe Damato self->params.busy_poll_budget = 16;
27760e0f986SJoe Damato self->params.prefer_busy_poll = 1;
27860e0f986SJoe Damato
27960e0f986SJoe Damato ret = ioctl(self->fd, EPIOCSPARAMS, &self->params);
28060e0f986SJoe Damato
28160e0f986SJoe Damato EXPECT_EQ(0, ret)
28260e0f986SJoe Damato TH_LOG("EPIOCSPARAMS with valid params should not error");
28360e0f986SJoe Damato
28460e0f986SJoe Damato /* check that the kernel returns the same values back */
28560e0f986SJoe Damato
28660e0f986SJoe Damato memset(&self->params, 0, sizeof(struct epoll_params));
28760e0f986SJoe Damato
28860e0f986SJoe Damato ret = ioctl(self->fd, EPIOCGPARAMS, &self->params);
28960e0f986SJoe Damato
29060e0f986SJoe Damato EXPECT_EQ(0, ret)
29160e0f986SJoe Damato TH_LOG("EPIOCGPARAMS should not error");
29260e0f986SJoe Damato
29360e0f986SJoe Damato EXPECT_EQ(25, self->params.busy_poll_usecs)
29460e0f986SJoe Damato TH_LOG("params.busy_poll_usecs incorrect");
29560e0f986SJoe Damato
29660e0f986SJoe Damato EXPECT_EQ(16, self->params.busy_poll_budget)
29760e0f986SJoe Damato TH_LOG("params.busy_poll_budget incorrect");
29860e0f986SJoe Damato
29960e0f986SJoe Damato EXPECT_EQ(1, self->params.prefer_busy_poll)
30060e0f986SJoe Damato TH_LOG("params.prefer_busy_poll incorrect");
30160e0f986SJoe Damato
30260e0f986SJoe Damato EXPECT_EQ(0, self->params.__pad)
30360e0f986SJoe Damato TH_LOG("params.__pad was not 0");
30460e0f986SJoe Damato }
30560e0f986SJoe Damato
TEST_F(epoll_busy_poll,test_invalid_ioctl)30660e0f986SJoe Damato TEST_F(epoll_busy_poll, test_invalid_ioctl)
30760e0f986SJoe Damato {
30860e0f986SJoe Damato int invalid_ioctl = EPIOCGPARAMS + 10;
30960e0f986SJoe Damato int ret;
31060e0f986SJoe Damato
31160e0f986SJoe Damato ret = ioctl(self->fd, invalid_ioctl, &self->params);
31260e0f986SJoe Damato
31360e0f986SJoe Damato EXPECT_EQ(-1, ret)
31460e0f986SJoe Damato TH_LOG("invalid ioctl should return error");
31560e0f986SJoe Damato
31660e0f986SJoe Damato EXPECT_EQ(EINVAL, errno)
31760e0f986SJoe Damato TH_LOG("invalid ioctl should set errno to EINVAL");
31860e0f986SJoe Damato }
31960e0f986SJoe Damato
32060e0f986SJoe Damato TEST_HARNESS_MAIN
321