* [RFC mptcp-next v2 1/8] tls: add MPTCP protocol support
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 2/8] mptcp: enable TLS setsockopt Geliang Tang
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
Extend TLS subsystem to support MPTCP protocol by implementing
MPTCP-specific versions of key operations:
- mptcp_sendmsg_locked() for TLS record transmission;
- mptcp_inq_hint() and mptcp_recv_skb() for receive side handling;
- mptcp_read_sock() and mptcp_read_done() for data reading;
- mptcp_disconnect() for disconnect.
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/mptcp.h | 42 ++++++++++++++++++++++++++++
net/mptcp/protocol.c | 66 ++++++++++++++++++++++++++++++++++++--------
net/tls/tls_main.c | 6 +++-
net/tls/tls_strp.c | 20 +++++++++++---
4 files changed, 118 insertions(+), 16 deletions(-)
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 4cf59e83c1c5..ffbbeb08a8be 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -237,6 +237,19 @@ static inline __be32 mptcp_reset_option(const struct sk_buff *skb)
}
void mptcp_active_detect_blackhole(struct sock *sk, bool expired);
+
+int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len);
+
+unsigned int mptcp_inq_hint(const struct sock *sk);
+
+struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off);
+
+int mptcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+ sk_read_actor_t recv_actor);
+
+void mptcp_read_done(struct sock *sk, size_t len);
+
+int mptcp_disconnect(struct sock *sk, int flags);
#else
static inline void mptcp_init(void)
@@ -323,6 +336,35 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques
static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }
static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { }
+
+static inline int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg,
+ size_t len)
+{
+ return 0;
+}
+
+static inline unsigned int mptcp_inq_hint(const struct sock *sk)
+{
+ return 0;
+}
+
+static inline struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off)
+{
+ return NULL;
+}
+
+static inline int mptcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+ sk_read_actor_t recv_actor)
+{
+ return 0;
+}
+
+static inline void mptcp_read_done(struct sock *sk, size_t len) { }
+
+static inline int mptcp_disconnect(struct sock *sk, int flags)
+{
+ return 0;
+}
#endif /* CONFIG_MPTCP */
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index b31724523ed5..e5e2ba1cd976 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1752,8 +1752,6 @@ static void __mptcp_subflow_push_pending(struct sock *sk, struct sock *ssk, bool
}
}
-static int mptcp_disconnect(struct sock *sk, int flags);
-
static int mptcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
size_t len, int *copied_syn)
{
@@ -1862,7 +1860,7 @@ static void mptcp_rps_record_subflows(const struct mptcp_sock *msk)
}
}
-static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct page_frag *pfrag;
@@ -1873,8 +1871,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
/* silently ignore everything else */
msg->msg_flags &= MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL | MSG_FASTOPEN;
- lock_sock(sk);
-
mptcp_rps_record_subflows(msk);
if (unlikely(inet_test_bit(DEFER_CONNECT, sk) ||
@@ -1982,7 +1978,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
__mptcp_push_pending(sk, msg->msg_flags);
out:
- release_sock(sk);
return copied;
do_error:
@@ -1993,6 +1988,17 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
goto out;
}
+static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
+{
+ int ret;
+
+ lock_sock(sk);
+ ret = mptcp_sendmsg_locked(sk, msg, len);
+ release_sock(sk);
+
+ return ret;
+}
+
static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied);
static void mptcp_eat_recv_skb(struct sock *sk, struct sk_buff *skb)
@@ -2224,7 +2230,7 @@ static bool mptcp_move_skbs(struct sock *sk)
return enqueued;
}
-static unsigned int mptcp_inq_hint(const struct sock *sk)
+unsigned int mptcp_inq_hint(const struct sock *sk)
{
const struct mptcp_sock *msk = mptcp_sk(sk);
const struct sk_buff *skb;
@@ -3329,7 +3335,7 @@ static void mptcp_destroy_common(struct mptcp_sock *msk)
mptcp_pm_destroy(msk);
}
-static int mptcp_disconnect(struct sock *sk, int flags)
+int mptcp_disconnect(struct sock *sk, int flags)
{
struct mptcp_sock *msk = mptcp_sk(sk);
@@ -4271,7 +4277,7 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
return mask;
}
-static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off)
+struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct sk_buff *skb;
@@ -4295,8 +4301,8 @@ static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off)
* Note:
* - It is assumed that the socket was locked by the caller.
*/
-static int mptcp_read_sock(struct sock *sk, read_descriptor_t *desc,
- sk_read_actor_t recv_actor)
+int mptcp_read_sock(struct sock *sk, read_descriptor_t *desc,
+ sk_read_actor_t recv_actor)
{
struct mptcp_sock *msk = mptcp_sk(sk);
size_t len = sk->sk_rcvbuf;
@@ -4453,6 +4459,44 @@ static ssize_t mptcp_splice_read(struct socket *sock, loff_t *ppos,
return ret;
}
+void mptcp_read_done(struct sock *sk, size_t len)
+{
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ struct sk_buff *skb;
+ size_t left;
+ u32 offset;
+
+ msk_owned_by_me(msk);
+
+ if (sk->sk_state == TCP_LISTEN)
+ return;
+
+ left = len;
+ while (left && (skb = mptcp_recv_skb(sk, &offset)) != NULL) {
+ int used;
+
+ used = min_t(size_t, skb->len - offset, left);
+ left -= used;
+ msk->bytes_consumed += used;
+ MPTCP_SKB_CB(skb)->offset += used;
+ MPTCP_SKB_CB(skb)->map_seq += used;
+
+ if (skb->len > offset + used)
+ break;
+
+ mptcp_eat_recv_skb(sk, skb);
+ }
+
+ mptcp_rcv_space_adjust(msk, len - left);
+
+ /* Clean up data we have read: This will do ACK frames. */
+ if (left != len) {
+ mptcp_recv_skb(sk, &offset);
+ mptcp_cleanup_rbuf(msk, len - left);
+ }
+}
+EXPORT_SYMBOL(mptcp_read_done);
+
static const struct proto_ops mptcp_stream_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 56ce0bc8317b..7d7bde1702c1 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -194,7 +194,9 @@ int tls_push_sg(struct sock *sk,
bvec_set_page(&bvec, p, size, offset);
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, &bvec, 1, size);
- ret = tcp_sendmsg_locked(sk, &msg, size);
+ ret = sk->sk_protocol == IPPROTO_MPTCP ?
+ mptcp_sendmsg_locked(sk, &msg, size) :
+ tcp_sendmsg_locked(sk, &msg, size);
if (ret != size) {
if (ret > 0) {
@@ -907,6 +909,8 @@ static int tls_setsockopt(struct sock *sk, int level, int optname,
static int tls_disconnect(struct sock *sk, int flags)
{
+ if (sk->sk_protocol == IPPROTO_MPTCP)
+ return mptcp_disconnect(sk, flags);
return -EOPNOTSUPP;
}
diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c
index 98e12f0ff57e..3985e77f3351 100644
--- a/net/tls/tls_strp.c
+++ b/net/tls/tls_strp.c
@@ -132,6 +132,8 @@ int tls_strp_msg_cow(struct tls_sw_context_rx *ctx)
tls_strp_anchor_free(strp);
strp->anchor = skb;
+ strp->sk->sk_protocol == IPPROTO_MPTCP ?
+ mptcp_read_done(strp->sk, strp->stm.full_len) :
tcp_read_done(strp->sk, strp->stm.full_len);
strp->copy_mode = 1;
@@ -383,6 +385,8 @@ static int tls_strp_read_copyin(struct tls_strparser *strp)
desc.count = 1; /* give more than one skb per call */
/* sk should be locked here, so okay to do read_sock */
+ strp->sk->sk_protocol == IPPROTO_MPTCP ?
+ mptcp_read_sock(strp->sk, &desc, tls_strp_copyin) :
tcp_read_sock(strp->sk, &desc, tls_strp_copyin);
return desc.error;
@@ -464,8 +468,10 @@ static void tls_strp_load_anchor_with_queue(struct tls_strparser *strp, int len)
struct sk_buff *first;
u32 offset;
- first = tcp_recv_skb(strp->sk, tp->copied_seq, &offset);
- if (WARN_ON_ONCE(!first))
+ first = strp->sk->sk_protocol == IPPROTO_MPTCP ?
+ mptcp_recv_skb(strp->sk, &offset) :
+ tcp_recv_skb(strp->sk, tp->copied_seq, &offset);
+ if (!first)
return;
/* Bestow the state onto the anchor */
@@ -490,7 +496,9 @@ bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh)
DEBUG_NET_WARN_ON_ONCE(!strp->stm.full_len);
if (!strp->copy_mode && force_refresh) {
- if (unlikely(tcp_inq(strp->sk) < strp->stm.full_len)) {
+ if (unlikely((strp->sk->sk_protocol == IPPROTO_MPTCP ?
+ mptcp_inq_hint(strp->sk) :
+ tcp_inq(strp->sk)) < strp->stm.full_len)) {
WRITE_ONCE(strp->msg_ready, 0);
memset(&strp->stm, 0, sizeof(strp->stm));
return false;
@@ -513,7 +521,9 @@ static int tls_strp_read_sock(struct tls_strparser *strp)
{
int sz, inq;
- inq = tcp_inq(strp->sk);
+ inq = strp->sk->sk_protocol == IPPROTO_MPTCP ?
+ mptcp_inq_hint(strp->sk) :
+ tcp_inq(strp->sk);
if (inq < 1)
return 0;
@@ -586,6 +596,8 @@ void tls_strp_msg_done(struct tls_strparser *strp)
WARN_ON(!strp->stm.full_len);
if (likely(!strp->copy_mode))
+ strp->sk->sk_protocol == IPPROTO_MPTCP ?
+ mptcp_read_done(strp->sk, strp->stm.full_len) :
tcp_read_done(strp->sk, strp->stm.full_len);
else
tls_strp_flush_anchor_copy(strp);
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC mptcp-next v2 2/8] mptcp: enable TLS setsockopt
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 1/8] tls: add MPTCP protocol support Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 3/8] mptcp: update ULP getsockopt Geliang Tang
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
Add support for TLS-related socket options in MPTCP protocol:
- Allow TCP_ULP option with "tls" parameter;
- Support TLS_TX and TLS_RX options from SOL_TLS level;
- Delegate TLS option handling to underlying TCP implementation.
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/sockopt.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index de90a2897d2d..54ad674da151 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -12,6 +12,7 @@
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/mptcp.h>
+#include <net/tls.h>
#include "protocol.h"
#define MIN_INFO_OPTLEN_SIZE 16
@@ -567,6 +568,7 @@ static bool mptcp_supported_sockopt(int level, int optname)
case TCP_FASTOPEN_CONNECT:
case TCP_FASTOPEN_KEY:
case TCP_FASTOPEN_NO_COOKIE:
+ case TCP_ULP:
return true;
}
@@ -576,6 +578,13 @@ static bool mptcp_supported_sockopt(int level, int optname)
* TCP_REPAIR_WINDOW are not supported, better avoid this mess
*/
}
+ if (level == SOL_TLS) {
+ switch (optname) {
+ case TLS_TX:
+ case TLS_RX:
+ return true;
+ }
+ }
return false;
}
@@ -819,11 +828,18 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
sockptr_t optval, unsigned int optlen)
{
struct sock *sk = (void *)msk;
+ char ulp[4] = "";
int ret, val;
switch (optname) {
case TCP_ULP:
- return -EOPNOTSUPP;
+ if (copy_from_user(ulp, optval.user, 4))
+ return -EFAULT;
+ if (strcmp(ulp, "tls\0"))
+ return -EOPNOTSUPP;
+ if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))
+ return -EINVAL;
+ return tcp_setsockopt(sk, SOL_TCP, optname, optval, optlen);
case TCP_CONGESTION:
return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen);
case TCP_DEFER_ACCEPT:
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC mptcp-next v2 3/8] mptcp: update ULP getsockopt
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 1/8] tls: add MPTCP protocol support Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 2/8] mptcp: enable TLS setsockopt Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 4/8] selftests: mptcp: connect: update sock_test_tcpulp Geliang Tang
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
TCP_ULP was obtained by calling mptcp_getsockopt_first_sf_only() to get
the ULP of the first subflow. Now that the mechanism has changed, a new
helper needs to be implemented to get the ULP of the msk.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/sockopt.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 54ad674da151..52ff75702404 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -1409,6 +1409,17 @@ static int mptcp_put_int_option(struct mptcp_sock *msk, char __user *optval,
return 0;
}
+static int mptcp_getsockopt_msk(struct sock *sk, int level, int optname,
+ char __user *optval, int __user *optlen)
+{
+ int ret;
+
+ lock_sock(sk);
+ ret = tcp_getsockopt(sk, level, optname, optval, optlen);
+ release_sock(sk);
+ return ret;
+}
+
static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
char __user *optval, int __user *optlen)
{
@@ -1416,6 +1427,7 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
switch (optname) {
case TCP_ULP:
+ return mptcp_getsockopt_msk(sk, SOL_TCP, optname, optval, optlen);
case TCP_CONGESTION:
case TCP_INFO:
case TCP_CC_INFO:
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC mptcp-next v2 4/8] selftests: mptcp: connect: update sock_test_tcpulp
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
` (2 preceding siblings ...)
2025-11-19 10:05 ` [RFC mptcp-next v2 3/8] mptcp: update ULP getsockopt Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 5/8] selftests: mptcp: connect: fix uninitialized peer warning Geliang Tang
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Improve sock_test_tcpulp() function to properly validate TLS ULP
setup on MPTCP sockets. The updated logic verifies that TLS can be
correctly configured based on the socket protocol type and state.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_connect.c | 36 ++++++++++++-------
1 file changed, 24 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c
index 2e50d6f93640..badb04b58a64 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c
@@ -266,13 +266,25 @@ static void set_mptfo(int fd, int pf)
perror("TCP_FASTOPEN");
}
+static int is_mptcp(int fd)
+{
+ socklen_t optlen;
+ int mptcp = 0;
+
+ optlen = sizeof(mptcp);
+ if (getsockopt(fd, IPPROTO_TCP, TCP_IS_MPTCP, &mptcp, &optlen) == -1)
+ perror("TCP_IS_MPTCP");
+
+ return mptcp;
+}
+
static int do_ulp_so(int sock, const char *name)
{
return setsockopt(sock, IPPROTO_TCP, TCP_ULP, name, strlen(name));
}
#define X(m) xerror("%s:%u: %s: failed for proto %d at line %u", __FILE__, __LINE__, (m), proto, line)
-static void sock_test_tcpulp(int sock, int proto, unsigned int line)
+static void sock_test_tcpulp(int sock, int proto, int r, unsigned int line)
{
socklen_t buflen = 8;
char buf[8] = "";
@@ -282,14 +294,14 @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line)
X("getsockopt");
if (buflen > 0) {
- if (strcmp(buf, "mptcp") != 0)
+ if (strcmp(buf, is_mptcp(sock) ? "tls" : "mptcp") != 0)
xerror("unexpected ULP '%s' for proto %d at line %u", buf, proto, line);
ret = do_ulp_so(sock, "tls");
- if (ret == 0)
+ if (ret != r)
X("setsockopt");
} else if (proto == IPPROTO_MPTCP) {
ret = do_ulp_so(sock, "tls");
- if (ret != -1)
+ if (ret != r)
X("setsockopt");
}
@@ -300,7 +312,7 @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line)
#undef X
}
-#define SOCK_TEST_TCPULP(s, p) sock_test_tcpulp((s), (p), __LINE__)
+#define SOCK_TEST_TCPULP(s, p, r) sock_test_tcpulp((s), (p), (r), __LINE__)
static int sock_listen_mptcp(const char * const listenaddr,
const char * const port)
@@ -325,7 +337,7 @@ static int sock_listen_mptcp(const char * const listenaddr,
if (sock < 0)
continue;
- SOCK_TEST_TCPULP(sock, cfg_sock_proto);
+ SOCK_TEST_TCPULP(sock, cfg_sock_proto, -1);
if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one,
sizeof(one)))
@@ -352,7 +364,7 @@ static int sock_listen_mptcp(const char * const listenaddr,
return sock;
}
- SOCK_TEST_TCPULP(sock, cfg_sock_proto);
+ SOCK_TEST_TCPULP(sock, cfg_sock_proto, -1);
if (listen(sock, 20)) {
perror("listen");
@@ -360,7 +372,7 @@ static int sock_listen_mptcp(const char * const listenaddr,
return -1;
}
- SOCK_TEST_TCPULP(sock, cfg_sock_proto);
+ SOCK_TEST_TCPULP(sock, cfg_sock_proto, -1);
return sock;
}
@@ -388,7 +400,7 @@ static int sock_connect_mptcp(const char * const remoteaddr,
continue;
}
- SOCK_TEST_TCPULP(sock, proto);
+ SOCK_TEST_TCPULP(sock, proto, -1);
if (cfg_mark)
set_mark(sock, cfg_mark);
@@ -425,7 +437,7 @@ static int sock_connect_mptcp(const char * const remoteaddr,
freeaddrinfo(addr);
if (sock != -1)
- SOCK_TEST_TCPULP(sock, proto);
+ SOCK_TEST_TCPULP(sock, proto, is_mptcp(sock) ? 0 : -1);
return sock;
}
@@ -1202,7 +1214,7 @@ int main_loop_s(int listensock)
xerror("can't open %s: %d", cfg_input, errno);
}
- SOCK_TEST_TCPULP(remotesock, 0);
+ SOCK_TEST_TCPULP(remotesock, 0, 0);
memset(&winfo, 0, sizeof(winfo));
err = copyfd_io(fd, remotesock, 1, true, &winfo);
@@ -1381,7 +1393,7 @@ int main_loop(void)
again:
check_getpeername_connect(fd);
- SOCK_TEST_TCPULP(fd, cfg_sock_proto);
+ SOCK_TEST_TCPULP(fd, cfg_sock_proto, -1);
if (cfg_rcvbuf)
set_rcvbuf(fd, cfg_rcvbuf);
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC mptcp-next v2 5/8] selftests: mptcp: connect: fix uninitialized peer warning
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
` (3 preceding siblings ...)
2025-11-19 10:05 ` [RFC mptcp-next v2 4/8] selftests: mptcp: connect: update sock_test_tcpulp Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 6/8] selftests: mptcp: sockopt: add protocol arguments Geliang Tang
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Initialize 'peer' addrinfo pointer to NULL in main_loop() to fix the
following compiler warning:
1415:37: warning: 'peer' may be used uninitialized [-Wmaybe-uninitialized]
1415 | if (connect(fd, peer->ai_addr, peer->ai_addrlen))
| ~~~~^~~~~~~~~
1368:26: note: 'peer' was declared here
1368 | struct addrinfo *peer;
| ^~~~
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/mptcp_connect.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c
index badb04b58a64..4d7016475218 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c
@@ -1376,7 +1376,7 @@ void xdisconnect(int fd)
int main_loop(void)
{
int fd = 0, ret, fd_in = 0;
- struct addrinfo *peer;
+ struct addrinfo *peer = NULL;
struct wstate winfo;
if (cfg_input && cfg_sockopt_types.mptfo) {
@@ -1414,7 +1414,7 @@ int main_loop(void)
if (cfg_truncate > 0) {
shutdown(fd, SHUT_WR);
- } else if (--cfg_repeat > 0) {
+ } else if (--cfg_repeat > 0 && peer) {
xdisconnect(fd);
/* the socket could be unblocking at this point, we need the
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC mptcp-next v2 6/8] selftests: mptcp: sockopt: add protocol arguments
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
` (4 preceding siblings ...)
2025-11-19 10:05 ` [RFC mptcp-next v2 5/8] selftests: mptcp: connect: fix uninitialized peer warning Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 7/8] selftests: mptcp: sockopt: skip mptcp getsockopt for tcp tests Geliang Tang
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Add -t and -r options to specify tx/rx protocols (TCP/MPTCP). This
increases testing flexibility by allowing explicit protocol selection
for both transmission and reception paths.
These codes are from mptcp_inq.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 29 +++++++++++++++----
1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 286164f7246e..e4752f848f08 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -27,6 +27,8 @@
#include <linux/tcp.h>
static int pf = AF_INET;
+static int proto_tx = IPPROTO_MPTCP;
+static int proto_rx = IPPROTO_MPTCP;
#ifndef IPPROTO_MPTCP
#define IPPROTO_MPTCP 262
@@ -135,7 +137,7 @@ static void die_perror(const char *msg)
static void die_usage(int r)
{
- fprintf(stderr, "Usage: mptcp_sockopt [-6]\n");
+ fprintf(stderr, "Usage: mptcp_sockopt [-6] [-t tcp|mptcp] [-r tcp|mptcp]\n");
exit(r);
}
@@ -201,7 +203,7 @@ static int sock_listen_mptcp(const char * const listenaddr,
hints.ai_family = pf;
for (a = addr; a; a = a->ai_next) {
- sock = socket(a->ai_family, a->ai_socktype, IPPROTO_MPTCP);
+ sock = socket(a->ai_family, a->ai_socktype, proto_rx);
if (sock < 0)
continue;
@@ -259,11 +261,22 @@ static int sock_connect_mptcp(const char * const remoteaddr,
return sock;
}
+static int protostr_to_num(const char *s)
+{
+ if (strcasecmp(s, "tcp") == 0)
+ return IPPROTO_TCP;
+ if (strcasecmp(s, "mptcp") == 0)
+ return IPPROTO_MPTCP;
+
+ die_usage(1);
+ return 0;
+}
+
static void parse_opts(int argc, char **argv)
{
int c;
- while ((c = getopt(argc, argv, "h6")) != -1) {
+ while ((c = getopt(argc, argv, "h6t:r:")) != -1) {
switch (c) {
case 'h':
die_usage(0);
@@ -271,6 +284,12 @@ static void parse_opts(int argc, char **argv)
case '6':
pf = AF_INET6;
break;
+ case 't':
+ proto_tx = protostr_to_num(optarg);
+ break;
+ case 'r':
+ proto_rx = protostr_to_num(optarg);
+ break;
default:
die_usage(1);
break;
@@ -776,10 +795,10 @@ static int client(int pipefd)
switch (pf) {
case AF_INET:
- fd = sock_connect_mptcp("127.0.0.1", "15432", IPPROTO_MPTCP);
+ fd = sock_connect_mptcp("127.0.0.1", "15432", proto_tx);
break;
case AF_INET6:
- fd = sock_connect_mptcp("::1", "15432", IPPROTO_MPTCP);
+ fd = sock_connect_mptcp("::1", "15432", proto_tx);
break;
default:
xerror("Unknown pf %d\n", pf);
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC mptcp-next v2 7/8] selftests: mptcp: sockopt: skip mptcp getsockopt for tcp tests
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
` (5 preceding siblings ...)
2025-11-19 10:05 ` [RFC mptcp-next v2 6/8] selftests: mptcp: sockopt: add protocol arguments Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 10:05 ` [RFC mptcp-next v2 8/8] selftests: mptcp: sockopt: add KTLS test cases Geliang Tang
2025-11-19 13:09 ` [RFC mptcp-next v2 0/8] MPTCP KTLS support MPTCP CI
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Skip mptcp getsockopt checks during tcp tests since MPTCP socket options
are not available for them.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
.../selftests/net/mptcp/mptcp_sockopt.c | 21 ++++++++-----------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index e4752f848f08..59c07eda12cd 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -384,7 +384,7 @@ static void do_getsockopt_mptcp_info(struct so_state *s, int fd, size_t w)
ret = getsockopt(fd, SOL_MPTCP, MPTCP_INFO, &i, &olen);
if (ret < 0)
- die_perror("getsockopt MPTCP_INFO");
+ return;
s->pkt_stats_avail = olen >= sizeof(i);
@@ -415,7 +415,7 @@ static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t
ret = getsockopt(fd, SOL_MPTCP, MPTCP_TCPINFO, &ti, &olen);
if (ret < 0)
- xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
+ return;
assert(olen <= sizeof(ti));
assert(ti.d.size_kernel > 0);
@@ -470,7 +470,7 @@ static void do_getsockopt_subflow_addrs(struct so_state *s, int fd)
ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, &addrs, &olen);
if (ret < 0)
- die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
+ return;
assert(olen <= sizeof(addrs));
assert(addrs.d.size_kernel > 0);
@@ -540,13 +540,8 @@ static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
olen = data_size;
ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen);
- if (ret < 0) {
- if (errno == EOPNOTSUPP) {
- perror("MPTCP_FULL_INFO test skipped");
- return;
- }
- xerror("getsockopt MPTCP_FULL_INFO");
- }
+ if (ret < 0)
+ return;
assert(olen <= data_size);
assert(mfi.size_tcpinfo_kernel > 0);
@@ -650,7 +645,8 @@ static void connect_one_server(int fd, int pipefd)
if (eof)
total += 1; /* sequence advances due to FIN */
- assert(s.mptcpi_rcv_delta == (uint64_t)total);
+ if (s.mptcpi_rcv_delta)
+ assert(s.mptcpi_rcv_delta == (uint64_t)total);
close(fd);
}
@@ -685,7 +681,8 @@ static void process_one_client(int fd, int pipefd)
xerror("expected EOF, got %lu", ret3);
do_getsockopts(&s, fd, ret, ret2);
- if (s.mptcpi_rcv_delta != (uint64_t)ret + 1)
+ if (s.mptcpi_rcv_delta &&
+ s.mptcpi_rcv_delta != (uint64_t)ret + 1)
xerror("mptcpi_rcv_delta %" PRIu64 ", expect %" PRIu64 ", diff %" PRId64,
s.mptcpi_rcv_delta, ret + 1, s.mptcpi_rcv_delta - (ret + 1));
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC mptcp-next v2 8/8] selftests: mptcp: sockopt: add KTLS test cases
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
` (6 preceding siblings ...)
2025-11-19 10:05 ` [RFC mptcp-next v2 7/8] selftests: mptcp: sockopt: skip mptcp getsockopt for tcp tests Geliang Tang
@ 2025-11-19 10:05 ` Geliang Tang
2025-11-19 13:09 ` [RFC mptcp-next v2 0/8] MPTCP KTLS support MPTCP CI
8 siblings, 0 replies; 10+ messages in thread
From: Geliang Tang @ 2025-11-19 10:05 UTC (permalink / raw)
To: mptcp, hare, hare; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Add Kernel TLS (KTLS) testing support to mptcp_sockopt:
- New '-c' option to enable TLS testing;
- TLS socket setup with AES-GCM-128 cipher;
- Test cases for both TCP and MPTCP with TLS;
- IPv4 and IPv6 support for TLS tests.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/config | 1 +
.../selftests/net/mptcp/mptcp_sockopt.c | 75 ++++++++++++++++++-
.../selftests/net/mptcp/mptcp_sockopt.sh | 47 ++++++++++++
3 files changed, 121 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config
index 59051ee2a986..18bd29ac5b24 100644
--- a/tools/testing/selftests/net/mptcp/config
+++ b/tools/testing/selftests/net/mptcp/config
@@ -34,3 +34,4 @@ CONFIG_NFT_SOCKET=m
CONFIG_NFT_TPROXY=m
CONFIG_SYN_COOKIES=y
CONFIG_VETH=y
+CONFIG_TLS=y
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
index 59c07eda12cd..7a43f681abc0 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c
@@ -25,10 +25,12 @@
#include <netinet/in.h>
#include <linux/tcp.h>
+#include <linux/tls.h>
static int pf = AF_INET;
static int proto_tx = IPPROTO_MPTCP;
static int proto_rx = IPPROTO_MPTCP;
+static bool tls;
#ifndef IPPROTO_MPTCP
#define IPPROTO_MPTCP 262
@@ -36,6 +38,9 @@ static int proto_rx = IPPROTO_MPTCP;
#ifndef SOL_MPTCP
#define SOL_MPTCP 284
#endif
+#ifndef TCP_ULP
+#define TCP_ULP 31
+#endif
#ifndef MPTCP_INFO
struct mptcp_info {
@@ -137,7 +142,7 @@ static void die_perror(const char *msg)
static void die_usage(int r)
{
- fprintf(stderr, "Usage: mptcp_sockopt [-6] [-t tcp|mptcp] [-r tcp|mptcp]\n");
+ fprintf(stderr, "Usage: mptcp_sockopt [-6] [-t tcp|mptcp] [-r tcp|mptcp] [-c]\n");
exit(r);
}
@@ -184,6 +189,54 @@ static void xgetaddrinfo(const char *node, const char *service,
}
}
+#define TLS_OVERHEAD_SIZE 29
+
+static int do_setsockopt_tls(int fd)
+{
+ struct tls12_crypto_info_aes_gcm_128 tls_tx = {
+ .info = {
+ .version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_AES_GCM_128,
+ },
+ };
+ struct tls12_crypto_info_aes_gcm_128 tls_rx = {
+ .info = {
+ .version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_AES_GCM_128,
+ },
+ };
+ int so_buf = 6553500;
+ int err;
+
+ err = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
+ if (err) {
+ perror("setsockopt TCP_ULP");
+ return err;
+ }
+ err = setsockopt(fd, SOL_TLS, TLS_TX, (void *)&tls_tx, sizeof(tls_tx));
+ if (err) {
+ perror("setsockopt TLS_TX");
+ return err;
+ }
+ err = setsockopt(fd, SOL_TLS, TLS_RX, (void *)&tls_rx, sizeof(tls_rx));
+ if (err) {
+ perror("setsockopt TLS_RX");
+ return err;
+ }
+ err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &so_buf, sizeof(so_buf));
+ if (err) {
+ perror("setsockopt SO_SNDBUF");
+ return err;
+ }
+ err = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &so_buf, sizeof(so_buf));
+ if (err) {
+ perror("setsockopt SO_RCVBUF");
+ return err;
+ }
+
+ return 0;
+}
+
static int sock_listen_mptcp(const char * const listenaddr,
const char * const port)
{
@@ -276,7 +329,7 @@ static void parse_opts(int argc, char **argv)
{
int c;
- while ((c = getopt(argc, argv, "h6t:r:")) != -1) {
+ while ((c = getopt(argc, argv, "h6t:r:c")) != -1) {
switch (c) {
case 'h':
die_usage(0);
@@ -289,6 +342,8 @@ static void parse_opts(int argc, char **argv)
break;
case 'r':
proto_rx = protostr_to_num(optarg);
+ case 'c':
+ tls = true;
break;
default:
die_usage(1);
@@ -640,6 +695,11 @@ static void connect_one_server(int fd, int pipefd)
if (s.tcpi_rcv_delta)
assert(s.tcpi_rcv_delta <= total);
+ if (tls) {
+ ret += TLS_OVERHEAD_SIZE;
+ total += TLS_OVERHEAD_SIZE;
+ }
+
do_getsockopts(&s, fd, ret, ret);
if (eof)
@@ -680,6 +740,11 @@ static void process_one_client(int fd, int pipefd)
if (ret3 != 0)
xerror("expected EOF, got %lu", ret3);
+ if (tls) {
+ ret += TLS_OVERHEAD_SIZE;
+ ret2 += TLS_OVERHEAD_SIZE;
+ }
+
do_getsockopts(&s, fd, ret, ret2);
if (s.mptcpi_rcv_delta &&
s.mptcpi_rcv_delta != (uint64_t)ret + 1)
@@ -740,6 +805,9 @@ static int server(int pipefd)
alarm(15);
r = xaccept(fd);
+ if (tls)
+ do_setsockopt_tls(r);
+
process_one_client(r, pipefd);
close(fd);
@@ -803,6 +871,9 @@ static int client(int pipefd)
test_ip_tos_sockopt(fd);
+ if (tls)
+ do_setsockopt_tls(fd);
+
connect_one_server(fd, pipefd);
return 0;
diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
index ab8bce06b262..8840be8adea3 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
@@ -351,6 +351,52 @@ do_tcpinq_tests()
return $?
}
+do_tls_test()
+{
+ print_title "KTLS $*" | head -c 53
+ ip netns exec "$ns_sbox" ./mptcp_sockopt "$@"
+ local lret=$?
+ if [ $lret -ne 0 ];then
+ ret=$lret
+ mptcp_lib_pr_fail
+ mptcp_lib_result_fail "KTLS: $*"
+ return $lret
+ fi
+
+ mptcp_lib_pr_ok
+ mptcp_lib_result_pass "KTLS: $*"
+ return $lret
+}
+
+do_tls_tests()
+{
+ local lret=0
+
+ mptcp_lib_print_info "sockopt KTLS"
+
+ # TCP KTLS
+ do_tls_test -c -t tcp -r tcp
+ lret=$?
+ if [ $lret -ne 0 ] ; then
+ return $lret
+ fi
+ do_tls_test -6 -c -t tcp -r tcp
+ lret=$?
+ if [ $lret -ne 0 ] ; then
+ return $lret
+ fi
+
+ # MPTCP KTLS
+ do_tls_test -c
+ lret=$?
+ if [ $lret -ne 0 ] ; then
+ return $lret
+ fi
+ do_tls_test -6 -c
+ lret=$?
+ return $lret
+}
+
sin=$(mktemp)
sout=$(mktemp)
cin=$(mktemp)
@@ -366,6 +412,7 @@ run_tests $ns1 $ns2 dead:beef:1::1
do_mptcp_sockopt_tests
do_tcpinq_tests
+do_tls_tests
mptcp_lib_result_print_all_tap
exit $ret
--
2.51.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [RFC mptcp-next v2 0/8] MPTCP KTLS support
2025-11-19 10:04 [RFC mptcp-next v2 0/8] MPTCP KTLS support Geliang Tang
` (7 preceding siblings ...)
2025-11-19 10:05 ` [RFC mptcp-next v2 8/8] selftests: mptcp: sockopt: add KTLS test cases Geliang Tang
@ 2025-11-19 13:09 ` MPTCP CI
8 siblings, 0 replies; 10+ messages in thread
From: MPTCP CI @ 2025-11-19 13:09 UTC (permalink / raw)
To: Geliang Tang; +Cc: mptcp
Hi Geliang,
Thank you for your modifications, that's great!
Our CI did some validations and here is its report:
- KVM Validation: normal (except selftest_mptcp_join): Unstable: 1 failed test(s): packetdrill_dss 🔴
- KVM Validation: normal (only selftest_mptcp_join): Success! ✅
- KVM Validation: debug (except selftest_mptcp_join): Unstable: 2 failed test(s): packetdrill_add_addr packetdrill_dss 🔴
- KVM Validation: debug (only selftest_mptcp_join): Success! ✅
- KVM Validation: btf-normal (only bpftest_all): Success! ✅
- KVM Validation: btf-debug (only bpftest_all): Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/19498013524
Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/554098b28764
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1025245
If there are some issues, you can reproduce them using the same environment as
the one used by the CI thanks to a docker image, e.g.:
$ cd [kernel source code]
$ docker run -v "${PWD}:${PWD}:rw" -w "${PWD}" --privileged --rm -it \
--pull always mptcp/mptcp-upstream-virtme-docker:latest \
auto-normal
For more details:
https://github.com/multipath-tcp/mptcp-upstream-virtme-docker
Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)
Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (NGI0 Core)
^ permalink raw reply [flat|nested] 10+ messages in thread