-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests: Add test for timing a bind request to a port with a popula…
…ted bhash entry This test populates the bhash table for a given port with MAX_THREADS * MAX_CONNECTIONS sockets, and then times how long a bind request on the port takes. When populating the bhash table, we create the sockets and then bind the sockets to the same address and port (SO_REUSEADDR and SO_REUSEPORT are set). When timing how long a bind on the port takes, we bind on a different address without SO_REUSEPORT set. We do not set SO_REUSEPORT because we are interested in the case where the bind request does not go through the tb->fastreuseport path, which is fragile (eg tb->fastreuseport path does not work if binding with a different uid). To run the test locally, I did: * ulimit -n 65535000 * ip addr add 2001:0db8:0:f101::1 dev eth0 * ./bind_bhash_test 443 Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
- Loading branch information
Joanne Koong
authored and
Jakub Kicinski
committed
May 21, 2022
1 parent
d5a42de
commit 538aaf9
Showing
3 changed files
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,3 +36,4 @@ gro | |
ioam6_parser | ||
toeplitz | ||
cmsg_sender | ||
bind_bhash_test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* | ||
* This times how long it takes to bind to a port when the port already | ||
* has multiple sockets in its bhash table. | ||
* | ||
* In the setup(), we populate the port's bhash table with | ||
* MAX_THREADS * MAX_CONNECTIONS number of entries. | ||
*/ | ||
|
||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <netdb.h> | ||
#include <pthread.h> | ||
|
||
#define MAX_THREADS 600 | ||
#define MAX_CONNECTIONS 40 | ||
|
||
static const char *bind_addr = "::1"; | ||
static const char *port; | ||
|
||
static int fd_array[MAX_THREADS][MAX_CONNECTIONS]; | ||
|
||
static int bind_socket(int opt, const char *addr) | ||
{ | ||
struct addrinfo *res, hint = {}; | ||
int sock_fd, reuse = 1, err; | ||
|
||
sock_fd = socket(AF_INET6, SOCK_STREAM, 0); | ||
if (sock_fd < 0) { | ||
perror("socket fd err"); | ||
return -1; | ||
} | ||
|
||
hint.ai_family = AF_INET6; | ||
hint.ai_socktype = SOCK_STREAM; | ||
|
||
err = getaddrinfo(addr, port, &hint, &res); | ||
if (err) { | ||
perror("getaddrinfo failed"); | ||
return -1; | ||
} | ||
|
||
if (opt) { | ||
err = setsockopt(sock_fd, SOL_SOCKET, opt, &reuse, sizeof(reuse)); | ||
if (err) { | ||
perror("setsockopt failed"); | ||
return -1; | ||
} | ||
} | ||
|
||
err = bind(sock_fd, res->ai_addr, res->ai_addrlen); | ||
if (err) { | ||
perror("failed to bind to port"); | ||
return -1; | ||
} | ||
|
||
return sock_fd; | ||
} | ||
|
||
static void *setup(void *arg) | ||
{ | ||
int sock_fd, i; | ||
int *array = (int *)arg; | ||
|
||
for (i = 0; i < MAX_CONNECTIONS; i++) { | ||
sock_fd = bind_socket(SO_REUSEADDR | SO_REUSEPORT, bind_addr); | ||
if (sock_fd < 0) | ||
return NULL; | ||
array[i] = sock_fd; | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
int main(int argc, const char *argv[]) | ||
{ | ||
int listener_fd, sock_fd, i, j; | ||
pthread_t tid[MAX_THREADS]; | ||
clock_t begin, end; | ||
|
||
if (argc != 2) { | ||
printf("Usage: listener <port>\n"); | ||
return -1; | ||
} | ||
|
||
port = argv[1]; | ||
|
||
listener_fd = bind_socket(SO_REUSEADDR | SO_REUSEPORT, bind_addr); | ||
if (listen(listener_fd, 100) < 0) { | ||
perror("listen failed"); | ||
return -1; | ||
} | ||
|
||
/* Set up threads to populate the bhash table entry for the port */ | ||
for (i = 0; i < MAX_THREADS; i++) | ||
pthread_create(&tid[i], NULL, setup, fd_array[i]); | ||
|
||
for (i = 0; i < MAX_THREADS; i++) | ||
pthread_join(tid[i], NULL); | ||
|
||
begin = clock(); | ||
|
||
/* Bind to the same port on a different address */ | ||
sock_fd = bind_socket(0, "2001:0db8:0:f101::1"); | ||
|
||
end = clock(); | ||
|
||
printf("time spent = %f\n", (double)(end - begin) / CLOCKS_PER_SEC); | ||
|
||
/* clean up */ | ||
close(sock_fd); | ||
close(listener_fd); | ||
for (i = 0; i < MAX_THREADS; i++) { | ||
for (j = 0; i < MAX_THREADS; i++) | ||
close(fd_array[i][j]); | ||
} | ||
|
||
return 0; | ||
} |