From: David Carlier <devnexen@gmail.com>
To: mptcp@lists.linux.dev
Cc: Matthieu Baerts <matttbe@kernel.org>,
Mat Martineau <martineau@kernel.org>,
Geliang Tang <geliang@kernel.org>,
David Carlier <devnexen@gmail.com>
Subject: [PATCH mptcp-next v3 1/3] mptcp: propagate RECVERR sockopts to subflows
Date: Tue, 21 Apr 2026 23:33:36 +0100 [thread overview]
Message-ID: <20260421223338.52743-2-devnexen@gmail.com> (raw)
In-Reply-To: <20260421223338.52743-1-devnexen@gmail.com>
Propagate IP_RECVERR/IP_RECVERR_RFC4884 and
IPV6_RECVERR/IPV6_RECVERR_RFC4884 from the MPTCP socket to
existing and future subflows.
Apply the matching sockopt according to the subflow family so mixed-
family subflows stay aligned with the parent socket configuration,
including disable-time errqueue purge semantics.
Signed-off-by: David Carlier <devnexen@gmail.com>
Assisted-by: Codex:gpt-5
Signed-off-by: David Carlier <devnexen@gmail.com>
---
net/mptcp/sockopt.c | 129 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c
index 79db15903e7a..acb0ca330e44 100644
--- a/net/mptcp/sockopt.c
+++ b/net/mptcp/sockopt.c
@@ -8,6 +8,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
#include <net/sock.h>
#include <net/protocol.h>
#include <net/tcp.h>
@@ -384,6 +386,72 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname,
return -EOPNOTSUPP;
}
+static bool mptcp_recverr_enabled(const struct sock *sk, bool rfc4884)
+{
+ bool enabled;
+
+ enabled = rfc4884 ? inet_test_bit(RECVERR_RFC4884, sk) :
+ inet_test_bit(RECVERR, sk);
+
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == AF_INET6)
+ enabled |= rfc4884 ? inet6_test_bit(RECVERR6_RFC4884, sk) :
+ inet6_test_bit(RECVERR6, sk);
+#endif
+
+ return enabled;
+}
+
+static int mptcp_subflow_set_recverr(struct sock *sk, struct sock *ssk,
+ bool rfc4884)
+{
+ int level, optname, val;
+
+#if IS_ENABLED(CONFIG_IPV6)
+ if (ssk->sk_family == AF_INET6) {
+ level = SOL_IPV6;
+ optname = rfc4884 ? IPV6_RECVERR_RFC4884 : IPV6_RECVERR;
+ } else
+#endif
+ {
+ level = SOL_IP;
+ optname = rfc4884 ? IP_RECVERR_RFC4884 : IP_RECVERR;
+ }
+
+ val = mptcp_recverr_enabled(sk, rfc4884);
+ return tcp_setsockopt(ssk, level, optname, KERNEL_SOCKPTR(&val),
+ sizeof(val));
+}
+
+#if IS_ENABLED(CONFIG_IPV6)
+static int mptcp_setsockopt_v6_recverr(struct mptcp_sock *msk, int optname,
+ sockptr_t optval, unsigned int optlen)
+{
+ struct mptcp_subflow_context *subflow;
+ struct sock *sk = (struct sock *)msk;
+ int ret;
+
+ ret = ipv6_setsockopt(sk, SOL_IPV6, optname, optval, optlen);
+ if (ret)
+ return ret;
+
+ lock_sock(sk);
+ sockopt_seq_inc(msk);
+ mptcp_for_each_subflow(msk, subflow) {
+ struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+ bool rfc4884 = optname == IPV6_RECVERR_RFC4884;
+
+ ret = mptcp_subflow_set_recverr(sk, ssk, rfc4884);
+ if (ret)
+ break;
+ subflow->setsockopt_seq = msk->setsockopt_seq;
+ }
+ release_sock(sk);
+
+ return ret;
+}
+#endif
+
static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
sockptr_t optval, unsigned int optlen)
{
@@ -426,6 +494,12 @@ static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname,
release_sock(sk);
break;
+#if IS_ENABLED(CONFIG_IPV6)
+ case IPV6_RECVERR:
+ case IPV6_RECVERR_RFC4884:
+ ret = mptcp_setsockopt_v6_recverr(msk, optname, optval, optlen);
+ break;
+#endif
}
return ret;
@@ -760,6 +834,33 @@ static int mptcp_setsockopt_v4_set_tos(struct mptcp_sock *msk, int optname,
return 0;
}
+static int mptcp_setsockopt_v4_recverr(struct mptcp_sock *msk, int optname,
+ sockptr_t optval, unsigned int optlen)
+{
+ struct mptcp_subflow_context *subflow;
+ struct sock *sk = (struct sock *)msk;
+ int err;
+
+ err = ip_setsockopt(sk, SOL_IP, optname, optval, optlen);
+ if (err)
+ return err;
+
+ lock_sock(sk);
+ sockopt_seq_inc(msk);
+ mptcp_for_each_subflow(msk, subflow) {
+ struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
+ bool rfc4884 = optname == IP_RECVERR_RFC4884;
+
+ err = mptcp_subflow_set_recverr(sk, ssk, rfc4884);
+ if (err)
+ break;
+ subflow->setsockopt_seq = msk->setsockopt_seq;
+ }
+ release_sock(sk);
+
+ return err;
+}
+
static int mptcp_setsockopt_v4(struct mptcp_sock *msk, int optname,
sockptr_t optval, unsigned int optlen)
{
@@ -771,6 +872,9 @@ static int mptcp_setsockopt_v4(struct mptcp_sock *msk, int optname,
return mptcp_setsockopt_sol_ip_set(msk, optname, optval, optlen);
case IP_TOS:
return mptcp_setsockopt_v4_set_tos(msk, optname, optval, optlen);
+ case IP_RECVERR:
+ case IP_RECVERR_RFC4884:
+ return mptcp_setsockopt_v4_recverr(msk, optname, optval, optlen);
}
return -EOPNOTSUPP;
@@ -1459,6 +1563,12 @@ static int mptcp_getsockopt_v4(struct mptcp_sock *msk, int optname,
case IP_LOCAL_PORT_RANGE:
return mptcp_put_int_option(msk, optval, optlen,
READ_ONCE(inet_sk(sk)->local_port_range));
+ case IP_RECVERR:
+ return mptcp_put_int_option(msk, optval, optlen,
+ inet_test_bit(RECVERR, sk));
+ case IP_RECVERR_RFC4884:
+ return mptcp_put_int_option(msk, optval, optlen,
+ inet_test_bit(RECVERR_RFC4884, sk));
}
return -EOPNOTSUPP;
@@ -1479,6 +1589,12 @@ static int mptcp_getsockopt_v6(struct mptcp_sock *msk, int optname,
case IPV6_FREEBIND:
return mptcp_put_int_option(msk, optval, optlen,
inet_test_bit(FREEBIND, sk));
+ case IPV6_RECVERR:
+ return mptcp_put_int_option(msk, optval, optlen,
+ inet6_test_bit(RECVERR6, sk));
+ case IPV6_RECVERR_RFC4884:
+ return mptcp_put_int_option(msk, optval, optlen,
+ inet6_test_bit(RECVERR6_RFC4884, sk));
}
return -EOPNOTSUPP;
@@ -1536,6 +1652,7 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
{
static const unsigned int tx_rx_locks = SOCK_RCVBUF_LOCK | SOCK_SNDBUF_LOCK;
struct sock *sk = (struct sock *)msk;
+ bool recverr, recverr_rfc4884;
bool keep_open;
keep_open = sock_flag(sk, SOCK_KEEPOPEN);
@@ -1586,6 +1703,18 @@ static void sync_socket_options(struct mptcp_sock *msk, struct sock *ssk)
inet_assign_bit(FREEBIND, ssk, inet_test_bit(FREEBIND, sk));
inet_assign_bit(BIND_ADDRESS_NO_PORT, ssk, inet_test_bit(BIND_ADDRESS_NO_PORT, sk));
WRITE_ONCE(inet_sk(ssk)->local_port_range, READ_ONCE(inet_sk(sk)->local_port_range));
+ recverr = mptcp_recverr_enabled(sk, false);
+ recverr_rfc4884 = mptcp_recverr_enabled(sk, true);
+#if IS_ENABLED(CONFIG_IPV6)
+ if (ssk->sk_family == AF_INET6) {
+ inet6_assign_bit(RECVERR6, ssk, recverr);
+ inet6_assign_bit(RECVERR6_RFC4884, ssk, recverr_rfc4884);
+ } else
+#endif
+ {
+ inet_assign_bit(RECVERR, ssk, recverr);
+ inet_assign_bit(RECVERR_RFC4884, ssk, recverr_rfc4884);
+ }
}
void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk)
--
2.53.0
next prev parent reply other threads:[~2026-04-21 22:33 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-21 22:33 [PATCH mptcp-next v3 0/3] mptcp: MSG_ERRQUEUE support on the parent socket David Carlier
2026-04-21 22:33 ` David Carlier [this message]
2026-04-22 8:05 ` [PATCH mptcp-next v3 1/3] mptcp: propagate RECVERR sockopts to subflows Paolo Abeni
2026-04-22 8:32 ` Matthieu Baerts
2026-04-22 8:35 ` Matthieu Baerts
2026-04-22 8:36 ` Matthieu Baerts
2026-04-22 8:48 ` Paolo Abeni
2026-04-22 8:50 ` Matthieu Baerts
2026-04-22 13:53 ` Paolo Abeni
2026-04-22 21:51 ` David CARLIER
2026-04-27 17:07 ` Matthieu Baerts
2026-04-21 22:33 ` [PATCH mptcp-next v3 2/3] mptcp: support MSG_ERRQUEUE on the parent socket David Carlier
2026-04-22 8:28 ` Paolo Abeni
2026-04-22 21:54 ` David CARLIER
2026-04-21 22:33 ` [PATCH mptcp-next v3 3/3] selftests: mptcp: cover IP_RECVERR sockopt propagation David Carlier
2026-04-21 23:38 ` [PATCH mptcp-next v3 0/3] mptcp: MSG_ERRQUEUE support on the parent socket MPTCP CI
2026-04-22 8:22 ` Matthieu Baerts
2026-04-22 8:56 ` David CARLIER
2026-04-27 21:10 ` [PATCH mptcp-next v4 0/4] " David Carlier
2026-04-27 21:10 ` [PATCH mptcp-next v4 1/4] mptcp: sockopt: factor inet_flags propagation into a mask David Carlier
2026-04-27 21:10 ` [PATCH mptcp-next v4 2/4] mptcp: propagate RECVERR sockopts to subflows David Carlier
2026-05-01 15:56 ` Matthieu Baerts
2026-04-27 21:10 ` [PATCH mptcp-next v4 3/4] mptcp: support MSG_ERRQUEUE on the parent socket David Carlier
2026-04-27 21:10 ` [PATCH mptcp-next v4 4/4] selftests: mptcp: cover IP_RECVERR sockopt propagation David Carlier
2026-04-28 18:48 ` [PATCH mptcp-next v4 0/4] mptcp: MSG_ERRQUEUE support on the parent socket Matthieu Baerts
2026-04-28 18:56 ` Matthieu Baerts
2026-04-28 19:15 ` David CARLIER
2026-05-01 14:49 ` Matthieu Baerts
2026-05-01 15:28 ` David CARLIER
2026-05-01 15:56 ` Matthieu Baerts
2026-04-28 19:48 ` MPTCP CI
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=20260421223338.52743-2-devnexen@gmail.com \
--to=devnexen@gmail.com \
--cc=geliang@kernel.org \
--cc=martineau@kernel.org \
--cc=matttbe@kernel.org \
--cc=mptcp@lists.linux.dev \
/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.