* [RFC net-next 00/17] MPTCP KTLS support
@ 2026-06-22 10:43 Geliang Tang
2026-06-22 10:43 ` [RFC net-next 01/17] tls: make tls_ctx_create and update_sk_prot static Geliang Tang
` (17 more replies)
0 siblings, 18 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
Prior to this work, MPTCP did not support TLS. The two protocols
conflicted because both MPTCP and TLS use the ULP (Upper Layer
Protocol) infrastructure in the Linux kernel. ULP settings, including
TLS configuration, were disabled in MPTCP. If an application attempted
to set TLS for an MPTCP socket, the system would return an error code
indicating EOPNOTSUPP (Operation not supported).
This series adds KTLS support for MPTCP. Since no ULP is currently
attached to the MPTCP socket (msk), KTLS can be configured directly on
the msk rather than on individual subflows. This does not affect its
existing communication, and leverages HMAC-based authentication to
ensure subflow security.
RFC versions of this series have gone through many iterations on MPTCP
mailing list, mainly to address Sashiko's review comments. It is now mostly
stable.
A follow-up series will add MPTCP support to the TLS selftests
(tools/testing/selftests/net/tls.c). All existing TCP test cases have
already been verified to pass over MPTCP as well.
The primary validation use case for this work is NVMe over MPTCP with KTLS.
NVMe over TCP is a storage protocol that transports NVMe commands over TCP.
By combining it with MPTCP, multipath capabilities for storage traffic are
gained. By adding KTLS, the storage traffic is secured with encryption.
Although NVMe over MPTCP is still under active development, I have already
verified that KTLS operates correctly on top of it.
All feedback is welcome.
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/480
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Gang Yan (1):
mptcp: update mptcp_check_readable helper
Geliang Tang (16):
tls: make tls_ctx_create and update_sk_prot static
tls: factor out __tls_build_proto for mptcp support
tls: add protocol dimension to tls operation cache
mptcp: add sendmsg_locked to proto_ops
tls: use sendmsg_locked from the underlying socket
mptcp: implement peek_len for proto_ops
tls: replace tcp_inq with socket peek_len
tls: store original read_sock for non-tcp sockets
tls: introduce tls protocol ops structure
tls: use protocol ops via tls_context
mptcp: implement mptcp-specific tls protocol ops
tls: add mptcp support for sk_poll
tls: disable device offload for mptcp sockets
mptcp: implement ulp getsockopt for tls support
mptcp: implement ulp setsockopt for tls support
selftests: mptcp: connect: use espintcp for ulp test
include/net/mptcp.h | 11 +
include/net/tcp.h | 1 +
include/net/tls.h | 19 ++
net/ipv4/tcp.c | 9 +-
net/mptcp/protocol.c | 180 +++++++++++++-
net/mptcp/protocol.h | 1 +
net/mptcp/sockopt.c | 68 +++++-
net/tls/tls.h | 2 -
net/tls/tls_device.c | 10 +-
net/tls/tls_main.c | 227 +++++++++++++++---
net/tls/tls_strp.c | 35 ++-
net/tls/tls_sw.c | 10 +-
tools/testing/selftests/net/mptcp/config | 4 +
.../selftests/net/mptcp/mptcp_connect.c | 4 +-
14 files changed, 516 insertions(+), 65 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC net-next 01/17] tls: make tls_ctx_create and update_sk_prot static
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 02/17] tls: factor out __tls_build_proto for mptcp support Geliang Tang
` (16 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
The TLS TOE (TCP offload engine) support has been removed. As a result,
tls_ctx_create() and update_sk_prot() are no longer used outside of
tls_main.c.
Make them static and remove their prototypes from tls.h. This avoids
exporting unnecessary symbols and cleans up the internal API.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/tls/tls.h | 2 --
net/tls/tls_main.c | 4 ++--
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/net/tls/tls.h b/net/tls/tls.h
index 60a37bdaaa25..68dfe109808e 100644
--- a/net/tls/tls.h
+++ b/net/tls/tls.h
@@ -136,9 +136,7 @@ struct tls_rec {
int __net_init tls_proc_init(struct net *net);
void __net_exit tls_proc_fini(struct net *net);
-struct tls_context *tls_ctx_create(struct sock *sk);
void tls_ctx_free(struct sock *sk, struct tls_context *ctx);
-void update_sk_prot(struct sock *sk, struct tls_context *ctx);
int wait_on_pending_writer(struct sock *sk, long *timeo);
void tls_err_abort(struct sock *sk, int err);
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 8c588cdab733..9675c75bc50c 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -126,7 +126,7 @@ 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);
-void update_sk_prot(struct sock *sk, struct tls_context *ctx)
+static void update_sk_prot(struct sock *sk, struct tls_context *ctx)
{
int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
@@ -913,7 +913,7 @@ static int tls_disconnect(struct sock *sk, int flags)
return -EOPNOTSUPP;
}
-struct tls_context *tls_ctx_create(struct sock *sk)
+static struct tls_context *tls_ctx_create(struct sock *sk)
{
struct inet_connection_sock *icsk = inet_csk(sk);
struct tls_context *ctx;
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 02/17] tls: factor out __tls_build_proto for mptcp support
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
2026-06-22 10:43 ` [RFC net-next 01/17] tls: make tls_ctx_create and update_sk_prot static Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 03/17] tls: add protocol dimension to tls operation cache Geliang Tang
` (15 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
tls_build_proto() contains duplicated logic for building IPv4 and IPv6
TLS protocol caches.
Factor out the common code into a new helper __tls_build_proto(), which
takes the saved protocol pointer, mutex, and IP family as parameters.
This prepares for adding MPTCP support by reducing the amount of
duplicated code needed when introducing additional protocol variants.
No functional change intended.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/tls/tls_main.c | 46 ++++++++++++++++++++++++----------------------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 9675c75bc50c..be824affd1b1 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -968,35 +968,37 @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG]
#endif
}
-static void tls_build_proto(struct sock *sk)
+static void __tls_build_proto(struct sock *sk,
+ const struct proto *saved_prot,
+ struct mutex *prot_mutex,
+ int family)
{
int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
struct proto *prot = READ_ONCE(sk->sk_prot);
- /* Build IPv6 TLS whenever the address of tcpv6 _prot changes */
- if (ip_ver == TLSV6 &&
- unlikely(prot != smp_load_acquire(&saved_tcpv6_prot))) {
- mutex_lock(&tcpv6_prot_mutex);
- if (likely(prot != saved_tcpv6_prot)) {
- build_protos(tls_prots[TLSV6], prot);
- build_proto_ops(tls_proto_ops[TLSV6],
- sk->sk_socket->ops);
- smp_store_release(&saved_tcpv6_prot, prot);
+ if (ip_ver == family) {
+ /* smp_load_acquire pairs with smp_store_release below */
+ if (unlikely(prot != smp_load_acquire(&saved_prot))) {
+ mutex_lock(prot_mutex);
+ if (likely(prot != saved_prot)) {
+ build_protos(tls_prots[family], prot);
+ build_proto_ops(tls_proto_ops[family],
+ sk->sk_socket->ops);
+ /* pairs with smp_load_acquire above */
+ smp_store_release(&saved_prot, prot);
+ }
+ mutex_unlock(prot_mutex);
}
- mutex_unlock(&tcpv6_prot_mutex);
}
+}
- if (ip_ver == TLSV4 &&
- unlikely(prot != smp_load_acquire(&saved_tcpv4_prot))) {
- mutex_lock(&tcpv4_prot_mutex);
- if (likely(prot != saved_tcpv4_prot)) {
- build_protos(tls_prots[TLSV4], prot);
- build_proto_ops(tls_proto_ops[TLSV4],
- sk->sk_socket->ops);
- smp_store_release(&saved_tcpv4_prot, prot);
- }
- mutex_unlock(&tcpv4_prot_mutex);
- }
+static void tls_build_proto(struct sock *sk)
+{
+ /* Build IPv6 TLS whenever the address of tcpv6 _prot changes */
+ __tls_build_proto(sk, saved_tcpv6_prot, &tcpv6_prot_mutex,
+ TLSV6);
+ __tls_build_proto(sk, saved_tcpv4_prot, &tcpv4_prot_mutex,
+ TLSV4);
}
static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 03/17] tls: add protocol dimension to tls operation cache
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
2026-06-22 10:43 ` [RFC net-next 01/17] tls: make tls_ctx_create and update_sk_prot static Geliang Tang
2026-06-22 10:43 ` [RFC net-next 02/17] tls: factor out __tls_build_proto for mptcp support Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 04/17] mptcp: add sendmsg_locked to proto_ops Geliang Tang
` (14 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
The current TLS operation cache is indexed solely by IP version
(IPv4/IPv6). This was sufficient when only TCP was supported.
Rename TLS_NUM_PROTS to TLS_NUM_FAMILY to accurately reflect that it
represents the number of address families.
With the introduction of MPTCP, both TCP and MPTCP sockets within the
same IP version now share the same cache entries. When an MPTCP socket
enables TLS, it overwrites the cache with MPTCP-specific operations,
causing existing TCP TLS sockets to use the wrong ops, leading to type
confusion and kernel panics.
Fix by extending the cache arrays with a protocol dimension to separate
TCP and MPTCP. Introduce TLSTCP and TLSMPTCP enum values, along with
separate saved protocol pointers and mutexes for MPTCP. update_sk_prot()
and __tls_build_proto() now select the appropriate cache based on
sk->sk_protocol.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/tls/tls_main.c | 40 +++++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 11 deletions(-)
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index be824affd1b1..94133d62f73e 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -53,7 +53,13 @@ MODULE_ALIAS_TCP_ULP("tls");
enum {
TLSV4,
TLSV6,
- TLS_NUM_PROTS,
+ TLS_NUM_FAMILY,
+};
+
+enum {
+ TLSTCP,
+ TLSMPTCP,
+ TLS_NUM_PROTO,
};
#define CHECK_CIPHER_DESC(cipher,ci) \
@@ -117,23 +123,30 @@ CHECK_CIPHER_DESC(TLS_CIPHER_SM4_CCM, tls12_crypto_info_sm4_ccm);
CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_128, tls12_crypto_info_aria_gcm_128);
CHECK_CIPHER_DESC(TLS_CIPHER_ARIA_GCM_256, tls12_crypto_info_aria_gcm_256);
+static const struct proto *saved_mptcpv6_prot;
+static DEFINE_MUTEX(mptcpv6_prot_mutex);
static const struct proto *saved_tcpv6_prot;
static DEFINE_MUTEX(tcpv6_prot_mutex);
+static const struct proto *saved_mptcpv4_prot;
+static DEFINE_MUTEX(mptcpv4_prot_mutex);
static const struct proto *saved_tcpv4_prot;
static DEFINE_MUTEX(tcpv4_prot_mutex);
-static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
-static struct proto_ops tls_proto_ops[TLS_NUM_PROTS][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
+static struct proto
+tls_prots[TLS_NUM_FAMILY][TLS_NUM_PROTO][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
+static struct proto_ops
+tls_proto_ops[TLS_NUM_FAMILY][TLS_NUM_PROTO][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
const struct proto *base);
static void update_sk_prot(struct sock *sk, struct tls_context *ctx)
{
+ int proto = sk->sk_protocol == IPPROTO_MPTCP ? TLSMPTCP : TLSTCP;
int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
WRITE_ONCE(sk->sk_prot,
- &tls_prots[ip_ver][ctx->tx_conf][ctx->rx_conf]);
+ &tls_prots[ip_ver][proto][ctx->tx_conf][ctx->rx_conf]);
WRITE_ONCE(sk->sk_socket->ops,
- &tls_proto_ops[ip_ver][ctx->tx_conf][ctx->rx_conf]);
+ &tls_proto_ops[ip_ver][proto][ctx->tx_conf][ctx->rx_conf]);
}
int wait_on_pending_writer(struct sock *sk, long *timeo)
@@ -971,18 +984,19 @@ static void build_proto_ops(struct proto_ops ops[TLS_NUM_CONFIG][TLS_NUM_CONFIG]
static void __tls_build_proto(struct sock *sk,
const struct proto *saved_prot,
struct mutex *prot_mutex,
- int family)
+ int family, int protocol)
{
+ int proto = sk->sk_protocol == IPPROTO_MPTCP ? TLSMPTCP : TLSTCP;
int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
struct proto *prot = READ_ONCE(sk->sk_prot);
- if (ip_ver == family) {
+ if (ip_ver == family && proto == protocol) {
/* smp_load_acquire pairs with smp_store_release below */
if (unlikely(prot != smp_load_acquire(&saved_prot))) {
mutex_lock(prot_mutex);
if (likely(prot != saved_prot)) {
- build_protos(tls_prots[family], prot);
- build_proto_ops(tls_proto_ops[family],
+ build_protos(tls_prots[family][protocol], prot);
+ build_proto_ops(tls_proto_ops[family][protocol],
sk->sk_socket->ops);
/* pairs with smp_load_acquire above */
smp_store_release(&saved_prot, prot);
@@ -995,10 +1009,14 @@ static void __tls_build_proto(struct sock *sk,
static void tls_build_proto(struct sock *sk)
{
/* Build IPv6 TLS whenever the address of tcpv6 _prot changes */
+ __tls_build_proto(sk, saved_mptcpv6_prot, &mptcpv6_prot_mutex,
+ TLSV6, TLSMPTCP);
__tls_build_proto(sk, saved_tcpv6_prot, &tcpv6_prot_mutex,
- TLSV6);
+ TLSV6, TLSTCP);
+ __tls_build_proto(sk, saved_mptcpv4_prot, &mptcpv4_prot_mutex,
+ TLSV4, TLSMPTCP);
__tls_build_proto(sk, saved_tcpv4_prot, &tcpv4_prot_mutex,
- TLSV4);
+ TLSV4, TLSTCP);
}
static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 04/17] mptcp: add sendmsg_locked to proto_ops
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (2 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 03/17] tls: add protocol dimension to tls operation cache Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 05/17] tls: use sendmsg_locked from the underlying socket Geliang Tang
` (13 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
MPTCP currently provides a standard sendmsg() implementation which
acquires and releases the socket lock internally. However, certain
upper layers (e.g., TLS) need to call the sendmsg method while the
socket lock is already held.
Split the existing mptcp_sendmsg() into mptcp_sendmsg_locked() which
assumes the caller holds the socket lock, and a tiny wrapper
mptcp_sendmsg() that acquires the lock and calls the locked version.
Expose .sendmsg_locked in both mptcp_stream_ops and mptcp_v6_stream_ops.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/protocol.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index a4f7e99b30db..7f0c560f6b7e 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1967,7 +1967,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;
@@ -1979,8 +1979,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
msg->msg_flags &= MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL |
MSG_FASTOPEN | MSG_EOR;
- lock_sock(sk);
-
mptcp_rps_record_subflows(msk);
if (unlikely(inet_test_bit(DEFER_CONNECT, sk) ||
@@ -2096,7 +2094,6 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
}
out:
- release_sock(sk);
return copied;
do_error:
@@ -2107,6 +2104,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)
@@ -4703,6 +4711,7 @@ static const struct proto_ops mptcp_stream_ops = {
.set_rcvlowat = mptcp_set_rcvlowat,
.read_sock = mptcp_read_sock,
.splice_read = mptcp_splice_read,
+ .sendmsg_locked = mptcp_sendmsg_locked,
};
static struct inet_protosw mptcp_protosw = {
@@ -4815,6 +4824,7 @@ static const struct proto_ops mptcp_v6_stream_ops = {
.set_rcvlowat = mptcp_set_rcvlowat,
.read_sock = mptcp_read_sock,
.splice_read = mptcp_splice_read,
+ .sendmsg_locked = mptcp_sendmsg_locked,
};
static struct proto mptcp_v6_prot;
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 05/17] tls: use sendmsg_locked from the underlying socket
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (3 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 04/17] mptcp: add sendmsg_locked to proto_ops Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 06/17] mptcp: implement peek_len for proto_ops Geliang Tang
` (12 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
TLS offload (device and sw) may call tcp_sendmsg_locked() directly
when pushing TLS records. This assumes the underlying socket is always
a TCP socket. With MPTCP, the socket can be an MPTCP socket, which
does not directly expose a sendmsg_locked method via its proto_ops.
Replace the hard-coded tcp_sendmsg_locked() call with
sk->sk_socket->ops->sendmsg_locked(). This enables TLS to work
transparently over any socket that implements .sendmsg_locked,
including MPTCP after the previous commit.
The change is safe because both TCP and MPTCP now provide a conformant
.sendmsg_locked implementation.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/tls/tls_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 94133d62f73e..b6adfa67491b 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -205,7 +205,7 @@ 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_socket->ops->sendmsg_locked(sk, &msg, size);
if (ret != size) {
if (ret > 0) {
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 06/17] mptcp: implement peek_len for proto_ops
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (4 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 05/17] tls: use sendmsg_locked from the underlying socket Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 07/17] tls: replace tcp_inq with socket peek_len Geliang Tang
` (11 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
The TLS stack uses tcp_inq() to query the amount of data available
in the receive queue without consuming it. For MPTCP sockets, this
information is not directly available from a TCP subflow; it must be
computed from the MPTCP receive queue and the current mapping.
Introduce mptcp_peek_len() which returns the number of bytes that
can be peeked from the MPTCP socket. It reuses the existing
mptcp_inq() helper (used by ioctl SIOCINQ). The implementation
considers the first skb in the receive queue, the current ack_seq,
and handles the FIN case.
Assign .peek_len in both mptcp_stream_ops and mptcp_v6_stream_ops
so that upper layers (e.g., TLS) can obtain the correct in-queue
byte count for an MPTCP connection.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/protocol.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 7f0c560f6b7e..18c8b6c64c3f 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -4689,6 +4689,38 @@ static ssize_t mptcp_splice_read(struct socket *sock, loff_t *ppos,
return ret;
}
+static int mptcp_inq(struct sock *sk)
+{
+ const struct mptcp_sock *msk = mptcp_sk(sk);
+ const struct sk_buff *skb;
+
+ if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))
+ return 0;
+
+ skb = skb_peek(&sk->sk_receive_queue);
+ if (skb) {
+ u64 answ = READ_ONCE(msk->ack_seq) - MPTCP_SKB_CB(skb)->map_seq;
+
+ if (answ >= INT_MAX)
+ answ = INT_MAX;
+
+ /* Subtract 1, if FIN was received */
+ if (answ &&
+ (sk->sk_state == TCP_CLOSE ||
+ (sk->sk_shutdown & RCV_SHUTDOWN)))
+ answ--;
+
+ return (int)answ;
+ }
+
+ return 0;
+}
+
+static int mptcp_peek_len(struct socket *sock)
+{
+ return mptcp_inq(sock->sk);
+}
+
static const struct proto_ops mptcp_stream_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
@@ -4712,6 +4744,7 @@ static const struct proto_ops mptcp_stream_ops = {
.read_sock = mptcp_read_sock,
.splice_read = mptcp_splice_read,
.sendmsg_locked = mptcp_sendmsg_locked,
+ .peek_len = mptcp_peek_len,
};
static struct inet_protosw mptcp_protosw = {
@@ -4825,6 +4858,7 @@ static const struct proto_ops mptcp_v6_stream_ops = {
.read_sock = mptcp_read_sock,
.splice_read = mptcp_splice_read,
.sendmsg_locked = mptcp_sendmsg_locked,
+ .peek_len = mptcp_peek_len,
};
static struct proto mptcp_v6_prot;
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 07/17] tls: replace tcp_inq with socket peek_len
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (5 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 06/17] mptcp: implement peek_len for proto_ops Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 08/17] tls: store original read_sock for non-tcp sockets Geliang Tang
` (10 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
TLS (device, strparser, and software) calls tcp_inq() directly to
determine how much data is still pending in the socket receive queue.
This breaks when the underlying socket is not TCP (e.g., MPTCP).
Switch all occurrences of tcp_inq(sk) to sk->sk_socket->ops->
peek_len(sk->sk_socket). This operation is implemented for both TCP
and MPTCP (after the previous commits), making TLS transparently
usable over MPTCP connections.
The change is straightforward: every place where TLS needed the
available in-queue bytes now uses the protocol-specific peek_len
method instead of assuming a TCP socket.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/tls/tls_device.c | 4 ++--
net/tls/tls_strp.c | 6 ++++--
net/tls/tls_sw.c | 4 +++-
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index 741aef09bfd3..c44a59d9d715 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -805,7 +805,7 @@ void tls_device_rx_resync_new_rec(struct sock *sk, u32 rcd_len, u32 seq)
/* head of next rec is already in, note that the sock_inq will
* include the currently parsed message when called from parser
*/
- sock_data = tcp_inq(sk);
+ sock_data = sk->sk_socket->ops->peek_len(sk->sk_socket);
if (sock_data > rcd_len) {
trace_tls_device_rx_resync_nh_delay(sk, sock_data,
rcd_len);
@@ -864,7 +864,7 @@ static void tls_device_core_ctrl_rx_resync(struct tls_context *tls_ctx,
rxm = strp_msg(skb);
/* head of next rec is already in, parser will sync for us */
- if (tcp_inq(sk) > rxm->full_len) {
+ if (sk->sk_socket->ops->peek_len(sk->sk_socket) > rxm->full_len) {
trace_tls_device_rx_resync_nh_schedule(sk);
ctx->resync_nh_do_now = 1;
} else {
diff --git a/net/tls/tls_strp.c b/net/tls/tls_strp.c
index 61b10c697ecc..82a5b64b5f48 100644
--- a/net/tls/tls_strp.c
+++ b/net/tls/tls_strp.c
@@ -484,12 +484,14 @@ bool tls_strp_msg_load(struct tls_strparser *strp, bool force_refresh)
{
struct strp_msg *rxm;
struct tls_msg *tlm;
+ int inq;
DEBUG_NET_WARN_ON_ONCE(!strp->msg_ready);
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)) {
+ inq = strp->sk->sk_socket->ops->peek_len(strp->sk->sk_socket);
+ if (unlikely(inq < strp->stm.full_len)) {
WRITE_ONCE(strp->msg_ready, 0);
strp->msg_announced = 0;
memset(&strp->stm, 0, sizeof(strp->stm));
@@ -513,7 +515,7 @@ static int tls_strp_read_sock(struct tls_strparser *strp)
{
int sz, inq;
- inq = tcp_inq(strp->sk);
+ inq = strp->sk->sk_socket->ops->peek_len(strp->sk->sk_socket);
if (inq < 1)
return 0;
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 9324e4ed20a3..35fb0c3c965a 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -1706,12 +1706,14 @@ tls_read_flush_backlog(struct sock *sk, struct tls_prot_info *prot,
size_t *flushed_at)
{
size_t max_rec;
+ int inq;
if (len_left <= decrypted)
return false;
+ inq = sk->sk_socket->ops->peek_len(sk->sk_socket);
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 && inq > max_rec)
return false;
*flushed_at = done;
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 08/17] tls: store original read_sock for non-tcp sockets
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (6 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 07/17] tls: replace tcp_inq with socket peek_len Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 09/17] tls: introduce tls protocol ops structure Geliang Tang
` (9 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
TLS strparser uses tcp_read_sock() to copy data from the underlying
socket. This assumes the socket is always TCP, which fails when TLS
is used over MPTCP.
Store the original socket's read_sock method (sk->sk_socket->ops->
read_sock) in a new .sk_read_sock callback inside struct tls_context.
Then in tls_strp_read_copyin(), call this stored callback instead of
the hard-coded tcp_read_sock().
With this change, TLS strparser works transparently over any socket
that implements .read_sock (including MPTCP, which already provides
mptcp_read_sock). Behavior for plain TCP remains unchanged.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/tls.h | 2 ++
net/tls/tls_main.c | 1 +
net/tls/tls_strp.c | 3 ++-
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/include/net/tls.h b/include/net/tls.h
index e57bef58851e..aee4f74dc3d9 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -262,6 +262,8 @@ struct tls_context {
struct sock *sk;
void (*sk_destruct)(struct sock *sk);
+ int (*sk_read_sock)(struct sock *sk, read_descriptor_t *desc,
+ sk_read_actor_t recv_actor);
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 b6adfa67491b..c9499bfd7a1d 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -1086,6 +1086,7 @@ 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->sk_read_sock = sk->sk_socket->ops->read_sock;
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 82a5b64b5f48..9945d17b2f8c 100644
--- a/net/tls/tls_strp.c
+++ b/net/tls/tls_strp.c
@@ -375,6 +375,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;
@@ -382,7 +383,7 @@ 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->sk_read_sock(strp->sk, &desc, tls_strp_copyin);
return desc.error;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 09/17] tls: introduce tls protocol ops structure
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (7 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 08/17] tls: store original read_sock for non-tcp sockets Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 10/17] tls: use protocol ops via tls_context Geliang Tang
` (8 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
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_register().
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/tls.h | 15 +++++++
net/tls/tls_main.c | 101 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 115 insertions(+), 1 deletion(-)
diff --git a/include/net/tls.h b/include/net/tls.h
index aee4f74dc3d9..500fe87b50d2 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -224,6 +224,21 @@ struct tls_prot_info {
u16 tail_size;
};
+struct tls_prot_ops {
+ struct module *owner;
+ struct list_head list;
+ int protocol;
+
+ struct sk_buff *(*recv_skb)(struct sock *sk, u32 *off);
+ bool (*lock_is_held)(struct sock *sk);
+ void (*read_done)(struct sock *sk, size_t len);
+ u32 (*get_skb_seq)(struct sk_buff *skb);
+ int (*skb_get_header)(const struct sk_buff *skb, int offset,
+ void *to, int len);
+ 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 c9499bfd7a1d..296d133fa61f 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -137,6 +137,8 @@ static struct proto_ops
tls_proto_ops[TLS_NUM_FAMILY][TLS_NUM_PROTO][TLS_NUM_CONFIG][TLS_NUM_CONFIG];
static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
const struct proto *base);
+static LIST_HEAD(tls_prot_ops_list);
+static DEFINE_SPINLOCK(tls_prot_ops_lock);
static void update_sk_prot(struct sock *sk, struct tls_context *ctx)
{
@@ -1059,6 +1061,22 @@ static void build_protos(struct proto prot[TLS_NUM_CONFIG][TLS_NUM_CONFIG],
#endif
}
+static struct tls_prot_ops *tls_prot_ops_find(int protocol)
+{
+ struct tls_prot_ops *ops, *ret = NULL;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ops, &tls_prot_ops_list, list) {
+ if (ops->protocol == protocol) {
+ ret = ops;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return ret;
+}
+
static int tls_init(struct sock *sk)
{
struct tls_context *ctx;
@@ -1245,6 +1263,80 @@ 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->recv_skb || !ops->lock_is_held ||
+ !ops->read_done || !ops->get_skb_seq ||
+ !ops->skb_get_header || !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_bh(&tls_prot_ops_lock);
+ if (tls_prot_ops_find(ops->protocol)) {
+ spin_unlock_bh(&tls_prot_ops_lock);
+ return -EEXIST;
+ }
+
+ list_add_tail_rcu(&ops->list, &tls_prot_ops_list);
+ spin_unlock_bh(&tls_prot_ops_lock);
+
+ pr_debug("tls_prot_ops %d registered\n", ops->protocol);
+ return 0;
+}
+
+static void tls_unregister_prot_ops(struct tls_prot_ops *ops)
+{
+ spin_lock_bh(&tls_prot_ops_lock);
+ list_del_rcu(&ops->list);
+ spin_unlock_bh(&tls_prot_ops_lock);
+ synchronize_rcu();
+}
+
+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 bool tls_tcp_lock_is_held(struct sock *sk)
+{
+ return sock_owned_by_user_nocheck(sk);
+}
+
+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 = {
+ .owner = THIS_MODULE,
+ .protocol = IPPROTO_TCP,
+ .recv_skb = tls_tcp_recv_skb,
+ .lock_is_held = tls_tcp_lock_is_held,
+ .read_done = tcp_read_done,
+ .get_skb_seq = tls_tcp_get_skb_seq,
+ .skb_get_header = skb_copy_bits,
+ .epollin_ready = tls_tcp_epollin_ready,
+ .check_app_limited = tcp_rate_check_app_limited,
+};
+
static int __init tls_register(void)
{
int err;
@@ -1257,13 +1349,19 @@ static int __init tls_register(void)
if (err)
goto err_pernet;
- err = tls_device_init();
+ err = tls_register_prot_ops(&tls_tcp_ops);
if (err)
goto err_strp;
+ err = tls_device_init();
+ if (err)
+ goto err_ops;
+
tcp_register_ulp(&tcp_tls_ulp_ops);
return 0;
+err_ops:
+ tls_unregister_prot_ops(&tls_tcp_ops);
err_strp:
tls_strp_dev_exit();
err_pernet:
@@ -1274,6 +1372,7 @@ static int __init tls_register(void)
static void __exit tls_unregister(void)
{
tcp_unregister_ulp(&tcp_tls_ulp_ops);
+ tls_unregister_prot_ops(&tls_tcp_ops);
tls_strp_dev_exit();
tls_device_cleanup();
unregister_pernet_subsys(&tls_proc_ops);
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 10/17] tls: use protocol ops via tls_context
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (8 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 09/17] tls: introduce tls protocol ops structure Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 11/17] mptcp: implement mptcp-specific tls protocol ops Geliang Tang
` (7 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
Currently, TLS code directly calls TCP-specific functions (e.g.,
tcp_rate_check_app_limited, tcp_read_done, tcp_epollin_ready, etc.)
and accesses TCP-specific fields (e.g., TCP_SKB_CB(skb)->seq).
This makes it hard to support other protocols like MPTCP.
Introduce a struct tls_prot_ops pointer in tls_context, which is
initialized during tls_init based on the socket protocol (TCP or
MPTCP). All protocol-dependent operations are now invoked via this
ops pointer, allowing each protocol to provide its own implementation.
Also add proper module reference counting for the ops owner.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/tls.h | 2 ++
net/tls/tls_main.c | 15 ++++++++++++++-
net/tls/tls_strp.c | 26 ++++++++++++++++++--------
net/tls/tls_sw.c | 6 ++++--
4 files changed, 38 insertions(+), 11 deletions(-)
diff --git a/include/net/tls.h b/include/net/tls.h
index 500fe87b50d2..9270de42787b 100644
--- a/include/net/tls.h
+++ b/include/net/tls.h
@@ -280,6 +280,8 @@ struct tls_context {
int (*sk_read_sock)(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor);
+ 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 296d133fa61f..b45890e75c9e 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -201,7 +201,7 @@ 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);
@@ -340,6 +340,11 @@ void tls_ctx_free(struct sock *sk, struct tls_context *ctx)
if (!ctx)
return;
+ if (ctx->ops) {
+ module_put(ctx->ops->owner);
+ ctx->ops = NULL;
+ }
+
memzero_explicit(&ctx->crypto_send, sizeof(ctx->crypto_send));
memzero_explicit(&ctx->crypto_recv, sizeof(ctx->crypto_recv));
mutex_destroy(&ctx->tx_lock);
@@ -1079,6 +1084,7 @@ static struct tls_prot_ops *tls_prot_ops_find(int protocol)
static int tls_init(struct sock *sk)
{
+ struct tls_prot_ops *ops;
struct tls_context *ctx;
int rc = 0;
@@ -1101,10 +1107,17 @@ static int tls_init(struct sock *sk)
goto out;
}
+ ops = tls_prot_ops_find(sk->sk_protocol);
+ if (!ops || !try_module_get(ops->owner)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
ctx->tx_conf = TLS_BASE;
ctx->rx_conf = TLS_BASE;
ctx->tx_max_payload_len = TLS_MAX_PAYLOAD_SIZE;
ctx->sk_read_sock = sk->sk_socket->ops->read_sock;
+ ctx->ops = ops;
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 9945d17b2f8c..48eb4b692f47 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 = tls_get_ctx(strp->sk);
struct sk_buff *skb;
if (strp->copy_mode)
@@ -132,7 +133,7 @@ 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->ops->read_done(strp->sk, strp->stm.full_len);
strp->copy_mode = 1;
return 0;
@@ -390,6 +391,7 @@ static int tls_strp_read_copyin(struct tls_strparser *strp)
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 +400,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 +436,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 +452,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 +463,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;
@@ -565,6 +568,11 @@ void tls_strp_check_rcv(struct tls_strparser *strp, bool announce)
/* Lower sock lock held */
void tls_strp_data_ready(struct tls_strparser *strp)
{
+ struct tls_context *ctx = tls_get_ctx(strp->sk);
+
+ if (!ctx)
+ return;
+
/* This check is needed to synchronize with do_tls_strp_work.
* do_tls_strp_work acquires a process lock (lock_sock) whereas
* the lock held here is bh_lock_sock. The two locks can be
@@ -572,7 +580,7 @@ void tls_strp_data_ready(struct tls_strparser *strp)
* allows a thread in BH context to safely check if the process
* lock is held. In this case, if the lock is held, queue work.
*/
- if (sock_owned_by_user_nocheck(strp->sk)) {
+ if (ctx->ops->lock_is_held(strp->sk)) {
queue_work(tls_strp_wq, &strp->work);
return;
}
@@ -597,10 +605,12 @@ static void tls_strp_work(struct work_struct *w)
*/
void tls_strp_msg_consume(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 35fb0c3c965a..71ab9763b1ed 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -2171,7 +2171,8 @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb)
}
/* Linearize header to local buffer */
- ret = skb_copy_bits(skb, strp->stm.offset, header, prot->prepend_size);
+ ret = tls_ctx->ops->skb_get_header(skb, strp->stm.offset, header,
+ prot->prepend_size);
if (ret < 0)
goto read_failure;
@@ -2202,7 +2203,8 @@ int tls_rx_msg_size(struct tls_strparser *strp, struct sk_buff *skb)
}
tls_device_rx_resync_new_rec(strp->sk, data_len + TLS_HEADER_SIZE,
- TCP_SKB_CB(skb)->seq + strp->stm.offset);
+ tls_ctx->ops->get_skb_seq(skb) +
+ strp->stm.offset);
return data_len + TLS_HEADER_SIZE;
read_failure:
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 11/17] mptcp: implement mptcp-specific tls protocol ops
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (9 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 10/17] tls: use protocol ops via tls_context Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 12/17] tls: add mptcp support for sk_poll Geliang Tang
` (6 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
This patch implements the MPTCP-specific struct tls_prot_ops, named
'tls_mptcp_ops'.
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.
When MPTCP implements lock_is_held interface, it not only checks
sock_owned_by_user_nocheck(sk) as TCP does, but also needs to check
whether the MPTCP data lock is held. This is required because TLS
may call lock_is_held from softirq context with bh_lock_sock held.
Checking both conditions ensures TLS always defers to workqueue when
the MPTCP data lock is held, avoiding deadlock.
Implement mptcp_skb_get_header() to handle fragmented MPTCP skbs when
copying TLS record headers.
In tls_strp_read_sock(), tls_strp_load_anchor_with_queue() first
attaches the skbs from TCP/MPTCP to the frag_list of strp->anchor.
In TCP, this is fine because the skb data is contiguous; however,
in MPTCP, each skb has its own offset, causing the data to be
non-contiguous. As a result, during the subsequent tls_rx_msg_size()
process, skb_copy_bits() may access across skbs. In MPTCP, the offset
of the second skb is ignored, leading to data access errors.
Therefore, mptcp_skb_get_header() can effectively handle this
problem and obtain the correct TLS header.
In the later process, tls_strp_check_queue_ok() handles the copy_mode
scenario. When an MPTCP skb has a non-zero offset, it falls back to
copy_mode, copying the valid data from each skb one by one into
anchor->frag_list, thus resolving the offset issue. Hence, the impact
of the offset within the TLS module is completely eliminated.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
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 | 113 +++++++++++++++++++++++++++++++++++++++++++
net/mptcp/protocol.h | 1 +
net/tls/tls_main.c | 13 +++++
6 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 333bde2a0b76..ba2257986b13 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 6d376ea4d1c0..ac823492d3e4 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -849,6 +849,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 b427f924608c..b875be6ae5bc 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1096,9 +1096,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 &&
@@ -1111,6 +1111,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 18c8b6c64c3f..f4cd7a6e5770 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -24,6 +24,7 @@
#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"
@@ -4894,3 +4895,115 @@ int __init mptcp_proto_v6_init(void)
return err;
}
#endif
+
+static bool mptcp_lock_is_held(struct sock *sk)
+{
+ return sock_owned_by_user_nocheck(sk) ||
+ mptcp_data_is_locked(sk);
+}
+
+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_seq(struct sk_buff *skb)
+{
+ return MPTCP_SKB_CB(skb)->map_seq - MPTCP_SKB_CB(skb)->offset;
+}
+
+static int mptcp_skb_get_header(const struct sk_buff *skb, int off,
+ void *buf, int len)
+{
+ const struct sk_buff *iter = skb_shinfo(skb)->frag_list;
+ int copied = 0;
+ int ret = 0;
+
+ if (!iter)
+ return skb_copy_bits(skb, off, buf, len);
+
+ /* Make absolute to positive */
+ off -= MPTCP_SKB_CB(iter)->offset;
+
+ while (iter && copied < len) {
+ int skb_off = MPTCP_SKB_CB(iter)->offset;
+ int data_len = iter->len - skb_off;
+ int count;
+
+ if (off >= data_len) {
+ off -= data_len; /* MPTCP skb avail data */
+ iter = iter->next;
+ continue;
+ }
+
+ count = min((int)(data_len - off), len - copied);
+ ret = skb_copy_bits(iter, skb_off + off, buf + copied, count);
+ if (ret)
+ break;
+ copied += count;
+ off = 0;
+ iter = iter->next;
+ }
+
+ if (copied < len && !ret)
+ ret = -EFAULT;
+ return ret;
+}
+
+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 = {
+ .owner = THIS_MODULE,
+ .protocol = IPPROTO_MPTCP,
+ .recv_skb = mptcp_recv_skb,
+ .lock_is_held = mptcp_lock_is_held,
+ .read_done = mptcp_read_done,
+ .get_skb_seq = mptcp_get_skb_seq,
+ .skb_get_header = mptcp_skb_get_header,
+ .epollin_ready = mptcp_epollin_ready,
+ .check_app_limited = mptcp_check_app_limited,
+};
+EXPORT_SYMBOL(tls_mptcp_ops);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index da40c6f3705f..6dea626348d9 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -380,6 +380,7 @@ struct mptcp_sock {
#define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock)
#define mptcp_data_unlock(sk) spin_unlock_bh(&(sk)->sk_lock.slock)
+#define mptcp_data_is_locked(sk) spin_is_locked(&(sk)->sk_lock.slock)
#define mptcp_for_each_subflow(__msk, __subflow) \
list_for_each_entry(__subflow, &((__msk)->conn_list), node)
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index b45890e75c9e..170ccbb9d36d 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -1366,6 +1366,12 @@ static int __init tls_register(void)
if (err)
goto err_strp;
+#ifdef CONFIG_MPTCP
+ err = tls_register_prot_ops(&tls_mptcp_ops);
+ if (err)
+ goto err_tcp;
+#endif
+
err = tls_device_init();
if (err)
goto err_ops;
@@ -1374,6 +1380,10 @@ static int __init tls_register(void)
return 0;
err_ops:
+#ifdef CONFIG_MPTCP
+ tls_unregister_prot_ops(&tls_mptcp_ops);
+err_tcp:
+#endif
tls_unregister_prot_ops(&tls_tcp_ops);
err_strp:
tls_strp_dev_exit();
@@ -1385,6 +1395,9 @@ static int __init tls_register(void)
static void __exit tls_unregister(void)
{
tcp_unregister_ulp(&tcp_tls_ulp_ops);
+#ifdef CONFIG_MPTCP
+ tls_unregister_prot_ops(&tls_mptcp_ops);
+#endif
tls_unregister_prot_ops(&tls_tcp_ops);
tls_strp_dev_exit();
tls_device_cleanup();
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 12/17] tls: add mptcp support for sk_poll
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (10 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 11/17] mptcp: implement mptcp-specific tls protocol ops Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 13/17] tls: disable device offload for mptcp sockets Geliang Tang
` (5 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
The tls_sk_poll() function currently uses tcp_poll() unconditionally
to obtain the base poll mask, which works only for TCP. This prevents
TLS over MPTCP from working correctly with poll().
Make the poll function protocol-aware by selecting the appropriate
poll function based on sk->sk_protocol. For TCP it calls tcp_poll(),
for MPTCP it calls mptcp_poll() (guarded by CONFIG_MPTCP). Any other
protocol returns 0.
Also export mptcp_poll() symbol so that the TLS module can use it.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
include/net/mptcp.h | 9 +++++++++
net/mptcp/protocol.c | 5 +++--
net/tls/tls_main.c | 17 ++++++++++++++++-
3 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index ba2257986b13..b0a172c38891 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -239,6 +239,9 @@ static inline __be32 mptcp_reset_option(const struct sk_buff *skb)
}
void mptcp_active_detect_blackhole(struct sock *sk, bool expired);
+
+__poll_t mptcp_poll(struct file *file, struct socket *sock,
+ struct poll_table_struct *wait);
#else
static inline void mptcp_init(void)
@@ -316,6 +319,12 @@ 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 __poll_t mptcp_poll(struct file *file, struct socket *sock,
+ struct poll_table_struct *wait)
+{
+ return 0;
+}
#endif /* CONFIG_MPTCP */
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index f4cd7a6e5770..169bd468f212 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -4446,8 +4446,8 @@ static __poll_t mptcp_check_writeable(struct mptcp_sock *msk)
return 0;
}
-static __poll_t mptcp_poll(struct file *file, struct socket *sock,
- struct poll_table_struct *wait)
+__poll_t mptcp_poll(struct file *file, struct socket *sock,
+ struct poll_table_struct *wait)
{
struct sock *sk = sock->sk;
struct mptcp_sock *msk;
@@ -4494,6 +4494,7 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
return mask;
}
+EXPORT_SYMBOL_GPL(mptcp_poll);
static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off)
{
diff --git a/net/tls/tls_main.c b/net/tls/tls_main.c
index 170ccbb9d36d..fa9fda3480da 100644
--- a/net/tls/tls_main.c
+++ b/net/tls/tls_main.c
@@ -416,6 +416,21 @@ static void tls_sk_proto_close(struct sock *sk, long timeout)
tls_ctx_free(sk, ctx);
}
+static __poll_t tls_proto_poll(struct file *file, struct socket *sock,
+ struct poll_table_struct *wait)
+{
+ switch (sock->sk->sk_protocol) {
+ case IPPROTO_TCP:
+ return tcp_poll(file, sock, wait);
+#ifdef CONFIG_MPTCP
+ case IPPROTO_MPTCP:
+ return mptcp_poll(file, sock, wait);
+#endif
+ default:
+ return 0;
+ }
+}
+
static __poll_t tls_sk_poll(struct file *file, struct socket *sock,
struct poll_table_struct *wait)
{
@@ -426,7 +441,7 @@ static __poll_t tls_sk_poll(struct file *file, struct socket *sock,
u8 shutdown;
int state;
- mask = tcp_poll(file, sock, wait);
+ mask = tls_proto_poll(file, sock, wait);
state = inet_sk_state_load(sk);
shutdown = READ_ONCE(sk->sk_shutdown);
--
2.53.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC net-next 13/17] tls: disable device offload for mptcp sockets
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (11 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 12/17] tls: add mptcp support for sk_poll Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 14/17] mptcp: update mptcp_check_readable helper Geliang Tang
` (4 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
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>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
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 c44a59d9d715..e535edc23d0d 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] 19+ messages in thread
* [RFC net-next 14/17] mptcp: update mptcp_check_readable helper
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (12 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 13/17] tls: disable device offload for mptcp sockets Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 15/17] mptcp: implement ulp getsockopt for tls support Geliang Tang
` (3 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Gang Yan, netdev, mptcp
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 169bd468f212..4951b1dd013b 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3410,9 +3410,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)
@@ -4476,7 +4478,8 @@ __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] 19+ messages in thread
* [RFC net-next 15/17] mptcp: implement ulp getsockopt for tls support
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (13 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 14/17] mptcp: update mptcp_check_readable helper Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 16/17] mptcp: implement ulp setsockopt " Geliang Tang
` (2 subsequent siblings)
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
Add mptcp_getsockopt_tcp_ulp() to handle TCP_ULP getsockopt on MPTCP
sockets. The helper reads the user length once, checks for negative
value, takes the socket lock, caps the length to TCP_ULP_NAME_MAX, and
copies the ULP name (or sets the length to zero if no ULP is attached)
to userspace. The lock ensures safe access to icsk->icsk_ulp_ops.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/sockopt.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index fcf6feb2a9eb..cc45491cd3b2 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -1408,6 +1408,39 @@ 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)
+{
+ struct inet_connection_sock *icsk = inet_csk(sk);
+ int ret = 0, len;
+
+ if (copy_from_sockptr(&len, USER_SOCKPTR(optlen), sizeof(int)))
+ return -EFAULT;
+
+ if (len < 0)
+ return -EINVAL;
+
+ lock_sock(sk);
+ len = min_t(unsigned int, len, TCP_ULP_NAME_MAX);
+ if (!icsk->icsk_ulp_ops) {
+ len = 0;
+ if (copy_to_sockptr(USER_SOCKPTR(optlen), &len, sizeof(int)))
+ ret = -EFAULT;
+ goto out;
+ }
+ if (copy_to_sockptr(USER_SOCKPTR(optlen), &len, sizeof(int))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if (copy_to_sockptr(USER_SOCKPTR(optval), icsk->icsk_ulp_ops->name,
+ len))
+ ret = -EFAULT;
+out:
+ release_sock(sk);
+ return ret;
+}
+
static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
char __user *optval, int __user *optlen)
{
@@ -1415,6 +1448,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] 19+ messages in thread
* [RFC net-next 16/17] mptcp: implement ulp setsockopt for tls support
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (14 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 15/17] mptcp: implement ulp getsockopt for tls support Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 10:43 ` [RFC net-next 17/17] selftests: mptcp: connect: use espintcp for ulp test Geliang Tang
2026-06-22 16:00 ` [RFC net-next 00/17] MPTCP KTLS support Jakub Kicinski
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
From: Geliang Tang <tanggeliang@kylinos.cn>
Allow MPTCP sockets to set the TCP_ULP socket option to enable TLS.
Add mptcp_setsockopt_tcp_ulp() which validates the socket state (must
not be CLOSE or LISTEN), only accepts "tls" as the ULP name, and then
calls tcp_set_ulp().
Include TCP_ULP in the list of supported options in supported_sockopt(),
and handle it in setsockopt_sol_tcp() instead of returning -EOPNOTSUPP.
Call tcp_cleanup_ulp() in mptcp_destroy_common() to release ULP module's
reference count.
Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/protocol.c | 1 +
net/mptcp/sockopt.c | 34 +++++++++++++++++++++++++++++++++-
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 4951b1dd013b..a13acee67688 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3765,6 +3765,7 @@ static void mptcp_destroy(struct sock *sk)
/* allow the following to close even the initial subflow */
msk->free_first = 1;
mptcp_destroy_common(msk);
+ tcp_cleanup_ulp(sk);
sk_sockets_allocated_dec(sk);
}
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index cc45491cd3b2..eeb348336195 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -577,6 +577,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;
}
@@ -830,6 +831,37 @@ 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];
+ 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;
+
+ if (strcmp(name, "tls"))
+ return -EOPNOTSUPP;
+
+ sockopt_lock_sock(sk);
+ if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) {
+ err = -ENOTCONN;
+ goto out;
+ }
+ err = tcp_set_ulp(sk, name);
+out:
+ sockopt_release_sock(sk);
+ return err;
+}
+
static int mptcp_setsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
sockptr_t optval, unsigned int optlen)
{
@@ -838,7 +870,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] 19+ messages in thread
* [RFC net-next 17/17] selftests: mptcp: connect: use espintcp for ulp test
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (15 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 16/17] mptcp: implement ulp setsockopt " Geliang Tang
@ 2026-06-22 10:43 ` Geliang Tang
2026-06-22 16:00 ` [RFC net-next 00/17] MPTCP KTLS support Jakub Kicinski
17 siblings, 0 replies; 19+ messages in thread
From: Geliang Tang @ 2026-06-22 10:43 UTC (permalink / raw)
To: Matthieu Baerts, Mat Martineau, Geliang Tang, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Neal Cardwell, Kuniyuki Iwashima, John Fastabend, Sabrina Dubroca,
Hannes Reinecke
Cc: Geliang Tang, netdev, mptcp, Gang Yan, Zqiang
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>
Co-developed-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Zqiang <qiang.zhang@linux.dev>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
tools/testing/selftests/net/mptcp/config | 4 ++++
tools/testing/selftests/net/mptcp/mptcp_connect.c | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/net/mptcp/config b/tools/testing/selftests/net/mptcp/config
index 59051ee2a986..f48bd5183fb3 100644
--- a/tools/testing/selftests/net/mptcp/config
+++ b/tools/testing/selftests/net/mptcp/config
@@ -34,3 +34,7 @@ CONFIG_NFT_SOCKET=m
CONFIG_NFT_TPROXY=m
CONFIG_SYN_COOKIES=y
CONFIG_VETH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_ESPINTCP=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_ESPINTCP=y
diff --git a/tools/testing/selftests/net/mptcp/mptcp_connect.c b/tools/testing/selftests/net/mptcp/mptcp_connect.c
index cbe573c4ab3a..299a7a02d6f5 100644
--- a/tools/testing/selftests/net/mptcp/mptcp_connect.c
+++ b/tools/testing/selftests/net/mptcp/mptcp_connect.c
@@ -285,11 +285,11 @@ static void sock_test_tcpulp(int sock, int proto, unsigned int line)
if (buflen > 0) {
if (strcmp(buf, "mptcp") != 0)
xerror("unexpected ULP '%s' for proto %d at line %u", buf, proto, line);
- ret = do_ulp_so(sock, "tls");
+ ret = do_ulp_so(sock, "espintcp");
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] 19+ messages in thread
* Re: [RFC net-next 00/17] MPTCP KTLS support
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
` (16 preceding siblings ...)
2026-06-22 10:43 ` [RFC net-next 17/17] selftests: mptcp: connect: use espintcp for ulp test Geliang Tang
@ 2026-06-22 16:00 ` Jakub Kicinski
17 siblings, 0 replies; 19+ messages in thread
From: Jakub Kicinski @ 2026-06-22 16:00 UTC (permalink / raw)
To: Geliang Tang
Cc: Matthieu Baerts, Mat Martineau, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Neal Cardwell, Kuniyuki Iwashima,
John Fastabend, Sabrina Dubroca, Hannes Reinecke, Geliang Tang,
netdev, mptcp, Gang Yan, Zqiang
On Mon, 22 Jun 2026 18:43:20 +0800 Geliang Tang wrote:
> Subject: [RFC net-next 00/17] MPTCP KTLS support
Please no. We have a ton of unfixed bugs and may have to revert some of
the features we dropped back in. I'd prefer to avoid large new bug
surfaces until we reach an LTS release.
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-06-22 16:01 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22 10:43 [RFC net-next 00/17] MPTCP KTLS support Geliang Tang
2026-06-22 10:43 ` [RFC net-next 01/17] tls: make tls_ctx_create and update_sk_prot static Geliang Tang
2026-06-22 10:43 ` [RFC net-next 02/17] tls: factor out __tls_build_proto for mptcp support Geliang Tang
2026-06-22 10:43 ` [RFC net-next 03/17] tls: add protocol dimension to tls operation cache Geliang Tang
2026-06-22 10:43 ` [RFC net-next 04/17] mptcp: add sendmsg_locked to proto_ops Geliang Tang
2026-06-22 10:43 ` [RFC net-next 05/17] tls: use sendmsg_locked from the underlying socket Geliang Tang
2026-06-22 10:43 ` [RFC net-next 06/17] mptcp: implement peek_len for proto_ops Geliang Tang
2026-06-22 10:43 ` [RFC net-next 07/17] tls: replace tcp_inq with socket peek_len Geliang Tang
2026-06-22 10:43 ` [RFC net-next 08/17] tls: store original read_sock for non-tcp sockets Geliang Tang
2026-06-22 10:43 ` [RFC net-next 09/17] tls: introduce tls protocol ops structure Geliang Tang
2026-06-22 10:43 ` [RFC net-next 10/17] tls: use protocol ops via tls_context Geliang Tang
2026-06-22 10:43 ` [RFC net-next 11/17] mptcp: implement mptcp-specific tls protocol ops Geliang Tang
2026-06-22 10:43 ` [RFC net-next 12/17] tls: add mptcp support for sk_poll Geliang Tang
2026-06-22 10:43 ` [RFC net-next 13/17] tls: disable device offload for mptcp sockets Geliang Tang
2026-06-22 10:43 ` [RFC net-next 14/17] mptcp: update mptcp_check_readable helper Geliang Tang
2026-06-22 10:43 ` [RFC net-next 15/17] mptcp: implement ulp getsockopt for tls support Geliang Tang
2026-06-22 10:43 ` [RFC net-next 16/17] mptcp: implement ulp setsockopt " Geliang Tang
2026-06-22 10:43 ` [RFC net-next 17/17] selftests: mptcp: connect: use espintcp for ulp test Geliang Tang
2026-06-22 16:00 ` [RFC net-next 00/17] MPTCP KTLS support Jakub Kicinski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox