1634bb9e4SMark Johnston /*- 2634bb9e4SMark Johnston * Copyright (c) 2018 The FreeBSD Foundation 3634bb9e4SMark Johnston * 4634bb9e4SMark Johnston * This software was developed by Mark Johnston under sponsorship from 5634bb9e4SMark Johnston * the FreeBSD Foundation. 6634bb9e4SMark Johnston * 7634bb9e4SMark Johnston * Redistribution and use in source and binary forms, with or without 8634bb9e4SMark Johnston * modification, are permitted provided that the following conditions are 9634bb9e4SMark Johnston * met: 10634bb9e4SMark Johnston * 1. Redistributions of source code must retain the above copyright 11634bb9e4SMark Johnston * notice, this list of conditions and the following disclaimer. 12634bb9e4SMark Johnston * 2. Redistributions in binary form must reproduce the above copyright 13634bb9e4SMark Johnston * notice, this list of conditions and the following disclaimer in 14634bb9e4SMark Johnston * the documentation and/or other materials provided with the 15634bb9e4SMark Johnston * distribution. 16634bb9e4SMark Johnston * 17634bb9e4SMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18634bb9e4SMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19634bb9e4SMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20634bb9e4SMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21634bb9e4SMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22634bb9e4SMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23634bb9e4SMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24634bb9e4SMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25634bb9e4SMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26634bb9e4SMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27634bb9e4SMark Johnston * SUCH DAMAGE. 28634bb9e4SMark Johnston */ 29634bb9e4SMark Johnston 30634bb9e4SMark Johnston #include <sys/param.h> 317cbb6b6eSMark Johnston #include <sys/event.h> 32634bb9e4SMark Johnston #include <sys/socket.h> 33634bb9e4SMark Johnston 34634bb9e4SMark Johnston #include <netinet/in.h> 357cbb6b6eSMark Johnston #include <netinet/tcp.h> 36634bb9e4SMark Johnston 37634bb9e4SMark Johnston #include <err.h> 38634bb9e4SMark Johnston #include <errno.h> 397cbb6b6eSMark Johnston #include <pthread.h> 407cbb6b6eSMark Johnston #include <stdatomic.h> 41634bb9e4SMark Johnston #include <stdlib.h> 42634bb9e4SMark Johnston #include <unistd.h> 43634bb9e4SMark Johnston 44634bb9e4SMark Johnston #include <atf-c.h> 45634bb9e4SMark Johnston 46634bb9e4SMark Johnston /* 47634bb9e4SMark Johnston * Given an array of non-blocking listening sockets configured in a LB group 48634bb9e4SMark Johnston * for "addr", try connecting to "addr" in a loop and verify that connections 49634bb9e4SMark Johnston * are roughly balanced across the sockets. 50634bb9e4SMark Johnston */ 51634bb9e4SMark Johnston static void 52634bb9e4SMark Johnston lb_simple_accept_loop(int domain, const struct sockaddr *addr, int sds[], 53634bb9e4SMark Johnston size_t nsds, int nconns) 54634bb9e4SMark Johnston { 55634bb9e4SMark Johnston size_t i; 56634bb9e4SMark Johnston int *acceptcnt; 57634bb9e4SMark Johnston int csd, error, excnt, sd; 580d46edd0SOlivier Cochard const struct linger lopt = { 1, 0 }; 59634bb9e4SMark Johnston 60634bb9e4SMark Johnston /* 61634bb9e4SMark Johnston * We expect each listening socket to accept roughly nconns/nsds 62634bb9e4SMark Johnston * connections, but allow for some error. 63634bb9e4SMark Johnston */ 64634bb9e4SMark Johnston excnt = nconns / nsds / 8; 65634bb9e4SMark Johnston acceptcnt = calloc(nsds, sizeof(*acceptcnt)); 66634bb9e4SMark Johnston ATF_REQUIRE_MSG(acceptcnt != NULL, "calloc() failed: %s", 67634bb9e4SMark Johnston strerror(errno)); 68634bb9e4SMark Johnston 69634bb9e4SMark Johnston while (nconns-- > 0) { 70634bb9e4SMark Johnston sd = socket(domain, SOCK_STREAM, 0); 71634bb9e4SMark Johnston ATF_REQUIRE_MSG(sd >= 0, "socket() failed: %s", 72634bb9e4SMark Johnston strerror(errno)); 73634bb9e4SMark Johnston 74634bb9e4SMark Johnston error = connect(sd, addr, addr->sa_len); 75634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "connect() failed: %s", 76634bb9e4SMark Johnston strerror(errno)); 77634bb9e4SMark Johnston 780d46edd0SOlivier Cochard error = setsockopt(sd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt)); 790d46edd0SOlivier Cochard ATF_REQUIRE_MSG(error == 0, "Setting linger failed: %s", 800d46edd0SOlivier Cochard strerror(errno)); 810d46edd0SOlivier Cochard 82634bb9e4SMark Johnston /* 83634bb9e4SMark Johnston * Poll the listening sockets. 84634bb9e4SMark Johnston */ 85634bb9e4SMark Johnston do { 86634bb9e4SMark Johnston for (i = 0; i < nsds; i++) { 87634bb9e4SMark Johnston csd = accept(sds[i], NULL, NULL); 88634bb9e4SMark Johnston if (csd < 0) { 89634bb9e4SMark Johnston ATF_REQUIRE_MSG(errno == EWOULDBLOCK || 90634bb9e4SMark Johnston errno == EAGAIN, 91634bb9e4SMark Johnston "accept() failed: %s", 92634bb9e4SMark Johnston strerror(errno)); 93634bb9e4SMark Johnston continue; 94634bb9e4SMark Johnston } 95634bb9e4SMark Johnston 96634bb9e4SMark Johnston error = close(csd); 97634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, 98634bb9e4SMark Johnston "close() failed: %s", strerror(errno)); 99634bb9e4SMark Johnston 100634bb9e4SMark Johnston acceptcnt[i]++; 101634bb9e4SMark Johnston break; 102634bb9e4SMark Johnston } 103634bb9e4SMark Johnston } while (i == nsds); 104634bb9e4SMark Johnston 105634bb9e4SMark Johnston error = close(sd); 106634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "close() failed: %s", 107634bb9e4SMark Johnston strerror(errno)); 108634bb9e4SMark Johnston } 109634bb9e4SMark Johnston 110634bb9e4SMark Johnston for (i = 0; i < nsds; i++) 111634bb9e4SMark Johnston ATF_REQUIRE_MSG(acceptcnt[i] > excnt, "uneven balancing"); 112634bb9e4SMark Johnston } 113634bb9e4SMark Johnston 114634bb9e4SMark Johnston static int 115634bb9e4SMark Johnston lb_listen_socket(int domain, int flags) 116634bb9e4SMark Johnston { 1179b287735SAlfredo Dal'Ava Junior int one; 118634bb9e4SMark Johnston int error, sd; 119634bb9e4SMark Johnston 120634bb9e4SMark Johnston sd = socket(domain, SOCK_STREAM | flags, 0); 121634bb9e4SMark Johnston ATF_REQUIRE_MSG(sd >= 0, "socket() failed: %s", strerror(errno)); 122634bb9e4SMark Johnston 123634bb9e4SMark Johnston one = 1; 124634bb9e4SMark Johnston error = setsockopt(sd, SOL_SOCKET, SO_REUSEPORT_LB, &one, sizeof(one)); 125634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "setsockopt(SO_REUSEPORT_LB) failed: %s", 126634bb9e4SMark Johnston strerror(errno)); 127634bb9e4SMark Johnston 128634bb9e4SMark Johnston return (sd); 129634bb9e4SMark Johnston } 130634bb9e4SMark Johnston 131634bb9e4SMark Johnston ATF_TC_WITHOUT_HEAD(basic_ipv4); 132634bb9e4SMark Johnston ATF_TC_BODY(basic_ipv4, tc) 133634bb9e4SMark Johnston { 134634bb9e4SMark Johnston struct sockaddr_in addr; 135634bb9e4SMark Johnston socklen_t slen; 136634bb9e4SMark Johnston size_t i; 137634bb9e4SMark Johnston const int nconns = 16384; 138634bb9e4SMark Johnston int error, sds[16]; 139634bb9e4SMark Johnston uint16_t port; 140634bb9e4SMark Johnston 141634bb9e4SMark Johnston sds[0] = lb_listen_socket(PF_INET, SOCK_NONBLOCK); 142634bb9e4SMark Johnston 143634bb9e4SMark Johnston memset(&addr, 0, sizeof(addr)); 144634bb9e4SMark Johnston addr.sin_len = sizeof(addr); 145634bb9e4SMark Johnston addr.sin_family = AF_INET; 146634bb9e4SMark Johnston addr.sin_port = htons(0); 147634bb9e4SMark Johnston addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 148634bb9e4SMark Johnston error = bind(sds[0], (const struct sockaddr *)&addr, sizeof(addr)); 149634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); 150634bb9e4SMark Johnston error = listen(sds[0], 1); 151634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno)); 152634bb9e4SMark Johnston 153634bb9e4SMark Johnston slen = sizeof(addr); 154634bb9e4SMark Johnston error = getsockname(sds[0], (struct sockaddr *)&addr, &slen); 155634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "getsockname() failed: %s", 156634bb9e4SMark Johnston strerror(errno)); 157634bb9e4SMark Johnston ATF_REQUIRE_MSG(slen == sizeof(addr), "sockaddr size changed"); 158634bb9e4SMark Johnston port = addr.sin_port; 159634bb9e4SMark Johnston 160634bb9e4SMark Johnston memset(&addr, 0, sizeof(addr)); 161634bb9e4SMark Johnston addr.sin_len = sizeof(addr); 162634bb9e4SMark Johnston addr.sin_family = AF_INET; 163634bb9e4SMark Johnston addr.sin_port = port; 164634bb9e4SMark Johnston addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 165634bb9e4SMark Johnston for (i = 1; i < nitems(sds); i++) { 166634bb9e4SMark Johnston sds[i] = lb_listen_socket(PF_INET, SOCK_NONBLOCK); 167634bb9e4SMark Johnston 168634bb9e4SMark Johnston error = bind(sds[i], (const struct sockaddr *)&addr, 169634bb9e4SMark Johnston sizeof(addr)); 170634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", 171634bb9e4SMark Johnston strerror(errno)); 172634bb9e4SMark Johnston error = listen(sds[i], 1); 173634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", 174634bb9e4SMark Johnston strerror(errno)); 175634bb9e4SMark Johnston } 176634bb9e4SMark Johnston 177634bb9e4SMark Johnston lb_simple_accept_loop(PF_INET, (struct sockaddr *)&addr, sds, 178634bb9e4SMark Johnston nitems(sds), nconns); 179634bb9e4SMark Johnston for (i = 0; i < nitems(sds); i++) { 180634bb9e4SMark Johnston error = close(sds[i]); 181634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "close() failed: %s", 182634bb9e4SMark Johnston strerror(errno)); 183634bb9e4SMark Johnston } 184634bb9e4SMark Johnston } 185634bb9e4SMark Johnston 186634bb9e4SMark Johnston ATF_TC_WITHOUT_HEAD(basic_ipv6); 187634bb9e4SMark Johnston ATF_TC_BODY(basic_ipv6, tc) 188634bb9e4SMark Johnston { 189634bb9e4SMark Johnston const struct in6_addr loopback6 = IN6ADDR_LOOPBACK_INIT; 190634bb9e4SMark Johnston struct sockaddr_in6 addr; 191634bb9e4SMark Johnston socklen_t slen; 192634bb9e4SMark Johnston size_t i; 193634bb9e4SMark Johnston const int nconns = 16384; 194634bb9e4SMark Johnston int error, sds[16]; 195634bb9e4SMark Johnston uint16_t port; 196634bb9e4SMark Johnston 197634bb9e4SMark Johnston sds[0] = lb_listen_socket(PF_INET6, SOCK_NONBLOCK); 198634bb9e4SMark Johnston 199634bb9e4SMark Johnston memset(&addr, 0, sizeof(addr)); 200634bb9e4SMark Johnston addr.sin6_len = sizeof(addr); 201634bb9e4SMark Johnston addr.sin6_family = AF_INET6; 202634bb9e4SMark Johnston addr.sin6_port = htons(0); 203634bb9e4SMark Johnston addr.sin6_addr = loopback6; 204634bb9e4SMark Johnston error = bind(sds[0], (const struct sockaddr *)&addr, sizeof(addr)); 205634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); 206634bb9e4SMark Johnston error = listen(sds[0], 1); 207634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno)); 208634bb9e4SMark Johnston 209634bb9e4SMark Johnston slen = sizeof(addr); 210634bb9e4SMark Johnston error = getsockname(sds[0], (struct sockaddr *)&addr, &slen); 211634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "getsockname() failed: %s", 212634bb9e4SMark Johnston strerror(errno)); 213634bb9e4SMark Johnston ATF_REQUIRE_MSG(slen == sizeof(addr), "sockaddr size changed"); 214634bb9e4SMark Johnston port = addr.sin6_port; 215634bb9e4SMark Johnston 216634bb9e4SMark Johnston memset(&addr, 0, sizeof(addr)); 217634bb9e4SMark Johnston addr.sin6_len = sizeof(addr); 218634bb9e4SMark Johnston addr.sin6_family = AF_INET6; 219634bb9e4SMark Johnston addr.sin6_port = port; 220634bb9e4SMark Johnston addr.sin6_addr = loopback6; 221634bb9e4SMark Johnston for (i = 1; i < nitems(sds); i++) { 222634bb9e4SMark Johnston sds[i] = lb_listen_socket(PF_INET6, SOCK_NONBLOCK); 223634bb9e4SMark Johnston 224634bb9e4SMark Johnston error = bind(sds[i], (const struct sockaddr *)&addr, 225634bb9e4SMark Johnston sizeof(addr)); 226634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", 227634bb9e4SMark Johnston strerror(errno)); 228634bb9e4SMark Johnston error = listen(sds[i], 1); 229634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", 230634bb9e4SMark Johnston strerror(errno)); 231634bb9e4SMark Johnston } 232634bb9e4SMark Johnston 233634bb9e4SMark Johnston lb_simple_accept_loop(PF_INET6, (struct sockaddr *)&addr, sds, 234634bb9e4SMark Johnston nitems(sds), nconns); 235634bb9e4SMark Johnston for (i = 0; i < nitems(sds); i++) { 236634bb9e4SMark Johnston error = close(sds[i]); 237634bb9e4SMark Johnston ATF_REQUIRE_MSG(error == 0, "close() failed: %s", 238634bb9e4SMark Johnston strerror(errno)); 239634bb9e4SMark Johnston } 240634bb9e4SMark Johnston } 241634bb9e4SMark Johnston 2427cbb6b6eSMark Johnston struct concurrent_add_softc { 2437cbb6b6eSMark Johnston struct sockaddr_storage ss; 2447cbb6b6eSMark Johnston int socks[128]; 2457cbb6b6eSMark Johnston int kq; 2467cbb6b6eSMark Johnston }; 2477cbb6b6eSMark Johnston 2487cbb6b6eSMark Johnston static void * 2497cbb6b6eSMark Johnston listener(void *arg) 2507cbb6b6eSMark Johnston { 2517cbb6b6eSMark Johnston for (struct concurrent_add_softc *sc = arg;;) { 2527cbb6b6eSMark Johnston struct kevent kev; 2537cbb6b6eSMark Johnston ssize_t n; 2547cbb6b6eSMark Johnston int error, count, cs, s; 2557cbb6b6eSMark Johnston uint8_t b; 2567cbb6b6eSMark Johnston 2577cbb6b6eSMark Johnston count = kevent(sc->kq, NULL, 0, &kev, 1, NULL); 2587cbb6b6eSMark Johnston ATF_REQUIRE_MSG(count == 1, 2597cbb6b6eSMark Johnston "kevent() failed: %s", strerror(errno)); 2607cbb6b6eSMark Johnston 2617cbb6b6eSMark Johnston s = (int)kev.ident; 2627cbb6b6eSMark Johnston cs = accept(s, NULL, NULL); 2637cbb6b6eSMark Johnston ATF_REQUIRE_MSG(cs >= 0, 2647cbb6b6eSMark Johnston "accept() failed: %s", strerror(errno)); 2657cbb6b6eSMark Johnston 2667cbb6b6eSMark Johnston b = 'M'; 2677cbb6b6eSMark Johnston n = write(cs, &b, sizeof(b)); 2687cbb6b6eSMark Johnston ATF_REQUIRE_MSG(n >= 0, "write() failed: %s", strerror(errno)); 2697cbb6b6eSMark Johnston ATF_REQUIRE(n == 1); 2707cbb6b6eSMark Johnston 2717cbb6b6eSMark Johnston error = close(cs); 2727cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0 || errno == ECONNRESET, 2737cbb6b6eSMark Johnston "close() failed: %s", strerror(errno)); 2747cbb6b6eSMark Johnston } 2757cbb6b6eSMark Johnston } 2767cbb6b6eSMark Johnston 2777cbb6b6eSMark Johnston static void * 2787cbb6b6eSMark Johnston connector(void *arg) 2797cbb6b6eSMark Johnston { 2807cbb6b6eSMark Johnston for (struct concurrent_add_softc *sc = arg;;) { 2817cbb6b6eSMark Johnston ssize_t n; 2827cbb6b6eSMark Johnston int error, s; 2837cbb6b6eSMark Johnston uint8_t b; 2847cbb6b6eSMark Johnston 2857cbb6b6eSMark Johnston s = socket(sc->ss.ss_family, SOCK_STREAM, 0); 2867cbb6b6eSMark Johnston ATF_REQUIRE_MSG(s >= 0, "socket() failed: %s", strerror(errno)); 2877cbb6b6eSMark Johnston 2887cbb6b6eSMark Johnston error = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, 2897cbb6b6eSMark Johnston sizeof(int)); 2907cbb6b6eSMark Johnston 2917cbb6b6eSMark Johnston error = connect(s, (struct sockaddr *)&sc->ss, sc->ss.ss_len); 2927cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, "connect() failed: %s", 2937cbb6b6eSMark Johnston strerror(errno)); 2947cbb6b6eSMark Johnston 2957cbb6b6eSMark Johnston n = read(s, &b, sizeof(b)); 2967cbb6b6eSMark Johnston ATF_REQUIRE_MSG(n >= 0, "read() failed: %s", 2977cbb6b6eSMark Johnston strerror(errno)); 2987cbb6b6eSMark Johnston ATF_REQUIRE(n == 1); 2997cbb6b6eSMark Johnston ATF_REQUIRE(b == 'M'); 3007cbb6b6eSMark Johnston error = close(s); 3017cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, 3027cbb6b6eSMark Johnston "close() failed: %s", strerror(errno)); 3037cbb6b6eSMark Johnston } 3047cbb6b6eSMark Johnston } 3057cbb6b6eSMark Johnston 3067cbb6b6eSMark Johnston /* 3077cbb6b6eSMark Johnston * Run three threads. One accepts connections from listening sockets on a 3087cbb6b6eSMark Johnston * kqueue, while the other makes connections. The third thread slowly adds 3097cbb6b6eSMark Johnston * sockets to the LB group. This is meant to help flush out race conditions. 3107cbb6b6eSMark Johnston */ 3117cbb6b6eSMark Johnston ATF_TC_WITHOUT_HEAD(concurrent_add); 3127cbb6b6eSMark Johnston ATF_TC_BODY(concurrent_add, tc) 3137cbb6b6eSMark Johnston { 3147cbb6b6eSMark Johnston struct concurrent_add_softc sc; 3157cbb6b6eSMark Johnston struct sockaddr_in *sin; 3167cbb6b6eSMark Johnston pthread_t threads[4]; 3177cbb6b6eSMark Johnston int error; 3187cbb6b6eSMark Johnston 3197cbb6b6eSMark Johnston sc.kq = kqueue(); 3207cbb6b6eSMark Johnston ATF_REQUIRE_MSG(sc.kq >= 0, "kqueue() failed: %s", strerror(errno)); 3217cbb6b6eSMark Johnston 3227cbb6b6eSMark Johnston error = pthread_create(&threads[0], NULL, listener, &sc); 3237cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, "pthread_create() failed: %s", 3247cbb6b6eSMark Johnston strerror(error)); 3257cbb6b6eSMark Johnston 3267cbb6b6eSMark Johnston sin = (struct sockaddr_in *)&sc.ss; 3277cbb6b6eSMark Johnston memset(sin, 0, sizeof(*sin)); 3287cbb6b6eSMark Johnston sin->sin_len = sizeof(*sin); 3297cbb6b6eSMark Johnston sin->sin_family = AF_INET; 3307cbb6b6eSMark Johnston sin->sin_port = htons(0); 3317cbb6b6eSMark Johnston sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3327cbb6b6eSMark Johnston 3337cbb6b6eSMark Johnston for (size_t i = 0; i < nitems(sc.socks); i++) { 3347cbb6b6eSMark Johnston struct kevent kev; 3357cbb6b6eSMark Johnston int s; 3367cbb6b6eSMark Johnston 3377cbb6b6eSMark Johnston sc.socks[i] = s = socket(AF_INET, SOCK_STREAM, 0); 3387cbb6b6eSMark Johnston ATF_REQUIRE_MSG(s >= 0, "socket() failed: %s", strerror(errno)); 3397cbb6b6eSMark Johnston 3407cbb6b6eSMark Johnston error = setsockopt(s, SOL_SOCKET, SO_REUSEPORT_LB, (int[]){1}, 3417cbb6b6eSMark Johnston sizeof(int)); 3427cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, 3437cbb6b6eSMark Johnston "setsockopt(SO_REUSEPORT_LB) failed: %s", strerror(errno)); 3447cbb6b6eSMark Johnston 3457cbb6b6eSMark Johnston error = bind(s, (struct sockaddr *)sin, sizeof(*sin)); 3467cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", 3477cbb6b6eSMark Johnston strerror(errno)); 3487cbb6b6eSMark Johnston 3497cbb6b6eSMark Johnston error = listen(s, 5); 3507cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", 3517cbb6b6eSMark Johnston strerror(errno)); 3527cbb6b6eSMark Johnston 3537cbb6b6eSMark Johnston EV_SET(&kev, s, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); 3547cbb6b6eSMark Johnston error = kevent(sc.kq, &kev, 1, NULL, 0, NULL); 3557cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, "kevent() failed: %s", 3567cbb6b6eSMark Johnston strerror(errno)); 3577cbb6b6eSMark Johnston 3587cbb6b6eSMark Johnston if (i == 0) { 3597cbb6b6eSMark Johnston socklen_t slen = sizeof(sc.ss); 3607cbb6b6eSMark Johnston 3617cbb6b6eSMark Johnston error = getsockname(sc.socks[i], 3627cbb6b6eSMark Johnston (struct sockaddr *)&sc.ss, &slen); 3637cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, "getsockname() failed: %s", 3647cbb6b6eSMark Johnston strerror(errno)); 3657cbb6b6eSMark Johnston ATF_REQUIRE(sc.ss.ss_family == AF_INET); 3667cbb6b6eSMark Johnston 3677cbb6b6eSMark Johnston for (size_t j = 1; j < nitems(threads); j++) { 3687cbb6b6eSMark Johnston error = pthread_create(&threads[j], NULL, 3697cbb6b6eSMark Johnston connector, &sc); 3707cbb6b6eSMark Johnston ATF_REQUIRE_MSG(error == 0, 3717cbb6b6eSMark Johnston "pthread_create() failed: %s", 3727cbb6b6eSMark Johnston strerror(error)); 3737cbb6b6eSMark Johnston } 3747cbb6b6eSMark Johnston } 3757cbb6b6eSMark Johnston 3767cbb6b6eSMark Johnston usleep(20000); 3777cbb6b6eSMark Johnston } 3787cbb6b6eSMark Johnston } 3797cbb6b6eSMark Johnston 380*63efd7f5SMark Johnston /* 381*63efd7f5SMark Johnston * Try calling listen(2) twice on a socket with SO_REUSEPORT_LB set. 382*63efd7f5SMark Johnston */ 383*63efd7f5SMark Johnston ATF_TC_WITHOUT_HEAD(double_listen_ipv4); 384*63efd7f5SMark Johnston ATF_TC_BODY(double_listen_ipv4, tc) 385*63efd7f5SMark Johnston { 386*63efd7f5SMark Johnston struct sockaddr_in sin; 387*63efd7f5SMark Johnston int error, s; 388*63efd7f5SMark Johnston 389*63efd7f5SMark Johnston s = lb_listen_socket(PF_INET, 0); 390*63efd7f5SMark Johnston 391*63efd7f5SMark Johnston memset(&sin, 0, sizeof(sin)); 392*63efd7f5SMark Johnston sin.sin_len = sizeof(sin); 393*63efd7f5SMark Johnston sin.sin_family = AF_INET; 394*63efd7f5SMark Johnston sin.sin_port = htons(0); 395*63efd7f5SMark Johnston sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 396*63efd7f5SMark Johnston error = bind(s, (struct sockaddr *)&sin, sizeof(sin)); 397*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); 398*63efd7f5SMark Johnston 399*63efd7f5SMark Johnston error = listen(s, 1); 400*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno)); 401*63efd7f5SMark Johnston error = listen(s, 2); 402*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno)); 403*63efd7f5SMark Johnston 404*63efd7f5SMark Johnston error = close(s); 405*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "close() failed: %s", strerror(errno)); 406*63efd7f5SMark Johnston } 407*63efd7f5SMark Johnston 408*63efd7f5SMark Johnston /* 409*63efd7f5SMark Johnston * Try calling listen(2) twice on a socket with SO_REUSEPORT_LB set. 410*63efd7f5SMark Johnston */ 411*63efd7f5SMark Johnston ATF_TC_WITHOUT_HEAD(double_listen_ipv6); 412*63efd7f5SMark Johnston ATF_TC_BODY(double_listen_ipv6, tc) 413*63efd7f5SMark Johnston { 414*63efd7f5SMark Johnston struct sockaddr_in6 sin6; 415*63efd7f5SMark Johnston int error, s; 416*63efd7f5SMark Johnston 417*63efd7f5SMark Johnston s = lb_listen_socket(PF_INET6, 0); 418*63efd7f5SMark Johnston 419*63efd7f5SMark Johnston memset(&sin6, 0, sizeof(sin6)); 420*63efd7f5SMark Johnston sin6.sin6_len = sizeof(sin6); 421*63efd7f5SMark Johnston sin6.sin6_family = AF_INET6; 422*63efd7f5SMark Johnston sin6.sin6_port = htons(0); 423*63efd7f5SMark Johnston sin6.sin6_addr = in6addr_loopback; 424*63efd7f5SMark Johnston error = bind(s, (struct sockaddr *)&sin6, sizeof(sin6)); 425*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "bind() failed: %s", strerror(errno)); 426*63efd7f5SMark Johnston 427*63efd7f5SMark Johnston error = listen(s, 1); 428*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno)); 429*63efd7f5SMark Johnston error = listen(s, 2); 430*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "listen() failed: %s", strerror(errno)); 431*63efd7f5SMark Johnston 432*63efd7f5SMark Johnston error = close(s); 433*63efd7f5SMark Johnston ATF_REQUIRE_MSG(error == 0, "close() failed: %s", strerror(errno)); 434*63efd7f5SMark Johnston } 435*63efd7f5SMark Johnston 436634bb9e4SMark Johnston ATF_TP_ADD_TCS(tp) 437634bb9e4SMark Johnston { 438634bb9e4SMark Johnston ATF_TP_ADD_TC(tp, basic_ipv4); 439634bb9e4SMark Johnston ATF_TP_ADD_TC(tp, basic_ipv6); 4407cbb6b6eSMark Johnston ATF_TP_ADD_TC(tp, concurrent_add); 441*63efd7f5SMark Johnston ATF_TP_ADD_TC(tp, double_listen_ipv4); 442*63efd7f5SMark Johnston ATF_TP_ADD_TC(tp, double_listen_ipv6); 443634bb9e4SMark Johnston 444634bb9e4SMark Johnston return (atf_no_error()); 445634bb9e4SMark Johnston } 446