Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next v2] net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS
@ 2026-11-09  1:45 Vitaly Zuevsky
       [not found] ` <sashiko-outbox-205984@kernel.org>
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Vitaly Zuevsky @ 2026-11-09  1:45 UTC (permalink / raw)
  To: netdev, David Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Richard Henderson, Matt Turner, Magnus Lindholm,
	Thomas Bogendoerfer, James E.J. Bottomley, Helge Deller,
	Andreas Larsson, Kuniyuki Iwashima, Willem de Bruijn,
	Arnd Bergmann, Christian Brauner, Andrew Halaney, Jori Koolstra,
	Alexander Mikhalitsyn, Tariq Toukan, Saeed Mahameed, Chuang Wang,
	linux-doc, linux-kernel, linux-alpha, linux-mips, linux-parisc,
	sparclinux, linux-arch

RFS and accelerated RFS are enabled per host and per rx queue, but
whether steering helps is a property of the flow. A host that carries
a few long-lived flows which benefit from steering alongside a large
churn of short-lived flows which arrive on the right CPU already has
no way to express that today.

Add a boolean socket option, SO_BYPASS_RFS. While set,
sock_rps_record_flow() leaves the socket out of rps_sock_flow_table,
so get_rps_cpu() finds no match and neither software RFS nor
ndo_rx_flow_steer() acts on the flow; it stays on the CPU chosen by
RSS or RPS.

The bit lives in sock_common next to skc_state, in the space reclaimed
by commit 13df9cc6fc0b ("net: Shrink skc_reuse:4 to 2 bits."), so the
test shares the cache line the record path already reads and
sock_copy() carries it to accepted children: setting it on a listening
socket excludes every connection accepted from it, while sockets the
same process connects itself remain eligible.

Setting the option clears the socket's entry, so a flow recorded
earlier stops being steered with the next packet. Closing a bypassing
socket leaves the table alone: a close clears its slot without checking
who last wrote it, and a churn of bypassing sockets could evict
the hints of the steered flows.

Both tests sit behind the rfs_needed static branch, so hosts without
RFS pay nothing.

Signed-off-by: Vitaly Zuevsky <vitaly.zuevsky@gcore.com>
---
v2:
 - fold the documentation into this patch
 - rename SO_NO_RFS to SO_BYPASS_RFS (Kuniyuki Iwashima)
 - keep the state in a sock_common bit instead of sk_flags (Kuniyuki)
 - test it in the rps.h wrappers, next to rfs_is_needed()
 - clear the table entry when the option is set on a recorded socket
 - drop the comments and the unlikely()
 - guard the sockopt with CONFIG_RPS
v1: https://lore.kernel.org/netdev/20261031113330.45704-1-vitaly.zuevsky@gcore.com/

 Documentation/networking/scaling.rst  | 15 +++++++++++++++
 arch/alpha/include/uapi/asm/socket.h  |  2 ++
 arch/mips/include/uapi/asm/socket.h   |  2 ++
 arch/parisc/include/uapi/asm/socket.h |  2 ++
 arch/sparc/include/uapi/asm/socket.h  |  2 ++
 include/net/rps.h                     |  4 ++--
 include/net/sock.h                    |  5 ++++-
 include/uapi/asm-generic/socket.h     |  2 ++
 net/core/sock.c                       | 15 +++++++++++++++
 9 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/Documentation/networking/scaling.rst b/Documentation/networking/scaling.rst
index 6c9836000a8d..b23c87405622 100644
--- a/Documentation/networking/scaling.rst
+++ b/Documentation/networking/scaling.rst
@@ -428,6 +428,21 @@ queues. So for instance, if rps_sock_flow_entries is set to 131072 and there
 are 16 configured receive queues, rps_flow_cnt for each queue might be
 configured as 8192.
 
+Excluding individual sockets
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+RFS is configured per host and per queue, but whether it pays off
+depends on the traffic pattern. SO_BYPASS_RFS keeps a socket's flow
+out of rps_sock_flow_table, so neither RFS nor accelerated RFS acts on
+it: packets stay on the CPU chosen by RSS or RPS, and no filter is
+programmed into the NIC. The option is inherited through accept(), so
+a listening socket that sets it excludes every connection it accepts
+while the sockets the process connects itself remain steered. It may
+be set at any time; an entry already recorded is removed. This suits
+a host carrying a few long-lived flows worth steering alongside a
+churn of short-lived ones for which the cross-CPU enqueue, the wakeup
+and the filter update cost more than they save.
+
 
 Accelerated RFS
 ===============
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index 5d3524c26b2b..4df4e1c520fb 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -161,6 +161,8 @@
 
 #define SO_PEERPIDFD_THREAD    87
 
+#define SO_BYPASS_RFS          88
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 245a43f52fb1..e1e9d34afdb3 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -172,6 +172,8 @@
 
 #define SO_PEERPIDFD_THREAD    87
 
+#define SO_BYPASS_RFS          88
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index f23710e1c671..c38445422129 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -153,6 +153,8 @@
 
 #define SO_PEERPIDFD_THREAD	0x4055
 
+#define SO_BYPASS_RFS		0x4056
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index b35b25bdefc2..f0cf0a3d2916 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -154,6 +154,8 @@
 
 #define SO_PEERPIDFD_THREAD      0x0060
 
+#define SO_BYPASS_RFS            0x0061
+
 #if !defined(__KERNEL__)
 
 
diff --git a/include/net/rps.h b/include/net/rps.h
index e33c6a2fa8bb..7c62ae607d18 100644
--- a/include/net/rps.h
+++ b/include/net/rps.h
@@ -149,7 +149,7 @@ static inline void sock_rps_record_flow_hash(__u32 hash)
 static inline void sock_rps_record_flow(const struct sock *sk)
 {
 #ifdef CONFIG_RPS
-	if (!rfs_is_needed())
+	if (!rfs_is_needed() || sk->sk_bypass_rfs)
 		return;
 
 	_sock_rps_record_flow(sk);
@@ -159,7 +159,7 @@ static inline void sock_rps_record_flow(const struct sock *sk)
 static inline void sock_rps_delete_flow(const struct sock *sk)
 {
 #ifdef CONFIG_RPS
-	if (!rfs_is_needed())
+	if (!rfs_is_needed() || sk->sk_bypass_rfs)
 		return;
 
 	_sock_rps_delete_flow(sk);
diff --git a/include/net/sock.h b/include/net/sock.h
index 9bba1e793f1e..a52db61775d8 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -124,6 +124,7 @@ typedef __u64 __bitwise __addrpair;
  *	@skc_ipv6only: socket is IPV6 only
  *	@skc_net_refcnt: socket is using net ref counting
  *	@skc_bypass_prot_mem: bypass the per-protocol memory accounting for skb
+ *	@skc_bypass_rfs: %SO_BYPASS_RFS setting
  *	@skc_unused: unused bits
  *	@skc_bound_dev_if: bound device index if != 0
  *	@skc_bind_node: bind hash linkage for various protocol lookup tables
@@ -182,7 +183,8 @@ struct sock_common {
 	unsigned char		skc_ipv6only:1;
 	unsigned char		skc_net_refcnt:1;
 	unsigned char		skc_bypass_prot_mem:1;
-	unsigned char		skc_unused:2;
+	unsigned char		skc_bypass_rfs:1;
+	unsigned char		skc_unused:1;
 	int			skc_bound_dev_if;
 	union {
 		struct hlist_node	skc_bind_node;
@@ -395,6 +397,7 @@ struct sock {
 #define sk_ipv6only		__sk_common.skc_ipv6only
 #define sk_net_refcnt		__sk_common.skc_net_refcnt
 #define sk_bypass_prot_mem	__sk_common.skc_bypass_prot_mem
+#define sk_bypass_rfs		__sk_common.skc_bypass_rfs
 #define sk_bound_dev_if		__sk_common.skc_bound_dev_if
 #define sk_bind_node		__sk_common.skc_bind_node
 #define sk_prot			__sk_common.skc_prot
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 56fed7ab27ab..6f6987cb8a53 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -156,6 +156,8 @@
 
 #define SO_PEERPIDFD_THREAD	87
 
+#define SO_BYPASS_RFS		88
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
diff --git a/net/core/sock.c b/net/core/sock.c
index e2401d735c5a..00808217aebf 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -144,6 +144,7 @@
 #include <trace/events/sock.h>
 
 #include <net/psp.h>
+#include <net/rps.h>
 #include <net/tcp.h>
 #include <net/busy_poll.h>
 #include <net/phonet/phonet.h>
@@ -1597,6 +1598,14 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
 		reuseport_update_incoming_cpu(sk, val);
 		break;
 
+#ifdef CONFIG_RPS
+	case SO_BYPASS_RFS:
+		if (valbool)
+			sock_rps_delete_flow(sk);
+		sk->sk_bypass_rfs = valbool;
+		break;
+#endif
+
 	case SO_CNX_ADVICE:
 		if (val == 1)
 			dst_negative_advice(sk);
@@ -2118,6 +2127,12 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 		v.val = READ_ONCE(sk->sk_incoming_cpu);
 		break;
 
+#ifdef CONFIG_RPS
+	case SO_BYPASS_RFS:
+		v.val = sk->sk_bypass_rfs;
+		break;
+#endif
+
 	case SO_MEMINFO:
 	{
 		u32 meminfo[SK_MEMINFO_VARS];

base-commit: fa5196392691051963726787944db872420dfa75
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH net-next v2] net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS
       [not found] ` <sashiko-outbox-205984@kernel.org>
