Skip to content

Commit 76a2ea3

Browse files
nrybowskikernel-patches-bot
authored andcommitted
This patch adds a base for MPTCP specific tests.
It is currently limited to the is_mptcp field in case of plain TCP connection because for the moment there is no easy way to get the subflow sk from a msk in userspace. This implies that we cannot lookup the sk_storage attached to the subflow sk in the sockops program. Acked-by: Matthieu Baerts <[email protected]> Signed-off-by: Nicolas Rybowski <[email protected]> --- Notes: v1 -> v2: - new patch: mandatory selftests (Alexei) tools/testing/selftests/bpf/config | 1 + tools/testing/selftests/bpf/network_helpers.c | 37 +++++- tools/testing/selftests/bpf/network_helpers.h | 3 + .../testing/selftests/bpf/prog_tests/mptcp.c | 119 ++++++++++++++++++ tools/testing/selftests/bpf/progs/mptcp.c | 48 +++++++ 5 files changed, 203 insertions(+), 5 deletions(-) create mode 100644 tools/testing/selftests/bpf/prog_tests/mptcp.c create mode 100644 tools/testing/selftests/bpf/progs/mptcp.c
1 parent eb90504 commit 76a2ea3

File tree

5 files changed

+203
-5
lines changed

5 files changed

+203
-5
lines changed

tools/testing/selftests/bpf/config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ CONFIG_BPF_JIT=y
3939
CONFIG_BPF_LSM=y
4040
CONFIG_SECURITY=y
4141
CONFIG_LIRC=y
42+
CONFIG_MPTCP=y

tools/testing/selftests/bpf/network_helpers.c

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
#include "bpf_util.h"
1515
#include "network_helpers.h"
1616

17+
#ifndef IPPROTO_MPTCP
18+
#define IPPROTO_MPTCP 262
19+
#endif
20+
1721
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
1822
#define log_err(MSG, ...) ({ \
1923
int __save = errno; \
@@ -66,8 +70,8 @@ static int settimeo(int fd, int timeout_ms)
6670

6771
#define save_errno_close(fd) ({ int __save = errno; close(fd); errno = __save; })
6872

