Skip to content

Commit 44c7926

Browse files
q2venkernel-patches-bot
authored andcommitted
bpf: Test BPF_SK_REUSEPORT_SELECT_OR_MIGRATE.
This patch adds a test for BPF_SK_REUSEPORT_SELECT_OR_MIGRATE. Reviewed-by: Benjamin Herrenschmidt <[email protected]> Signed-off-by: Kuniyuki Iwashima <[email protected]>
1 parent 7fcc5f6 commit 44c7926

File tree

2 files changed

+226
-0
lines changed

2 files changed

+226
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Check if we can migrate child sockets.
4+
*
5+
* 1. call listen() for 5 server sockets.
6+
* 2. update a map to migrate all child socket
7+
* to the last server socket (migrate_map[cookie] = 4)
8+
* 3. call connect() for 25 client sockets.
9+
* 4. call close() for first 4 server sockets.
10+
* 5. call accept() for the last server socket.
11+
*
12+
* Author: Kuniyuki Iwashima <[email protected]>
13+
*/
14+
15+
#include <bpf/bpf.h>
16+
#include <bpf/libbpf.h>
17+
18+
#include "test_progs.h"
19+
#include "test_select_reuseport_migrate.skel.h"
20+
21+
#define ADDRESS "127.0.0.1"
22+
#define PORT 80
23+
#define NUM_SERVERS 5
24+
#define NUM_CLIENTS (NUM_SERVERS * 5)
25+
26+
27+
static int test_listen(struct test_select_reuseport_migrate *skel, int server_fds[])
28+
{
29+
int i, err, optval = 1, migrated_to = NUM_SERVERS - 1;
30+
int prog_fd, reuseport_map_fd, migrate_map_fd;
31+
struct sockaddr_in addr;
32+
socklen_t addr_len;
33+
__u64 value;
34+
35+
prog_fd = bpf_program__fd(skel->progs.prog_select_reuseport_migrate);
36+
reuseport_map_fd = bpf_map__fd(skel->maps.reuseport_map);
37+
migrate_map_fd = bpf_map__fd(skel->maps.migrate_map);
38+
39+
addr_len = sizeof(addr);
40+
addr.sin_family = AF_INET;
41+
addr.sin_port = htons(PORT);
42+
inet_pton(AF_INET, ADDRESS, &addr.sin_addr.s_addr);
43+
44+
for (i = 0; i < NUM_SERVERS; i++) {
45+
server_fds[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
46+
if (CHECK_FAIL(server_fds[i] == -1))
47+
return -1;
48+
49+
err = setsockopt(server_fds[i], SOL_SOCKET, SO_REUSEPORT,
50+
&optval, sizeof(optval));
51+
if (CHECK_FAIL(err == -1))
52+
return -1;
53+
54+
if (i == 0) {
55+
err = setsockopt(server_fds[i], SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF,
56+
&prog_fd, sizeof(prog_fd));
57+
if (CHECK_FAIL(err == -1))
58+
return -1;
59+
}
60+
61+
err = bind(server_fds[i], (struct sockaddr *)&addr, addr_len);
62+
if (CHECK_FAIL(err == -1))
63+
return -1;
64+
65+
err = listen(server_fds[i], 32);
66+
if (CHECK_FAIL(err == -1))
67+
return -1;
68+
69+
err = bpf_map_update_elem(reuseport_map_fd, &i, &server_fds[i], BPF_NOEXIST);
70+
if (CHECK_FAIL(err == -1))
71+
return -1;
72+
73+
err = bpf_map_lookup_elem(reuseport_map_fd, &i, &value);
74+
if (CHECK_FAIL(err == -1))
75+
return -1;
76+
77+
err = bpf_map_update_elem(migrate_map_fd, &value, &migrated_to, BPF_NOEXIST);
78+
if (CHECK_FAIL(err == -1))
79+
return -1;
80+
}
81+
82+
return 0;
83+
}
84+
85+
static int test_connect(int client_fds[])
86+
{
87+
struct sockaddr_in addr;
88+
socklen_t addr_len;
89+
int i, err;
90+
91+
addr_len = sizeof(addr);
92+
addr.sin_family = AF_INET;
93+
addr.sin_port = htons(PORT);
94+
inet_pton(AF_INET, ADDRESS, &addr.sin_addr.s_addr);
95+
96+
for (i = 0; i < NUM_CLIENTS; i++) {
97+
client_fds[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
98+
if (CHECK_FAIL(client_fds[i] == -1))
99+
return -1;
100+
101+
err = connect(client_fds[i], (struct sockaddr *)&addr, addr_len);
102+
if (CHECK_FAIL(err == -1))
103+
return -1;
104+
}
105+
106+
return 0;
107+
}
108+
109+
static void test_close(int server_fds[], int num)
110+
{
111+
int i;
112+
113+
for (i = 0; i < num; i++)
114+
if (server_fds[i] > 0)
115+
close(server_fds[i]);
116+
}
117+
118+
static int test_accept(int server_fd)
119+
{
120+
struct sockaddr_in addr;
121+
socklen_t addr_len;
122+
int cnt, client_fd;
123+
124+
fcntl(server_fd, F_SETFL, O_NONBLOCK);
125+
addr_len = sizeof(addr);
126+
127+
for (cnt = 0; cnt < NUM_CLIENTS; cnt++) {
128+
client_fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
129+
if (CHECK_FAIL(client_fd == -1))
130+
return -1;
131+
}
132+
133+
return cnt;
134+
}
135+
136+
137+
void test_select_reuseport_migrate(void)
138+
{
139+
struct test_select_reuseport_migrate *skel;
140+
int server_fds[NUM_SERVERS] = {0};
141+
int client_fds[NUM_CLIENTS] = {0};
142+
__u32 duration = 0;
143+
int err;
144+
145+
skel = test_select_reuseport_migrate__open_and_load();
146+
if (CHECK_FAIL(!skel))
147+
goto destroy;
148+
149+
err = test_listen(skel, server_fds);
150+
if (err)
151+
goto close_server;
152+
153+
err = test_connect(client_fds);
154+
if (err)
155+
goto close_client;
156+
157+
test_close(server_fds, NUM_SERVERS - 1);
158+
159+
err = test_accept(server_fds[NUM_SERVERS - 1]);
160+
CHECK(err != NUM_CLIENTS,
161+
"accept",
162+
"expected (%d) != actual (%d)\n",
163+
NUM_CLIENTS, err);
164+
165+
close_client:
166+
test_close(client_fds, NUM_CLIENTS);
167+
168+
close_server:
169+
test_close(server_fds, NUM_SERVERS);
170+
171+
destroy:
172+
test_select_reuseport_migrate__destroy(skel);
173+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Check if we can migrate child sockets.
4+
*
5+
* 1. If reuse_md->migration is 0 (SYN packet),
6+
* return SK_PASS without selecting a listener.
7+
* 2. If reuse_md->migration is not 0 (socket migration),
8+
* select a listener (reuseport_map[migrate_map[cookie]])
9+
*
10+
* Author: Kuniyuki Iwashima <[email protected]>
11+
*/
12+
13+
#include <linux/bpf.h>
14+
#include <bpf/bpf_helpers.h>
15+
16+
#define NULL ((void *)0)
17+
18+
struct bpf_map_def SEC("maps") reuseport_map = {
19+
.type = BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
20+
.key_size = sizeof(int),
21+
.value_size = sizeof(__u64),
22+
.max_entries = 256,
23+
};
24+
25+
struct bpf_map_def SEC("maps") migrate_map = {
26+
.type = BPF_MAP_TYPE_HASH,
27+
.key_size = sizeof(__u64),
28+
.value_size = sizeof(int),
29+
.max_entries = 256,
30+
};
31+
32+
SEC("sk_reuseport/migrate")
33+
int prog_select_reuseport_migrate(struct sk_reuseport_md *reuse_md)
34+
{
35+
int *key, flags = 0;
36+
__u64 cookie;
37+
38+
if (!reuse_md->migration)
39+
return SK_PASS;
40+
41+
cookie = bpf_get_socket_cookie(reuse_md->sk);
42+
43+
key = bpf_map_lookup_elem(&migrate_map, &cookie);
44+
if (key == NULL)
45+
return SK_DROP;
46+
47+
bpf_sk_select_reuseport(reuse_md, &reuseport_map, key, flags);
48+
49+
return SK_PASS;
50+
}
51+
52+
int _version SEC("version") = 1;
53+
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)