Merge tag 'v5.11' into next
[linux-2.6-microblaze.git] / tools / testing / selftests / net / reuseport_addr_any.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /* Test that sockets listening on a specific address are preferred
4  * over sockets listening on addr_any.
5  */
6
7 #define _GNU_SOURCE
8
9 #include <arpa/inet.h>
10 #include <errno.h>
11 #include <error.h>
12 #include <linux/dccp.h>
13 #include <linux/in.h>
14 #include <linux/unistd.h>
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/epoll.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23
24 #ifndef SOL_DCCP
25 #define SOL_DCCP 269
26 #endif
27
28 static const char *IP4_ADDR = "127.0.0.1";
29 static const char *IP6_ADDR = "::1";
30 static const char *IP4_MAPPED6 = "::ffff:127.0.0.1";
31
32 static const int PORT = 8888;
33
34 static void build_rcv_fd(int family, int proto, int *rcv_fds, int count,
35                          const char *addr_str)
36 {
37         struct sockaddr_in  addr4 = {0};
38         struct sockaddr_in6 addr6 = {0};
39         struct sockaddr *addr;
40         int opt, i, sz;
41
42         memset(&addr, 0, sizeof(addr));
43
44         switch (family) {
45         case AF_INET:
46                 addr4.sin_family = family;
47                 if (!addr_str)
48                         addr4.sin_addr.s_addr = htonl(INADDR_ANY);
49                 else if (!inet_pton(family, addr_str, &addr4.sin_addr.s_addr))
50                         error(1, errno, "inet_pton failed: %s", addr_str);
51                 addr4.sin_port = htons(PORT);
52                 sz = sizeof(addr4);
53                 addr = (struct sockaddr *)&addr4;
54                 break;
55         case AF_INET6:
56                 addr6.sin6_family = AF_INET6;
57                 if (!addr_str)
58                         addr6.sin6_addr = in6addr_any;
59                 else if (!inet_pton(family, addr_str, &addr6.sin6_addr))
60                         error(1, errno, "inet_pton failed: %s", addr_str);
61                 addr6.sin6_port = htons(PORT);
62                 sz = sizeof(addr6);
63                 addr = (struct sockaddr *)&addr6;
64                 break;
65         default:
66                 error(1, 0, "Unsupported family %d", family);
67                 /* clang does not recognize error() above as terminating
68                  * the program, so it complains that saddr, sz are
69                  * not initialized when this code path is taken. Silence it.
70                  */
71                 return;
72         }
73
74         for (i = 0; i < count; ++i) {
75                 rcv_fds[i] = socket(family, proto, 0);
76                 if (rcv_fds[i] < 0)
77                         error(1, errno, "failed to create receive socket");
78
79                 opt = 1;
80                 if (setsockopt(rcv_fds[i], SOL_SOCKET, SO_REUSEPORT, &opt,
81                                sizeof(opt)))
82                         error(1, errno, "failed to set SO_REUSEPORT");
83
84                 if (bind(rcv_fds[i], addr, sz))
85                         error(1, errno, "failed to bind receive socket");
86
87                 if (proto == SOCK_STREAM && listen(rcv_fds[i], 10))
88                         error(1, errno, "tcp: failed to listen on receive port");
89                 else if (proto == SOCK_DCCP) {
90                         if (setsockopt(rcv_fds[i], SOL_DCCP,
91                                         DCCP_SOCKOPT_SERVICE,
92                                         &(int) {htonl(42)}, sizeof(int)))
93                                 error(1, errno, "failed to setsockopt");
94
95                         if (listen(rcv_fds[i], 10))
96                                 error(1, errno, "dccp: failed to listen on receive port");
97                 }
98         }
99 }
100
101 static int connect_and_send(int family, int proto)
102 {
103         struct sockaddr_in  saddr4 = {0};
104         struct sockaddr_in  daddr4 = {0};
105         struct sockaddr_in6 saddr6 = {0};
106         struct sockaddr_in6 daddr6 = {0};
107         struct sockaddr *saddr, *daddr;
108         int fd, sz;
109
110         switch (family) {
111         case AF_INET:
112                 saddr4.sin_family = AF_INET;
113                 saddr4.sin_addr.s_addr = htonl(INADDR_ANY);
114                 saddr4.sin_port = 0;
115
116                 daddr4.sin_family = AF_INET;
117                 if (!inet_pton(family, IP4_ADDR, &daddr4.sin_addr.s_addr))
118                         error(1, errno, "inet_pton failed: %s", IP4_ADDR);
119                 daddr4.sin_port = htons(PORT);
120
121                 sz = sizeof(saddr4);
122                 saddr = (struct sockaddr *)&saddr4;
123                 daddr = (struct sockaddr *)&daddr4;
124         break;
125         case AF_INET6:
126                 saddr6.sin6_family = AF_INET6;
127                 saddr6.sin6_addr = in6addr_any;
128
129                 daddr6.sin6_family = AF_INET6;
130                 if (!inet_pton(family, IP6_ADDR, &daddr6.sin6_addr))
131                         error(1, errno, "inet_pton failed: %s", IP6_ADDR);
132                 daddr6.sin6_port = htons(PORT);
133
134                 sz = sizeof(saddr6);
135                 saddr = (struct sockaddr *)&saddr6;
136                 daddr = (struct sockaddr *)&daddr6;
137         break;
138         default:
139                 error(1, 0, "Unsupported family %d", family);
140                 /* clang does not recognize error() above as terminating
141                  * the program, so it complains that saddr, daddr, sz are
142                  * not initialized when this code path is taken. Silence it.
143                  */
144                 return -1;
145         }
146
147         fd = socket(family, proto, 0);
148         if (fd < 0)
149                 error(1, errno, "failed to create send socket");
150
151         if (proto == SOCK_DCCP &&
152                 setsockopt(fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
153                                 &(int){htonl(42)}, sizeof(int)))
154                 error(1, errno, "failed to setsockopt");
155
156         if (bind(fd, saddr, sz))
157                 error(1, errno, "failed to bind send socket");
158
159         if (connect(fd, daddr, sz))
160                 error(1, errno, "failed to connect send socket");
161
162         if (send(fd, "a", 1, 0) < 0)
163                 error(1, errno, "failed to send message");
164
165         return fd;
166 }
167
168 static int receive_once(int epfd, int proto)
169 {
170         struct epoll_event ev;
171         int i, fd;
172         char buf[8];
173
174         i = epoll_wait(epfd, &ev, 1, 3);
175         if (i < 0)
176                 error(1, errno, "epoll_wait failed");
177
178         if (proto == SOCK_STREAM || proto == SOCK_DCCP) {
179                 fd = accept(ev.data.fd, NULL, NULL);
180                 if (fd < 0)
181                         error(1, errno, "failed to accept");
182                 i = recv(fd, buf, sizeof(buf), 0);
183                 close(fd);
184         } else {
185                 i = recv(ev.data.fd, buf, sizeof(buf), 0);
186         }
187
188         if (i < 0)
189                 error(1, errno, "failed to recv");
190
191         return ev.data.fd;
192 }
193
194 static void test(int *rcv_fds, int count, int family, int proto, int fd)
195 {
196         struct epoll_event ev;
197         int epfd, i, send_fd, recv_fd;
198
199         epfd = epoll_create(1);
200         if (epfd < 0)
201                 error(1, errno, "failed to create epoll");
202
203         ev.events = EPOLLIN;
204         for (i = 0; i < count; ++i) {
205                 ev.data.fd = rcv_fds[i];
206                 if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev))
207                         error(1, errno, "failed to register sock epoll");
208         }
209
210         send_fd = connect_and_send(family, proto);
211
212         recv_fd = receive_once(epfd, proto);
213         if (recv_fd != fd)
214                 error(1, 0, "received on an unexpected socket");
215
216         close(send_fd);
217         close(epfd);
218 }
219
220
221 static void run_one_test(int fam_send, int fam_rcv, int proto,
222                          const char *addr_str)
223 {
224         /* Below we test that a socket listening on a specific address
225          * is always selected in preference over a socket listening
226          * on addr_any. Bugs where this is not the case often result
227          * in sockets created first or last to get picked. So below
228          * we make sure that there are always addr_any sockets created
229          * before and after a specific socket is created.
230          */
231         int rcv_fds[10], i;
232
233         build_rcv_fd(AF_INET, proto, rcv_fds, 2, NULL);
234         build_rcv_fd(AF_INET6, proto, rcv_fds + 2, 2, NULL);
235         build_rcv_fd(fam_rcv, proto, rcv_fds + 4, 1, addr_str);
236         build_rcv_fd(AF_INET, proto, rcv_fds + 5, 2, NULL);
237         build_rcv_fd(AF_INET6, proto, rcv_fds + 7, 2, NULL);
238         test(rcv_fds, 9, fam_send, proto, rcv_fds[4]);
239         for (i = 0; i < 9; ++i)
240                 close(rcv_fds[i]);
241         fprintf(stderr, "pass\n");
242 }
243
244 static void test_proto(int proto, const char *proto_str)
245 {
246         if (proto == SOCK_DCCP) {
247                 int test_fd;
248
249                 test_fd = socket(AF_INET, proto, 0);
250                 if (test_fd < 0) {
251                         if (errno == ESOCKTNOSUPPORT) {
252                                 fprintf(stderr, "DCCP not supported: skipping DCCP tests\n");
253                                 return;
254                         } else
255                                 error(1, errno, "failed to create a DCCP socket");
256                 }
257                 close(test_fd);
258         }
259
260         fprintf(stderr, "%s IPv4 ... ", proto_str);
261         run_one_test(AF_INET, AF_INET, proto, IP4_ADDR);
262
263         fprintf(stderr, "%s IPv6 ... ", proto_str);
264         run_one_test(AF_INET6, AF_INET6, proto, IP6_ADDR);
265
266         fprintf(stderr, "%s IPv4 mapped to IPv6 ... ", proto_str);
267         run_one_test(AF_INET, AF_INET6, proto, IP4_MAPPED6);
268 }
269
270 int main(void)
271 {
272         test_proto(SOCK_DGRAM, "UDP");
273         test_proto(SOCK_STREAM, "TCP");
274         test_proto(SOCK_DCCP, "DCCP");
275
276         fprintf(stderr, "SUCCESS\n");
277         return 0;
278 }