From: "Matthieu Baerts (NGI0)" <matttbe@kernel.org>
To: Mat Martineau <martineau@kernel.org>,
Geliang Tang <geliang@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>
Cc: netdev@vger.kernel.org, mptcp@lists.linux.dev,
linux-kernel@vger.kernel.org,
"Matthieu Baerts (NGI0)" <matttbe@kernel.org>,
David Carlier <devnexen@gmail.com>
Subject: [PATCH net-next 1/4] mptcp: support MSG_ERRQUEUE on the parent socket
Date: Fri, 18 Sep 2026 20:38:25 +0200 [thread overview]
Message-ID: <20260918-net-next-mptcp-msg_errqueue-v1-1-dd77e1738248@kernel.org> (raw)
In-Reply-To: <20260918-net-next-mptcp-msg_errqueue-v1-0-dd77e1738248@kernel.org>
From: David Carlier <devnexen@gmail.com>
Splice pending err skbs from each subflow's error queue onto the parent
msk's error queue at error-report time, so poll() and recvmsg(MSG_ERRQUEUE)
on the parent socket observe TX timestamps through the standard inet ABI.
The splice filters by SO_EE_ORIGIN: TIMESTAMPING events forward to the
parent because they are tied to user-handed data, not to a specific
path; subflow-level ICMP errors are dropped because the legacy RECVERR
ABI cannot meaningfully convey their per-subflow peer identity to
single-path-aware userspace. Such events will be carried by a future
MPTCP_RECERR channel.
Forwarded events all go through sock_queue_err_skb(), which re-homes
skb->sk onto the parent and charges sk_rmem_alloc, so the parent's error
queue stays bounded by sk_rcvbuf and is dropped under rmem pressure
(sk_rmem_alloc + truesize >= sk_rcvbuf), matching tcp's sk_rcvbuf-gated
tx-timestamp path and ip_icmp_error() / ipv6_icmp_error(). The
MSG_ERRQUEUE branch of mptcp_recvmsg() forwards to inet_recv_error()
directly, and poll() advertises EPOLLERR purely on the parent's sk_err /
sk_error_queue, matching tcp_poll().
Signed-off-by: David Carlier <devnexen@gmail.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
---
net/mptcp/protocol.c | 55 +++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 46 insertions(+), 9 deletions(-)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index e89a69ab927c..15ae270ee6fd 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -11,6 +11,7 @@
#include <linux/netdevice.h>
#include <linux/sched/signal.h>
#include <linux/atomic.h>
+#include <linux/errqueue.h>
#include <net/aligned_data.h>
#include <net/rps.h>
#include <net/sock.h>
@@ -919,21 +920,52 @@ static bool __mptcp_ofo_queue(struct mptcp_sock *msk)
return moved;
}
+static bool mptcp_errqueue_skb_forwardable(const struct sk_buff *skb)
+{
+ /* Subflow-level ICMP errors are dropped: the legacy RECVERR ABI
+ * cannot convey their per-subflow peer identity.
+ */
+ return SKB_EXT_ERR(skb)->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING;
+}
+
+static bool __mptcp_subflow_splice_errqueue(struct sock *sk, struct sock *ssk)
+{
+ struct sk_buff *skb;
+ bool moved = false;
+
+ while ((skb = skb_dequeue(&ssk->sk_error_queue))) {
+ /* sock_queue_err_skb() re-homes skb->sk onto the parent and
+ * charges sk_rmem_alloc, bounding the queue by sk_rcvbuf.
+ */
+ if (!mptcp_errqueue_skb_forwardable(skb) ||
+ sock_queue_err_skb(sk, skb)) {
+ kfree_skb(skb);
+ continue;
+ }
+ moved = true;
+ }
+
+ return moved;
+}
+
static bool __mptcp_subflow_error_report(struct sock *sk, struct sock *ssk)
{
+ bool propagated = false;
int ssk_state;
+ bool report;
int err;
+ report = __mptcp_subflow_splice_errqueue(sk, ssk);
+
/* only propagate errors on fallen-back sockets or
* on MPC connect
*/
if (sk->sk_state != TCP_SYN_SENT && !__mptcp_check_fallback(mptcp_sk(sk)))
- return false;
+ goto out;
err = sock_error(ssk);
if (!err)
- return false;
-
+ goto out;
/* We need to propagate only transition to CLOSE state.
* Orphaned socket will see such state change via
* subflow_sched_work_if_closed() and that path will properly
@@ -943,11 +975,16 @@ static bool __mptcp_subflow_error_report(struct sock *sk, struct sock *ssk)
if (ssk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DEAD))
mptcp_set_state(sk, ssk_state);
WRITE_ONCE(sk->sk_err, -err);
+ report = true;
+ propagated = true;
- /* This barrier is coupled with smp_rmb() in mptcp_poll() */
- smp_wmb();
- sk_error_report(sk);
- return true;
+out:
+ if (report) {
+ /* This barrier is coupled with smp_rmb() in mptcp_poll() */
+ smp_wmb();
+ sk_error_report(sk);
+ }
+ return propagated;
}
void __mptcp_error_report(struct sock *sk)
@@ -2385,7 +2422,6 @@ static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
int target;
long timeo;
- /* MSG_ERRQUEUE is really a no-op till we support IP_RECVERR */
if (unlikely(flags & MSG_ERRQUEUE))
return inet_recv_error(sk, msg, len);
@@ -4523,7 +4559,8 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
/* This barrier is coupled with smp_wmb() in __mptcp_error_report() */
smp_rmb();
- if (READ_ONCE(sk->sk_err))
+ if (READ_ONCE(sk->sk_err) ||
+ !skb_queue_empty_lockless(&sk->sk_error_queue))
mask |= EPOLLERR;
return mask;
--
2.55.0
next prev parent reply other threads:[~2026-09-18 18:38 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 18:38 [PATCH net-next 0/4] mptcp: support MSG_ERRQUEUE Matthieu Baerts (NGI0)
2026-09-18 18:38 ` Matthieu Baerts (NGI0) [this message]
2026-09-21 18:39 ` [PATCH net-next 1/4] mptcp: support MSG_ERRQUEUE on the parent socket netdev-bot+sashiko
2026-09-22 13:30 ` Paolo Abeni
2026-09-22 20:59 ` David CARLIER
2026-09-18 18:38 ` [PATCH net-next 2/4] mptcp: sockopt: factor inet_flags propagation into a mask Matthieu Baerts (NGI0)
2026-09-18 18:38 ` [PATCH net-next 3/4] mptcp: propagate RECVERR sockopts to subflows Matthieu Baerts (NGI0)
2026-09-21 18:39 ` netdev-bot+sashiko
2026-09-18 18:38 ` [PATCH net-next 4/4] selftests: mptcp: cover IP_RECVERR sockopt propagation Matthieu Baerts (NGI0)
2026-09-21 18:39 ` netdev-bot+sashiko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260918-net-next-mptcp-msg_errqueue-v1-1-dd77e1738248@kernel.org \
--to=matttbe@kernel.org \
--cc=davem@davemloft.net \
--cc=devnexen@gmail.com \
--cc=edumazet@google.com \
--cc=geliang@kernel.org \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=martineau@kernel.org \
--cc=mptcp@lists.linux.dev \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.