69-
int start_server(int family, int type, const char *addr_str, __u16 port,
70-
int timeout_ms)
73+
static int start_server_proto(int family, int type, int protocol,
74+
const char *addr_str, __u16 port, int timeout_ms)
7175
{
7276
struct sockaddr_storage addr = {};
7377
socklen_t len;
@@ -76,7 +80,7 @@ int start_server(int family, int type, const char *addr_str, __u16 port,
7680
if (make_sockaddr(family, addr_str, port, &addr, &len))
7781
return -1;
7882

79-
fd = socket(family, type, 0);
83+
fd = socket(family, type, protocol);
8084
if (fd < 0) {
8185
log_err("Failed to create server socket");
8286
return -1;
@@ -104,6 +108,19 @@ int start_server(int family, int type, const char *addr_str, __u16 port,
104108
return -1;
105109
}
106110

111+
int start_server(int family, int type, const char *addr_str, __u16 port,
112+
int timeout_ms)
113+
{
114+
return start_server_proto(family, type, 0, addr_str, port, timeout_ms);
115+
}
116+
117+
int start_mptcp_server(int family, const char *addr_str, __u16 port,
118+
int timeout_ms)
119+
{
120+
return start_server_proto(family, SOCK_STREAM, IPPROTO_MPTCP, addr_str,
121+
port, timeout_ms);
122+
}
123+
107124
int fastopen_connect(int server_fd, const char *data, unsigned int data_len,
108125
int timeout_ms)
109126
{
@@ -153,7 +170,7 @@ static int connect_fd_to_addr(int fd,
153170
return 0;
154171
}
155172

156-
int connect_to_fd(int server_fd, int timeout_ms)
173+
static int connect_to_fd_proto(int server_fd, int protocol, int timeout_ms)
157174
{
158175
struct sockaddr_storage addr;
159176
struct sockaddr_in *addr_in;
@@ -173,7 +190,7 @@ int connect_to_fd(int server_fd, int timeout_ms)
173190
}
174191

175192
addr_in = (struct sockaddr_in *)&addr;
176-
fd = socket(addr_in->sin_family, type, 0);
193+
fd = socket(addr_in->sin_family, type, protocol);
177194
if (fd < 0) {
178195
log_err("Failed to create client socket");
179196
return -1;
@@ -192,6 +209,16 @@ int connect_to_fd(int server_fd, int timeout_ms)
192209
return -1;
193210
}
194211

212+
int connect_to_fd(int server_fd, int timeout_ms)
213+
{
214+
return connect_to_fd_proto(server_fd, 0, timeout_ms);
215+
}
216+
217+
int connect_to_mptcp_fd(int server_fd, int timeout_ms)
218+
{
219+
return connect_to_fd_proto(server_fd, IPPROTO_MPTCP, timeout_ms);
220+
}
221+
195222
int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms)
196223
{
197224
struct sockaddr_storage addr;

tools/testing/selftests/bpf/network_helpers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ extern struct ipv6_packet pkt_v6;
3535

3636
int start_server(int family, int type, const char *addr, __u16 port,
3737
int timeout_ms);
38+
int start_mptcp_server(int family, const char *addr, __u16 port,
39+
int timeout_ms);
3840
int connect_to_fd(int server_fd, int timeout_ms);
41+
int connect_to_mptcp_fd(int server_fd, int timeout_ms);
3942
int connect_fd_to_fd(int client_fd, int server_fd, int timeout_ms);
4043
int fastopen_connect(int server_fd, const char *data, unsigned int data_len,
4144
int timeout_ms);
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <test_progs.h>
3+
#include "cgroup_helpers.h"
4+
#include "network_helpers.h"
5+
6+
struct mptcp_storage {
7+
__u32 invoked;
8+
__u32 is_mptcp;
9+
};
10+
11+
static int verify_sk(int map_fd, int client_fd, const char *msg, __u32 is_mptcp)
12+
{
13+
int err = 0, cfd = client_fd;
14+
struct mptcp_storage val;
15+
16+
/* Currently there is no easy way to get back the subflow sk from the MPTCP
17+
* sk, thus we cannot access here the sk_storage associated to the subflow
18+
* sk. Also, there is no sk_storage associated with the MPTCP sk since it
19+
* does not trigger sockops events.
20+
* We silently pass this situation at the moment.
21+
*/
22+
if (is_mptcp == 1)
23+
return 0;
24+
25+
if (CHECK_FAIL(bpf_map_lookup_elem(map_fd, &cfd, &val) < 0)) {
26+
perror("Failed to read socket storage");
27+
return -1;
28+
}
29+
30+
if (val.invoked != 1) {
31+
log_err("%s: unexpected invoked count %d != %d",
32+
msg, val.invoked, 1);
33+
err++;
34+
}
35+
36+
if (val.is_mptcp != is_mptcp) {
37+
log_err("%s: unexpected bpf_tcp_sock.is_mptcp %d != %d",
38+
msg, val.is_mptcp, is_mptcp);
39+
err++;
40+
}
41+
42+
return err;
43+
}
44+
45+
static int run_test(int cgroup_fd, int server_fd, bool is_mptcp)
46+
{
47+
int client_fd, prog_fd, map_fd, err;
48+
struct bpf_object *obj;
49+
struct bpf_map *map;
50+
51+
struct bpf_prog_load_attr attr = {
52+
.prog_type = BPF_PROG_TYPE_SOCK_OPS,
53+
.file = "./mptcp.o",
54+
.expected_attach_type = BPF_CGROUP_SOCK_OPS,
55+
};
56+
57+
err = bpf_prog_load_xattr(&attr, &obj, &prog_fd);
58+
if (err) {
59+
log_err("Failed to load BPF object");
60+
return -1;
61+
}
62+
63+
map = bpf_map__next(NULL, obj);
64+
map_fd = bpf_map__fd(map);
65+
66+
err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
67+
if (err) {
68+
log_err("Failed to attach BPF program");
69+
goto close_bpf_object;
70+
}
71+
72+
client_fd = is_mptcp ? connect_to_mptcp_fd(server_fd, 0) :
73+
connect_to_fd(server_fd, 0);
74+
if (client_fd < 0) {
75+
err = -1;
76+
goto close_client_fd;
77+
}
78+
79+
err += is_mptcp ? verify_sk(map_fd, client_fd, "MPTCP subflow socket", 1) :
80+
verify_sk(map_fd, client_fd, "plain TCP socket", 0);
81+
82+
close_client_fd:
83+
close(client_fd);
84+
85+
close_bpf_object:
86+
bpf_object__close(obj);
87+
return err;
88+
}
89+
90+
void test_mptcp(void)
91+
{
92+
int server_fd, cgroup_fd;
93+
94+
cgroup_fd = test__join_cgroup("/mptcp");
95+
if (CHECK_FAIL(cgroup_fd < 0))
96+
return;
97+
98+
/* without MPTCP */
99+
server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);
100+
if (CHECK_FAIL(server_fd < 0))
101+
goto with_mptcp;
102+
103+
CHECK_FAIL(run_test(cgroup_fd, server_fd, false));
104+
105+
close(server_fd);
106+
107+
with_mptcp:
108+
/* with MPTCP */
109+
server_fd = start_mptcp_server(AF_INET, NULL, 0, 0);
110+
if (CHECK_FAIL(server_fd < 0))
111+
goto close_cgroup_fd;
112+
113+
CHECK_FAIL(run_test(cgroup_fd, server_fd, true));
114+
115+
close(server_fd);
116+
117+
close_cgroup_fd:
118+
close(cgroup_fd);
119+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_helpers.h>
4+
5+
char _license[] SEC("license") = "GPL";
6+
__u32 _version SEC("version") = 1;
7+
8+
struct mptcp_storage {
9+
__u32 invoked;
10+
__u32 is_mptcp;
11+
};
12+
13+
struct {
14+
__uint(type, BPF_MAP_TYPE_SK_STORAGE);
15+
__uint(map_flags, BPF_F_NO_PREALLOC);
16+
__type(key, int);
17+
__type(value, struct mptcp_storage);
18+
} socket_storage_map SEC(".maps");
19+
20+
SEC("sockops")
21+
int _sockops(struct bpf_sock_ops *ctx)
22+
{
23+
struct mptcp_storage *storage;
24+
struct bpf_tcp_sock *tcp_sk;
25+
int op = (int)ctx->op;
26+
struct bpf_sock *sk;
27+
28+
sk = ctx->sk;
29+
if (!sk)
30+
return 1;
31+
32+
storage = bpf_sk_storage_get(&socket_storage_map, sk, 0,
33+
BPF_SK_STORAGE_GET_F_CREATE);
34+
if (!storage)
35+
return 1;
36+
37+
if (op != BPF_SOCK_OPS_TCP_CONNECT_CB)
38+
return 1;
39+
40+
tcp_sk = bpf_tcp_sock(sk);
41+
if (!tcp_sk)
42+
return 1;
43+
44+
storage->invoked++;
45+
storage->is_mptcp = tcp_sk->is_mptcp;
46+
47+
return 1;
48+
}

0 commit comments

Comments
 (0)