// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ /* Test listening on the same port 443 with multiple VIPS. * Each VIP:443 will have multiple sk listening on by using * SO_REUSEPORT. */ #include #include #include #include #include #include #include #define IP6_LADDR_START "2401:dead::1" #define IP6_LPORT 443 #define NSEC_PER_SEC 1000000000L #define NSEC_PER_USEC 1000L static unsigned int nr_socks_per_vip; static unsigned int nr_vips; static int *bind_reuseport_sock6(void) { int *lfds, *cur_fd, err, optvalue = 1; struct sockaddr_in6 sa6 = {}; unsigned int i, j; sa6.sin6_family = AF_INET6; sa6.sin6_port = htons(IP6_LPORT); err = inet_pton(AF_INET6, IP6_LADDR_START, &sa6.sin6_addr); if (err != 1) error(1, err, "inet_pton(%s)", IP6_LADDR_START); lfds = malloc(nr_vips * nr_socks_per_vip * sizeof(lfds[0])); if (!lfds) error(1, errno, "cannot alloc array of lfds"); cur_fd = lfds; for (i = 0; i < nr_vips; i++) { for (j = 0; j < nr_socks_per_vip; j++) { *cur_fd = socket(AF_INET6, SOCK_STREAM, 0); if (*cur_fd == -1) error(1, errno, "lfds[%u,%u] = socket(AF_INET6)", i, j); err = setsockopt(*cur_fd, SOL_SOCKET, SO_REUSEPORT, &optvalue, sizeof(optvalue)); if (err) error(1, errno, "setsockopt(lfds[%u,%u], SO_REUSEPORT)", i, j); err = bind(*cur_fd, (struct sockaddr *)&sa6, sizeof(sa6)); if (err) error(1, errno, "bind(lfds[%u,%u])", i, j); cur_fd++; } sa6.sin6_addr.s6_addr32[3]++; } return lfds; } int main(int argc, const char *argv[]) { struct timespec start_ts, end_ts; unsigned long start_ns, end_ns; unsigned int nr_lsocks; int *lfds, i, err; if (argc != 3 || atoi(argv[1]) <= 0 || atoi(argv[2]) <= 0) error(1, 0, "Usage: %s \n", argv[0]); nr_vips = atoi(argv[1]); nr_socks_per_vip = atoi(argv[2]); nr_lsocks = nr_vips * nr_socks_per_vip; lfds = bind_reuseport_sock6(); clock_gettime(CLOCK_MONOTONIC, &start_ts); for (i = 0; i < nr_lsocks; i++) { err = listen(lfds[i], 0); if (err) error(1, errno, "listen(lfds[%d])", i); } clock_gettime(CLOCK_MONOTONIC, &end_ts); start_ns = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec; end_ns = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec; printf("listen %d socks took %lu.%lu\n", nr_lsocks, (end_ns - start_ns) / NSEC_PER_SEC, (end_ns - start_ns) / NSEC_PER_USEC); for (i = 0; i < nr_lsocks; i++) close(lfds[i]); free(lfds); return 0; }