Skip to contentSkip to conversation

net: introduce rps_default_mask

PATCH Applied Paolo Abeni 4 participants 11 messages Feb 7, 2023 – Feb 10, 2023

Subsystems (4)
lore
Share & tools
lore

Paolo Abeni

author maintainer
#0 lore raw

v4 cover net: introduce rps_default_mask

Real-time setups try hard to ensure proper isolation between time critical applications and e.g. network processing performed by the network stack in softirq and RPS is used to move the softirq activity away from the isolated core.

If the network configuration is dynamic, with netns and devices routinely created at run-time, enforcing the correct RPS setting on each newly created device allowing to transient bad configuration became complex.

Additionally, when multi-queue devices are involved, configuring rps in user-space on each queue easily becomes very expensive, e.g. some setups use veths with per cpu queues.

These series try to address the above, introducing a new sysctl knob: rps_default_mask. The new sysctl entry allows configuring a netns-wide RPS mask, to be enforced since receive queue creation time without any fourther per device configuration required.

Additionally, a simple self-test is introduced to check the rps_default_mask behavior.

v3 -> v4:
- fix build warning

v2 -> v3:
- reduce code duplication
- rebased

Paolo Abeni (4):
net-sysctl: factor out cpumask parsing helper
net-sysctl: factor-out rpm mask manipulation helpers
net: introduce default_rps_mask netns attribute
self-tests: introduce self-tests for RPS default mask

 Documentation/admin-guide/sysctl/net.rst      |  6 ++
 include/linux/netdevice.h                     |  1 +
 net/core/dev.h                                |  2 +
 net/core/net-sysfs.c                          | 79 +++++++++++-------
 net/core/sysctl_net_core.c                    | 81 ++++++++++++++-----
 tools/testing/selftests/net/Makefile          |  1 +
 tools/testing/selftests/net/config            |  3 +
 .../testing/selftests/net/rps_default_mask.sh | 57 +++++++++++++
 8 files changed, 182 insertions(+), 48 deletions(-)
 create mode 100755 tools/testing/selftests/net/rps_default_mask.sh
Signature · 1 line
2.39.1
author maintainer
#1 lore raw

PATCH v4 1/4 net-sysctl: factor out cpumask parsing helper

Will be used by the following patch to avoid code duplication. No functional changes intended.

The only difference is that now flow_limit_cpu_sysctl() will always compute the flow limit mask on each read operation, even when read() will not return any byte to user-space.

Note that the new helper is placed under a new #ifdef at the file start to better fit the usage in the later patch

---
v3 -> v4:
- fix warning reported by the kernel test robot

---
 net/core/sysctl_net_core.c | 46 +++++++++++++++++++++++---------------
 1 file changed, 28 insertions(+), 18 deletions(-)
net/core/sysctl_net_core.c +28 -18
index e7b98162c632..6935ecdc84b0 100644
@@ -45,6 +45,33 @@ EXPORT_SYMBOL(sysctl_fb_tunnels_only_for_init_net);
 int sysctl_devconf_inherit_init_net __read_mostly;
 EXPORT_SYMBOL(sysctl_devconf_inherit_init_net);
 
+#if IS_ENABLED(CONFIG_NET_FLOW_LIMIT)
+static void dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
+			 struct cpumask *mask)
+{
+	char kbuf[128];
+	int len;
+
+	if (*ppos || !*lenp) {
+		*lenp = 0;
+		return;
+	}
+
+	len = min(sizeof(kbuf) - 1, *lenp);
+	len = scnprintf(kbuf, len, "%*pb", cpumask_pr_args(mask));
+	if (!len) {
+		*lenp = 0;
+		return;
+	}
+
+	if (len < *lenp)
+		kbuf[len++] = '\n';
+	memcpy(buffer, kbuf, len);
+	*lenp = len;
+	*ppos += len;
+}
+#endif
+
 #ifdef CONFIG_RPS
 static int rps_sock_flow_sysctl(struct ctl_table *table, int write,
 				void *buffer, size_t *lenp, loff_t *ppos)