@ 2026-11-11 16:47   ` Vitaly Zuevsky
  0 siblings, 0 replies; 4+ messages in thread
From: Vitaly Zuevsky @ 2026-11-11 16:47 UTC (permalink / raw)
  To: netdev
  Cc: sashiko-reviews, davem, edumazet, kuba, pabeni, horms, willemb,
	Kuniyuki Iwashima

On 09/11/2026 20:45, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential
> issue to consider:
> - [Medium] net: race in sk_setsockopt() deleting RFS flow before setting
>    sk_bypass_rfs
> It also noticed 1 related pre-existing issue this patch does not
> introduce:
> - [Medium] net: file descriptor leak in sk_getsockopt() [1]
> --
> 
> commit 0bb55ec9420355430d450dec603d8adf895ff281
> Author: Vitaly Zuevsky <vitaly.zuevsky@gcore.com>
> 
> net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS
> 
> This commit adds the SO_BYPASS_RFS boolean socket option and a skc_bypass_rfs
> bit in struct sock_common to exclude a socket from RFS and aRFS flow recording
> and deletion.
> 
>> diff --git a/net/core/sock.c b/net/core/sock.c
>> index e2401d735c5a7..00808217aebf1 100644
>> --- a/net/core/sock.c
>> +++ b/net/core/sock.c
> [ ... ]
>> @@ -1597,6 +1598,14 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
>>   		reuseport_update_incoming_cpu(sk, val);
>>   		break;
>>   
>> +#ifdef CONFIG_RPS
>> +	case SO_BYPASS_RFS:
>> +		if (valbool)
>> +			sock_rps_delete_flow(sk);
>> +		sk->sk_bypass_rfs = valbool;
>> +		break;
>> +#endif
>> +
>>   	case SO_CNX_ADVICE:
>>   		if (val == 1)
>>   			dst_negative_advice(sk);
> 
> [Severity: Medium]
> Can a concurrent receive or send re-record the flow between
> sock_rps_delete_flow() and setting sk->sk_bypass_rfs?
> 
> Callers such as inet_recvmsg() invoke sock_rps_record_flow() without
> holding the socket lock:
> 
> CPU0                              CPU1
> sk_setsockopt(SO_BYPASS_RFS, 1)
>    sock_rps_delete_flow(sk)
>      _sock_rps_delete_flow(sk)
>                                    inet_recvmsg()
>                                      sock_rps_record_flow(sk)
>                                        /* sk->sk_bypass_rfs is still 0 */
>                                        _sock_rps_record_flow(sk)  <-- re-records flow
>    sk->sk_bypass_rfs = 1;
> 
> Once sk->sk_bypass_rfs is set, sock_rps_delete_flow() returns early, so
> the re-recorded entry stays in rps_sock_flow_table while SO_BYPASS_RFS is
> enabled and is not cleared when the socket closes.  Setting
> sk->sk_bypass_rfs before calling _sock_rps_delete_flow() would avoid
> leaving a stale entry if a concurrent reader races with setsockopt().

The record path is lockless by design and the table holds hints; a 
recvmsg() racing with the setsockopt() can leave one, which is tolerated 
like any other stale entry. Reordering narrows race-window at a cost of 
dropping the wrapper, consider:

sk->sk_bypass_rfs = valbool;
if (valbool) _sock_rps_delete_flow(sk);

|CPU0: setsockopt       |CPU1: recvmsg
                         |CPU1: test bit -> 0
|CPU0: bit = 1          |CPU1: preemted
|CPU0: delete slot      |CPU1: preemted
                         |CPU1: record   -> hint written


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net-next v2] net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS
  2026-11-09  1:45 [PATCH net-next v2] net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS Vitaly Zuevsky
       [not found] ` <sashiko-outbox-205984@kernel.org>
