[PATCH mptcp-next v2 1/2] net: Add rfs_needed() helper

Christoph Paasch via B4 Relay posted 2 patches 3 weeks, 1 day ago
[PATCH mptcp-next v2 1/2] net: Add rfs_needed() helper
Posted by Christoph Paasch via B4 Relay 3 weeks, 1 day ago
From: Christoph Paasch <cpaasch@openai.com>

Add a helper to check if RFS is needed or not. Allows to make the code a
bit cleaner and the next patch to have MPTCP use this helper to decide
whether or not to iterate over the subflows.

tun_flow_update() was calling sock_rps_record_flow_hash() regardless of
the state of rfs_needed. This was not really a bug as sock_flow_table
simply ends up being NULL and thus everything will be fine.
This commit here thus also implicitly makes tun_flow_update() respect
the state of rfs_needed.

Suggested-by: Matthieu Baerts <matttbe@kernel.org>
Signed-off-by: Christoph Paasch <cpaasch@openai.com>
---
 include/net/rps.h | 85 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 56 insertions(+), 29 deletions(-)

diff --git a/include/net/rps.h b/include/net/rps.h
index d8ab3a08bcc4882e2ad9c84c22ef26b254c14680..a89d2822a257a1fcf54e9722fdc22d01c28cc87b 100644
--- a/include/net/rps.h
+++ b/include/net/rps.h
@@ -82,11 +82,8 @@ static inline void rps_record_sock_flow(struct rps_sock_flow_table *table,
 		WRITE_ONCE(table->ents[index], val);
 }
 
-#endif /* CONFIG_RPS */
-
-static inline void sock_rps_record_flow_hash(__u32 hash)
+static inline void _sock_rps_record_flow_hash(__u32 hash)
 {
-#ifdef CONFIG_RPS
 	struct rps_sock_flow_table *sock_flow_table;
 
 	if (!hash)
@@ -96,42 +93,33 @@ static inline void sock_rps_record_flow_hash(__u32 hash)
 	if (sock_flow_table)
 		rps_record_sock_flow(sock_flow_table, hash);
 	rcu_read_unlock();
-#endif
 }
 
-static inline void sock_rps_record_flow(const struct sock *sk)
+static inline void _sock_rps_record_flow(const struct sock *sk)
 {
-#ifdef CONFIG_RPS
-	if (static_branch_unlikely(&rfs_needed)) {
-		/* Reading sk->sk_rxhash might incur an expensive cache line
-		 * miss.
-		 *
-		 * TCP_ESTABLISHED does cover almost all states where RFS
-		 * might be useful, and is cheaper [1] than testing :
-		 *	IPv4: inet_sk(sk)->inet_daddr
-		 * 	IPv6: ipv6_addr_any(&sk->sk_v6_daddr)
-		 * OR	an additional socket flag
-		 * [1] : sk_state and sk_prot are in the same cache line.
+	/* Reading sk->sk_rxhash might incur an expensive cache line
+	 * miss.
+	 *
+	 * TCP_ESTABLISHED does cover almost all states where RFS
+	 * might be useful, and is cheaper [1] than testing :
+	 *	IPv4: inet_sk(sk)->inet_daddr
+	 *	IPv6: ipv6_addr_any(&sk->sk_v6_daddr)
+	 * OR	an additional socket flag
+	 * [1] : sk_state and sk_prot are in the same cache line.
+	 */
+	if (sk->sk_state == TCP_ESTABLISHED) {
+		/* This READ_ONCE() is paired with the WRITE_ONCE()
+		 * from sock_rps_save_rxhash() and sock_rps_reset_rxhash().
 		 */
-		if (sk->sk_state == TCP_ESTABLISHED) {
-			/* This READ_ONCE() is paired with the WRITE_ONCE()
-			 * from sock_rps_save_rxhash() and sock_rps_reset_rxhash().
-			 */
-			sock_rps_record_flow_hash(READ_ONCE(sk->sk_rxhash));
-		}
+		_sock_rps_record_flow_hash(READ_ONCE(sk->sk_rxhash));
 	}
-#endif
 }
 
-static inline void sock_rps_delete_flow(const struct sock *sk)
+static inline void _sock_rps_delete_flow(const struct sock *sk)
 {
-#ifdef CONFIG_RPS
 	struct rps_sock_flow_table *table;
 	u32 hash, index;
 
-	if (!static_branch_unlikely(&rfs_needed))
-		return;
-
 	hash = READ_ONCE(sk->sk_rxhash);
 	if (!hash)
 		return;
@@ -144,6 +132,45 @@ static inline void sock_rps_delete_flow(const struct sock *sk)
 			WRITE_ONCE(table->ents[index], RPS_NO_CPU);
 	}
 	rcu_read_unlock();
+}
+#endif /* CONFIG_RPS */
+
+static inline bool rfs_is_needed(void)
+{
+#ifdef CONFIG_RPS
+	return static_branch_unlikely(&rfs_needed);
+#else
+	return false;
+#endif
+}
+
+static inline void sock_rps_record_flow_hash(__u32 hash)
+{
+#ifdef CONFIG_RPS
+	if (!rfs_is_needed())
+		return;
+
+	_sock_rps_record_flow_hash(hash);
+#endif
+}
+
+static inline void sock_rps_record_flow(const struct sock *sk)
+{
+#ifdef CONFIG_RPS
+	if (!rfs_is_needed())
+		return;
+
+	_sock_rps_record_flow(sk);
+#endif
+}
+
+static inline void sock_rps_delete_flow(const struct sock *sk)
+{
+#ifdef CONFIG_RPS
+	if (!rfs_is_needed())
+		return;
+
+	_sock_rps_delete_flow(sk);
 #endif
 }
 