@@ -155,13 +182,6 @@ static int flow_limit_cpu_sysctl(struct ctl_table *table, int write,
 write_unlock:
 		mutex_unlock(&flow_limit_update_mutex);
 	} else {
-		char kbuf[128];
-
-		if (*ppos || !*lenp) {
-			*lenp = 0;
-			goto done;
-		}
-
 		cpumask_clear(mask);
 		rcu_read_lock();
 		for_each_possible_cpu(i) {
@@ -171,17 +191,7 @@ static int flow_limit_cpu_sysctl(struct ctl_table *table, int write,
 		}
 		rcu_read_unlock();
 
-		len = min(sizeof(kbuf) - 1, *lenp);
-		len = scnprintf(kbuf, len, "%*pb", cpumask_pr_args(mask));
-		if (!len) {
-			*lenp = 0;
-			goto done;
-		}
-		if (len < *lenp)
-			kbuf[len++] = '\n';
-		memcpy(buffer, kbuf, len);
-		*lenp = len;
-		*ppos += len;
+		dump_cpumask(buffer, lenp, ppos, mask);
 	}
 
 done:
Signature · 1 line
2.39.1
Reviewed-by on v4 1/4
#2 lore raw

Re: [PATCH v4 net-next 1/4] net-sysctl: factor out cpumask parsing helper

Quoted 11 lines · Paolo Abeni

Will be used by the following patch to avoid code duplication. No functional changes intended.

The only difference is that now flow_limit_cpu_sysctl() will always compute the flow limit mask on each read operation, even when read() will not return any byte to user-space.

Note that the new helper is placed under a new #ifdef at the file start to better fit the usage in the later patch

author maintainer
#3 lore raw

PATCH v4 2/4 net-sysctl: factor-out rpm mask manipulation helpers

In reply to Paolo Abeni

Will simplify the following patch. No functional change intended.

---
v2 -> v3: factor out the new rps_cpumask_housekeeping() helper

---
 net/core/dev.h       |  2 ++
 net/core/net-sysfs.c | 72 ++++++++++++++++++++++++++------------------
 2 files changed, 44 insertions(+), 30 deletions(-)
net/core/dev.h +2 -0
index a065b7571441..e075e198092c 100644
@@ -9,6 +9,7 @@ struct net_device;
 struct netdev_bpf;
 struct netdev_phys_item_id;
 struct netlink_ext_ack;
+struct cpumask;
 
 /* Random bits of netdevice that don't need to be exposed */
 #define FLOW_LIMIT_HISTORY	(1 << 7)  /* must be ^2 and !overflow buckets */
@@ -134,4 +135,5 @@ static inline void netif_set_gro_ipv4_max_size(struct net_device *dev,
 	WRITE_ONCE(dev->gro_ipv4_max_size, size);
 }
 
+int rps_cpumask_housekeeping(struct cpumask *mask);
 #endif
net/core/net-sysfs.c +42 -30

93 lines not on this page · raw message

Signature · 1 line
2.39.1
author maintainer
#5 lore raw

PATCH v4 3/4 net: introduce default_rps_mask netns attribute

In reply to Paolo Abeni

If RPS is enabled, this allows configuring a default rps mask, which is effective since receive queue creation time.

A default RPS mask allows the system admin to ensure proper isolation, avoiding races at network namespace or device creation time.

The default RPS mask is initially empty, and can be modified via a newly added sysctl entry.

---
v2 -> v3:
- avoid a bit of code duplication thanks to new helpers in patch 1/4 and 2/4

---
 Documentation/admin-guide/sysctl/net.rst |  6 ++++
 include/linux/netdevice.h                |  1 +
 net/core/net-sysfs.c                     |  7 +++++
 net/core/sysctl_net_core.c               | 37 +++++++++++++++++++++++-
 4 files changed, 50 insertions(+), 1 deletion(-)
Documentation/admin-guide/sysctl/net.rst +6 -0
index 6394f5dc2303..466c560b0c30 100644
@@ -215,6 +215,12 @@ rmem_max
 
 The maximum receive socket buffer size in bytes.
 
+rps_default_mask
+----------------
+
+The default RPS CPU mask used on newly created network devices. An empty
+mask means RPS disabled by default.
+
 tstamp_allow_data
 -----------------
 Allow processes to receive tx timestamps looped together with the original
include/linux/netdevice.h +1 -0
index d5ef4c1fedd2..38ab96ae0d68 100644
@@ -223,6 +223,7 @@ struct net_device_core_stats {
 #include <linux/static_key.h>
 extern struct static_key_false rps_needed;
 extern struct static_key_false rfs_needed;
+extern struct cpumask rps_default_mask;
 #endif
 
 struct neighbour;
net/core/net-sysfs.c +7 -0
index 2126970a4bfd..4b361ac6a252 100644
@@ -1083,6 +1083,13 @@ static int rx_queue_add_kobject(struct net_device *dev, int index)
 			goto err;
 	}
 
+#if IS_ENABLED(CONFIG_RPS) && IS_ENABLED(CONFIG_SYSCTL)
+	if (!cpumask_empty(&rps_default_mask)) {
+		error = netdev_rx_queue_set_rps_mask(queue, &rps_default_mask);
+		if (error)
+			goto err;
+	}
+#endif
 	kobject_uevent(kobj, KOBJ_ADD);
 
 	return error;
net/core/sysctl_net_core.c +36 -1
index 6935ecdc84b0..7130e6d9e263 100644
@@ -16,6 +16,7 @@
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/sched/isolation.h>
 
 #include <net/ip.h>
 #include <net/sock.h>
@@ -45,7 +46,7 @@ EXPORT_SYMBOL(sysctl_fb_tunnels_only_for_init_net);
 int sysctl_devconf_inherit_init_net __read_mostly;
 EXPORT_SYMBOL(sysctl_devconf_inherit_init_net);
 
-#if IS_ENABLED(CONFIG_NET_FLOW_LIMIT)
+#if IS_ENABLED(CONFIG_NET_FLOW_LIMIT) || IS_ENABLED(CONFIG_RPS)
 static void dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
 			 struct cpumask *mask)
 {
@@ -73,6 +74,31 @@ static void dump_cpumask(void *buffer, size_t *lenp, loff_t *ppos,
 #endif
 
 #ifdef CONFIG_RPS
+struct cpumask rps_default_mask;
+
+static int rps_default_mask_sysctl(struct ctl_table *table, int write,
+				   void *buffer, size_t *lenp, loff_t *ppos)
+{
+	int err = 0;
+
+	rtnl_lock();
+	if (write) {
+		err = cpumask_parse(buffer, &rps_default_mask);
+		if (err)
+			goto done;
+
+		err = rps_cpumask_housekeeping(&rps_default_mask);
+		if (err)
+			goto done;
+	} else {
+		dump_cpumask(buffer, lenp, ppos, &rps_default_mask);
+	}
+
+done:
+	rtnl_unlock();
+	return err;
+}
+
 static int rps_sock_flow_sysctl(struct ctl_table *table, int write,
 				void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -482,6 +508,11 @@ static struct ctl_table net_core_table[] = {
 		.mode		= 0644,
 		.proc_handler	= rps_sock_flow_sysctl
 	},
+	{
+		.procname	= "rps_default_mask",
+		.mode		= 0644,
+		.proc_handler	= rps_default_mask_sysctl
+	},
 #endif
 #ifdef CONFIG_NET_FLOW_LIMIT
 	{
@@ -685,6 +716,10 @@ static __net_initdata struct pernet_operations sysctl_core_ops = {
 
 static __init int sysctl_core_init(void)
 {
+#if IS_ENABLED(CONFIG_RPS)
+	cpumask_copy(&rps_default_mask, cpu_none_mask);
+#endif
+
 	register_net_sysctl(&init_net, "net/core", net_core_table);
 	return register_pernet_subsys(&sysctl_core_ops);
 }
Signature · 1 line
2.39.1
Reviewed-by on v4 3/4
#6 lore raw

Re: [PATCH v4 net-next 3/4] net: introduce default_rps_mask netns attribute

Quoted 11 lines · Paolo Abeni

If RPS is enabled, this allows configuring a default rps mask, which is effective since receive queue creation time.

A default RPS mask allows the system admin to ensure proper isolation, avoiding races at network namespace or device creation time.

The default RPS mask is initially empty, and can be modified via a newly added sysctl entry.

author maintainer
#7 lore raw

PATCH v4 4/4 self-tests: introduce self-tests for RPS default mask

In reply to Paolo Abeni

Ensure that RPS default mask changes take place on all newly created netns/devices and don't affect existing ones.

---
 tools/testing/selftests/net/Makefile          |  1 +
 tools/testing/selftests/net/config            |  3 +
 .../testing/selftests/net/rps_default_mask.sh | 57 +++++++++++++++++++
 3 files changed, 61 insertions(+)
 create mode 100755 tools/testing/selftests/net/rps_default_mask.sh
tools/testing/selftests/net/Makefile +1 -0
index 951bd5342bc6..3364c548a23b 100644
@@ -46,6 +46,7 @@ TEST_PROGS += stress_reuseport_listen.sh
 TEST_PROGS += l2_tos_ttl_inherit.sh
 TEST_PROGS += bind_bhash.sh
 TEST_PROGS += ip_local_port_range.sh
+TEST_PROGS += rps_default_mask.sh
 TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
 TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh
 TEST_GEN_FILES =  socket nettest
tools/testing/selftests/net/config +3 -0
index bd89198cd817..cc9fd55ab869 100644
@@ -3,6 +3,9 @@ CONFIG_NET_NS=y
 CONFIG_BPF_SYSCALL=y
 CONFIG_TEST_BPF=m
 CONFIG_NUMA=y
+CONFIG_RPS=y
+CONFIG_SYSFS=y
+CONFIG_PROC_SYSCTL=y
 CONFIG_NET_VRF=y
 CONFIG_NET_L3_MASTER_DEV=y
 CONFIG_IPV6=y
tools/testing/selftests/net/rps_default_mask.sh new file +57 -0

57 lines not on this page · raw message

Signature · 1 line
2.39.1
Reviewed-by on the v4 series
#9 lore raw
In reply to Paolo Abeni
Quoted 15 lines · Paolo Abeni

Real-time setups try hard to ensure proper isolation between time critical applications and e.g. network processing performed by the network stack in softirq and RPS is used to move the softirq activity away from the isolated core.

If the network configuration is dynamic, with netns and devices routinely created at run-time, enforcing the correct RPS setting on each newly created device allowing to transient bad configuration became complex.

Additionally, when multi-queue devices are involved, configuring rps in user-space on each queue easily becomes very expensive, e.g. some setups use veths with per cpu queues.

Quoted 5 lines

These series try to address the above, introducing a new sysctl knob: rps_default_mask. The new sysctl entry allows configuring a netns-wide RPS mask, to be enforced since receive queue creation time without any fourther per device configuration required.

#10 lore raw
In reply to Paolo Abeni
This series was applied to netdev/net-next.git (master) by Jakub Kicinski <[email protected]>:

Hello:

This series was applied to netdev/net-next.git (master) by Jakub Kicinski <[email protected]>:

Quoted 11 lines · On Tue, 7 Feb 2023 19:44:54 +0100 you wrote:

Real-time setups try hard to ensure proper isolation between time critical applications and e.g. network processing performed by the network stack in softirq and RPS is used to move the softirq activity away from the isolated core.

If the network configuration is dynamic, with netns and devices routinely created at run-time, enforcing the correct RPS setting on each newly created device allowing to transient bad configuration became complex.

[...]

Here is the summary with links:
- [v4,net-next,1/4] net-sysctl: factor out cpumask parsing helper

    https://git.kernel.org/netdev/net-next/c/135746c61fa6
  - [v4,net-next,2/4] net-sysctl: factor-out rpm mask manipulation helpers
    https://git.kernel.org/netdev/net-next/c/370ca718fd5e
  - [v4,net-next,3/4] net: introduce default_rps_mask netns attribute
    https://git.kernel.org/netdev/net-next/c/605cfa1b1090
  - [v4,net-next,4/4] self-tests: introduce self-tests for RPS default mask
    https://git.kernel.org/netdev/net-next/c/c12e0d5f267d

You are awesome, thank you!

Signature · 2 lines
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html