xref: /linux/tools/testing/selftests/net/reuseport_dualstack.c (revision dfecb0c5af3b07ebfa84be63a7a21bfc9e29a872)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * It is possible to use SO_REUSEPORT to open multiple sockets bound to
4  * equivalent local addresses using AF_INET and AF_INET6 at the same time.  If
5  * the AF_INET6 socket has IPV6_V6ONLY set, it's clear which socket should
6  * receive a given incoming packet.  However, when it is not set, incoming v4
7  * packets should prefer the AF_INET socket(s).  This behavior was defined with
8  * the original SO_REUSEPORT implementation, but broke with
9  * e32ea7e74727 ("soreuseport: fast reuseport UDP socket selection")
10  * This test creates these mixed AF_INET/AF_INET6 sockets and asserts the
11  * AF_INET preference for v4 packets.
12  */
13 
14 #define _GNU_SOURCE
15 
16 #include <arpa/inet.h>
17 #include <errno.h>
18 #include <error.h>
19 #include <linux/in.h>
20 #include <linux/unistd.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/epoll.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <unistd.h>
28 #include <sched.h>
29 
30 static const int PORT = 8888;
31 
32 static void build_rcv_fd(int family, int proto, int *rcv_fds, int count)
33 {
34 	struct sockaddr_storage addr;
35 	struct sockaddr_in  *addr4;
36 	struct sockaddr_in6 *addr6;
37 	int opt, i;
38 
39 	switch (family) {
40 	case AF_INET:
41 		addr4 = (struct sockaddr_in *)&addr;
42 		addr4->sin_family = AF_INET;
43 		addr4->sin_addr.s_addr = htonl(INADDR_ANY);
44 		addr4->sin_port = htons(PORT);
45 		break;
46 	case AF_INET6:
47 		addr6 = (struct sockaddr_in6 *)&addr;
48 		addr6->sin6_family = AF_INET6;
49 		addr6->sin6_addr = in6addr_any;
50 		addr6->sin6_port = htons(PORT);
51 		break;
52 	default:
53 		error(1, 0, "Unsupported family %d", family);
54 	}
55 
56 	for (i = 0; i < count; ++i) {
57 		rcv_fds[i] = socket(family, proto, 0);
58 		if (rcv_fds[i] < 0)
59 			error(1, errno, "failed to create receive socket");
60 
61 		opt = 1;
62 		if (setsockopt(rcv_fds[i], SOL_SOCKET, SO_REUSEPORT, &opt,
63 			       sizeof(opt)))
64 			error(1, errno, "failed to set SO_REUSEPORT");
65 
66 		if (bind(rcv_fds[i], (struct sockaddr *)&addr, sizeof(addr)))
67 			error(1, errno, "failed to bind receive socket");
68 
69 		if (proto == SOCK_STREAM && listen(rcv_fds[i], 10))
70 			error(1, errno, "failed to listen on receive port");
71 	}
72 }
73 
74 static void send_from_v4(int proto)
75 {
76 	struct sockaddr_in  saddr, daddr;
77 	int fd;
78 
79 	saddr.sin_family = AF_INET;
80 	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
81 	saddr.sin_port = 0;
82 
83 	daddr.sin_family = AF_INET;
84 	daddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
85 	daddr.sin_port = htons(PORT);
86 
87 	fd = socket(AF_INET, proto, 0);
88 	if (fd < 0)
89 		error(1, errno, "failed to create send socket");
90 
91 	if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)))
92 		error(1, errno, "failed to bind send socket");
93 
94 	if (connect(fd, (struct sockaddr *)&daddr, sizeof(daddr)))
95 		error(1, errno, "failed to connect send socket");
96 
97 	if (send(fd, "a", 1, 0) < 0)
98 		error(1, errno, "failed to send message");
99 
100 	close(fd);
101 }
102 
103 static int receive_once(int epfd, int proto)
104 {
105 	struct epoll_event ev;
106 	int i, fd;
107 	char buf[8];
108 
109 	i = epoll_wait(epfd, &ev, 1, -1);
110 	if (i < 0)
111 		error(1, errno, "epoll_wait failed");
112 
113 	if (proto == SOCK_STREAM) {
114 		fd = accept(ev.data.fd, NULL, NULL);
115 		if (fd < 0)
116 			error(1, errno, "failed to accept");
117 		i = recv(fd, buf, sizeof(buf), 0);
118 		close(fd);
119 	} else {
120 		i = recv(ev.data.fd, buf, sizeof(buf), 0);
121 	}
122 
123 	if (i < 0)
124 		error(1, errno, "failed to recv");
125 
126 	return ev.data.fd;
127 }
128 
129 static void test(int *rcv_fds, int count, int proto)
130 {
131 	struct epoll_event ev;
132 	int epfd, i, test_fd;
133 	int test_family;
134 	socklen_t len;
135 
136 	epfd = epoll_create(1);
137 	if (epfd < 0)
138 		error(1, errno, "failed to create epoll");
139 
140 	ev.events = EPOLLIN;
141 	for (i = 0; i < count; ++i) {
142 		ev.data.fd = rcv_fds[i];
143 		if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev))
144 			error(1, errno, "failed to register sock epoll");
145 	}
146 
147 	send_from_v4(proto);
148 
149 	test_fd = receive_once(epfd, proto);
150 	len = sizeof(test_family);
151 	if (getsockopt(test_fd, SOL_SOCKET, SO_DOMAIN, &test_family, &len))
152 		error(1, errno, "failed to read socket domain");
153 	if (test_family != AF_INET)
154 		error(1, 0, "expected to receive on v4 socket but got v6 (%d)",
155 		      test_family);
156 
157 	close(epfd);
158 }
159 
160 static void setup_netns(void)
161 {
162 	if (unshare(CLONE_NEWNET))
163 		error(1, errno, "failed to unshare netns");
164 	if (system("ip link set lo up"))
165 		error(1, 0, "failed to bring up lo interface in netns");
166 }
167 
168 int main(void)
169 {
170 	int rcv_fds[32], i;
171 
172 	setup_netns();
173 
174 	fprintf(stderr, "---- UDP IPv4 created before IPv6 ----\n");
175 	build_rcv_fd(AF_INET, SOCK_DGRAM, rcv_fds, 5);
176 	build_rcv_fd(AF_INET6, SOCK_DGRAM, &(rcv_fds[5]), 5);
177 	test(rcv_fds, 10, SOCK_DGRAM);
178 	for (i = 0; i < 10; ++i)
179 		close(rcv_fds[i]);
180 
181 	fprintf(stderr, "---- UDP IPv6 created before IPv4 ----\n");
182 	build_rcv_fd(AF_INET6, SOCK_DGRAM, rcv_fds, 5);
183 	build_rcv_fd(AF_INET, SOCK_DGRAM, &(rcv_fds[5]), 5);
184 	test(rcv_fds, 10, SOCK_DGRAM);
185 	for (i = 0; i < 10; ++i)
186 		close(rcv_fds[i]);
187 
188 	/* NOTE: UDP socket lookups traverse a different code path when there
189 	 * are > 10 sockets in a group.
190 	 */
191 	fprintf(stderr, "---- UDP IPv4 created before IPv6 (large) ----\n");
192 	build_rcv_fd(AF_INET, SOCK_DGRAM, rcv_fds, 16);
193 	build_rcv_fd(AF_INET6, SOCK_DGRAM, &(rcv_fds[16]), 16);
194 	test(rcv_fds, 32, SOCK_DGRAM);
195 	for (i = 0; i < 32; ++i)
196 		close(rcv_fds[i]);
197 
198 	fprintf(stderr, "---- UDP IPv6 created before IPv4 (large) ----\n");
199 	build_rcv_fd(AF_INET6, SOCK_DGRAM, rcv_fds, 16);
200 	build_rcv_fd(AF_INET, SOCK_DGRAM, &(rcv_fds[16]), 16);
201 	test(rcv_fds, 32, SOCK_DGRAM);
202 	for (i = 0; i < 32; ++i)
203 		close(rcv_fds[i]);
204 
205 	fprintf(stderr, "---- TCP IPv4 created before IPv6 ----\n");
206 	build_rcv_fd(AF_INET, SOCK_STREAM, rcv_fds, 5);
207 	build_rcv_fd(AF_INET6, SOCK_STREAM, &(rcv_fds[5]), 5);
208 	test(rcv_fds, 10, SOCK_STREAM);
209 	for (i = 0; i < 10; ++i)
210 		close(rcv_fds[i]);
211 
212 	fprintf(stderr, "---- TCP IPv6 created before IPv4 ----\n");
213 	build_rcv_fd(AF_INET6, SOCK_STREAM, rcv_fds, 5);
214 	build_rcv_fd(AF_INET, SOCK_STREAM, &(rcv_fds[5]), 5);
215 	test(rcv_fds, 10, SOCK_STREAM);
216 	for (i = 0; i < 10; ++i)
217 		close(rcv_fds[i]);
218 
219 	fprintf(stderr, "SUCCESS\n");
220 	return 0;
221 }
222