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
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.
[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
© 2016 - 2025 Red Hat, Inc.