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

selftest: add a reuseaddr test

This is to test for a regression introduced by

b9470c27607b ("inet: kill smallest_size and smallest_port")

which introduced a problem with reuseaddr and bind conflicts.

Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>

authored by

Josef Bacik and committed by
Shuah Khan
422d8dc6 fbcab13d

+116 -1
+1
tools/testing/selftests/net/.gitignore
··· 6 6 reuseport_bpf_cpu 7 7 reuseport_bpf_numa 8 8 reuseport_dualstack 9 + reuseaddr_conflict
+1 -1
tools/testing/selftests/net/Makefile
··· 7 7 TEST_GEN_FILES = socket 8 8 TEST_GEN_FILES += psock_fanout psock_tpacket 9 9 TEST_GEN_FILES += reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa 10 - TEST_GEN_FILES += reuseport_dualstack msg_zerocopy 10 + TEST_GEN_FILES += reuseport_dualstack msg_zerocopy reuseaddr_conflict 11 11 12 12 include ../lib.mk 13 13
+114
tools/testing/selftests/net/reuseaddr_conflict.c
··· 1 + /* 2 + * Test for the regression introduced by 3 + * 4 + * b9470c27607b ("inet: kill smallest_size and smallest_port") 5 + * 6 + * If we open an ipv4 socket on a port with reuseaddr we shouldn't reset the tb 7 + * when we open the ipv6 conterpart, which is what was happening previously. 8 + */ 9 + #include <errno.h> 10 + #include <error.h> 11 + #include <arpa/inet.h> 12 + #include <netinet/in.h> 13 + #include <stdbool.h> 14 + #include <stdio.h> 15 + #include <sys/socket.h> 16 + #include <sys/types.h> 17 + #include <unistd.h> 18 + 19 + #define PORT 9999 20 + 21 + int open_port(int ipv6, int any) 22 + { 23 + int fd = -1; 24 + int reuseaddr = 1; 25 + int v6only = 1; 26 + int addrlen; 27 + int ret = -1; 28 + struct sockaddr *addr; 29 + int family = ipv6 ? AF_INET6 : AF_INET; 30 + 31 + struct sockaddr_in6 addr6 = { 32 + .sin6_family = AF_INET6, 33 + .sin6_port = htons(PORT), 34 + .sin6_addr = in6addr_any 35 + }; 36 + struct sockaddr_in addr4 = { 37 + .sin_family = AF_INET, 38 + .sin_port = htons(PORT), 39 + .sin_addr.s_addr = any ? htonl(INADDR_ANY) : inet_addr("127.0.0.1"), 40 + }; 41 + 42 + 43 + if (ipv6) { 44 + addr = (struct sockaddr*)&addr6; 45 + addrlen = sizeof(addr6); 46 + } else { 47 + addr = (struct sockaddr*)&addr4; 48 + addrlen = sizeof(addr4); 49 + } 50 + 51 + if ((fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) { 52 + perror("socket"); 53 + goto out; 54 + } 55 + 56 + if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only, 57 + sizeof(v6only)) < 0) { 58 + perror("setsockopt IPV6_V6ONLY"); 59 + goto out; 60 + } 61 + 62 + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, 63 + sizeof(reuseaddr)) < 0) { 64 + perror("setsockopt SO_REUSEADDR"); 65 + goto out; 66 + } 67 + 68 + if (bind(fd, addr, addrlen) < 0) { 69 + perror("bind"); 70 + goto out; 71 + } 72 + 73 + if (any) 74 + return fd; 75 + 76 + if (listen(fd, 1) < 0) { 77 + perror("listen"); 78 + goto out; 79 + } 80 + return fd; 81 + out: 82 + close(fd); 83 + return ret; 84 + } 85 + 86 + int main(void) 87 + { 88 + int listenfd; 89 + int fd1, fd2; 90 + 91 + fprintf(stderr, "Opening 127.0.0.1:%d\n", PORT); 92 + listenfd = open_port(0, 0); 93 + if (listenfd < 0) 94 + error(1, errno, "Couldn't open listen socket"); 95 + fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT); 96 + fd1 = open_port(0, 1); 97 + if (fd1 >= 0) 98 + error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket"); 99 + fprintf(stderr, "Opening in6addr_any:%d\n", PORT); 100 + fd1 = open_port(1, 1); 101 + if (fd1 < 0) 102 + error(1, errno, "Couldn't open ipv6 reuseport"); 103 + fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT); 104 + fd2 = open_port(0, 1); 105 + if (fd2 >= 0) 106 + error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket"); 107 + close(fd1); 108 + fprintf(stderr, "Opening INADDR_ANY:%d after closing ipv6 socket\n", PORT); 109 + fd1 = open_port(0, 1); 110 + if (fd1 >= 0) 111 + error(1, 0, "Was allowed to create an ipv4 reuseport on an already bound non-reuseport socket with no ipv6"); 112 + fprintf(stderr, "Success"); 113 + return 0; 114 + }