-- 
2.50.1
Re: [PATCH mptcp-next v2 1/2] net: Add rfs_needed() helper
Posted by Matthieu Baerts 2 weeks, 6 days ago
Hi Christoph,

On 26/08/2025 06:30, Christoph Paasch via B4 Relay wrote:
> From: Christoph Paasch <cpaasch@openai.com>
> 
> Add a helper to check if RFS is needed or not. Allows to make the code a
> bit cleaner and the next patch to have MPTCP use this helper to decide
> whether or not to iterate over the subflows.
> 
> tun_flow_update() was calling sock_rps_record_flow_hash() regardless of
> the state of rfs_needed. This was not really a bug as sock_flow_table
> simply ends up being NULL and thus everything will be fine.
> This commit here thus also implicitly makes tun_flow_update() respect
> the state of rfs_needed.

Thank you for having added this new helper!

Acked-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>

> Suggested-by: Matthieu Baerts <matttbe@kernel.org>
> Signed-off-by: Christoph Paasch <cpaasch@openai.com>
> ---
>  include/net/rps.h | 85 ++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 56 insertions(+), 29 deletions(-)
> 
> diff --git a/include/net/rps.h b/include/net/rps.h
> index d8ab3a08bcc4882e2ad9c84c22ef26b254c14680..a89d2822a257a1fcf54e9722fdc22d01c28cc87b 100644
> --- a/include/net/rps.h
> +++ b/include/net/rps.h

(...)
> @@ -144,6 +132,45 @@ static inline void sock_rps_delete_flow(const struct sock *sk)
>  			WRITE_ONCE(table->ents[index], RPS_NO_CPU);
>  	}
>  	rcu_read_unlock();
> +}
> +#endif /* CONFIG_RPS */
> +
> +static inline bool rfs_is_needed(void)
> +{
> +#ifdef CONFIG_RPS
> +	return static_branch_unlikely(&rfs_needed);
> +#else
> +	return false;
> +#endif

It looks strange to see all these #ifdef/#else inside the functions,
instead of "empty" functions at the end when CONFIG_RPS is not defined
as it is usually being done. But I see you are following what is
currently being done in this file, so all good!

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.
Re: [PATCH mptcp-next v2 1/2] net: Add rfs_needed() helper
Posted by Christoph Paasch 2 weeks, 6 days ago
[resend without HTML - how do I turn on "Plain Text Mode" in the gmail app ???]

On Thu, Aug 28, 2025 at 8:50 AM Matthieu Baerts <matttbe@kernel.org> wrote:
>
> Hi Christoph,
>
> On 26/08/2025 06:30, Christoph Paasch via B4 Relay wrote:
> > From: Christoph Paasch <cpaasch@openai.com>
> >
> > Add a helper to check if RFS is needed or not. Allows to make the code a
> > bit cleaner and the next patch to have MPTCP use this helper to decide
> > whether or not to iterate over the subflows.
> >
> > tun_flow_update() was calling sock_rps_record_flow_hash() regardless of
> > the state of rfs_needed. This was not really a bug as sock_flow_table
> > simply ends up being NULL and thus everything will be fine.
> > This commit here thus also implicitly makes tun_flow_update() respect
> > the state of rfs_needed.
>
> Thank you for having added this new helper!
>
> Acked-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
>
> > Suggested-by: Matthieu Baerts <matttbe@kernel.org>
> > Signed-off-by: Christoph Paasch <cpaasch@openai.com>
> > ---
> >  include/net/rps.h | 85 ++++++++++++++++++++++++++++++++++++-------------------
> >  1 file changed, 56 insertions(+), 29 deletions(-)
> >
> > diff --git a/include/net/rps.h b/include/net/rps.h
> > index d8ab3a08bcc4882e2ad9c84c22ef26b254c14680..a89d2822a257a1fcf54e9722fdc22d01c28cc87b 100644
> > --- a/include/net/rps.h
> > +++ b/include/net/rps.h
>
> (...)
> > @@ -144,6 +132,45 @@ static inline void sock_rps_delete_flow(const struct sock *sk)
> >                       WRITE_ONCE(table->ents[index], RPS_NO_CPU);
> >       }
> >       rcu_read_unlock();
> > +}
> > +#endif /* CONFIG_RPS */
> > +
> > +static inline bool rfs_is_needed(void)
> > +{
> > +#ifdef CONFIG_RPS
> > +     return static_branch_unlikely(&rfs_needed);
> > +#else
> > +     return false;
> > +#endif
>
> It looks strange to see all these #ifdef/#else inside the functions,
> instead of "empty" functions at the end when CONFIG_RPS is not defined
> as it is usually being done. But I see you are following what is
> currently being done in this file, so all good!

Yes, I also prefer the style with the empty function. But also yes, I
just followed the style of the file.


Christoph