@ 2026-11-12  1:46 ` netdev-bot+sashiko
  2026-11-12  1:57 ` Jakub Kicinski
  2 siblings, 0 replies; 4+ messages in thread
From: netdev-bot+sashiko @ 2026-11-12  1:46 UTC (permalink / raw)
  To: vitaly.zuevsky
  Cc: netdev, davem, edumazet, kuba, pabeni, horms, corbet, skhan,
	rdunlap, richard.henderson, mattst88, linmag7, tsbogend,
	James.Bottomley, deller, andreas, kuniyu, willemb, arnd, brauner,
	andrew, jkoolstra, alexander, tariqt, saeedm, nashuiliang,
	linux-doc, linux-kernel, linux-alpha, linux-mips, linux-parisc,
	sparclinux, linux-arch

Thank you for your contribution! Sashiko AI review found 5 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 2 · Low: 3

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] The commit message says setting SO_BYPASS_RFS on a socket that
  was already recorded means the flow "stops being steered with the next…
- [Medium] Setting SO_BYPASS_RFS does not reliably remove the socket's
  rps_sock_flow_table entry, and an entry re-recorded in a race is never…
- [Low] The commit message says that setting SO_BYPASS_RFS on a listening
  socket "excludes every connection accepted from it".
- [Low] SO_BYPASS_RFS is added as a generic SOL_SOCKET option, but
  MPTCP's SOL_SOCKET handler was not updated.
