* [RFC mptcp-next v10 01/14] tls: introduce struct tls_prot_ops for protocol ops
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 02/14] tls: add tls_prot_ops pointer to tls_context Geliang Tang
` (13 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
To extend MPTCP support based on TCP TLS, a tls_prot_ops structure has
been introduced for TLS, encapsulating TCP-specific helpers within this
structure.
Add registering, validating and finding functions for this structure to
add, validate and find a tls_prot_ops on the global list tls_prot_ops_list.
Register TCP-specific structure tls_tcp_ops in tls_init().
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/tls.h | 19 +++++++++++
net/tls/tls_main.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+)
diff --git a/include/net/tls.h b/include/net/tls.h
index ebd2550280ae..40001110bccb 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -220,6 +220,25 @@ struct tls_prot_info {
u16 tail_size;
};
+struct tls_prot_ops {
+ int protocol;
+ struct module *owner;
+ struct list_head list;
+
+ int (*inq)(struct sock *sk);
+ int (*sendmsg_locked)(struct sock *sk, struct msghdr *msg, size_t size);
+ struct sk_buff *(*recv_skb)(struct sock *sk, u32 *off);
+ int (*read_sock)(struct sock *sk, read_descriptor_t *desc,
+ sk_read_actor_t recv_actor);
+ void (*read_done)(struct sock *sk, size_t len);
+ u32 (*get_skb_off)(struct sk_buff *skb);
+ u32 (*get_skb_seq)(struct sk_buff *skb);
+ __poll_t (*poll)(struct file *file, struct socket *sock,
+ struct poll_table_struct *wait);
+ bool (*epollin_ready)(const struct sock *sk);
+ void (*check_app_limited)(struct sock *sk);
+};
+
struct tls_context {
/* read-only cache line */
struct tls_prot_info prot_info;
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index fd39acf41a61..e628b729cbd3 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -128,6 +128,24 @@ static struct proto_ops tls_proto_ops[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CON
static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
const struct proto *base);
+static DEFINE_SPINLOCK(tls_prot_ops_lock);
+static LIST_HEAD(tls_prot_ops_list);
+
+/* Must be called with rcu read lock held */
+static struct tls_prot_ops *tls_prot_ops_find(int protocol)
+{
+ struct tls_prot_ops *ops, *ret = NULL;
+
+ list_for_each_entry_rcu(ops, &tls_prot_ops_list, list) {
+ if (ops->protocol == protocol) {
+ ret = ops;
+ break;
+ }
+ }
+
+ return ret;
+}
+
void update_sk_prot(struct sock *sk, struct tls_context *ctx)
{
int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
@@ -1236,6 +1254,68 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
.get_info_size = tls_get_info_size,
};
+static int tls_validate_prot_ops(const struct tls_prot_ops *ops)
+{
+ if (!ops->inq || !ops->sendmsg_locked ||
+ !ops->recv_skb || !ops->read_sock ||
+ !ops->read_done || !ops->get_skb_seq ||
+ !ops->poll || !ops->epollin_ready ||
+ !ops->check_app_limited) {
+ pr_err("%d does not implement required ops\n", ops->protocol);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tls_register_prot_ops(struct tls_prot_ops *ops)
+{
+ int ret;
+
+ ret = tls_validate_prot_ops(ops);
+ if (ret)
+ return ret;
+
+ spin_lock(&tls_prot_ops_lock);
+ if (tls_prot_ops_find(ops->protocol)) {
+ spin_unlock(&tls_prot_ops_lock);
+ return -EEXIST;
+ }
+ list_add_tail_rcu(&ops->list, &tls_prot_ops_list);
+ spin_unlock(&tls_prot_ops_lock);
+
+ pr_debug("tls_prot_ops %d registered\n", ops->protocol);
+ return 0;
+}
+
+static struct sk_buff *tls_tcp_recv_skb(struct sock *sk, u32 *off)
+{
+ return tcp_recv_skb(sk, tcp_sk(sk)->copied_seq, off);
+}
+
+static u32 tls_tcp_get_skb_seq(struct sk_buff *skb)
+{
+ return TCP_SKB_CB(skb)->seq;
+}
+
+static bool tls_tcp_epollin_ready(const struct sock *sk)
+{
+ return tcp_epollin_ready(sk, INT_MAX);
+}
+
+static struct tls_prot_ops tls_tcp_ops = {
+ .protocol = IPPROTO_TCP,
+ .inq = tcp_inq,
+ .sendmsg_locked = tcp_sendmsg_locked,
+ .recv_skb = tls_tcp_recv_skb,
+ .read_sock = tcp_read_sock,
+ .read_done = tcp_read_done,
+ .get_skb_seq = tls_tcp_get_skb_seq,
+ .poll = tcp_poll,
+ .epollin_ready = tls_tcp_epollin_ready,
+ .check_app_limited = tcp_rate_check_app_limited,
+};
+
static int __init tls_register(void)
{
int err;
@@ -1254,6 +1334,8 @@ static int __init tls_register(void)
tcp_register_ulp(&tcp_tls_ulp_ops);
+ tls_register_prot_ops(&tls_tcp_ops);
+
return 0;
err_strp:
tls_strp_dev_exit();
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 02/14] tls: add tls_prot_ops pointer to tls_context
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 01/14] tls: introduce struct tls_prot_ops for protocol ops Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 03/14] tls: add MPTCP SKB offset check in strp queue walk Geliang Tang
` (12 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
A pointer to struct tls_prot_ops, named 'ops', has been added to struct
tls_context. The places originally calling TLS-specific helpers have now
been modified to indirectly invoke them via 'ops' pointer in tls_context.
In do_tls_setsockopt_conf(), ctx->ops is assigned either 'tls_mptcp_ops'
or 'tls_tcp_ops' based on the socket protocol.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/tls.h | 1 +
net/tls/tls_main.c | 15 +++++++++++----
net/tls/tls_strp.c | 29 +++++++++++++++++++----------
net/tls/tls_sw.c | 7 +++++--
4 files changed, 36 insertions(+), 16 deletions(-)
diff --git a/include/net/tls.h b/include/net/tls.h
index 40001110bccb..3c67c45f13be 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -277,6 +277,7 @@ struct tls_context {
struct sock *sk;
void (*sk_destruct)(struct sock *sk);
+ const struct tls_prot_ops *ops;
union tls_crypto_context crypto_send;
union tls_crypto_context crypto_recv;
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index e628b729cbd3..fe8ba116504a 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -206,13 +206,13 @@ int tls_push_sg(struct sock *sk,
ctx->splicing_pages = true;
while (1) {
/* is sending application-limited? */
- tcp_rate_check_app_limited(sk);
+ ctx->ops->check_app_limited(sk);
p = sg_page(sg);
retry:
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 = ctx->ops->sendmsg_locked(sk, &msg, size);
if (ret != size) {
if (ret > 0) {
@@ -427,14 +427,14 @@ static __poll_t tls_sk_poll(struct file *file, struct socket *sock,
u8 shutdown;
int state;
- mask = tcp_poll(file, sock, wait);
+ tls_ctx = tls_get_ctx(sk);
+ mask = tls_ctx->ops->poll(file, sock, wait);
state = inet_sk_state_load(sk);
shutdown = READ_ONCE(sk->sk_shutdown);
if (unlikely(state != TCP_ESTABLISHED || shutdown & RCV_SHUTDOWN))
return mask;
- tls_ctx = tls_get_ctx(sk);
ctx = tls_sw_ctx_rx(tls_ctx);
psock = sk_psock_get(sk);
@@ -1094,6 +1094,13 @@ static int tls_init(struct sock *sk)
ctx->tx_conf = TLS_BASE;
ctx->rx_conf = TLS_BASE;
ctx->tx_max_payload_len = TLS_MAX_PAYLOAD_SIZE;
+ ctx->ops = tls_prot_ops_find(sk->sk_protocol);
+ if (!ctx->ops) {
+ tls_ctx_free(sk, ctx);
+ inet_csk(sk)->icsk_ulp_ops = NULL;
+ rc = -EINVAL;
+ goto out;
+ }
update_sk_prot(sk, ctx);
out:
write_unlock_bh(&sk->sk_callback_lock);
diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c
index 98e12f0ff57e..ef1a8659ee18 100644
--- a/net/tls/tls_strp.c
+++ b/net/tls/tls_strp.c
@@ -120,6 +120,7 @@ struct sk_buff *tls_strp_msg_detach(struct tls_sw_context_rx *ctx)
int tls_strp_msg_cow(struct tls_sw_context_rx *ctx)
{
struct tls_strparser *strp = &ctx->strp;
+ struct tls_context *tls_ctx;
struct sk_buff *skb;
if (strp->copy_mode)
@@ -132,7 +133,8 @@ int tls_strp_msg_cow(struct tls_sw_context_rx *ctx)
tls_strp_anchor_free(strp);
strp->anchor = skb;
- tcp_read_done(strp->sk, strp->stm.full_len);
+ tls_ctx = tls_get_ctx(strp->sk);
+ tls_ctx->ops->read_done(strp->sk, strp->stm.full_len);
strp->copy_mode = 1;
return 0;
@@ -376,6 +378,7 @@ static int tls_strp_copyin(read_descriptor_t *desc, struct sk_buff *in_skb,
static int tls_strp_read_copyin(struct tls_strparser *strp)
{
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
read_descriptor_t desc;
desc.arg.data = strp;
@@ -383,13 +386,14 @@ 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 */
- tcp_read_sock(strp->sk, &desc, tls_strp_copyin);
+ ctx->ops->read_sock(strp->sk, &desc, tls_strp_copyin);
return desc.error;
}
static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort)
{
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
struct skb_shared_info *shinfo;
struct page *page;
int need_spc, len;
@@ -398,7 +402,7 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort)
* to read the data out. Otherwise the connection will stall.
* Without pressure threshold of INT_MAX will never be ready.
*/
- if (likely(qshort && !tcp_epollin_ready(strp->sk, INT_MAX)))
+ if (likely(qshort && !ctx->ops->epollin_ready(strp->sk)))
return 0;
shinfo = skb_shinfo(strp->anchor);
@@ -434,12 +438,13 @@ static int tls_strp_read_copy(struct tls_strparser *strp, bool qshort)
static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
{
unsigned int len = strp->stm.offset + strp->stm.full_len;
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
struct sk_buff *first, *skb;
u32 seq;
first = skb_shinfo(strp->anchor)->frag_list;
skb = first;
- seq = TCP_SKB_CB(first)->seq;
+ seq = ctx->ops->get_skb_seq(first);
/* Make sure there's no duplicate data in the queue,
* and the decrypted status matches.
@@ -449,7 +454,7 @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
len -= skb->len;
skb = skb->next;
- if (TCP_SKB_CB(skb)->seq != seq)
+ if (ctx->ops->get_skb_seq(skb) != seq)
return false;
if (skb_cmp_decrypted(first, skb))
return false;
@@ -460,11 +465,11 @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
static void tls_strp_load_anchor_with_queue(struct tls_strparser *strp, int len)
{
- struct tcp_sock *tp = tcp_sk(strp->sk);
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
struct sk_buff *first;
u32 offset;
- first = tcp_recv_skb(strp->sk, tp->copied_seq, &offset);
+ first = ctx->ops->recv_skb(strp->sk, &offset);
if (WARN_ON_ONCE(!first))
return;
@@ -483,6 +488,7 @@ static void tls_strp_load_anchor_with_queue(struct tls_strparser *strp, int len)
bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh)
{
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
struct strp_msg *rxm;
struct tls_msg *tlm;
@@ -490,7 +496,7 @@ 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(ctx->ops->inq(strp->sk) < strp->stm.full_len)) {
WRITE_ONCE(strp->msg_ready, 0);
memset(&strp->stm, 0, sizeof(strp->stm));
return false;
@@ -511,9 +517,10 @@ bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh)
/* Called with lock held on lower socket */
static int tls_strp_read_sock(struct tls_strparser *strp)
{
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
int sz, inq;
- inq = tcp_inq(strp->sk);
+ inq = ctx->ops->inq(strp->sk);
if (inq < 1)
return 0;
@@ -583,10 +590,12 @@ static void tls_strp_work(struct work_struct *w)
void tls_strp_msg_done(struct tls_strparser *strp)
{
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
+
WARN_ON(!strp->stm.full_len);
if (likely(!strp->copy_mode))
- tcp_read_done(strp->sk, strp->stm.full_len);
+ ctx->ops->read_done(strp->sk, strp->stm.full_len);
else
tls_strp_flush_anchor_copy(strp);
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index a656ce235758..b6959ebcded8 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -1952,13 +1952,14 @@ tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot,
size_t len_left, size_t decrypted, ssize_t done,
size_t *flushed_at)
{
+ struct tls_context *tls_ctx = tls_get_ctx(sk);
size_t max_rec;
if (len_left <= decrypted)
return false;
max_rec = prot->overhead_size - prot->tail_size + TLS_MAX_PAYLOAD_SIZE;
- if (done - *flushed_at < SZ_128K && tcp_inq(sk) > max_rec)
+ if (done - *flushed_at < SZ_128K && tls_ctx->ops->inq(sk) > max_rec)
return false;
*flushed_at = done;
@@ -2445,6 +2446,7 @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb)
size_t cipher_overhead;
size_t data_len = 0;
int ret;
+ u32 seq;
/* Verify that we have a full TLS header, or wait for more data */
if (strp->stm.offset + prot->prepend_size > skb->len)
@@ -2487,8 +2489,9 @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb)
goto read_failure;
}
+ seq = tls_ctx->ops->get_skb_seq(skb);
tls_device_rx_resync_new_rec(strp->sk, data_len + TLS_HEADER_SIZE,
- TCP_SKB_CB(skb)->seq + strp->stm.offset);
+ seq + strp->stm.offset);
return data_len + TLS_HEADER_SIZE;
read_failure:
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 03/14] tls: add MPTCP SKB offset check in strp queue walk
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 01/14] tls: introduce struct tls_prot_ops for protocol ops Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 02/14] tls: add tls_prot_ops pointer to tls_context Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 04/14] mptcp: update mptcp_check_readable for TLS use Geliang Tang
` (11 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Gang Yan, Geliang Tang
From: Gang Yan <yangang@kylinos.cn>
In MPTCP, subflow SKBs can have non-zero offsets due to out-of-order
handling or partial delivery. When walking the TLS strp queue for
sequence and decryption checks, validate each SKB's offset except the
first using get_skb_off() to ensure queue consistency. This is specific
to MPTCP, as TCP does not require offset checks.
If any invalid offset is found, return false to trigger resynchronization.
Co-developed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
---
net/tls/tls_strp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c
index ef1a8659ee18..b6798d09c922 100644
--- a/net/tls/tls_strp.c
+++ b/net/tls/tls_strp.c
@@ -454,6 +454,9 @@ static bool tls_strp_check_queue_ok(struct tls_strparser *strp)
len -= skb->len;
skb = skb->next;
+ if (ctx->ops->get_skb_off &&
+ ctx->ops->get_skb_off(skb))
+ return false;
if (ctx->ops->get_skb_seq(skb) != seq)
return false;
if (skb_cmp_decrypted(first, skb))
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 04/14] mptcp: update mptcp_check_readable for TLS use
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (2 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 03/14] tls: add MPTCP SKB offset check in strp queue walk Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 05/14] mptcp: avoid sleeping in read_sock path under softirq Geliang Tang
` (10 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Gang Yan, Geliang Tang
From: Gang Yan <yangang@kylinos.cn>
This patch makes mptcp_check_readable() aligned with TCP, and renames it to
mptcp_stream_is_readable(). It will be used in the case of KTLS, because
'prot' will be modified, tls_sw_sock_is_readable() is expected to be called
from prot->sock_is_readable().
Co-developed-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Geliang Tang <geliang@kernel.org>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
---
net/mptcp/protocol.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 023a4fb68617..5585f43cf879 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3309,9 +3309,11 @@ void __mptcp_unaccepted_force_close(struct sock *sk)
__mptcp_destroy_sock(sk);
}
-static __poll_t mptcp_check_readable(struct sock *sk)
+static bool mptcp_stream_is_readable(struct sock *sk)
{
- return mptcp_epollin_ready(sk) ? EPOLLIN | EPOLLRDNORM : 0;
+ if (mptcp_epollin_ready(sk))
+ return true;
+ return sk_is_readable(sk);
}
static void mptcp_check_listen_stop(struct sock *sk)
@@ -4373,7 +4375,8 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
if (state != TCP_SYN_SENT && state != TCP_SYN_RECV) {
- mask |= mptcp_check_readable(sk);
+ if (mptcp_stream_is_readable(sk))
+ mask |= EPOLLIN | EPOLLRDNORM;
if (shutdown & SEND_SHUTDOWN)
mask |= EPOLLOUT | EPOLLWRNORM;
else
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 05/14] mptcp: avoid sleeping in read_sock path under softirq
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (3 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 04/14] mptcp: update mptcp_check_readable for TLS use Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 06/14] mptcp: implement tls_mptcp_ops for MPTCP TLS Geliang Tang
` (9 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
When mptcp_read_sock() is called from softirq context via TLS
read_sock, lock_sock_fast() in mptcp_rcv_space_adjust() and
mptcp_cleanup_rbuf() may trigger might_sleep() warnings or
illegal sleeps, as softirq context cannot block.
Replace lock_sock_fast() with spin_trylock_bh() to make locking
non-blocking and context-safe. Skip operations if the lock cannot
be acquired.
Also introduce mptcp_data_trylock() in mptcp_move_skbs() to make
data locking non-blocking in the read_sock path.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/protocol.c | 21 +++++++++++----------
net/mptcp/protocol.h | 1 +
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 5585f43cf879..1903f5b1fc44 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -561,12 +561,11 @@ static void mptcp_send_ack(struct mptcp_sock *msk)
static void mptcp_subflow_cleanup_rbuf(struct sock *ssk, int copied)
{
- bool slow;
-
- slow = lock_sock_fast(ssk);
- if (tcp_can_send_ack(ssk))
+ if (!spin_trylock_bh(&ssk->sk_lock.slock))
+ return;
+ if (!sock_owned_by_user(ssk) && tcp_can_send_ack(ssk))
tcp_cleanup_rbuf(ssk, copied);
- unlock_sock_fast(ssk, slow);
+ spin_unlock_bh(&ssk->sk_lock.slock);
}
static bool mptcp_subflow_could_cleanup(const struct sock *ssk, bool rx_empty)
@@ -2194,14 +2193,15 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
*/
mptcp_for_each_subflow(msk, subflow) {
struct sock *ssk;
- bool slow;
ssk = mptcp_subflow_tcp_sock(subflow);
- slow = lock_sock_fast(ssk);
+ if (!spin_trylock_bh(&ssk->sk_lock.slock))
+ continue;
/* subflows can be added before tcp_init_transfer() */
- if (tcp_sk(ssk)->rcvq_space.space)
+ if (!sock_owned_by_user(ssk) &&
+ tcp_sk(ssk)->rcvq_space.space)
tcp_rcvbuf_grow(ssk, copied);
- unlock_sock_fast(ssk, slow);
+ spin_unlock_bh(&ssk->sk_lock.slock);
}
}
@@ -2299,7 +2299,8 @@ static bool mptcp_move_skbs(struct sock *sk)
bool enqueued = false;
u32 moved;
- mptcp_data_lock(sk);
+ if (!mptcp_data_trylock(sk))
+ return false;
while (mptcp_can_spool_backlog(sk, &skbs)) {
mptcp_data_unlock(sk);
enqueued |= __mptcp_move_skbs(sk, &skbs, &moved);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index f0eaba2c61fa..7d8531837736 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -378,6 +378,7 @@ struct mptcp_sock {
};
#define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock)
+#define mptcp_data_trylock(sk) spin_trylock_bh(&(sk)->sk_lock.slock)
#define mptcp_data_unlock(sk) spin_unlock_bh(&(sk)->sk_lock.slock)
#define mptcp_for_each_subflow(__msk, __subflow) \
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 06/14] mptcp: implement tls_mptcp_ops for MPTCP TLS
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (4 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 05/14] mptcp: avoid sleeping in read_sock path under softirq Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 07/14] tls: disable device offload for MPTCP sockets Geliang Tang
` (8 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
This patch implements the MPTCP-specific struct tls_prot_ops, named
'tls_mptcp_ops'.
Note that there is a slight difference between mptcp_inq() and
mptcp_inq_hint(), it does not return 1 when the socket is closed or
shut down; instead, it returns 0. Otherwise, it would break the
condition "inq < 1" in tls_strp_read_sock().
Passing an MPTCP socket to tcp_sock_rate_check_app_limited() can
trigger a crash. Here, an MPTCP version of check_app_limited() is
implemented, which calls tcp_sock_rate_check_app_limited() for each
subflow.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/mptcp.h | 2 +
include/net/tcp.h | 1 +
net/ipv4/tcp.c | 9 +++-
net/mptcp/protocol.c | 106 ++++++++++++++++++++++++++++++++++++++++---
net/tls/tls_main.c | 3 ++
5 files changed, 113 insertions(+), 8 deletions(-)
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 4cf59e83c1c5..02564eceeb7e 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -132,6 +132,8 @@ struct mptcp_pm_ops {
void (*release)(struct mptcp_sock *msk);
} ____cacheline_aligned_in_smp;
+extern struct tls_prot_ops tls_mptcp_ops;
+
#ifdef CONFIG_MPTCP
void mptcp_init(void);
diff --git a/include/net/tcp.h b/include/net/tcp.h
index f87bdacb5a69..b198938945bf 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -851,6 +851,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
/* tcp.c */
void tcp_get_info(struct sock *, struct tcp_info *);
+void tcp_sock_rate_check_app_limited(struct tcp_sock *tp);
void tcp_rate_check_app_limited(struct sock *sk);
/* Read 'sendfile()'-style from a TCP socket */
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index dfd677c689ef..23a35201a05a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1110,9 +1110,9 @@ int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, int *copied,
}
/* If a gap is detected between sends, mark the socket application-limited. */
-void tcp_rate_check_app_limited(struct sock *sk)
+void tcp_sock_rate_check_app_limited(struct tcp_sock *tp)
{
- struct tcp_sock *tp = tcp_sk(sk);
+ struct sock *sk = (struct sock *)tp;
if (/* We have less than one packet to send. */
tp->write_seq - tp->snd_nxt < tp->mss_cache &&
@@ -1125,6 +1125,11 @@ void tcp_rate_check_app_limited(struct sock *sk)
tp->app_limited =
(tp->delivered + tcp_packets_in_flight(tp)) ? : 1;
}
+
+void tcp_rate_check_app_limited(struct sock *sk)
+{
+ tcp_sock_rate_check_app_limited(tcp_sk(sk));
+}
EXPORT_SYMBOL_GPL(tcp_rate_check_app_limited);
int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 1903f5b1fc44..04f9b3a0ab29 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -24,11 +24,12 @@
#include <net/mptcp.h>
#include <net/hotdata.h>
#include <net/xfrm.h>
+#include <net/tls.h>
#include <asm/ioctls.h>
#include "protocol.h"
#include "mib.h"
-static unsigned int mptcp_inq_hint(const struct sock *sk);
+static unsigned int mptcp_inq_hint(struct sock *sk);
static bool mptcp_can_spool_backlog(struct sock *sk, struct list_head *skbs);
static void mptcp_backlog_spooled(struct sock *sk, u32 moved,
struct list_head *skbs);
@@ -1927,7 +1928,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)
+static int mptcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct page_frag *pfrag;
@@ -1938,8 +1939,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) ||
@@ -2047,7 +2046,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:
@@ -2058,6 +2056,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)
@@ -2312,7 +2321,7 @@ static bool mptcp_move_skbs(struct sock *sk)
return enqueued;
}
-static unsigned int mptcp_inq_hint(const struct sock *sk)
+static int mptcp_inq(struct sock *sk)
{
const struct mptcp_sock *msk = mptcp_sk(sk);
const struct sk_buff *skb;
@@ -2327,6 +2336,16 @@ static unsigned int mptcp_inq_hint(const struct sock *sk)
return (unsigned int)hint_val;
}
+ return 0;
+}
+
+static unsigned int mptcp_inq_hint(struct sock *sk)
+{
+ unsigned int inq = mptcp_inq(sk);
+
+ if (inq)
+ return inq;
+
if (sk->sk_state == TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN))
return 1;
@@ -4752,3 +4771,78 @@ int __init mptcp_proto_v6_init(void)
return err;
}
#endif
+
+static 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);
+ msk->bytes_consumed += used;
+ MPTCP_SKB_CB(skb)->offset += used;
+ MPTCP_SKB_CB(skb)->map_seq += used;
+ left -= 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_cleanup_rbuf(msk, len - left);
+}
+
+static u32 mptcp_get_skb_off(struct sk_buff *skb)
+{
+ return MPTCP_SKB_CB(skb)->offset;
+}
+
+static u32 mptcp_get_skb_seq(struct sk_buff *skb)
+{
+ return MPTCP_SKB_CB(skb)->map_seq;
+}
+
+static void mptcp_check_app_limited(struct sock *sk)
+{
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ struct mptcp_subflow_context *subflow;
+
+ mptcp_for_each_subflow(msk, subflow) {
+ struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+ bool slow;
+
+ slow = lock_sock_fast(ssk);
+ tcp_sock_rate_check_app_limited(tcp_sk(ssk));
+ unlock_sock_fast(ssk, slow);
+ }
+}
+
+struct tls_prot_ops tls_mptcp_ops = {
+ .protocol = IPPROTO_MPTCP,
+ .inq = mptcp_inq,
+ .sendmsg_locked = mptcp_sendmsg_locked,
+ .recv_skb = mptcp_recv_skb,
+ .read_sock = mptcp_read_sock,
+ .read_done = mptcp_read_done,
+ .get_skb_off = mptcp_get_skb_off,
+ .get_skb_seq = mptcp_get_skb_seq,
+ .poll = mptcp_poll,
+ .epollin_ready = mptcp_epollin_ready,
+ .check_app_limited = mptcp_check_app_limited,
+};
+EXPORT_SYMBOL(tls_mptcp_ops);
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index fe8ba116504a..d98beec89ddb 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -1342,6 +1342,9 @@ static int __init tls_register(void)
tcp_register_ulp(&tcp_tls_ulp_ops);
tls_register_prot_ops(&tls_tcp_ops);
+#ifdef CONFIG_MPTCP
+ tls_register_prot_ops(&tls_mptcp_ops);
+#endif
return 0;
err_strp:
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 07/14] tls: disable device offload for MPTCP sockets
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (5 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 06/14] mptcp: implement tls_mptcp_ops for MPTCP TLS Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 08/14] mptcp: update ULP getsockopt for TLS support Geliang Tang
` (7 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
MPTCP TLS hardware offload is not yet implemented. Return -EOPNOTSUPP
when attempting to enable device offload on MPTCP sockets.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/tls/tls_device.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index 99c8eff9783e..6744c2494740 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -1074,6 +1074,9 @@ int tls_set_device_offload(struct sock *sk)
ctx = tls_get_ctx(sk);
prot = &ctx->prot_info;
+ if (sk->sk_protocol == IPPROTO_MPTCP)
+ return -EOPNOTSUPP;
+
if (ctx->priv_ctx_tx)
return -EEXIST;
@@ -1196,6 +1199,9 @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx)
struct net_device *netdev;
int rc = 0;
+ if (sk->sk_protocol == IPPROTO_MPTCP)
+ return -EOPNOTSUPP;
+
if (ctx->crypto_recv.info.version != TLS_1_2_VERSION)
return -EOPNOTSUPP;
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 08/14] mptcp: update ULP getsockopt for TLS support
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (6 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 07/14] tls: disable device offload for MPTCP sockets Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 09/14] mptcp: enable ULP setsockopt " Geliang Tang
` (6 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
This patch extracts TCP_ULP getsockopt operation into a tcp_sock_get_ulp()
helper so that it can also be used in MPTCP.
TCP_ULP was obtained by calling mptcp_getsockopt_first_sf_only() to get
ULP of the first subflow. Now that the mechanism has changed, a new helper
mptcp_getsockopt_tcp_ulp() is added to get ULP of msk.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/linux/tcp.h | 1 +
net/ipv4/tcp.c | 36 ++++++++++++++++++++++--------------
net/mptcp/sockopt.c | 12 ++++++++++++
3 files changed, 35 insertions(+), 14 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 6982f10e826b..2bb1cbd3eeab 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -653,6 +653,7 @@ void tcp_sock_set_quickack(struct sock *sk, int val);
int tcp_sock_set_syncnt(struct sock *sk, int val);
int tcp_sock_set_user_timeout(struct sock *sk, int val);
int tcp_sock_set_maxseg(struct sock *sk, int val);
+int tcp_sock_get_ulp(struct sock *sk, sockptr_t optval, sockptr_t optlen);
static inline bool dst_tcp_usec_ts(const struct dst_entry *dst)
{
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 23a35201a05a..55d8fb848842 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -4495,6 +4495,27 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,
return stats;
}
+int tcp_sock_get_ulp(struct sock *sk, sockptr_t optval, sockptr_t optlen)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ int len;
+
+ if (copy_from_sockptr(&len, optlen, sizeof(int)))
+ return -EFAULT;
+ len = min_t(unsigned int, len, TCP_ULP_NAME_MAX);
+ if (!icsk->icsk_ulp_ops) {
+ len = 0;
+ if (copy_to_sockptr(optlen, &len, sizeof(int)))
+ return -EFAULT;
+ return 0;
+ }
+ if (copy_to_sockptr(optlen, &len, sizeof(int)))
+ return -EFAULT;
+ if (copy_to_sockptr(optval, icsk->icsk_ulp_ops->name, len))
+ return -EFAULT;
+ return 0;
+}
+
int do_tcp_getsockopt(struct sock *sk, int level,
int optname, sockptr_t optval, sockptr_t optlen)
{
@@ -4604,20 +4625,7 @@ int do_tcp_getsockopt(struct sock *sk, int level,
return 0;
case TCP_ULP:
- if (copy_from_sockptr(&len, optlen, sizeof(int)))
- return -EFAULT;
- len = min_t(unsigned int, len, TCP_ULP_NAME_MAX);
- if (!icsk->icsk_ulp_ops) {
- len = 0;
- if (copy_to_sockptr(optlen, &len, sizeof(int)))
- return -EFAULT;
- return 0;
- }
- if (copy_to_sockptr(optlen, &len, sizeof(int)))
- return -EFAULT;
- if (copy_to_sockptr(optval, icsk->icsk_ulp_ops->name, len))
- return -EFAULT;
- return 0;
+ return tcp_sock_get_ulp(sk, optval, optlen);
case TCP_FASTOPEN_KEY: {
u64 key[TCP_FASTOPEN_KEY_BUF_LENGTH / sizeof(u64)];
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index de90a2897d2d..a6230f7910fd 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -1393,6 +1393,17 @@ static int mptcp_put_int_option(struct mptcp_sock *msk, char __user *optval,
return 0;
}
+static int mptcp_getsockopt_tcp_ulp(struct sock *sk, char __user *optval,
+ int __user *optlen)
+{
+ int ret;
+
+ lock_sock(sk);
+ ret = tcp_sock_get_ulp(sk, USER_SOCKPTR(optval), USER_SOCKPTR(optlen));
+ release_sock(sk);
+ return ret;
+}
+
static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
char __user *optval, int __user *optlen)
{
@@ -1400,6 +1411,7 @@ static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
switch (optname) {
case TCP_ULP:
+ return mptcp_getsockopt_tcp_ulp(sk, optval, optlen);
case TCP_CONGESTION:
case TCP_INFO:
case TCP_CC_INFO:
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 09/14] mptcp: enable ULP setsockopt for TLS support
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (7 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 08/14] mptcp: update ULP getsockopt for TLS support Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 10/14] selftests: mptcp: connect: use espintcp for ULP test Geliang Tang
` (5 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
This patch extracts TCP_ULP setsockopt operation into a tcp_sock_set_ulp()
helper so that it can also be used in MPTCP.
Add MPTCP ULP setsockopt support in mptcp_setsockopt_sol_tcp().
This option cannot be set when the socket is in CLOSE or LISTEN state.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/linux/tcp.h | 1 +
net/ipv4/tcp.c | 42 ++++++++++++++++++++++++------------------
net/mptcp/sockopt.c | 27 ++++++++++++++++++++++++++-
3 files changed, 51 insertions(+), 19 deletions(-)
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 2bb1cbd3eeab..00538b1aa2f0 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -654,6 +654,7 @@ int tcp_sock_set_syncnt(struct sock *sk, int val);
int tcp_sock_set_user_timeout(struct sock *sk, int val);
int tcp_sock_set_maxseg(struct sock *sk, int val);
int tcp_sock_get_ulp(struct sock *sk, sockptr_t optval, sockptr_t optlen);
+int tcp_sock_set_ulp(struct sock *sk, sockptr_t optval, unsigned int optlen);
static inline bool dst_tcp_usec_ts(const struct dst_entry *dst)
{
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 55d8fb848842..8ebd2402847e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3858,6 +3858,28 @@ int tcp_sock_set_maxseg(struct sock *sk, int val)
return 0;
}
+int tcp_sock_set_ulp(struct sock *sk, sockptr_t optval, unsigned int optlen)
+{
+ char name[TCP_ULP_NAME_MAX];
+ int err = 0;
+ size_t len;
+ int val;
+
+ if (optlen < 1)
+ return -EINVAL;
+
+ len = min_t(long, TCP_ULP_NAME_MAX - 1, optlen);
+ val = strncpy_from_sockptr(name, optval, len);
+ if (val < 0)
+ return -EFAULT;
+ name[val] = 0;
+
+ sockopt_lock_sock(sk);
+ err = tcp_set_ulp(sk, name);
+ sockopt_release_sock(sk);
+ return err;
+}
+
/*
* Socket option code for TCP.
*/
@@ -3891,24 +3913,8 @@ int do_tcp_setsockopt(struct sock *sk, int level, int optname,
sockopt_release_sock(sk);
return err;
}
- case TCP_ULP: {
- char name[TCP_ULP_NAME_MAX];
-
- if (optlen < 1)
- return -EINVAL;
-
- val = strncpy_from_sockptr(name, optval,
- min_t(long, TCP_ULP_NAME_MAX - 1,
- optlen));
- if (val < 0)
- return -EFAULT;
- name[val] = 0;
-
- sockopt_lock_sock(sk);
- err = tcp_set_ulp(sk, name);
- sockopt_release_sock(sk);
- return err;
- }
+ case TCP_ULP:
+ return tcp_sock_set_ulp(sk, optval, optlen);
case TCP_FASTOPEN_KEY: {
__u8 key[TCP_FASTOPEN_KEY_BUF_LENGTH];
__u8 *backup_key = NULL;
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index a6230f7910fd..d04eb98aaa32 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;
}
@@ -815,6 +817,29 @@ static int mptcp_setsockopt_all_sf(struct mptcp_sock *msk, int level,
return ret;
}
+static int mptcp_setsockopt_tcp_ulp(struct sock *sk, sockptr_t optval,
+ unsigned int optlen)
+{
+ char name[TCP_ULP_NAME_MAX];
+ size_t len;
+ int val;
+
+ if (optlen < 1)
+ return -EINVAL;
+
+ len = min_t(long, TCP_ULP_NAME_MAX - 1, optlen);
+ val = strncpy_from_sockptr(name, optval, len);
+ if (val < 0)
+ return -EFAULT;
+ name[val] = 0;
+
+ if (strcmp(name, "tls\0"))
+ return -EOPNOTSUPP;
+ if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))
+ return -ENOTCONN;
+ return tcp_sock_set_ulp(sk, optval, optlen);
+}
+
static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
sockptr_t optval, unsigned int optlen)
{
@@ -823,7 +848,7 @@ static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
switch (optname) {
case TCP_ULP:
- return -EOPNOTSUPP;
+ return mptcp_setsockopt_tcp_ulp(sk, optval, optlen);
case TCP_CONGESTION:
return mptcp_setsockopt_sol_tcp_congestion(msk, optval, optlen);
case TCP_DEFER_ACCEPT:
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 10/14] selftests: mptcp: connect: use espintcp for ULP test
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (8 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 09/14] mptcp: enable ULP setsockopt " Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 11/14] selftests: tls: add MPTCP variants for testing Geliang Tang
` (4 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
With KTLS being implemented, "tls" should no longer be used in
sock_test_tcpulp(), it breaks mptcp_connect.sh tests. Another ULP
name, "espintcp", is set instead in this patch.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/config | 1 +
tools/testing/selftests/net/mptcp/mptcp_connect.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
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_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c
index cbe573c4ab3a..0d4a944c4269 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c
@@ -289,7 +289,7 @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line)
if (ret == 0)
X("setsockopt");
} else if (proto == IPPROTO_MPTCP) {
- ret = do_ulp_so(sock, "tls");
+ ret = do_ulp_so(sock, "espintcp");
if (ret != -1)
X("setsockopt");
}
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 11/14] selftests: tls: add MPTCP variants for testing
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (9 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 10/14] selftests: mptcp: connect: use espintcp for ULP test Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 12/14] selftests: tls: adjust timeouts and data for MPTCP Geliang Tang
` (3 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
To enable easy MPTCP socket creation in MPTCP TLS tests, two protocol
parameters (cli_proto and srv_proto) have been added to ulp_sock_pair().
These are passed as third arguments of socket(): 0 creates TCP sockets,
IPPROTO_MPTCP creates MPTCP sockets.
New variants "mptcp" are added both in FIXTURE_VARIANT(tls) and
FIXTURE(tls_err) to control whether to create MPTCP sockets or not for
tests.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/tls.c | 37 +++++++++++++++++++++----------
1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index 9e2ccea13d70..539a2bbea103 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -26,6 +26,10 @@
#define TLS_PAYLOAD_MAX_LEN 16384
#define SOL_TLS 282
+#ifndef IPPROTO_MPTCP
+#define IPPROTO_MPTCP 262
+#endif
+
static int fips_enabled;
struct tls_crypto_info_keys {
@@ -109,7 +113,8 @@ static void memrnd(void *s, size_t n)
}
static void ulp_sock_pair(struct __test_metadata *_metadata,
- int *fd, int *cfd, bool *notls)
+ int *fd, int *cfd, bool *notls,
+ int cli_proto, int srv_proto)
{
struct sockaddr_in addr;
socklen_t len;
@@ -122,8 +127,8 @@ static void ulp_sock_pair(struct __test_metadata *_metadata,
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = 0;
- *fd = socket(AF_INET, SOCK_STREAM, 0);
- sfd = socket(AF_INET, SOCK_STREAM, 0);
+ *fd = socket(AF_INET, SOCK_STREAM, cli_proto);
+ sfd = socket(AF_INET, SOCK_STREAM, srv_proto);
ret = bind(sfd, &addr, sizeof(addr));
ASSERT_EQ(ret, 0);
@@ -232,7 +237,7 @@ FIXTURE(tls_basic)
FIXTURE_SETUP(tls_basic)
{
- ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
+ ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls, 0, 0);
}
FIXTURE_TEARDOWN(tls_basic)
@@ -310,6 +315,7 @@ FIXTURE_VARIANT(tls)
uint16_t tls_version;
uint16_t cipher_type;
bool nopad, fips_non_compliant;
+ bool mptcp;
};
FIXTURE_VARIANT_ADD(tls, 12_aes_gcm)
@@ -407,7 +413,9 @@ FIXTURE_SETUP(tls)
tls_crypto_info_init(variant->tls_version, variant->cipher_type,
&tls12, 0);
- ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
+ ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls,
+ variant->mptcp ? IPPROTO_MPTCP : 0,
+ variant->mptcp ? IPPROTO_MPTCP : 0);
if (self->notls)
return;
@@ -2473,7 +2481,7 @@ FIXTURE_SETUP(zero_len)
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_CCM_128,
&tls12, 0);
- ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
+ ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls, 0, 0);
if (self->notls)
return;
@@ -2534,6 +2542,7 @@ FIXTURE(tls_err)
FIXTURE_VARIANT(tls_err)
{
uint16_t tls_version;
+ bool mptcp;
};
FIXTURE_VARIANT_ADD(tls_err, 12_aes_gcm)
@@ -2554,8 +2563,12 @@ FIXTURE_SETUP(tls_err)
tls_crypto_info_init(variant->tls_version, TLS_CIPHER_AES_GCM_128,
&tls12, 0);
- ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls);
- ulp_sock_pair(_metadata, &self->fd2, &self->cfd2, &self->notls);
+ ulp_sock_pair(_metadata, &self->fd, &self->cfd, &self->notls,
+ variant->mptcp ? IPPROTO_MPTCP : 0,
+ variant->mptcp ? IPPROTO_MPTCP : 0);
+ ulp_sock_pair(_metadata, &self->fd2, &self->cfd2, &self->notls,
+ variant->mptcp ? IPPROTO_MPTCP : 0,
+ variant->mptcp ? IPPROTO_MPTCP : 0);
if (self->notls)
return;
@@ -2906,7 +2919,7 @@ TEST(tls_12_tx_max_payload_len)
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_CCM_128,
&tls12, 0);
- ulp_sock_pair(_metadata, &fd, &cfd, ¬ls);
+ ulp_sock_pair(_metadata, &fd, &cfd, ¬ls, 0, 0);
if (notls)
exit(KSFT_SKIP);
@@ -2955,7 +2968,7 @@ TEST(tls_12_tx_max_payload_len_open_rec)
tls_crypto_info_init(TLS_1_2_VERSION, TLS_CIPHER_AES_CCM_128,
&tls12, 0);
- ulp_sock_pair(_metadata, &fd, &cfd, ¬ls);
+ ulp_sock_pair(_metadata, &fd, &cfd, ¬ls, 0, 0);
if (notls)
exit(KSFT_SKIP);
@@ -3058,7 +3071,7 @@ TEST(keysizes) {
tls12.info.version = TLS_1_2_VERSION;
tls12.info.cipher_type = TLS_CIPHER_AES_GCM_256;
- ulp_sock_pair(_metadata, &fd, &cfd, ¬ls);
+ ulp_sock_pair(_metadata, &fd, &cfd, ¬ls, 0, 0);
if (!notls) {
ret = setsockopt(fd, SOL_TLS, TLS_TX, &tls12,
@@ -3084,7 +3097,7 @@ TEST(no_pad) {
tls12.info.version = TLS_1_3_VERSION;
tls12.info.cipher_type = TLS_CIPHER_AES_GCM_256;
- ulp_sock_pair(_metadata, &fd, &cfd, ¬ls);
+ ulp_sock_pair(_metadata, &fd, &cfd, ¬ls, 0, 0);
if (notls)
exit(KSFT_SKIP);
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 12/14] selftests: tls: adjust timeouts and data for MPTCP
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (10 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 11/14] selftests: tls: add MPTCP variants for testing Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 13/14] selftests: tls: add MPTCP test cases Geliang Tang
` (2 subsequent siblings)
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
MPTCP requires longer timeouts in poll/epoll tests due to subflow
establishment delays and slower state transitions. Increase timeout
values to prevent false failures.
Double the data size in nonblocking test to accommodate MPTCP's
multi-subflow behavior and ensure sufficient data for testing.
In shutdown_reuse tests, add a delay after shutdown to ensure sockets
transition to TCPF_CLOSE before bind() reuse.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/tls.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index 539a2bbea103..24ed6deb40fd 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -1293,6 +1293,7 @@ TEST_F(tls, bidir)
TEST_F(tls, pollin)
{
+ int timeout = variant->mptcp ? 100 : 20;
char const *test_str = "test_poll";
struct pollfd fd = { 0, 0, 0 };
char buf[10];
@@ -1302,11 +1303,11 @@ TEST_F(tls, pollin)
fd.fd = self->cfd;
fd.events = POLLIN;
- EXPECT_EQ(poll(&fd, 1, 20), 1);
+ EXPECT_EQ(poll(&fd, 1, timeout), 1);
EXPECT_EQ(fd.revents & POLLIN, 1);
EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_WAITALL), send_len);
/* Test timing out */
- EXPECT_EQ(poll(&fd, 1, 20), 0);
+ EXPECT_EQ(poll(&fd, 1, timeout), 0);
}
TEST_F(tls, poll_wait)
@@ -1398,6 +1399,9 @@ TEST_F(tls, nonblocking)
int flags;
int res;
+ if (variant->mptcp)
+ data *= 2;
+
flags = fcntl(self->fd, F_GETFL, 0);
fcntl(self->fd, F_SETFL, flags | O_NONBLOCK);
fcntl(self->cfd, F_SETFL, flags | O_NONBLOCK);
@@ -1677,6 +1681,9 @@ TEST_F(tls, shutdown_reuse)
shutdown(self->cfd, SHUT_RDWR);
close(self->cfd);
+ if (variant->mptcp)
+ usleep(500000);
+
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = 0;
@@ -2725,6 +2732,7 @@ TEST_F(tls_err, timeo)
TEST_F(tls_err, poll_partial_rec)
{
+ int timeout = variant->mptcp ? 100 : 1;
struct pollfd pfd = { };
ssize_t rec_len;
char rec[256];
@@ -2735,7 +2743,7 @@ TEST_F(tls_err, poll_partial_rec)
pfd.fd = self->cfd2;
pfd.events = POLLIN;
- EXPECT_EQ(poll(&pfd, 1, 1), 0);
+ EXPECT_EQ(poll(&pfd, 1, timeout), 0);
memrnd(buf, sizeof(buf));
EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf));
@@ -2747,18 +2755,19 @@ TEST_F(tls_err, poll_partial_rec)
/* ... no full record should mean no POLLIN */
pfd.fd = self->cfd2;
pfd.events = POLLIN;
- EXPECT_EQ(poll(&pfd, 1, 1), 0);
+ EXPECT_EQ(poll(&pfd, 1, timeout), 0);
/* Now write the rest, and it should all pop out of the other end. */
EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100);
pfd.fd = self->cfd2;
pfd.events = POLLIN;
- EXPECT_EQ(poll(&pfd, 1, 1), 1);
+ EXPECT_EQ(poll(&pfd, 1, timeout), 1);
EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf));
EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0);
}
TEST_F(tls_err, epoll_partial_rec)
{
+ int timeout = variant->mptcp ? 100 : 0;
struct epoll_event ev, events[10];
ssize_t rec_len;
char rec[256];
@@ -2776,7 +2785,7 @@ TEST_F(tls_err, epoll_partial_rec)
ev.data.fd = self->cfd2;
ASSERT_GE(epoll_ctl(epollfd, EPOLL_CTL_ADD, self->cfd2, &ev), 0);
- EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0);
+ EXPECT_EQ(epoll_wait(epollfd, events, 10, timeout), 0);
memrnd(buf, sizeof(buf));
EXPECT_EQ(send(self->fd, buf, sizeof(buf), 0), sizeof(buf));
@@ -2786,10 +2795,10 @@ TEST_F(tls_err, epoll_partial_rec)
/* Write 100B, not the full record ... */
EXPECT_EQ(send(self->fd2, rec, 100, 0), 100);
/* ... no full record should mean no POLLIN */
- EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 0);
+ EXPECT_EQ(epoll_wait(epollfd, events, 10, timeout), 0);
/* Now write the rest, and it should all pop out of the other end. */
EXPECT_EQ(send(self->fd2, rec + 100, rec_len - 100, 0), rec_len - 100);
- EXPECT_EQ(epoll_wait(epollfd, events, 10, 0), 1);
+ EXPECT_EQ(epoll_wait(epollfd, events, 10, timeout), 1);
EXPECT_EQ(recv(self->cfd2, rec, sizeof(rec), 0), sizeof(buf));
EXPECT_EQ(memcmp(buf, rec, sizeof(buf)), 0);
@@ -2798,6 +2807,7 @@ TEST_F(tls_err, epoll_partial_rec)
TEST_F(tls_err, poll_partial_rec_async)
{
+ int timeout = variant->mptcp ? 100 : 20;
struct pollfd pfd = { };
char token = '\0';
ssize_t rec_len;
@@ -2841,13 +2851,13 @@ TEST_F(tls_err, poll_partial_rec_async)
/* Child should sleep in poll(), never get a wake */
pfd.fd = self->cfd2;
pfd.events = POLLIN;
- EXPECT_EQ(poll(&pfd, 1, 20), 0);
+ EXPECT_EQ(poll(&pfd, 1, timeout), 0);
EXPECT_EQ(write(p[1], &token, 1), 1); /* Barrier #1 */
pfd.fd = self->cfd2;
pfd.events = POLLIN;
- EXPECT_EQ(poll(&pfd, 1, 20), 1);
+ EXPECT_EQ(poll(&pfd, 1, timeout), 1);
exit(!__test_passed(_metadata));
}
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 13/14] selftests: tls: add MPTCP test cases
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (11 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 12/14] selftests: tls: adjust timeouts and data for MPTCP Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 9:12 ` [RFC mptcp-next v10 14/14] selftests: mptcp: add TLS tests to CI Geliang Tang
2026-03-17 10:41 ` [RFC mptcp-next v10 00/14] MPTCP KTLS support MPTCP CI
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
This patch introduces MPTCP test cases for the TLS fixture. These "mptcp"
variants are configured to create MPTCP sockets specifically for MPTCP TLS
testing purposes.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/tls.c | 108 ++++++++++++++++++++++++++++++
1 file changed, 108 insertions(+)
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index 24ed6deb40fd..b50dd855e407 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -401,6 +401,102 @@ FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256)
.cipher_type = TLS_CIPHER_ARIA_GCM_256,
};
+FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_mptcp)
+{
+ .tls_version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_AES_GCM_128,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .cipher_type = TLS_CIPHER_AES_GCM_128,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 12_chacha_mptcp)
+{
+ .tls_version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
+ .fips_non_compliant = true,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_chacha_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .cipher_type = TLS_CIPHER_CHACHA20_POLY1305,
+ .fips_non_compliant = true,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_sm4_gcm_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .cipher_type = TLS_CIPHER_SM4_GCM,
+ .fips_non_compliant = true,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_sm4_ccm_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .cipher_type = TLS_CIPHER_SM4_CCM,
+ .fips_non_compliant = true,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 12_aes_ccm_mptcp)
+{
+ .tls_version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_AES_CCM_128,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_aes_ccm_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .cipher_type = TLS_CIPHER_AES_CCM_128,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 12_aes_gcm_256_mptcp)
+{
+ .tls_version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_AES_GCM_256,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_aes_gcm_256_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .cipher_type = TLS_CIPHER_AES_GCM_256,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 13_nopad_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .cipher_type = TLS_CIPHER_AES_GCM_128,
+ .nopad = true,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_mptcp)
+{
+ .tls_version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_ARIA_GCM_128,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls, 12_aria_gcm_256_mptcp)
+{
+ .tls_version = TLS_1_2_VERSION,
+ .cipher_type = TLS_CIPHER_ARIA_GCM_256,
+ .mptcp = true,
+};
+
FIXTURE_SETUP(tls)
{
struct tls_crypto_info_keys tls12;
@@ -2562,6 +2658,18 @@ FIXTURE_VARIANT_ADD(tls_err, 13_aes_gcm)
.tls_version = TLS_1_3_VERSION,
};
+FIXTURE_VARIANT_ADD(tls_err, 12_aes_gcm_mptcp)
+{
+ .tls_version = TLS_1_2_VERSION,
+ .mptcp = true,
+};
+
+FIXTURE_VARIANT_ADD(tls_err, 13_aes_gcm_mptcp)
+{
+ .tls_version = TLS_1_3_VERSION,
+ .mptcp = true,
+};
+
FIXTURE_SETUP(tls_err)
{
struct tls_crypto_info_keys tls12;
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* [RFC mptcp-next v10 14/14] selftests: mptcp: add TLS tests to CI
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (12 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 13/14] selftests: tls: add MPTCP test cases Geliang Tang
@ 2026-03-17 9:12 ` Geliang Tang
2026-03-17 10:41 ` [RFC mptcp-next v10 00/14] MPTCP KTLS support MPTCP CI
14 siblings, 0 replies; 20+ messages in thread
From: Geliang Tang @ 2026-03-17 9:12 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang, Gang Yan
From: Geliang Tang <tanggeliang@kylinos.cn>
The mptcp tests for tls.c is available now, this patch adds mptcp_tls.sh
to test it in the MPTCP CI by default.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/Makefile | 2 +
tools/testing/selftests/net/mptcp/config | 3 ++
.../testing/selftests/net/mptcp/mptcp_tls.sh | 49 +++++++++++++++++++
tools/testing/selftests/net/mptcp/tls.c | 1 +
4 files changed, 55 insertions(+)
create mode 100755 tools/testing/selftests/net/mptcp/mptcp_tls.sh
create mode 120000 tools/testing/selftests/net/mptcp/tls.c
diff --git a/tools/testing/selftests/net/mptcp/Makefile b/tools/testing/selftests/net/mptcp/Makefile
index 22ba0da2adb8..f7c959a25b3b 100644
--- a/tools/testing/selftests/net/mptcp/Makefile
+++ b/tools/testing/selftests/net/mptcp/Makefile
@@ -14,6 +14,7 @@ TEST_PROGS := \
mptcp_connect_splice.sh \
mptcp_join.sh \
mptcp_sockopt.sh \
+ mptcp_tls.sh \
pm_netlink.sh \
simult_flows.sh \
userspace_pm.sh \
@@ -25,6 +26,7 @@ TEST_GEN_FILES := \
mptcp_inq \
mptcp_sockopt \
pm_nl_ctl \
+ tls \
# end of TEST_GEN_FILES
TEST_FILES := \
diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config
index 18bd29ac5b24..471c7e0ba2be 100644
--- a/tools/testing/selftests/net/mptcp/config
+++ b/tools/testing/selftests/net/mptcp/config
@@ -35,3 +35,6 @@ CONFIG_NFT_TPROXY=m
CONFIG_SYN_COOKIES=y
CONFIG_VETH=y
CONFIG_TLS=y
+CONFIG_CRYPTO_ARIA=y
+CONFIG_CRYPTO_CHACHA20POLY1305=m
+CONFIG_CRYPTO_SM4_GENERIC=y
diff --git a/tools/testing/selftests/net/mptcp/mptcp_tls.sh b/tools/testing/selftests/net/mptcp/mptcp_tls.sh
new file mode 100755
index 000000000000..b91be338ad0b
--- /dev/null
+++ b/tools/testing/selftests/net/mptcp/mptcp_tls.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+. "$(dirname "${0}")/mptcp_lib.sh"
+
+cleanup()
+{
+ if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
+ kill "$pid" 2>/dev/null
+ wait "$pid" 2>/dev/null
+ fi
+
+ mptcp_lib_ns_exit "$ns1"
+}
+
+init()
+{
+ mptcp_lib_ns_init ns1
+
+ local i
+ for i in $(seq 1 4); do
+ mptcp_lib_pm_nl_add_endpoint "$ns1" \
+ "127.0.0.1" flags signal port 1000"$i"
+ done
+
+ mptcp_lib_pm_nl_set_limits "$ns1" 8 8
+
+ ip netns exec "$ns1" ip mptcp endpoint show
+ ip netns exec "$ns1" ip mptcp limits
+}
+
+init
+trap cleanup EXIT
+
+ip netns exec "$ns1" ./tls -v 12_aes_gcm_mptcp \
+ -v 13_aes_gcm_mptcp \
+ -v 12_chacha_mptcp \
+ -v 13_chacha_mptcp \
+ -v 13_sm4_gcm_mptcp \
+ -v 13_sm4_ccm_mptcp \
+ -v 12_aes_ccm_mptcp \
+ -v 13_aes_ccm_mptcp \
+ -v 12_aes_gcm_256_mptcp \
+ -v 13_aes_gcm_256_mptcp \
+ -v 13_nopad_mptcp \
+ -v 12_aria_gcm_mptcp \
+ -v 12_aria_gcm_256_mptcp &
+pid=$!
+wait $pid
diff --git a/tools/testing/selftests/net/mptcp/tls.c b/tools/testing/selftests/net/mptcp/tls.c
new file mode 120000
index 000000000000..724b1f047c89
--- /dev/null
+++ b/tools/testing/selftests/net/mptcp/tls.c
@@ -0,0 +1 @@
+../tls.c
\ No newline at end of file
--
2.53.0
^ permalink raw reply related [flat|nested] 20+ messages in thread* Re: [RFC mptcp-next v10 00/14] MPTCP KTLS support
2026-03-17 9:12 [RFC mptcp-next v10 00/14] MPTCP KTLS support Geliang Tang
` (13 preceding siblings ...)
2026-03-17 9:12 ` [RFC mptcp-next v10 14/14] selftests: mptcp: add TLS tests to CI Geliang Tang
@ 2026-03-17 10:41 ` MPTCP CI
2026-03-17 13:15 ` Matthieu Baerts
14 siblings, 1 reply; 20+ messages in thread
From: MPTCP CI @ 2026-03-17 10:41 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): Success! ✅
- KVM Validation: normal (only selftest_mptcp_join): Success! ✅
- KVM Validation: debug (except selftest_mptcp_join): Critical: KMemLeak ❌
- 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/23187580083
Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/0a240102aca6
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1067840
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] 20+ messages in thread* Re: [RFC mptcp-next v10 00/14] MPTCP KTLS support
2026-03-17 10:41 ` [RFC mptcp-next v10 00/14] MPTCP KTLS support MPTCP CI
@ 2026-03-17 13:15 ` Matthieu Baerts
2026-03-20 7:45 ` Geliang Tang
0 siblings, 1 reply; 20+ messages in thread
From: Matthieu Baerts @ 2026-03-17 13:15 UTC (permalink / raw)
To: Geliang Tang; +Cc: mptcp
Hi Geliang,
On 17/03/2026 11:41, MPTCP CI wrote:
> 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): Success! ✅
> - KVM Validation: normal (only selftest_mptcp_join): Success! ✅
> - KVM Validation: debug (except selftest_mptcp_join): Critical: KMemLeak ❌
It looks like the leak is linked to the new code. Is that right?
No hurry if it is, it is just to make sure it is not linked to:
https://github.com/multipath-tcp/mptcp_net-next/issues/583
(if it is linked, then we have a reproducer, that might be helpful)
Cheers,
Matt
--
Sponsored by the NGI0 Core fund.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC mptcp-next v10 00/14] MPTCP KTLS support
2026-03-17 13:15 ` Matthieu Baerts
@ 2026-03-20 7:45 ` Geliang Tang
2026-03-20 8:07 ` Matthieu Baerts
0 siblings, 1 reply; 20+ messages in thread
From: Geliang Tang @ 2026-03-20 7:45 UTC (permalink / raw)
To: Matthieu Baerts, Geliang Tang; +Cc: mptcp
Hi Matt,
On Tue, 2026-03-17 at 14:15 +0100, Matthieu Baerts wrote:
> Hi Geliang,
>
> On 17/03/2026 11:41, MPTCP CI wrote:
> > 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): Success! ✅
> > - KVM Validation: normal (only selftest_mptcp_join): Success! ✅
> > - KVM Validation: debug (except selftest_mptcp_join): Critical:
> > KMemLeak ❌
>
> It looks like the leak is linked to the new code. Is that right?
Yes, it's related to the changes to shutdown_reuse() in patch 12, and
it has been fixed in v11.
However, I noticed that v10 and v11 didn't trigger AI review. Any idea
why?
Thanks,
-Geliang
>
> No hurry if it is, it is just to make sure it is not linked to:
>
> https://github.com/multipath-tcp/mptcp_net-next/issues/583
>
> (if it is linked, then we have a reproducer, that might be helpful)
>
> Cheers,
> Matt
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC mptcp-next v10 00/14] MPTCP KTLS support
2026-03-20 7:45 ` Geliang Tang
@ 2026-03-20 8:07 ` Matthieu Baerts
2026-03-24 18:58 ` Matthieu Baerts
0 siblings, 1 reply; 20+ messages in thread
From: Matthieu Baerts @ 2026-03-20 8:07 UTC (permalink / raw)
To: Geliang Tang; +Cc: Geliang Tang, mptcp
Hi Geliang,
20 Mar 2026 08:45:58 Geliang Tang <geliang@kernel.org>:
> Hi Matt,
>
> On Tue, 2026-03-17 at 14:15 +0100, Matthieu Baerts wrote:
>> Hi Geliang,
>>
>> On 17/03/2026 11:41, MPTCP CI wrote:
>>> 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): Success! ✅
>>> - KVM Validation: normal (only selftest_mptcp_join): Success! ✅
>>> - KVM Validation: debug (except selftest_mptcp_join): Critical:
>>> KMemLeak ❌
>>
>> It looks like the leak is linked to the new code. Is that right?
>
> Yes, it's related to the changes to shutdown_reuse() in patch 12, and
> it has been fixed in v11.
Great, thanks!
> However, I noticed that v10 and v11 didn't trigger AI review. Any idea
> why?
Not sure, maybe the RFC prefix?
Cheers,
Matt
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [RFC mptcp-next v10 00/14] MPTCP KTLS support
2026-03-20 8:07 ` Matthieu Baerts
@ 2026-03-24 18:58 ` Matthieu Baerts
0 siblings, 0 replies; 20+ messages in thread
From: Matthieu Baerts @ 2026-03-24 18:58 UTC (permalink / raw)
To: Geliang Tang; +Cc: Geliang Tang, mptcp
Hi Geliang,
On 20/03/2026 09:07, Matthieu Baerts wrote:
> Hi Geliang,
>
> 20 Mar 2026 08:45:58 Geliang Tang <geliang@kernel.org>:
>
>> Hi Matt,
>>
>> On Tue, 2026-03-17 at 14:15 +0100, Matthieu Baerts wrote:
>>> Hi Geliang,
>>>
>>> On 17/03/2026 11:41, MPTCP CI wrote:
>>>> 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): Success! ✅
>>>> - KVM Validation: normal (only selftest_mptcp_join): Success! ✅
>>>> - KVM Validation: debug (except selftest_mptcp_join): Critical:
>>>> KMemLeak ❌
>>>
>>> It looks like the leak is linked to the new code. Is that right?
>>
>> Yes, it's related to the changes to shutdown_reuse() in patch 12, and
>> it has been fixed in v11.
>
> Great, thanks!
>
>> However, I noticed that v10 and v11 didn't trigger AI review. Any idea
>> why?
>
> Not sure, maybe the RFC prefix?
Most likely the AI review system doesn't support the Based-on tag you
are using, and it fails to apply the series without the dependence. I
don't have logs to confirm that.
Cheers,
Matt
--
Sponsored by the NGI0 Core fund.
^ permalink raw reply [flat|nested] 20+ messages in thread