drm/bridge: adv7511: Switch to atomic operations
[drm/drm-misc.git] / tools / testing / selftests / net / so_incoming_cpu.c
blobe9fa14e1073226829e883d7c6621ae9e9a2ce173
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright Amazon.com Inc. or its affiliates. */
3 #define _GNU_SOURCE
4 #include <sched.h>
6 #include <fcntl.h>
8 #include <netinet/in.h>
9 #include <sys/socket.h>
10 #include <sys/sysinfo.h>
12 #include "../kselftest_harness.h"
14 FIXTURE(so_incoming_cpu)
16 int *servers;
17 union {
18 struct sockaddr addr;
19 struct sockaddr_in in_addr;
21 socklen_t addrlen;
24 enum when_to_set {
25 BEFORE_REUSEPORT,
26 BEFORE_LISTEN,
27 AFTER_LISTEN,
28 AFTER_ALL_LISTEN,
31 FIXTURE_VARIANT(so_incoming_cpu)
33 int when_to_set;
36 FIXTURE_VARIANT_ADD(so_incoming_cpu, before_reuseport)
38 .when_to_set = BEFORE_REUSEPORT,
41 FIXTURE_VARIANT_ADD(so_incoming_cpu, before_listen)
43 .when_to_set = BEFORE_LISTEN,
46 FIXTURE_VARIANT_ADD(so_incoming_cpu, after_listen)
48 .when_to_set = AFTER_LISTEN,
51 FIXTURE_VARIANT_ADD(so_incoming_cpu, after_all_listen)
53 .when_to_set = AFTER_ALL_LISTEN,
56 static void write_sysctl(struct __test_metadata *_metadata,
57 char *filename, char *string)
59 int fd, len, ret;
61 fd = open(filename, O_WRONLY);
62 ASSERT_NE(fd, -1);
64 len = strlen(string);
65 ret = write(fd, string, len);
66 ASSERT_EQ(ret, len);
69 static void setup_netns(struct __test_metadata *_metadata)
71 ASSERT_EQ(unshare(CLONE_NEWNET), 0);
72 ASSERT_EQ(system("ip link set lo up"), 0);
74 write_sysctl(_metadata, "/proc/sys/net/ipv4/ip_local_port_range", "10000 60001");
75 write_sysctl(_metadata, "/proc/sys/net/ipv4/tcp_tw_reuse", "0");
78 #define NR_PORT (60001 - 10000 - 1)
79 #define NR_CLIENT_PER_SERVER_DEFAULT 32
80 static int nr_client_per_server, nr_server, nr_client;
82 FIXTURE_SETUP(so_incoming_cpu)
84 setup_netns(_metadata);
86 nr_server = get_nprocs();
87 ASSERT_LE(2, nr_server);
89 if (NR_CLIENT_PER_SERVER_DEFAULT * nr_server < NR_PORT)
90 nr_client_per_server = NR_CLIENT_PER_SERVER_DEFAULT;
91 else
92 nr_client_per_server = NR_PORT / nr_server;
94 nr_client = nr_client_per_server * nr_server;
96 self->servers = malloc(sizeof(int) * nr_server);
97 ASSERT_NE(self->servers, NULL);
99 self->in_addr.sin_family = AF_INET;
100 self->in_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
101 self->in_addr.sin_port = htons(0);
102 self->addrlen = sizeof(struct sockaddr_in);
105 FIXTURE_TEARDOWN(so_incoming_cpu)
107 int i;
109 for (i = 0; i < nr_server; i++)
110 close(self->servers[i]);
112 free(self->servers);
115 void set_so_incoming_cpu(struct __test_metadata *_metadata, int fd, int cpu)
117 int ret;
119 ret = setsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, sizeof(int));
120 ASSERT_EQ(ret, 0);
123 int create_server(struct __test_metadata *_metadata,
124 FIXTURE_DATA(so_incoming_cpu) *self,
125 const FIXTURE_VARIANT(so_incoming_cpu) *variant,
126 int cpu)
128 int fd, ret;
130 fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
131 ASSERT_NE(fd, -1);
133 if (variant->when_to_set == BEFORE_REUSEPORT)
134 set_so_incoming_cpu(_metadata, fd, cpu);
136 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int));
137 ASSERT_EQ(ret, 0);
139 ret = bind(fd, &self->addr, self->addrlen);
140 ASSERT_EQ(ret, 0);
142 if (variant->when_to_set == BEFORE_LISTEN)
143 set_so_incoming_cpu(_metadata, fd, cpu);
145 /* We don't use nr_client_per_server here not to block
146 * this test at connect() if SO_INCOMING_CPU is broken.
148 ret = listen(fd, nr_client);
149 ASSERT_EQ(ret, 0);
151 if (variant->when_to_set == AFTER_LISTEN)
152 set_so_incoming_cpu(_metadata, fd, cpu);
154 return fd;
157 void create_servers(struct __test_metadata *_metadata,
158 FIXTURE_DATA(so_incoming_cpu) *self,
159 const FIXTURE_VARIANT(so_incoming_cpu) *variant)
161 int i, ret;
163 for (i = 0; i < nr_server; i++) {
164 self->servers[i] = create_server(_metadata, self, variant, i);
166 if (i == 0) {
167 ret = getsockname(self->servers[i], &self->addr, &self->addrlen);
168 ASSERT_EQ(ret, 0);
172 if (variant->when_to_set == AFTER_ALL_LISTEN) {
173 for (i = 0; i < nr_server; i++)
174 set_so_incoming_cpu(_metadata, self->servers[i], i);
178 void create_clients(struct __test_metadata *_metadata,
179 FIXTURE_DATA(so_incoming_cpu) *self)
181 cpu_set_t cpu_set;
182 int i, j, fd, ret;
184 for (i = 0; i < nr_server; i++) {
185 CPU_ZERO(&cpu_set);
187 CPU_SET(i, &cpu_set);
188 ASSERT_EQ(CPU_COUNT(&cpu_set), 1);
189 ASSERT_NE(CPU_ISSET(i, &cpu_set), 0);
191 /* Make sure SYN will be processed on the i-th CPU
192 * and finally distributed to the i-th listener.
194 ret = sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
195 ASSERT_EQ(ret, 0);
197 for (j = 0; j < nr_client_per_server; j++) {
198 fd = socket(AF_INET, SOCK_STREAM, 0);
199 ASSERT_NE(fd, -1);
201 ret = connect(fd, &self->addr, self->addrlen);
202 ASSERT_EQ(ret, 0);
204 close(fd);
209 void verify_incoming_cpu(struct __test_metadata *_metadata,
210 FIXTURE_DATA(so_incoming_cpu) *self)
212 int i, j, fd, cpu, ret, total = 0;
213 socklen_t len = sizeof(int);
215 for (i = 0; i < nr_server; i++) {
216 for (j = 0; j < nr_client_per_server; j++) {
217 /* If we see -EAGAIN here, SO_INCOMING_CPU is broken */
218 fd = accept(self->servers[i], &self->addr, &self->addrlen);
219 ASSERT_NE(fd, -1);
221 ret = getsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, &len);
222 ASSERT_EQ(ret, 0);
223 ASSERT_EQ(cpu, i);
225 close(fd);
226 total++;
230 ASSERT_EQ(total, nr_client);
231 TH_LOG("SO_INCOMING_CPU is very likely to be "
232 "working correctly with %d sockets.", total);
235 TEST_F(so_incoming_cpu, test1)
237 create_servers(_metadata, self, variant);
238 create_clients(_metadata, self);
239 verify_incoming_cpu(_metadata, self);
242 TEST_F(so_incoming_cpu, test2)
244 int server;
246 create_servers(_metadata, self, variant);
248 /* No CPU specified */
249 server = create_server(_metadata, self, variant, -1);
250 close(server);
252 create_clients(_metadata, self);
253 verify_incoming_cpu(_metadata, self);
256 TEST_F(so_incoming_cpu, test3)
258 int server, client;
260 create_servers(_metadata, self, variant);
262 /* No CPU specified */
263 server = create_server(_metadata, self, variant, -1);
265 create_clients(_metadata, self);
267 /* Never receive any requests */
268 client = accept(server, &self->addr, &self->addrlen);
269 ASSERT_EQ(client, -1);
271 verify_incoming_cpu(_metadata, self);
274 TEST_HARNESS_MAIN