Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.6-rc7 242 lines 5.3 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright Amazon.com Inc. or its affiliates. */ 3#define _GNU_SOURCE 4#include <sched.h> 5 6#include <netinet/in.h> 7#include <sys/socket.h> 8#include <sys/sysinfo.h> 9 10#include "../kselftest_harness.h" 11 12#define CLIENT_PER_SERVER 32 /* More sockets, more reliable */ 13#define NR_SERVER self->nproc 14#define NR_CLIENT (CLIENT_PER_SERVER * NR_SERVER) 15 16FIXTURE(so_incoming_cpu) 17{ 18 int nproc; 19 int *servers; 20 union { 21 struct sockaddr addr; 22 struct sockaddr_in in_addr; 23 }; 24 socklen_t addrlen; 25}; 26 27enum when_to_set { 28 BEFORE_REUSEPORT, 29 BEFORE_LISTEN, 30 AFTER_LISTEN, 31 AFTER_ALL_LISTEN, 32}; 33 34FIXTURE_VARIANT(so_incoming_cpu) 35{ 36 int when_to_set; 37}; 38 39FIXTURE_VARIANT_ADD(so_incoming_cpu, before_reuseport) 40{ 41 .when_to_set = BEFORE_REUSEPORT, 42}; 43 44FIXTURE_VARIANT_ADD(so_incoming_cpu, before_listen) 45{ 46 .when_to_set = BEFORE_LISTEN, 47}; 48 49FIXTURE_VARIANT_ADD(so_incoming_cpu, after_listen) 50{ 51 .when_to_set = AFTER_LISTEN, 52}; 53 54FIXTURE_VARIANT_ADD(so_incoming_cpu, after_all_listen) 55{ 56 .when_to_set = AFTER_ALL_LISTEN, 57}; 58 59FIXTURE_SETUP(so_incoming_cpu) 60{ 61 self->nproc = get_nprocs(); 62 ASSERT_LE(2, self->nproc); 63 64 self->servers = malloc(sizeof(int) * NR_SERVER); 65 ASSERT_NE(self->servers, NULL); 66 67 self->in_addr.sin_family = AF_INET; 68 self->in_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 69 self->in_addr.sin_port = htons(0); 70 self->addrlen = sizeof(struct sockaddr_in); 71} 72 73FIXTURE_TEARDOWN(so_incoming_cpu) 74{ 75 int i; 76 77 for (i = 0; i < NR_SERVER; i++) 78 close(self->servers[i]); 79 80 free(self->servers); 81} 82 83void set_so_incoming_cpu(struct __test_metadata *_metadata, int fd, int cpu) 84{ 85 int ret; 86 87 ret = setsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, sizeof(int)); 88 ASSERT_EQ(ret, 0); 89} 90 91int create_server(struct __test_metadata *_metadata, 92 FIXTURE_DATA(so_incoming_cpu) *self, 93 const FIXTURE_VARIANT(so_incoming_cpu) *variant, 94 int cpu) 95{ 96 int fd, ret; 97 98 fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); 99 ASSERT_NE(fd, -1); 100 101 if (variant->when_to_set == BEFORE_REUSEPORT) 102 set_so_incoming_cpu(_metadata, fd, cpu); 103 104 ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &(int){1}, sizeof(int)); 105 ASSERT_EQ(ret, 0); 106 107 ret = bind(fd, &self->addr, self->addrlen); 108 ASSERT_EQ(ret, 0); 109 110 if (variant->when_to_set == BEFORE_LISTEN) 111 set_so_incoming_cpu(_metadata, fd, cpu); 112 113 /* We don't use CLIENT_PER_SERVER here not to block 114 * this test at connect() if SO_INCOMING_CPU is broken. 115 */ 116 ret = listen(fd, NR_CLIENT); 117 ASSERT_EQ(ret, 0); 118 119 if (variant->when_to_set == AFTER_LISTEN) 120 set_so_incoming_cpu(_metadata, fd, cpu); 121 122 return fd; 123} 124 125void create_servers(struct __test_metadata *_metadata, 126 FIXTURE_DATA(so_incoming_cpu) *self, 127 const FIXTURE_VARIANT(so_incoming_cpu) *variant) 128{ 129 int i, ret; 130 131 for (i = 0; i < NR_SERVER; i++) { 132 self->servers[i] = create_server(_metadata, self, variant, i); 133 134 if (i == 0) { 135 ret = getsockname(self->servers[i], &self->addr, &self->addrlen); 136 ASSERT_EQ(ret, 0); 137 } 138 } 139 140 if (variant->when_to_set == AFTER_ALL_LISTEN) { 141 for (i = 0; i < NR_SERVER; i++) 142 set_so_incoming_cpu(_metadata, self->servers[i], i); 143 } 144} 145 146void create_clients(struct __test_metadata *_metadata, 147 FIXTURE_DATA(so_incoming_cpu) *self) 148{ 149 cpu_set_t cpu_set; 150 int i, j, fd, ret; 151 152 for (i = 0; i < NR_SERVER; i++) { 153 CPU_ZERO(&cpu_set); 154 155 CPU_SET(i, &cpu_set); 156 ASSERT_EQ(CPU_COUNT(&cpu_set), 1); 157 ASSERT_NE(CPU_ISSET(i, &cpu_set), 0); 158 159 /* Make sure SYN will be processed on the i-th CPU 160 * and finally distributed to the i-th listener. 161 */ 162 ret = sched_setaffinity(0, sizeof(cpu_set), &cpu_set); 163 ASSERT_EQ(ret, 0); 164 165 for (j = 0; j < CLIENT_PER_SERVER; j++) { 166 fd = socket(AF_INET, SOCK_STREAM, 0); 167 ASSERT_NE(fd, -1); 168 169 ret = connect(fd, &self->addr, self->addrlen); 170 ASSERT_EQ(ret, 0); 171 172 close(fd); 173 } 174 } 175} 176 177void verify_incoming_cpu(struct __test_metadata *_metadata, 178 FIXTURE_DATA(so_incoming_cpu) *self) 179{ 180 int i, j, fd, cpu, ret, total = 0; 181 socklen_t len = sizeof(int); 182 183 for (i = 0; i < NR_SERVER; i++) { 184 for (j = 0; j < CLIENT_PER_SERVER; j++) { 185 /* If we see -EAGAIN here, SO_INCOMING_CPU is broken */ 186 fd = accept(self->servers[i], &self->addr, &self->addrlen); 187 ASSERT_NE(fd, -1); 188 189 ret = getsockopt(fd, SOL_SOCKET, SO_INCOMING_CPU, &cpu, &len); 190 ASSERT_EQ(ret, 0); 191 ASSERT_EQ(cpu, i); 192 193 close(fd); 194 total++; 195 } 196 } 197 198 ASSERT_EQ(total, NR_CLIENT); 199 TH_LOG("SO_INCOMING_CPU is very likely to be " 200 "working correctly with %d sockets.", total); 201} 202 203TEST_F(so_incoming_cpu, test1) 204{ 205 create_servers(_metadata, self, variant); 206 create_clients(_metadata, self); 207 verify_incoming_cpu(_metadata, self); 208} 209 210TEST_F(so_incoming_cpu, test2) 211{ 212 int server; 213 214 create_servers(_metadata, self, variant); 215 216 /* No CPU specified */ 217 server = create_server(_metadata, self, variant, -1); 218 close(server); 219 220 create_clients(_metadata, self); 221 verify_incoming_cpu(_metadata, self); 222} 223 224TEST_F(so_incoming_cpu, test3) 225{ 226 int server, client; 227 228 create_servers(_metadata, self, variant); 229 230 /* No CPU specified */ 231 server = create_server(_metadata, self, variant, -1); 232 233 create_clients(_metadata, self); 234 235 /* Never receive any requests */ 236 client = accept(server, &self->addr, &self->addrlen); 237 ASSERT_EQ(client, -1); 238 239 verify_incoming_cpu(_metadata, self); 240} 241 242TEST_HARNESS_MAIN