From nobody Tue May 5 11:27:26 2026 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3526C3D8910 for ; Tue, 21 Apr 2026 15:22:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776784946; cv=none; b=A+tg8Ocg6lP1Zs+t2IGzDUDzP2K8ITxIwGYGOCJrwt2sF4p2hF1HZzpwwlkqUm9KZUeYSUvEnA8GHdIj0WwJY3qZVrAWM27OSyd24jsOiHMoQOd2J4LUDoPrEi+rQHH3WRL+0cBFTNkQLnqbd98XVyLWD1pkOuZZSTs99XoC4rM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776784946; c=relaxed/simple; bh=10bVTT8LwhDFPnvBCTR3jKRRmNsviYTHVq+4E0ZWOds=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BZQn7zgQkbbeb7W90nkC+rPZuFgflzb2ysvUFh+6kiWTmdiqJ2LzNN2w5OhnFFzYj4orElju3cO44A3gysuppTN92R2A3uMwfj2dHY/d+fSRwvyoq2NODTiXwoS1oHokYTekk/jz+pxKI4cQTwVedO/q2tsw2tV75UAAquCgW2s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=gKtKeyYy; arc=none smtp.client-ip=209.85.221.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gKtKeyYy" Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-43eb05b1875so2596585f8f.3 for ; Tue, 21 Apr 2026 08:22:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776784944; x=1777389744; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=vej0hMbFq4b4vlO5xettSBT3c1QoZw4sK8xxsnU8g+A=; b=gKtKeyYyF3RVT8pCmNLDIDSeRJhTz4FiKfqm1a0NnBv/ef6BmSyzvBbGx2ZXyrQbIe ANtzkiav9q2g3zXF9PnXgH9pXwVY5TlscuMTUx1tUUMKHXaOTCocfbGbFeDBDYNbEYwY 1YUB0ryqu/Re7zIfGyzBj35pnkFzagY7xL7iUj+ckwYdy6ZJ+3F+wKCbKgYU0I58kWzC MTxBFGk2b5HqqSBOnHDb+DIjPk6nDMPazXOdi2YfeZ+Avz5ZFfdbZQBJrtR5JD+SYaQH Xektq8iychiFPzGXwHc8gizW7HG1rrjut4pLe2QYu88nj57UPgjxy8jxq4AKLUiyIR6A 7UnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776784944; x=1777389744; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=vej0hMbFq4b4vlO5xettSBT3c1QoZw4sK8xxsnU8g+A=; b=roYvJqV+0zRxu4UkgGG+0nBzVxjahoJv5GFF4AY/aT9kjtygKa+XEAig6hbG/wmqbk 16DRnHYUT3wuBFuKGGZyysyg5Wfh4N+GkC4472YIYWJCws2TGCh1VhqR9IbxMdkgenXs +5I3OF04J9rvu1oF43u9hMA1ly5seg6WPrX2hdFsDqLCfXQF2Qt+sQtoAvKquLGu9rCs d4EOGiwLJacK99klUvIYtiK+KjbnCPAId6uY5URwOHWin3pdaDVAQxRzaHkChP98lzmn YnWP1xBMyWTCaSxcoycqWROYzxZeYdRaNBkq6R/xN8O74lJyqer81hyGmosjOHXz4GYq dlTA== X-Forwarded-Encrypted: i=1; AFNElJ8a9Qp6zG7IR9lUrYHrql7tDbVK2ySkWrtcOimH9m3ng6lRtPqFnF/hG4yvunIVOPZSSudQDw==@lists.linux.dev X-Gm-Message-State: AOJu0Yw7bDzy2ElaHmUTAzicwjZM0OtDS873MOHlqxATmxE9O6ehzftB vaTSSevuQN0ozHOPrgt4OytRwElhBihxW3BDxY7BBAJEsuKv87id93Cg X-Gm-Gg: AeBDietNV9oJz4ah+mTRAHFGDHkBn2xAWC3ZB1NuOWZW/gbvdzdK5xgRkN78JcbPnQ5 AUa3krjF7bA8rF17JGzxkjYQ+ERZQN8L34WlwQ3skl0sUULO/RnafiExlEWtzanL8PXuLWxPm8a tj5eSVbNjr2Yt96INd5Obt/CHxQMh+d3tzxPXFOdobSNp5+4bmShwSyzBGCYYLBT92u4yLO0IGD VfzYh7ceeAgWLIJjwVhd2kVy76WBWCh2K5wWniNokowQMiuErtHsBnFqb+y+qJOBMxhtbMvCaqt +DpQtE2SmISqdag2sWBRvaMgDocRq8Y+thYiMaUCaDl1MRlnvSKFqynxD4n2BB1rp1Q8NGt6bmt 6R9ax2Bglikszd7pHNRh7wbIe+P0kYzmBQ656y3TeEgTfNFMtnNAOI6gs2rc6rrTn8iZstCYDMs QOitqrhrqNKcL0ZsbRi++5ectDdJMVmQV5VWpxm2AoVOgG1JWLepFHfxUlL02dBxKurf5/B90PO QJVhk9Lhf2y2cA9w8kXOQ== X-Received: by 2002:adf:f584:0:b0:43f:e16f:3cc3 with SMTP id ffacd0b85a97d-43fe3dfd5efmr19868551f8f.22.1776784943477; Tue, 21 Apr 2026 08:22:23 -0700 (PDT) Received: from dohko.chello.ie (188-141-5-72.dynamic.upc.ie. [188.141.5.72]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4411c9f4f03sm8975225f8f.1.2026.04.21.08.22.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Apr 2026 08:22:22 -0700 (PDT) From: David Carlier To: netdev@vger.kernel.org, mptcp@lists.linux.dev Cc: matttbe@kernel.org, martineau@kernel.org, geliang@kernel.org, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, David Carlier Subject: [PATCH 1/3] mptcp: propagate RECVERR sockopts to subflows Date: Tue, 21 Apr 2026 16:22:09 +0100 Message-ID: <20260421152216.38127-2-devnexen@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260421152216.38127-1-devnexen@gmail.com> References: <20260421152216.38127-1-devnexen@gmail.com> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 Assisted-by: Codex:gpt-5 --- net/mptcp/sockopt.c | 125 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c index de90a2897d2d..b2b7ef888dff 100644 --- a/net/mptcp/sockopt.c +++ b/net/mptcp/sockopt.c @@ -8,6 +8,8 @@ =20 #include #include +#include +#include #include #include #include @@ -384,6 +386,70 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_so= ck *msk, int optname, return -EOPNOTSUPP; } =20 +static bool mptcp_recverr_enabled(const struct sock *sk, bool rfc4884) +{ + bool enabled; + + enabled =3D rfc4884 ? inet_test_bit(RECVERR_RFC4884, sk) : + inet_test_bit(RECVERR, sk); + +#if IS_ENABLED(CONFIG_IPV6) + if (sk->sk_family =3D=3D AF_INET6) + enabled |=3D 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 =3D=3D AF_INET6) { + level =3D SOL_IPV6; + optname =3D rfc4884 ? IPV6_RECVERR_RFC4884 : IPV6_RECVERR; + } else +#endif + { + level =3D SOL_IP; + optname =3D rfc4884 ? IP_RECVERR_RFC4884 : IP_RECVERR; + } + + val =3D mptcp_recverr_enabled(sk, rfc4884); + return tcp_setsockopt(ssk, level, optname, KERNEL_SOCKPTR(&val), + sizeof(val)); +} + +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 =3D (struct sock *)msk; + int ret; + + ret =3D 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 =3D mptcp_subflow_tcp_sock(subflow); + bool rfc4884 =3D optname =3D=3D IPV6_RECVERR_RFC4884; + + ret =3D mptcp_subflow_set_recverr(sk, ssk, rfc4884); + if (ret) + break; + subflow->setsockopt_seq =3D msk->setsockopt_seq; + } + release_sock(sk); + + return ret; +} + static int mptcp_setsockopt_v6(struct mptcp_sock *msk, int optname, sockptr_t optval, unsigned int optlen) { @@ -426,6 +492,10 @@ static int mptcp_setsockopt_v6(struct mptcp_sock *msk,= int optname, =20 release_sock(sk); break; + case IPV6_RECVERR: + case IPV6_RECVERR_RFC4884: + ret =3D mptcp_setsockopt_v6_recverr(msk, optname, optval, optlen); + break; } =20 return ret; @@ -760,6 +830,33 @@ static int mptcp_setsockopt_v4_set_tos(struct mptcp_so= ck *msk, int optname, return 0; } =20 +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 =3D (struct sock *)msk; + int err; + + err =3D 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 =3D mptcp_subflow_tcp_sock(subflow); + bool rfc4884 =3D optname =3D=3D IP_RECVERR_RFC4884; + + err =3D mptcp_subflow_set_recverr(sk, ssk, rfc4884); + if (err) + break; + subflow->setsockopt_seq =3D 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 +868,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); } =20 return -EOPNOTSUPP; @@ -1459,6 +1559,12 @@ static int mptcp_getsockopt_v4(struct mptcp_sock *ms= k, 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)); } =20 return -EOPNOTSUPP; @@ -1479,6 +1585,12 @@ static int mptcp_getsockopt_v6(struct mptcp_sock *ms= k, 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)); } =20 return -EOPNOTSUPP; @@ -1536,6 +1648,7 @@ static void sync_socket_options(struct mptcp_sock *ms= k, struct sock *ssk) { static const unsigned int tx_rx_locks =3D SOCK_RCVBUF_LOCK | SOCK_SNDBUF_= LOCK; struct sock *sk =3D (struct sock *)msk; + bool recverr, recverr_rfc4884; bool keep_open; =20 keep_open =3D sock_flag(sk, SOCK_KEEPOPEN); @@ -1586,6 +1699,18 @@ static void sync_socket_options(struct mptcp_sock *m= sk, 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_p= ort_range)); + recverr =3D mptcp_recverr_enabled(sk, false); + recverr_rfc4884 =3D mptcp_recverr_enabled(sk, true); +#if IS_ENABLED(CONFIG_IPV6) + if (ssk->sk_family =3D=3D 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); + } } =20 void mptcp_sockopt_sync_locked(struct mptcp_sock *msk, struct sock *ssk) --=20 2.53.0 From nobody Tue May 5 11:27:26 2026 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B9D823D7D9D for ; Tue, 21 Apr 2026 15:22:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776784949; cv=none; b=MrpaSrcY3oRjUJJQYMfzRJHNabYYN5V3T7I7RDM8GHT8QiwC1xHByTFhkktp2bN19zy3102Gxu7qKZzH5Yvm7qnjXbTUkOAbHJA/3lo/4WF+2hqan/t/2JP6K46xjqwun+s/g5N/t5kARSQd3AzeK5QfRVqpAU5rEgOLUPV9wds= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776784949; c=relaxed/simple; bh=Y13M/z1PUkRYdx6T147SQvL+8nHPZtZjHP2OD6TEy6U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=paPxtE8kkIlQNsS8Tbh9CNXcnV8ZgYfUpdwdo93Aun/B3MmLL8VB0NGJ5+DngL3Ph+Dqp9gCqkjZJ/pSTdMLF19i/sggMvH6b+b+TXdiOgzDu6kMEXcDgeCqLlQo6Mx3uhAv1a6mNKulwBXQM68H1MP5lKs8qvX9vyNB5ph+oBg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=qXLBk6ha; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="qXLBk6ha" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-43cfd832155so3199137f8f.1 for ; Tue, 21 Apr 2026 08:22:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776784946; x=1777389746; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8vQyN4XtQNgy58qiSyngDxgLbuPWflaYDxCcpF1TE+w=; b=qXLBk6ha8tynamLPlBNxy762NSrmRfA4NtOM0imA5HxVxfDdcIz0JYoFDqMDN5Wtgv aazEG8hnf3HLua1fBVMF8v3UuVFL4lIf5DOHf7XlprLVffC2QNwF3/uFQA6ozpXF2M60 IiPq5lpG9NQhCW7MmS3OGxePauWW+xAzI6P9Qw+0naDu67Fkvs1JOHwRARZyAR7r+/i1 gcNgIsI8J2SnOnXhPkH3tKmpkAlLczduq9tEtRNRRkWtt90MsF4egW/tMyy+J5FHF5Ad AIoZcP6+EUxnW8NX5WRlCablrfGhZdeg8z8Fr0rslOc7DM1QdA/YddJZKQesrWx1UMTa aIFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776784946; x=1777389746; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8vQyN4XtQNgy58qiSyngDxgLbuPWflaYDxCcpF1TE+w=; b=apCU6WR7rk0wXPUCFB4Nkh7+Yu2t3Emh7BOcUef3BLg9/AeKeqWM1rNQiTMut/8GyF GXqnF3kz87ZzgpfPb+XnqsZrDv2a+14dObsarvC9hiY0+51bM38+ukdSBheaFx8LWwn6 Z1vDVQrbgfmJPZOTlLiCykUnkJUNpZbIpvvA/pQ9X5gE93ohlZX5cY7w30i0V99nVQz9 b2ka3bdSwJ1+21eqGt6SMc8eBTLqgi6/L0WTHW+SZjJYakfXFLz9ylw0Qw2i2wwWx1VG bi6E8Ff2GB8AokFUv4l+l7884Ysx0L+H8v3IuphFlbRnvEC9PUhV1h6JWmBI0mvMZPhe AW6w== X-Forwarded-Encrypted: i=1; AFNElJ9ESVXY5p8eck2t0VV/4HEiqTo22jpWmsugp6wyFyxL4IiWbtGcaeTjL2r529TORUK7gnlEug==@lists.linux.dev X-Gm-Message-State: AOJu0Yzf63Nnsz+alkLxHxzuKgMMaXUBX065oQBeKjf5eUrGUoDy/EST t+aMHY3WPhBQAvfC7cZwdXwoMiSSaRLITeenU/Cfwmqo9WZcDCl4qKPY X-Gm-Gg: AeBDiesW1MfrtAHW+dpykVTm+jdOmeCXc5KIwa5SR9P3oezcIE7dieNeU/cySK1xP8H 9VLCzYEQxmBcyTDGyKLPTibh13eVv0Yl5A0AaF2yTLlGqDRMZK2Nx7+gyFvmsxK06WjYzRx8qQ7 eaYiOXhXsRPLhjPBuWSRlFsQznb+lAlEw1tTp3Dh9wvxY5riyDvo91WZ0D3a8o6vya3EA/JS7sk 3a7xjQJo9O2C+K8cvH1L3VFQCIq3tfRpNcNEjmsmr5m2yW2NySX2Ey6IhFi++0RRZjrfFohL0Ah 54lMHEcy6JIQYoJC9ZFSutZiHYSSx8WhQzkL6WLUdDIkjz0NGURN9v4aY6TjVqQOzLJYdPnHV73 nGUJbpPlD4pTRM3mZWfInI+FeQADdEj3EBP2EEZwbx1SN9avMekaxuuTSR0u6I981SfzqquJZlL y6rfXu6mo9FfeC/rOnAw3p+3EISBFSD82S3CrJUHacc3k8/UDdo7K3JrQY0EqKxaeCd6tFhu0Qm tYMfYIhmoV/25NmS4wd5Q== X-Received: by 2002:a05:6000:250e:b0:439:b440:b8a2 with SMTP id ffacd0b85a97d-43fe3dfba35mr27902238f8f.28.1776784945891; Tue, 21 Apr 2026 08:22:25 -0700 (PDT) Received: from dohko.chello.ie (188-141-5-72.dynamic.upc.ie. [188.141.5.72]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4411c9f4f03sm8975225f8f.1.2026.04.21.08.22.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Apr 2026 08:22:25 -0700 (PDT) From: David Carlier To: netdev@vger.kernel.org, mptcp@lists.linux.dev Cc: matttbe@kernel.org, martineau@kernel.org, geliang@kernel.org, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, David Carlier Subject: [PATCH 2/3] mptcp: support MSG_ERRQUEUE on the parent socket Date: Tue, 21 Apr 2026 16:22:10 +0100 Message-ID: <20260421152216.38127-3-devnexen@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260421152216.38127-1-devnexen@gmail.com> References: <20260421152216.38127-1-devnexen@gmail.com> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Handle MSG_ERRQUEUE on the MPTCP socket by selecting a subflow with pending errqueue data, moving one error skb to the parent socket, and consuming it through the parent socket ABI. This surfaces subflow errqueue activity through poll(), keeps the userspace ABI tied to the socket being used, and restores the skb to the subflow errqueue if requeueing to the parent fails under rmem pressure. Signed-off-by: David Carlier Assisted-by: Codex:gpt-5 --- net/mptcp/protocol.c | 121 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 18 deletions(-) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index fbffd3a43fe8..1b2e3bede122 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -819,26 +819,29 @@ static bool __mptcp_subflow_error_report(struct sock = *sk, struct sock *ssk) { int ssk_state; int err; + bool has_errqueue; =20 - /* only propagate errors on fallen-back sockets or - * on MPC connect - */ - if (sk->sk_state !=3D TCP_SYN_SENT && !__mptcp_check_fallback(mptcp_sk(sk= ))) - return false; - + has_errqueue =3D !skb_queue_empty_lockless(&ssk->sk_error_queue); err =3D sock_error(ssk); - if (!err) + if (!err && !has_errqueue) return false; =20 - /* 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 - * destroy the msk as needed. + /* Errqueue notifications should wake poll()/recvmsg(MSG_ERRQUEUE) on + * the MPTCP socket, but only fallback sockets and the MPC connect path + * inherit TCP's sk_err semantics. */ - ssk_state =3D inet_sk_state_load(ssk); - if (ssk_state =3D=3D TCP_CLOSE && !sock_flag(sk, SOCK_DEAD)) - mptcp_set_state(sk, ssk_state); - WRITE_ONCE(sk->sk_err, -err); + if (err && + (sk->sk_state =3D=3D TCP_SYN_SENT || __mptcp_check_fallback(mptcp_sk(= sk)))) { + /* 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 + * destroy the msk as needed. + */ + ssk_state =3D inet_sk_state_load(ssk); + if (ssk_state =3D=3D TCP_CLOSE && !sock_flag(sk, SOCK_DEAD)) + mptcp_set_state(sk, ssk_state); + WRITE_ONCE(sk->sk_err, -err); + } =20 /* This barrier is coupled with smp_rmb() in mptcp_poll() */ smp_wmb(); @@ -2286,6 +2289,68 @@ static unsigned int mptcp_inq_hint(const struct sock= *sk) return 0; } =20 +static struct sock *mptcp_pick_errqueue_subflow(struct sock *sk) +{ + struct mptcp_subflow_context *subflow; + struct sock *ssk =3D NULL; + + lock_sock(sk); + mptcp_for_each_subflow(mptcp_sk(sk), subflow) { + struct sock *subflow_sk =3D mptcp_subflow_tcp_sock(subflow); + + if (skb_queue_empty_lockless(&subflow_sk->sk_error_queue)) + continue; + + if (!refcount_inc_not_zero(&subflow_sk->sk_refcnt)) + continue; + + ssk =3D subflow_sk; + break; + } + release_sock(sk); + + return ssk; +} + +static bool mptcp_has_error_queue(const struct sock *sk) +{ + return !skb_queue_empty_lockless(&sk->sk_error_queue); +} + +static int mptcp_recv_error(struct sock *sk, struct msghdr *msg, int len) +{ + struct sk_buff *skb; + struct sock *ssk; + int ret, ret2; + + if (mptcp_has_error_queue(sk)) + return inet_recv_error(sk, msg, len); + + ssk =3D mptcp_pick_errqueue_subflow(sk); + if (!ssk) + return -EAGAIN; + + skb =3D sock_dequeue_err_skb(ssk); + if (!skb) + goto put_ssk; + + ret =3D sock_queue_err_skb(sk, skb); + if (ret) { + ret2 =3D sock_queue_err_skb(ssk, skb); + sock_put(ssk); + if (ret2) + kfree_skb(skb); + return ret; + } + + sock_put(ssk); + return inet_recv_error(sk, msg, len); + +put_ssk: + sock_put(ssk); + return -EAGAIN; +} + static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags) { @@ -2295,9 +2360,8 @@ static int mptcp_recvmsg(struct sock *sk, struct msgh= dr *msg, size_t len, int target; long timeo; =20 - /* MSG_ERRQUEUE is really a no-op till we support IP_RECVERR */ if (unlikely(flags & MSG_ERRQUEUE)) - return inet_recv_error(sk, msg, len); + return mptcp_recv_error(sk, msg, len); =20 lock_sock(sk); if (unlikely(sk->sk_state =3D=3D TCP_LISTEN)) { @@ -4296,6 +4360,26 @@ static __poll_t mptcp_check_writeable(struct mptcp_s= ock *msk) return 0; } =20 +static bool mptcp_subflow_has_error(struct sock *sk) +{ + struct mptcp_subflow_context *subflow; + bool has_error =3D false; + + mptcp_data_lock(sk); + mptcp_for_each_subflow(mptcp_sk(sk), subflow) { + struct sock *ssk =3D mptcp_subflow_tcp_sock(subflow); + + if (READ_ONCE(ssk->sk_err) || + !skb_queue_empty_lockless(&ssk->sk_error_queue)) { + has_error =3D true; + break; + } + } + mptcp_data_unlock(sk); + + return has_error; +} + static __poll_t mptcp_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait) { @@ -4339,7 +4423,8 @@ static __poll_t mptcp_poll(struct file *file, struct = socket *sock, =20 /* 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) || mptcp_has_error_queue(sk) || + mptcp_subflow_has_error(sk)) mask |=3D EPOLLERR; =20 return mask; --=20 2.53.0 From nobody Tue May 5 11:27:26 2026 Received: from mail-wm1-f51.google.com (mail-wm1-f51.google.com [209.85.128.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCE5B3D9020 for ; Tue, 21 Apr 2026 15:22:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776784951; cv=none; b=tunY2QfCSIozGzW5WX7yBmkjZG2bRx5k9yCw8pXGTHCYDrSbfDPi6GzvGOjPMy5/nvXJB4IAxFk7a53wfBFsOMzSFVt6iltuvZzXwbEnhphoWe1CyzJFjkgSkgtrL4Gkxwqjm6xAqCMTU0xOxa1o55ZA08CcQxtQiJwcfWXOPuI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776784951; c=relaxed/simple; bh=H8bkG9DBL9Xfb/wm1zVD5wdpScJ3eI851mJ2Uf1xggk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SpMTBmFloWG9/DRROZZ5een6HIpBCpb7IxhO+KwTsSpB6yXV9QvHjsmPXCirESvLBNZnJ3marBOj9Y3uWWVyVJ0VkMGMMN9jmJy4otfB5fOOm8UpTphvEoS/Z2e7egRpjH5j46q7CFXBrB8j6SkQgtH9tsd5U1Uh4CH+p8bQxq4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=U6steckn; arc=none smtp.client-ip=209.85.128.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="U6steckn" Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-48334ee0aeaso44869085e9.1 for ; Tue, 21 Apr 2026 08:22:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1776784948; x=1777389748; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=ApK1G5L+Mc6Cb2sCCSVe+Ii36gaQQarOC5kERgb3MHY=; b=U6steckn7VVyHgqb7Ra5i1qWHYtnTGpp2DD+1ZS2nbmsuVFrtsUOrjYjpce53ptl+A 6tEmlXBneY4gs1EvVorizxQOWBLkSVcrV8RikS1vTSHidAMjWs4oHWod6f8YukbhAHUJ +6NaCigna+RCqo2jvS3TA+l3Ey7AjhLz6nkZu8aPMFV8wLJCzCh5YDMMr1VKDGTeOx3l xNb8yDDkERmHVMi+/S3eiMWmg2dfOsVwKliNRj5Ep1tRLLnMEZ/U6KWfp6Rc4E0FvGta psgT7NUCPZFLPsa5QsP9nh/hmcei28IgUepNeRLF6MUiw6Qd4v5uuxcxF1r8AAAgKEyg 9nqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776784948; x=1777389748; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=ApK1G5L+Mc6Cb2sCCSVe+Ii36gaQQarOC5kERgb3MHY=; b=RWP3K3X+8M6/xP0nFF5lVqtt5CDo90d+edNuD2oE9+6o36YbdRUsgomXELmWaMSL6e QFx8Rr8M6D9Jcr7rTUGAX8xW098uwdkC8P/aP86CoZEV7VUHXbrecLfa/RBg7ukTLtK5 M+xYvFw+yFwZbkx+OAMsBNlEWo4PxnbG3JsR41HlAQHsZdSqvLQhkBL4SY34JoUKM2zH 0ZyGVYt1adJbwDgZdteEznpC1ZLWNDBp+1I0VaiGjqyOsYcRZ7zi6G5i8VxMqV8ghAX3 EPBoxd40bbSCkYAe0+ux+v+5rKYQ8JuxNK1wPfsjjYyiagBSYPmH5TzFKzNxs6CmaIEs ntvA== X-Forwarded-Encrypted: i=1; AFNElJ+s6m8EUrLK3P/mgvpLugQYWG8HCryBF8U/Urx4yrT6SK3buAAvMtF/haTzeTb6Yuzg7st+9g==@lists.linux.dev X-Gm-Message-State: AOJu0YxWJbs1jjM9shbY2apJXa/J5p3hwAJ5eo1DCaUdUUfHGCD21/KA gP4OQuRl8DYTKiGX0sPatg0HuFa63wvhyzglN8UUsVLPRDK3Rj0JLwpt X-Gm-Gg: AeBDieu7py5QoCdtk/PHfhcZiGOO81sFNJ6GufVSyTTCnEh4nsq2hFcPnIunkx2wLs4 YuhTs3D6ccPGWRio6UBWs/ncB1t2idnuaj/j5TL7AbvXpMLWckc+narTWy3fIo4RH8pyt291BPF sO4jcmGy+xOOphX75FgXJAACh8+HcxLDiuJkCgqSWRkSv5KCeVvjfPij4aX1mPTpoy8jCGGs2/F OVfskg066kyhGtoNrwPlpVvi1O5tDLbWwk3HUwI2lVEAP4Std7IY2Svqld6e9r9hZ21ilyqLsva ot4vm7lTmNVdH4T7F1mEczdu0Wn9mTSS0fYDlOrMKZA56RlIn82Zw+vXQ0rFdzdRA019n3fIWGq +7sg2Q/0T1Vbz5MXg+7MpKsSfIhYwztHF/G9WRJ9sGB5/xLG1kmpKaTzlkwHYngZSIqrA0LiNfI ewqMjCcraqncIfEuWju3D3EHDppBWzSLbJVO9FNpJn0YNXZpQ5Jb9BJsOYhDDJ8M/XeB8ZEWI64 GBujG6x2aKhXpgvrNIX3RWx1KAzzao1 X-Received: by 2002:a05:600c:6296:b0:483:64b4:79da with SMTP id 5b1f17b1804b1-488fb7923a9mr250841765e9.26.1776784947890; Tue, 21 Apr 2026 08:22:27 -0700 (PDT) Received: from dohko.chello.ie (188-141-5-72.dynamic.upc.ie. [188.141.5.72]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4411c9f4f03sm8975225f8f.1.2026.04.21.08.22.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Apr 2026 08:22:27 -0700 (PDT) From: David Carlier To: netdev@vger.kernel.org, mptcp@lists.linux.dev Cc: matttbe@kernel.org, martineau@kernel.org, geliang@kernel.org, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com, horms@kernel.org, David Carlier Subject: [PATCH 3/3] selftests: mptcp: cover RECVERR and MSG_ERRQUEUE Date: Tue, 21 Apr 2026 16:22:11 +0100 Message-ID: <20260421152216.38127-4-devnexen@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260421152216.38127-1-devnexen@gmail.com> References: <20260421152216.38127-1-devnexen@gmail.com> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add MPTCP selftest coverage for RECVERR sockopt round-trips and parent-socket MSG_ERRQUEUE delivery. Enable TX software timestamping, send data over an MPTCP socket, wait for POLLERR, and verify that recvmsg(MSG_ERRQUEUE) returns timestamping metadata on the MPTCP parent socket. Signed-off-by: David Carlier Assisted-by: Codex:gpt-5 --- .../selftests/net/mptcp/mptcp_sockopt.c | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c b/tools/test= ing/selftests/net/mptcp/mptcp_sockopt.c index b6e58d936ebe..b499e7585d38 100644 --- a/tools/testing/selftests/net/mptcp/mptcp_sockopt.c +++ b/tools/testing/selftests/net/mptcp/mptcp_sockopt.c @@ -26,9 +26,17 @@ =20 #include #include +#include +#include + +#include =20 static int pf =3D AF_INET; =20 +#ifndef SCM_TIMESTAMPING +#define SCM_TIMESTAMPING SO_TIMESTAMPING +#endif + #ifndef IPPROTO_MPTCP #define IPPROTO_MPTCP 262 #endif @@ -128,6 +136,9 @@ struct so_state { #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif =20 +static void enable_tx_timestamping(int fd); +static void test_msg_errqueue_timestamping(int fd); + static void __noreturn die_perror(const char *msg) { perror(msg); @@ -598,6 +609,8 @@ static void connect_one_server(int fd, int pipefd) =20 assert(strncmp(buf2, "xmit", 4) =3D=3D 0); =20 + enable_tx_timestamping(fd); + ret =3D write(fd, buf, len); if (ret < 0) die_perror("write"); @@ -605,6 +618,8 @@ static void connect_one_server(int fd, int pipefd) if (ret !=3D (ssize_t)len) xerror("short write"); =20 + test_msg_errqueue_timestamping(fd); + total =3D 0; do { ret =3D read(fd, buf2 + total, sizeof(buf2) - total); @@ -769,6 +784,142 @@ static void test_ip_tos_sockopt(int fd) xerror("expect socklen_t =3D=3D -1"); } =20 +static void test_ip_recverr_sockopt(int fd) +{ + struct iovec iov =3D { + .iov_base =3D &(char){ 0 }, + .iov_len =3D 1, + }; + struct msghdr msg =3D { + .msg_iov =3D &iov, + .msg_iovlen =3D 1, + }; + int one =3D 1, zero =3D 0, val =3D -1; + socklen_t s =3D sizeof(val); + int level, optname, r; + + switch (pf) { + case AF_INET: + level =3D SOL_IP; + optname =3D IP_RECVERR; + break; + case AF_INET6: + level =3D SOL_IPV6; + optname =3D IPV6_RECVERR; + break; + default: + xerror("Unknown pf %d\n", pf); + } + + r =3D setsockopt(fd, level, optname, &one, sizeof(one)); + if (r) + die_perror("setsockopt recverr on"); + + r =3D getsockopt(fd, level, optname, &val, &s); + if (r) + die_perror("getsockopt recverr on"); + if (s !=3D sizeof(val) || val !=3D one) + xerror("recverr on mismatch val=3D%d len=3D%u", val, s); + + r =3D recvmsg(fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT); + if (r !=3D -1 || errno !=3D EAGAIN) + xerror("expected empty errqueue to return EAGAIN, ret=3D%d errno=3D%d", = r, errno); + + r =3D setsockopt(fd, level, optname, &zero, sizeof(zero)); + if (r) + die_perror("setsockopt recverr off"); + + val =3D -1; + s =3D sizeof(val); + r =3D getsockopt(fd, level, optname, &val, &s); + if (r) + die_perror("getsockopt recverr off"); + if (s !=3D sizeof(val) || val !=3D zero) + xerror("recverr off mismatch val=3D%d len=3D%u", val, s); +} + +static void enable_tx_timestamping(int fd) +{ + int val =3D SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_OPT_TSONLY; + int ret; + + ret =3D setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING_OLD, + &val, sizeof(val)); + if (ret) + die_perror("setsockopt SO_TIMESTAMPING"); +} + +static void test_msg_errqueue_timestamping(int fd) +{ + char ctrl[512] =3D { 0 }; + char data[32] =3D { 0 }; + struct iovec iov =3D { + .iov_base =3D data, + .iov_len =3D sizeof(data), + }; + struct msghdr msg =3D { + .msg_iov =3D &iov, + .msg_iovlen =3D 1, + .msg_control =3D ctrl, + .msg_controllen =3D sizeof(ctrl), + }; + struct pollfd pfd =3D { + .fd =3D fd, + .events =3D POLLERR, + }; + struct cmsghdr *cm; + struct scm_timestamping *tss =3D NULL; + struct sock_extended_err *serr =3D NULL; + int ret, i; + + for (i =3D 0; i < 10; i++) { + ret =3D poll(&pfd, 1, 1000); + if (ret < 0) + die_perror("poll errqueue"); + if (ret =3D=3D 0) + continue; + if (!(pfd.revents & POLLERR)) + xerror("expected POLLERR, got revents %#x", pfd.revents); + break; + } + + if (i =3D=3D 10) + xerror("timed out waiting for MSG_ERRQUEUE event"); + + ret =3D recvmsg(fd, &msg, MSG_ERRQUEUE); + if (ret < 0) + die_perror("recvmsg timestamping errqueue"); + if (!(msg.msg_flags & MSG_ERRQUEUE)) + xerror("expected MSG_ERRQUEUE in msg_flags, got %#x", + msg.msg_flags); + + for (cm =3D CMSG_FIRSTHDR(&msg); cm; cm =3D CMSG_NXTHDR(&msg, cm)) { + if (cm->cmsg_level =3D=3D SOL_SOCKET && + cm->cmsg_type =3D=3D SCM_TIMESTAMPING) + tss =3D (void *)CMSG_DATA(cm); + if ((cm->cmsg_level =3D=3D SOL_IP && + cm->cmsg_type =3D=3D IP_RECVERR) || + (cm->cmsg_level =3D=3D SOL_IPV6 && + cm->cmsg_type =3D=3D IPV6_RECVERR)) + serr =3D (void *)CMSG_DATA(cm); + } + + if (!tss) + xerror("missing SCM_TIMESTAMPING cmsg"); + if (!serr) + xerror("missing sock_extended_err cmsg"); + if (serr->ee_errno !=3D ENOMSG || + serr->ee_origin !=3D SO_EE_ORIGIN_TIMESTAMPING) + xerror("unexpected timestamping err ee_errno=3D%u ee_origin=3D%u", + serr->ee_errno, serr->ee_origin); + if (!tss->ts[0].tv_sec && !tss->ts[0].tv_nsec && + !tss->ts[1].tv_sec && !tss->ts[1].tv_nsec && + !tss->ts[2].tv_sec && !tss->ts[2].tv_nsec) + xerror("all timestamp slots are zero"); +} + static int client(int pipefd) { int fd =3D -1; @@ -787,6 +938,7 @@ static int client(int pipefd) } =20 test_ip_tos_sockopt(fd); + test_ip_recverr_sockopt(fd); =20 connect_one_server(fd, pipefd); =20 --=20 2.53.0