2024-05-23 08:01:09 +00:00
From 5f71968be8e8809e4e7b876ff04b4ef3f22eb141 Mon Sep 17 00:00:00 2001
From: Geliang Tang <geliang@kernel.org>
Date: Wed, 6 Mar 2024 11:23:33 +0800
Subject: [PATCH] add MPTCPv1 support
2023-08-01 18:54:21 +00:00
2024-05-23 08:01:09 +00:00
The Multipath TCP (MPTCP) protocol (v1 / RFC 8684) has been added in
the upstream Linux kernel since v5.6.
2023-08-01 18:54:21 +00:00
2024-05-23 08:01:09 +00:00
MPTCP is strongly tied to TCP, and the kernel APIs are almost the same.
The only required dependency is the 'IPPROTO_MPTCP' protocol number
definition, which should be provided by the netinet/in.h header if it
is recent enough.
This patch adds a new flag '-m' or '--mptcp' to support MPTCPv1. It can
be used like this:
> iperf3 -m -s
> iperf3 -m -c 127.0.0.1
There is no need to check for IPPROTO_MPTCP support in configure.ac
at build time, it is at runtime we will see if the kernel being use
supports or not MPTCP.
If IPPROTO_MPTCP is not supported by the kernel being tested, it is
normal to fail because the feature is not available and the user
explicitly asked to use MPTCP.
Closes: https://github.com/esnet/iperf/pull/1659
Co-developed-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Geliang Tang <geliang@kernel.org>
2023-08-01 18:54:21 +00:00
---
src/iperf.h | 1 +
src/iperf3.1 | 4 ++++
2024-05-23 08:01:09 +00:00
src/iperf_api.c | 19 ++++++++++++++++++-
src/iperf_locale.c | 3 +++
src/iperf_tcp.c | 22 +++++++++++++++++++---
src/net.c | 10 +++++-----
src/net.h | 2 +-
7 files changed, 51 insertions(+), 10 deletions(-)
2023-08-01 18:54:21 +00:00
diff --git a/src/iperf.h b/src/iperf.h
2024-05-23 08:01:09 +00:00
index dc3c0d1df..cb821e1f7 100644
2023-08-01 18:54:21 +00:00
--- a/src/iperf.h
+++ b/src/iperf.h
2024-05-23 08:01:09 +00:00
@@ -342,6 +342,7 @@ struct iperf_test
2023-08-01 18:54:21 +00:00
int repeating_payload; /* --repeating-payload */
int timestamps; /* --timestamps */
char *timestamp_format;
2024-05-23 08:01:09 +00:00
+ int mptcp; /* -m, --mptcp */
char *json_output_string; /* rendered JSON output if json_output is set */
/* Select related parameters */
2023-08-01 18:54:21 +00:00
diff --git a/src/iperf3.1 b/src/iperf3.1
2024-05-23 08:01:09 +00:00
index 2efd53dea..ebc603408 100644
2023-08-01 18:54:21 +00:00
--- a/src/iperf3.1
+++ b/src/iperf3.1
2024-05-23 08:01:09 +00:00
@@ -193,6 +193,10 @@ parameter is specified in ms, and defaults to the system settings.
This functionality depends on the TCP_USER_TIMEOUT socket option, and
will not work on systems that do not support it.
2023-08-01 18:54:21 +00:00
.TP
2024-05-23 08:01:09 +00:00
+.BR -m ", " --mptcp " "
+use mptcp variant for the current protocol. This only applies to
2023-08-01 18:54:21 +00:00
+TCP and enables MPTCP usage.
+.TP
2024-05-23 08:01:09 +00:00
.BR -d ", " --debug " "
emit debugging output.
Primarily (perhaps exclusively) of use to developers.
2023-08-01 18:54:21 +00:00
diff --git a/src/iperf_api.c b/src/iperf_api.c
2024-05-23 08:01:09 +00:00
index 1dcfaabf5..f7f1fbfb8 100644
2023-08-01 18:54:21 +00:00
--- a/src/iperf_api.c
+++ b/src/iperf_api.c
2024-05-23 08:01:09 +00:00
@@ -1144,6 +1144,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
2023-08-01 18:54:21 +00:00
{"idle-timeout", required_argument, NULL, OPT_IDLE_TIMEOUT},
{"rcv-timeout", required_argument, NULL, OPT_RCV_TIMEOUT},
{"snd-timeout", required_argument, NULL, OPT_SND_TIMEOUT},
2024-05-23 08:01:09 +00:00
+#if defined(linux)
+ {"mptcp", no_argument, NULL, 'm'},
+#endif
2023-08-01 18:54:21 +00:00
{"debug", optional_argument, NULL, 'd'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
2024-05-23 08:01:09 +00:00
@@ -1169,7 +1172,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
FILE *ptr_file;
2023-08-01 18:54:21 +00:00
#endif /* HAVE_SSL */
- while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:M:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
+ while ((flag = getopt_long(argc, argv, "p:f:i:D1VJvsc:ub:t:n:k:l:P:Rw:B:mM:N46S:L:ZO:F:A:T:C:dI:hX:", longopts, NULL)) != -1) {
switch (flag) {
case 'p':
portno = atoi(optarg);
2024-05-23 08:01:09 +00:00
@@ -1639,6 +1642,12 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv)
test->settings->connect_timeout = unit_atoi(optarg);
2023-08-01 18:54:21 +00:00
client_flag = 1;
2024-05-23 08:01:09 +00:00
break;
+#if defined(linux)
+ case 'm':
+ set_protocol(test, Ptcp);
+ test->mptcp = 1;
+ break;
+#endif
case 'h':
usage_long(stdout);
exit(0);
@@ -2216,6 +2225,10 @@ send_parameters(struct iperf_test *test)
2023-08-01 18:54:21 +00:00
cJSON_AddTrueToObject(j, "reverse");
if (test->bidirectional)
cJSON_AddTrueToObject(j, "bidirectional");
2024-05-23 08:01:09 +00:00
+#if defined(linux)
+ if (test->mptcp)
+ cJSON_AddTrueToObject(j, "mptcp");
+#endif
2023-08-01 18:54:21 +00:00
if (test->settings->socket_bufsize)
cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
if (test->settings->blksize)
2024-05-23 08:01:09 +00:00
@@ -2332,6 +2345,10 @@ get_parameters(struct iperf_test *test)
2023-08-01 18:54:21 +00:00
iperf_set_test_reverse(test, 1);
if ((j_p = cJSON_GetObjectItem(j, "bidirectional")) != NULL)
iperf_set_test_bidirectional(test, 1);
2024-05-23 08:01:09 +00:00
+#if defined(linux)
+ if ((j_p = cJSON_GetObjectItem(j, "mptcp")) != NULL)
+ test->mptcp = 1;
+#endif
2023-08-01 18:54:21 +00:00
if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)
test->settings->socket_bufsize = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)
diff --git a/src/iperf_locale.c b/src/iperf_locale.c
2024-05-23 08:01:09 +00:00
index ae0f63a41..d454af4f0 100644
2023-08-01 18:54:21 +00:00
--- a/src/iperf_locale.c
+++ b/src/iperf_locale.c
2024-05-23 08:01:09 +00:00
@@ -128,6 +128,9 @@ const char usage_longstr[] = "Usage: iperf3 [-s|-c host] [options]\n"
" --snd-timeout # timeout for unacknowledged TCP data\n"
" (in ms, default is system settings)\n"
#endif /* HAVE_TCP_USER_TIMEOUT */
+#if defined(linux)
+ " -m, --mptcp use MPTCP rather than plain TCP\n"
+#endif
" -d, --debug[=#] emit debugging output\n"
" (optional optional \"=\" and debug level: 1-4. Default is 4 - all messages)\n"
" -v, --version show version information and quit\n"
diff --git a/src/iperf_tcp.c b/src/iperf_tcp.c
index 184a1955e..a10322b75 100644
--- a/src/iperf_tcp.c
+++ b/src/iperf_tcp.c
2023-08-01 18:54:21 +00:00
@@ -44,6 +44,10 @@
#include "net.h"
#include "cjson.h"
+#ifndef IPPROTO_MPTCP
+#define IPPROTO_MPTCP 262
+#endif
+
#if defined(HAVE_FLOWLABEL)
#include "flowlabel.h"
#endif /* HAVE_FLOWLABEL */
2024-05-23 08:01:09 +00:00
@@ -182,9 +186,10 @@ iperf_tcp_listen(struct iperf_test *test)
2023-08-01 18:54:21 +00:00
*
* It's not clear whether this is a requirement or a convenience.
*/
- if (test->no_delay || test->settings->mss || test->settings->socket_bufsize) {
2024-05-23 08:01:09 +00:00
+ if (test->no_delay || test->mptcp || test->settings->mss || test->settings->socket_bufsize) {
2023-08-01 18:54:21 +00:00
struct addrinfo hints, *res;
char portstr[6];
2024-05-23 08:01:09 +00:00
+ int proto = 0;
2023-08-01 18:54:21 +00:00
2024-05-23 08:01:09 +00:00
FD_CLR(s, &test->read_set);
close(s);
@@ -210,7 +215,12 @@ iperf_tcp_listen(struct iperf_test *test)
2023-08-01 18:54:21 +00:00
return -1;
}
- if ((s = socket(res->ai_family, SOCK_STREAM, 0)) < 0) {
2024-05-23 08:01:09 +00:00
+#if defined(linux)
+ if (test->mptcp)
+ proto = IPPROTO_MPTCP;
+#endif
2023-08-01 18:54:21 +00:00
+
2024-05-23 08:01:09 +00:00
+ if ((s = socket(res->ai_family, SOCK_STREAM, proto)) < 0) {
2023-08-01 18:54:21 +00:00
freeaddrinfo(res);
i_errno = IESTREAMLISTEN;
return -1;
2024-05-23 08:01:09 +00:00
@@ -375,8 +385,14 @@ iperf_tcp_connect(struct iperf_test *test)
2023-08-01 18:54:21 +00:00
socklen_t optlen;
int saved_errno;
int rcvbuf_actual, sndbuf_actual;
2024-05-23 08:01:09 +00:00
+ int proto = 0;
2023-08-01 18:54:21 +00:00
+
2024-05-23 08:01:09 +00:00
+#if defined(linux)
+ if (test->mptcp)
+ proto = IPPROTO_MPTCP;
+#endif
2023-08-01 18:54:21 +00:00
- s = create_socket(test->settings->domain, SOCK_STREAM, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, &server_res);
2024-05-23 08:01:09 +00:00
+ s = create_socket(test->settings->domain, SOCK_STREAM, proto, test->bind_address, test->bind_dev, test->bind_port, test->server_hostname, test->server_port, &server_res);
2023-08-01 18:54:21 +00:00
if (s < 0) {
i_errno = IESTREAMCONNECT;
return -1;
2024-05-23 08:01:09 +00:00
diff --git a/src/net.c b/src/net.c
index c82caff1b..849e919f2 100644
--- a/src/net.c
+++ b/src/net.c
@@ -124,7 +124,7 @@ timeout_connect(int s, const struct sockaddr *name, socklen_t namelen,
2023-08-01 18:54:21 +00:00
/* create a socket */
int
-create_socket(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out)
2024-05-23 08:01:09 +00:00
+create_socket(int domain, int type, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out)
2023-08-01 18:54:21 +00:00
{
struct addrinfo hints, *local_res = NULL, *server_res = NULL;
int s, saved_errno;
2024-05-23 08:01:09 +00:00
@@ -133,14 +133,14 @@ create_socket(int domain, int proto, const char *local, const char *bind_dev, in
if (local) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = domain;
- hints.ai_socktype = proto;
+ hints.ai_socktype = type;
if ((gerror = getaddrinfo(local, NULL, &hints, &local_res)) != 0)
return -1;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = domain;
- hints.ai_socktype = proto;
+ hints.ai_socktype = type;
snprintf(portstr, sizeof(portstr), "%d", port);
if ((gerror = getaddrinfo(server, portstr, &hints, &server_res)) != 0) {
if (local)
@@ -148,7 +148,7 @@ create_socket(int domain, int proto, const char *local, const char *bind_dev, in
2023-08-01 18:54:21 +00:00
return -1;
}
- s = socket(server_res->ai_family, proto, 0);
2024-05-23 08:01:09 +00:00
+ s = socket(server_res->ai_family, type, proto);
2023-08-01 18:54:21 +00:00
if (s < 0) {
if (local)
freeaddrinfo(local_res);
2024-05-23 08:01:09 +00:00
@@ -238,7 +238,7 @@ netdial(int domain, int proto, const char *local, const char *bind_dev, int loca
2023-08-01 18:54:21 +00:00
struct addrinfo *server_res = NULL;
int s, saved_errno;
- s = create_socket(domain, proto, local, bind_dev, local_port, server, port, &server_res);
2024-05-23 08:01:09 +00:00
+ s = create_socket(domain, proto, 0, local, bind_dev, local_port, server, port, &server_res);
2023-08-01 18:54:21 +00:00
if (s < 0) {
return -1;
}
2024-05-23 08:01:09 +00:00
diff --git a/src/net.h b/src/net.h
index f0e1b4f98..1f5cc4d34 100644
--- a/src/net.h
+++ b/src/net.h
2023-08-01 18:54:21 +00:00
@@ -28,7 +28,7 @@
#define __NET_H
int timeout_connect(int s, const struct sockaddr *name, socklen_t namelen, int timeout);
-int create_socket(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out);
2024-05-23 08:01:09 +00:00
+int create_socket(int domain, int type, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, struct addrinfo **server_res_out);
2023-08-01 18:54:21 +00:00
int netdial(int domain, int proto, const char *local, const char *bind_dev, int local_port, const char *server, int port, int timeout);
int netannounce(int domain, int proto, const char *local, const char *bind_dev, int port);
int Nread(int fd, char *buf, size_t count, int prot);