- [Low] sk_bypass_rfs is a 1-bit bitfield in sock_common
  (include/net/sock.h:186).

--

net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS

This adds a boolean SOL_SOCKET option, SO_BYPASS_RFS, that keeps a
socket out of rps_sock_flow_table, so neither RFS nor aRFS steers its
flow. The state is a new bit in sock_common that sock_copy() copies to
children, and setting the option clears any existing table entry. Close
time deletion is skipped for bypassing sockets.

> diff --git a/Documentation/networking/scaling.rst b/Documentation/networking/scaling.rst
> index 6c9836000a8d1..b23c874056225 100644
> --- a/Documentation/networking/scaling.rst
> +++ b/Documentation/networking/scaling.rst
> @@ -428,6 +428,21 @@ queues. So for instance, if rps_sock_flow_entries is set to 131072 and there
>  are 16 configured receive queues, rps_flow_cnt for each queue might be
>  configured as 8192.
>  
> +Excluding individual sockets
> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> +
> +RFS is configured per host and per queue, but whether it pays off
> +depends on the traffic pattern. SO_BYPASS_RFS keeps a socket's flow
> +out of rps_sock_flow_table, so neither RFS nor accelerated RFS acts on
> +it: packets stay on the CPU chosen by RSS or RPS, and no filter is
> +programmed into the NIC. The option is inherited through accept(), so
> +a listening socket that sets it excludes every connection it accepts
> +while the sockets the process connects itself remain steered. It may
> +be set at any time; an entry already recorded is removed. This suits

[Severity: Low]

Is "inherited through accept()" accurate? The bit sits in the copied
part of sock_common. It reaches the child through sock_copy() in
sk_clone() when the child is created at handshake completion, not at
accept():

	memcpy(nsk, osk, offsetof(struct sock, sk_dontcopy_begin));

Setting the option on the listener does not walk the accept queue. A
connection whose handshake finished before the setsockopt() therefore
has sk_bypass_rfs == 0. When that connection is accepted later,
__inet_accept() still does:

	sock_rps_record_flow(newsk);

