2 * It is possible to use SO_REUSEPORT to open multiple sockets bound to
3 * equivalent local addresses using AF_INET and AF_INET6 at the same time. If
4 * the AF_INET6 socket has IPV6_V6ONLY set, it's clear which socket should
5 * receive a given incoming packet. However, when it is not set, incoming v4
6 * packets should prefer the AF_INET socket(s). This behavior was defined with
7 * the original SO_REUSEPORT implementation, but broke with
8 * e32ea7e74727 ("soreuseport: fast reuseport UDP socket selection")
9 * This test creates these mixed AF_INET/AF_INET6 sockets and asserts the
10 * AF_INET preference for v4 packets.
15 #include <arpa/inet.h>
19 #include <linux/unistd.h>
23 #include <sys/epoll.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
28 static const int PORT
= 8888;
30 static void build_rcv_fd(int family
, int proto
, int *rcv_fds
, int count
)
32 struct sockaddr_storage addr
;
33 struct sockaddr_in
*addr4
;
34 struct sockaddr_in6
*addr6
;
39 addr4
= (struct sockaddr_in
*)&addr
;
40 addr4
->sin_family
= AF_INET
;
41 addr4
->sin_addr
.s_addr
= htonl(INADDR_ANY
);
42 addr4
->sin_port
= htons(PORT
);
45 addr6
= (struct sockaddr_in6
*)&addr
;
46 addr6
->sin6_family
= AF_INET6
;
47 addr6
->sin6_addr
= in6addr_any
;
48 addr6
->sin6_port
= htons(PORT
);
51 error(1, 0, "Unsupported family %d", family
);
54 for (i
= 0; i
< count
; ++i
) {
55 rcv_fds
[i
] = socket(family
, proto
, 0);
57 error(1, errno
, "failed to create receive socket");
60 if (setsockopt(rcv_fds
[i
], SOL_SOCKET
, SO_REUSEPORT
, &opt
,
62 error(1, errno
, "failed to set SO_REUSEPORT");
64 if (bind(rcv_fds
[i
], (struct sockaddr
*)&addr
, sizeof(addr
)))
65 error(1, errno
, "failed to bind receive socket");
67 if (proto
== SOCK_STREAM
&& listen(rcv_fds
[i
], 10))
68 error(1, errno
, "failed to listen on receive port");
72 static void send_from_v4(int proto
)
74 struct sockaddr_in saddr
, daddr
;
77 saddr
.sin_family
= AF_INET
;
78 saddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
81 daddr
.sin_family
= AF_INET
;
82 daddr
.sin_addr
.s_addr
= htonl(INADDR_LOOPBACK
);
83 daddr
.sin_port
= htons(PORT
);
85 fd
= socket(AF_INET
, proto
, 0);
87 error(1, errno
, "failed to create send socket");
89 if (bind(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)))
90 error(1, errno
, "failed to bind send socket");
92 if (connect(fd
, (struct sockaddr
*)&daddr
, sizeof(daddr
)))
93 error(1, errno
, "failed to connect send socket");
95 if (send(fd
, "a", 1, 0) < 0)
96 error(1, errno
, "failed to send message");
101 static int receive_once(int epfd
, int proto
)
103 struct epoll_event ev
;
107 i
= epoll_wait(epfd
, &ev
, 1, -1);
109 error(1, errno
, "epoll_wait failed");
111 if (proto
== SOCK_STREAM
) {
112 fd
= accept(ev
.data
.fd
, NULL
, NULL
);
114 error(1, errno
, "failed to accept");
115 i
= recv(fd
, buf
, sizeof(buf
), 0);
118 i
= recv(ev
.data
.fd
, buf
, sizeof(buf
), 0);
122 error(1, errno
, "failed to recv");
127 static void test(int *rcv_fds
, int count
, int proto
)
129 struct epoll_event ev
;
130 int epfd
, i
, test_fd
;
131 uint16_t test_family
;
134 epfd
= epoll_create(1);
136 error(1, errno
, "failed to create epoll");
139 for (i
= 0; i
< count
; ++i
) {
140 ev
.data
.fd
= rcv_fds
[i
];
141 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, rcv_fds
[i
], &ev
))
142 error(1, errno
, "failed to register sock epoll");
147 test_fd
= receive_once(epfd
, proto
);
148 if (getsockopt(test_fd
, SOL_SOCKET
, SO_DOMAIN
, &test_family
, &len
))
149 error(1, errno
, "failed to read socket domain");
150 if (test_family
!= AF_INET
)
151 error(1, 0, "expected to receive on v4 socket but got v6 (%d)",
161 fprintf(stderr
, "---- UDP IPv4 created before IPv6 ----\n");
162 build_rcv_fd(AF_INET
, SOCK_DGRAM
, rcv_fds
, 5);
163 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, &(rcv_fds
[5]), 5);
164 test(rcv_fds
, 10, SOCK_DGRAM
);
165 for (i
= 0; i
< 10; ++i
)
168 fprintf(stderr
, "---- UDP IPv6 created before IPv4 ----\n");
169 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, rcv_fds
, 5);
170 build_rcv_fd(AF_INET
, SOCK_DGRAM
, &(rcv_fds
[5]), 5);
171 test(rcv_fds
, 10, SOCK_DGRAM
);
172 for (i
= 0; i
< 10; ++i
)
175 /* NOTE: UDP socket lookups traverse a different code path when there
176 * are > 10 sockets in a group.
178 fprintf(stderr
, "---- UDP IPv4 created before IPv6 (large) ----\n");
179 build_rcv_fd(AF_INET
, SOCK_DGRAM
, rcv_fds
, 16);
180 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, &(rcv_fds
[16]), 16);
181 test(rcv_fds
, 32, SOCK_DGRAM
);
182 for (i
= 0; i
< 32; ++i
)
185 fprintf(stderr
, "---- UDP IPv6 created before IPv4 (large) ----\n");
186 build_rcv_fd(AF_INET6
, SOCK_DGRAM
, rcv_fds
, 16);
187 build_rcv_fd(AF_INET
, SOCK_DGRAM
, &(rcv_fds
[16]), 16);
188 test(rcv_fds
, 32, SOCK_DGRAM
);
189 for (i
= 0; i
< 32; ++i
)
192 fprintf(stderr
, "---- TCP IPv4 created before IPv6 ----\n");
193 build_rcv_fd(AF_INET
, SOCK_STREAM
, rcv_fds
, 5);
194 build_rcv_fd(AF_INET6
, SOCK_STREAM
, &(rcv_fds
[5]), 5);
195 test(rcv_fds
, 10, SOCK_STREAM
);
196 for (i
= 0; i
< 10; ++i
)
199 fprintf(stderr
, "---- TCP IPv6 created before IPv4 ----\n");
200 build_rcv_fd(AF_INET6
, SOCK_STREAM
, rcv_fds
, 5);
201 build_rcv_fd(AF_INET
, SOCK_STREAM
, &(rcv_fds
[5]), 5);
202 test(rcv_fds
, 10, SOCK_STREAM
);
203 for (i
= 0; i
< 10; ++i
)
206 fprintf(stderr
, "SUCCESS\n");