1 // SPDX-License-Identifier: GPL-2.0
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.
16 #include <arpa/inet.h>
20 #include <linux/unistd.h>
24 #include <sys/epoll.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
29 static const int PORT
= 8888;
31 static void build_rcv_fd(int family
, int proto
, int *rcv_fds
, int count
)
33 struct sockaddr_storage addr
;
34 struct sockaddr_in
*addr4
;
35 struct sockaddr_in6
*addr6
;
40 addr4
= (struct sockaddr_in
*)&addr
;
41 addr4
->sin_family
= AF_INET
;
42 addr4
->sin_addr
.s_addr
= htonl(INADDR_ANY
);
43 addr4
->sin_port
= htons(PORT
);
46 addr6
= (struct sockaddr_in6
*)&addr
;
47 addr6
->sin6_family
= AF_INET6
;
48 addr6
->sin6_addr
= in6addr_any
;
49 addr6
->sin6_port
= htons(PORT
);
52 error(1, 0, "Unsupported family %d", family
);
55 for (i
= 0; i
< count
; ++i
) {
56 rcv_fds
[i
] = socket(family
, proto
, 0);
58 error(1, errno
, "failed to create receive socket");
61 if (setsockopt(rcv_fds
[i
], SOL_SOCKET
, SO_REUSEPORT
, &opt
,
63 error(1, errno
, "failed to set SO_REUSEPORT");
65 if (bind(rcv_fds
[i
], (struct sockaddr
*)&addr
, sizeof(addr
)))
66 error(1, errno
, "failed to bind receive socket");
68 if (proto
== SOCK_STREAM
&& listen(rcv_fds
[i
], 10))
69 error(1, errno
, "failed to listen on receive port");
73 static void send_from_v4(int proto
)
75 struct sockaddr_in saddr
, daddr
;
78 saddr
.sin_family
= AF_INET
;
79 saddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
82 daddr
.sin_family
= AF_INET
;
83 daddr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
84 daddr
.sin_port
= htons(PORT
);
86 fd
= socket(AF_INET
, proto
, 0);
88 error(1, errno
, "failed to create send socket");
90 if (bind(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)))
91 error(1, errno
, "failed to bind send socket");
93 if (connect(fd
, (struct sockaddr
*)&daddr
, sizeof(daddr
)))
94 error(1, errno
, "failed to connect send socket");
96 if (send(fd
, "a", 1, 0) < 0)
97 error(1, errno
, "failed to send message");
102 static int receive_once(int epfd
, int proto
)
104 struct epoll_event ev
;
108 i
= epoll_wait(epfd
, &ev
, 1, -1);
110 error(1, errno
, "epoll_wait failed");
112 if (proto
== SOCK_STREAM
) {
113 fd
= accept(ev
.data
.fd
, NULL
, NULL
);
115 error(1, errno
, "failed to accept");
116 i
= recv(fd
, buf
, sizeof(buf
), 0);
119 i
= recv(ev
.data
.fd
, buf
, sizeof(buf
), 0);
123 error(1, errno
, "failed to recv");
128 static void test(int *rcv_fds
, int count
, int proto
)
130 struct epoll_event ev
;
131 int epfd
, i
, test_fd
;
135 epfd
= epoll_create(1);
137 error(1, errno
, "failed to create epoll");
140 for (i
= 0; i
< count
; ++i
) {
141 ev
.data
.fd
= rcv_fds
[i
];
142 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, rcv_fds
[i
], &ev
))
143 error(1, errno
, "failed to register sock epoll");
148 test_fd
= receive_once(epfd
, proto
);
149 len
= sizeof(test_family
);
150 if (getsockopt(test_fd
, SOL_SOCKET
, SO_DOMAIN
, &test_family
, &len
))
151 error(1, errno
, "failed to read socket domain");
152 if (test_family
!= AF_INET
)
153 error(1, 0, "expected to receive on v4 socket but got v6 (%d)",
163 fprintf(stderr
, "---- UDP IPv4 created before IPv6 ----\n");
164 build_rcv_fd(AF_INET
, SOCK_DGRAM
, rcv_fds
, 5);
165 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, &(rcv_fds
[5]), 5);
166 test(rcv_fds
, 10, SOCK_DGRAM
);
167 for (i
= 0; i
< 10; ++i
)
170 fprintf(stderr
, "---- UDP IPv6 created before IPv4 ----\n");
171 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, rcv_fds
, 5);
172 build_rcv_fd(AF_INET
, SOCK_DGRAM
, &(rcv_fds
[5]), 5);
173 test(rcv_fds
, 10, SOCK_DGRAM
);
174 for (i
= 0; i
< 10; ++i
)
177 /* NOTE: UDP socket lookups traverse a different code path when there
178 * are > 10 sockets in a group.
180 fprintf(stderr
, "---- UDP IPv4 created before IPv6 (large) ----\n");
181 build_rcv_fd(AF_INET
, SOCK_DGRAM
, rcv_fds
, 16);
182 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, &(rcv_fds
[16]), 16);
183 test(rcv_fds
, 32, SOCK_DGRAM
);
184 for (i
= 0; i
< 32; ++i
)
187 fprintf(stderr
, "---- UDP IPv6 created before IPv4 (large) ----\n");
188 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, rcv_fds
, 16);
189 build_rcv_fd(AF_INET
, SOCK_DGRAM
, &(rcv_fds
[16]), 16);
190 test(rcv_fds
, 32, SOCK_DGRAM
);
191 for (i
= 0; i
< 32; ++i
)
194 fprintf(stderr
, "---- TCP IPv4 created before IPv6 ----\n");
195 build_rcv_fd(AF_INET
, SOCK_STREAM
, rcv_fds
, 5);
196 build_rcv_fd(AF_INET6
, SOCK_STREAM
, &(rcv_fds
[5]), 5);
197 test(rcv_fds
, 10, SOCK_STREAM
);
198 for (i
= 0; i
< 10; ++i
)
201 fprintf(stderr
, "---- TCP IPv6 created before IPv4 ----\n");
202 build_rcv_fd(AF_INET6
, SOCK_STREAM
, rcv_fds
, 5);
203 build_rcv_fd(AF_INET
, SOCK_STREAM
, &(rcv_fds
[5]), 5);
204 test(rcv_fds
, 10, SOCK_STREAM
);
205 for (i
= 0; i
< 10; ++i
)
208 fprintf(stderr
, "SUCCESS\n");