so the flow is recorded and steered.

The commit message says "setting it on a listening socket excludes
every connection accepted from it". Should both texts say that only
connections established after the option is set inherit it?

[ ... ]

> diff --git a/include/net/rps.h b/include/net/rps.h
> index e33c6a2fa8bbc..7c62ae607d182 100644
> --- a/include/net/rps.h
> +++ b/include/net/rps.h
> @@ -149,7 +149,7 @@ static inline void sock_rps_record_flow_hash(__u32 hash)
>  static inline void sock_rps_record_flow(const struct sock *sk)
>  {
>  #ifdef CONFIG_RPS
> -	if (!rfs_is_needed())
> +	if (!rfs_is_needed() || sk->sk_bypass_rfs)
>  		return;

[Severity: Low]

Will KCSAN report this read? sk_bypass_rfs is a 1-bit bitfield. It
shares a byte with skc_reuse, skc_reuseport, skc_ipv6only,
skc_net_refcnt and skc_bypass_prot_mem.

sk_setsockopt() writes it with a plain read-modify-write under the
socket lock. sock_rps_record_flow() reads it without the lock on the
per-packet paths (inet_recvmsg(), inet_send_prepare(),
mptcp_rps_record_subflows() and others). sock_rps_delete_flow() and
sk_getsockopt() also read it without the lock.

Bitfields cannot be wrapped in READ_ONCE()/WRITE_ONCE(), and none of
these accesses use data_race(). Nearby lockless fields such as
sk_rxhash and sk_incoming_cpu use READ_ONCE()/WRITE_ONCE(), and the v1
sk_flags approach used atomic bitops. Would non-bitfield storage or
data_race() annotations be better here?

[ ... ]

> diff --git a/net/core/sock.c b/net/core/sock.c
> index e2401d735c5a7..00808217aebf1 100644
> --- a/net/core/sock.c
> +++ b/net/core/sock.c

[ ... ]

> @@ -1597,6 +1598,14 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
>  		reuseport_update_incoming_cpu(sk, val);
>  		break;
>  
> +#ifdef CONFIG_RPS
> +	case SO_BYPASS_RFS:
> +		if (valbool)
> +			sock_rps_delete_flow(sk);
> +		sk->sk_bypass_rfs = valbool;

[Severity: Medium]

Can a concurrent recvmsg() or sendmsg() put the entry back here? The
delete runs while sk_bypass_rfs is still 0. inet_recvmsg() and
inet_send_prepare() check the bit and write the table without the
socket lock:

CPU0 (setsockopt, lock_sock held)    CPU1 (recvmsg, no socket lock)
                                     sock_rps_record_flow()
                                       sees sk_bypass_rfs == 0
sock_rps_delete_flow()
  slot = RPS_NO_CPU
                                       _sock_rps_record_flow()
                                         slot = hash | cpu
sk->sk_bypass_rfs = 1

After this, every sock_rps_record_flow() and sock_rps_delete_flow() on
the socket returns early on the bit. That includes the close-time
cleanup in inet_unhash(), udp and sctp.

Does the stale entry then keep steering the flow through RFS after the
socket is closed, until a colliding hash overwrites it? With aRFS it
would also keep the NIC filter active, since rflow->last_qtail keeps
advancing.

Setting the bit before the delete would only narrow the window, unless
the record side re-checks after a paired barrier or the close-time
delete is kept for this case.

[Severity: Medium]

Does this stop steering for a flow that accelerated RFS has already
steered? The only cleanup here is
sock_rps_delete_flow()->_sock_rps_delete_flow(), which writes
RPS_NO_CPU into the rps_sock_flow_table slot. The per-rxqueue
rps_dev_flow entry and the filter installed by ndo_rx_flow_steer()
stay in place.

The driver removes that filter only when rps_may_expire_flow() returns
true:

net/core/dev.c:rps_may_expire_flow() {
    ...
		if (READ_ONCE(rflow->filter) == filter_id &&
		    rps_flow_is_active(rflow, log, cpu))
			expire = false;
    ...
}

Once the socket entry is cleared, get_rps_cpu() sends this flow to
try_rps:

		ident = READ_ONCE(sock_flow_table[flow_id].ent);
		if ((ident ^ hash) & ~net_hotdata.rps_cpu_mask)
			goto try_rps;

At that point rflow->last_qtail stops advancing. Expiry then depends
only on unrelated backlog traffic on the target CPU. If that CPU sees
little RPS/RFS backlog traffic, can the flow stay hardware-steered
indefinitely?

With software RFS, the flow also moves to the RSS/RPS CPU at once. It
skips the input_queue_head vs last_qtail check that get_rps_cpu()
normally uses to hand off in order. If the option is set mid-flow, can
packets still queued in the old CPU's backlog be delivered out of
order?

The commit message says "a flow recorded earlier stops being steered
with the next packet". scaling.rst says "no filter is programmed into
the NIC" and "It may be set at any time; an entry already recorded is
removed". Should the documentation describe these effects, or should
the rps_dev_flow and filter state be handled too?

> +		break;
> +#endif

[Severity: Low]

Should MPTCP be covered as well? mptcp_setsockopt_sol_socket() accepts
a fixed list of SOL_SOCKET options and ends with:

	return -EOPNOTSUPP;

so setsockopt(SO_BYPASS_RFS) on an MPTCP socket fails. The option is
also not in the comment there that lists unsupported options.

MPTCP records RFS entries per subflow through
mptcp_rps_record_subflows()->sock_rps_record_flow(ssk), which tests
ssk->sk_bypass_rfs. sync_socket_options() copies sk_incoming_cpu to new
subflows but has nothing for sk_bypass_rfs. So allowing the option on
the msk alone would not affect the subflows.

SO_INCOMING_CPU is handled in mptcp_setsockopt_sol_socket(),
mptcp_sol_socket_sync_intval() and sync_socket_options(). Could
SO_BYPASS_RFS be handled the same way, or at least be listed as
unsupported?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261109014547.81555-1-vitaly.zuevsky%40gcore.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net-next v2] net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS
  2026-11-09  1:45 [PATCH net-next v2] net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS Vitaly Zuevsky
       [not found] ` <sashiko-outbox-205984@kernel.org>
  2026-11-12  1:46 ` netdev-bot+sashiko
