Skip to content

Commit 3e8ae50

Browse files
Geliang Tangintel-lab-lkp
authored andcommitted
selftests: mptcp: add splice test
This patch adds a mptcp socket splice test named mptcp_splice. And a new test in mptcp_join.sh. Signed-off-by: Geliang Tang <[email protected]>
1 parent 6675f65 commit 3e8ae50

File tree

3 files changed

+222
-1
lines changed

3 files changed

+222
-1
lines changed

tools/testing/selftests/net/mptcp/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ CFLAGS += -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INC
77
TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \
88
simult_flows.sh mptcp_sockopt.sh userspace_pm.sh
99

10-
TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq mptcp_diag
10+
TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq mptcp_diag mptcp_splice
1111

1212
TEST_FILES := mptcp_lib.sh settings
1313

tools/testing/selftests/net/mptcp/mptcp_join.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3946,6 +3946,25 @@ endpoint_tests()
39463946
fi
39473947
}
39483948

3949+
splice_tests()
3950+
{
3951+
if reset "splice test"; then
3952+
mptcp_lib_pm_nl_set_limits $ns1 8 8
3953+
mptcp_lib_pm_nl_set_limits $ns2 8 8
3954+
mptcp_lib_pm_nl_add_endpoint $ns2 10.0.2.2 dev ns2eth2 flags subflow
3955+
mptcp_lib_pm_nl_add_endpoint $ns2 10.0.3.2 dev ns2eth3 flags subflow
3956+
mptcp_lib_pm_nl_add_endpoint $ns2 10.0.4.2 dev ns2eth4 flags subflow
3957+
3958+
ip netns exec $ns1 ./mptcp_splice -l -o "$sout" -p 8080 &
3959+
local tests_pid=$!
3960+
sleep 1
3961+
ip netns exec $ns2 ./mptcp_splice -i "$cin" -a 10.0.1.1 -p 8080
3962+
mptcp_lib_kill_wait $tests_pid
3963+
check_transfer "$cin" "$sout" "file received by server" 1052
3964+
chk_join_nr 3 3 3
3965+
fi
3966+
}
3967+
39493968
# [$1: error message]
39503969
usage()
39513970
{
@@ -3994,6 +4013,7 @@ all_tests_sorted=(
39944013
F@fail_tests
39954014
u@userspace_tests
39964015
I@endpoint_tests
4016+
L@splice_tests
39974017
)
39984018

39994019
all_tests_args=""
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2025, Kylin Software */
3+
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <stdbool.h>
7+
#include <unistd.h>
8+
#include <fcntl.h>
9+
#include <sys/socket.h>
10+
#include <netinet/in.h>
11+
#include <arpa/inet.h>
12+
#include <string.h>
13+
#include <errno.h>
14+
15+
#ifndef IPPROTO_MPTCP
16+
#define IPPROTO_MPTCP 262
17+
#endif
18+
19+
#define BUFFER_SIZE 65536
20+
21+
char *server_ip;
22+
int port;
23+
24+
static int server(char *output)
25+
{
26+
int server_fd, client_fd, out_fd;
27+
struct sockaddr_in address;
28+
int addrlen = sizeof(address);
29+
int pipefd[2];
30+
ssize_t bytes;
31+
int opt = 1;
32+
33+
server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP);
34+
if (server_fd < 0) {
35+
perror("socket failed");
36+
exit(EXIT_FAILURE);
37+
}
38+
39+
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
40+
&opt, sizeof(opt))) {
41+
perror("setsockopt");
42+
exit(EXIT_FAILURE);
43+
}
44+
45+
address.sin_family = AF_INET;
46+
address.sin_addr.s_addr = INADDR_ANY;
47+
address.sin_port = htons(port);
48+
49+
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
50+
perror("bind failed");
51+
exit(EXIT_FAILURE);
52+
}
53+
54+
if (listen(server_fd, 3) < 0) {
55+
perror("listen");
56+
exit(EXIT_FAILURE);
57+
}
58+
59+
printf("Server listening on port %d...\n", port);
60+
61+
client_fd = accept(server_fd, (struct sockaddr *)&address,
62+
(socklen_t *)&addrlen);
63+
if (client_fd < 0) {
64+
perror("accept");
65+
exit(EXIT_FAILURE);
66+
}
67+
68+
printf("Client connected. Receiving file...\n");
69+
70+
if (pipe(pipefd)) {
71+
perror("pipe");
72+
exit(EXIT_FAILURE);
73+
}
74+
75+
out_fd = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644);
76+
if (out_fd < 0) {
77+
perror("open");
78+
exit(EXIT_FAILURE);
79+
}
80+
81+
while ((bytes = splice(client_fd, NULL, pipefd[1], NULL, BUFFER_SIZE,
82+
SPLICE_F_MOVE | SPLICE_F_MORE)) > 0) {
83+
splice(pipefd[0], NULL, out_fd, NULL, bytes, SPLICE_F_MOVE | SPLICE_F_MORE);
84+
}
85+
86+
if (bytes == -1)
87+
perror("splice");
88+
89+
printf("File transfer completed. Received %ld bytes.\n",
90+
lseek(out_fd, 0, SEEK_CUR));
91+
92+
close(client_fd);
93+
close(out_fd);
94+
close(server_fd);
95+
96+
return 0;
97+
}
98+
99+
static int client(char *input)
100+
{
101+
struct sockaddr_in serv_addr;
102+
int sock_fd, in_fd;
103+
int pipefd[2];
104+
ssize_t bytes;
105+
106+
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP);
107+
if (sock_fd < 0) {
108+
perror("Socket creation error");
109+
exit(EXIT_FAILURE);
110+
}
111+
112+
serv_addr.sin_family = AF_INET;
113+
serv_addr.sin_port = htons(port);
114+
115+
if (inet_pton(AF_INET, server_ip, &serv_addr.sin_addr) <= 0) {
116+
perror("Invalid address/ Address not supported");
117+
exit(EXIT_FAILURE);
118+
}
119+
120+
if (connect(sock_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
121+
perror("Connection Failed");
122+
exit(EXIT_FAILURE);
123+
}
124+
125+
printf("Connected to server. Sending file...\n");
126+
127+
if (pipe(pipefd)) {
128+
perror("pipe");
129+
exit(EXIT_FAILURE);
130+
}
131+
132+
in_fd = open(input, O_RDONLY);
133+
if (in_fd == -1) {
134+
perror("open");
135+
exit(EXIT_FAILURE);
136+
}
137+
138+
while ((bytes = splice(in_fd, NULL, pipefd[1], NULL, BUFFER_SIZE,
139+
SPLICE_F_MOVE | SPLICE_F_MORE)) > 0) {
140+
splice(pipefd[0], NULL, sock_fd, NULL, bytes, SPLICE_F_MOVE | SPLICE_F_MORE);
141+
}
142+
143+
if (bytes == -1)
144+
perror("splice");
145+
146+
printf("File transfer completed. Sent %ld bytes.\n",
147+
lseek(in_fd, 0, SEEK_CUR));
148+
149+
shutdown(sock_fd, SHUT_WR);
150+
close(in_fd);
151+
close(sock_fd);
152+
153+
return 0;
154+
}
155+
156+
static void die_usage(void)
157+
{
158+
fprintf(stderr, "Usage: mptcp_splice -l -p <port> -o <output_file>\n");
159+
fprintf(stderr, " mptcp_splice -a <addr> -p <port> -i <input_file>\n");
160+
exit(EXIT_FAILURE);
161+
}
162+
163+
int main(int argc, char *argv[])
164+
{
165+
char *input = "", *output = "";
166+
bool listen_mode = false;
167+
int c;
168+
169+
if (argc < 2)
170+
die_usage();
171+
172+
while ((c = getopt(argc, argv, "hli:o:a:p:")) != -1) {
173+
switch (c) {
174+
case 'h':
175+
die_usage();
176+
break;
177+
case 'l':
178+
listen_mode = true;
179+
break;
180+
case 'i':
181+
input = optarg;
182+
break;
183+
case 'o':
184+
output = optarg;
185+
break;
186+
case 'a':
187+
server_ip = optarg;
188+
break;
189+
case 'p':
190+
port = atoi(optarg);
191+
break;
192+
default:
193+
die_usage();
194+
break;
195+
}
196+
}
197+
198+
if (listen_mode)
199+
return server(output);
200+
return client(input);
201+
}

0 commit comments

Comments
 (0)