@ 2026-11-12  1:57 ` Jakub Kicinski
  2 siblings, 0 replies; 4+ messages in thread
From: Jakub Kicinski @ 2026-11-12  1:57 UTC (permalink / raw)
  To: Vitaly Zuevsky
  Cc: netdev, David Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
	Jonathan Corbet, Shuah Khan, Randy Dunlap, Richard Henderson,
	Matt Turner, Magnus Lindholm, Thomas Bogendoerfer,
	James E.J. Bottomley, Helge Deller, Andreas Larsson,
	Kuniyuki Iwashima, Willem de Bruijn, Arnd Bergmann,
	Christian Brauner, Andrew Halaney, Jori Koolstra,
	Alexander Mikhalitsyn, Tariq Toukan, Saeed Mahameed, Chuang Wang,
	linux-doc, linux-kernel, linux-alpha, linux-mips, linux-parisc,
	sparclinux, linux-arch

On Sun,  8 Nov 2026 20:45:47 -0500 Vitaly Zuevsky wrote:
> RFS and accelerated RFS are enabled per host and per rx queue, but
> whether steering helps is a property of the flow. A host that carries
> a few long-lived flows which benefit from steering alongside a large
> churn of short-lived flows which arrive on the right CPU already has
> no way to express that today.

1) Please respond to netdev-bot+sashiko@kernel.org, we don't use 
the global bot (you only got a reply from it because you CCed half 
of the universe for no real reason).

2) Some data showing the win from this on real production workloads
would be nice.

3) The API looks backwards? I'd think that most users would want an opt
in for sockets they care about rather than having to chase down every
other socket on the system to exclude?

4) Please trim the slop in the documentation.
-- 
pw-bot: cr

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-11-12  1:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09  1:45 [PATCH net-next v2] net: add SO_BYPASS_RFS to exclude a socket from RFS and aRFS Vitaly Zuevsky
     [not found] ` <sashiko-outbox-205984@kernel.org>
2026-11-11 16:47   ` Vitaly Zuevsky
2026-11-12  1:46 ` netdev-bot+sashiko
2026-11-12  1:57 ` Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox