mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Alexey Gladkov <legion@kernel.org>
To: Linus Torvalds <torvalds@linux-foundation.org>,
	"Eric W . Biederman" <ebiederm@xmission.com>,
	Kees Cook <kees@kernel.org>,
	Joel Granados <joel.granados@kernel.org>
Cc: LKML <linux-kernel@vger.kernel.org>, linux-fsdevel@vger.kernel.org
Subject: [RFC PATCH v1 18/30] sysctl: net: use sysctl_field in core IPv6 sysctls
Date: Wed, 26 Aug 2026 21:42:22 +0200	[thread overview]
Message-ID: <e10a1f7d819dde0bfa5931479f28ce6e4cc2b158.1787771905.git.legion@kernel.org> (raw)
In-Reply-To: <cover.1787771905.git.legion@kernel.org>

The core IPv6, route and ICMP sysctl tables are per-netns, but they
currently get there by cloning ctl_table arrays and patching each data
pointer after allocation. That keeps writable table copies around for
every net namespace and makes the code depend on table indexes staying
in sync with the patch-up code.

Describe these tables with sysctl_field instead. The data pointers are
now derived from the registration context, so the tables can stay static
and const while still resolving to the right net namespace.

Keep the few non-standard handlers as custom fields. The route flush
handler now derives the net namespace from its data pointer instead of
using extra1, and the multipath and wide IOAM handlers keep their limits
inside the handler-local ctl_table copy.

Signed-off-by: Alexey Gladkov <legion@kernel.org>
---
 include/net/ipv6.h         |   6 +-
 net/ipv6/icmp.c            | 127 ++++++---------
 net/ipv6/route.c           | 173 ++++++++------------
 net/ipv6/sysctl_net_ipv6.c | 322 ++++++++++++-------------------------
 4 files changed, 224 insertions(+), 404 deletions(-)

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 1dec81faff28..08ede58aabfb 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -1207,10 +1207,8 @@ static inline int snmp6_unregister_dev(struct inet6_dev *idev) { return 0; }
 #endif
 
 #ifdef CONFIG_SYSCTL
-struct ctl_table *ipv6_icmp_sysctl_init(struct net *net);
-size_t ipv6_icmp_sysctl_table_size(void);
-struct ctl_table *ipv6_route_sysctl_init(struct net *net);
-size_t ipv6_route_sysctl_table_size(struct net *net);
+int ipv6_icmp_sysctl_register(struct sysctl_context *ctx);
+int ipv6_route_sysctl_register(struct sysctl_context *ctx);
 int ipv6_sysctl_register(void);
 void ipv6_sysctl_unregister(void);
 #endif
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index efb23807a026..8fd0dc035ccd 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -1371,87 +1371,62 @@ EXPORT_SYMBOL(icmpv6_err_convert);
 
 #ifdef CONFIG_SYSCTL
 
-static u32 icmpv6_errors_extension_mask_all =
+static unsigned int icmpv6_errors_extension_mask_all =
 	GENMASK_U8(ICMP_ERR_EXT_COUNT - 1, 0);
 
-static struct ctl_table ipv6_icmp_table_template[] = {
-	{
-		.procname	= "ratelimit",
-		.data		= &init_net.ipv6.sysctl.icmpv6_time,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec_ms_jiffies,
-	},
-	{
-		.procname	= "echo_ignore_all",
-		.data		= &init_net.ipv6.sysctl.icmpv6_echo_ignore_all,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler = proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "echo_ignore_multicast",
-		.data		= &init_net.ipv6.sysctl.icmpv6_echo_ignore_multicast,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler = proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "echo_ignore_anycast",
-		.data		= &init_net.ipv6.sysctl.icmpv6_echo_ignore_anycast,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler = proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "ratemask",
-		.data		= &init_net.ipv6.sysctl.icmpv6_ratemask_ptr,
-		.maxlen		= ICMPV6_MSG_MAX + 1,
-		.mode		= 0644,
-		.proc_handler = proc_do_large_bitmap,
-	},
-	{
-		.procname	= "error_anycast_as_unicast",
-		.data		= &init_net.ipv6.sysctl.icmpv6_error_anycast_as_unicast,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-		.extra1		= SYSCTL_ZERO,
-		.extra2		= SYSCTL_ONE,
-	},
-	{
-		.procname	= "errors_extension_mask",
-		.data		= &init_net.ipv6.sysctl.icmpv6_errors_extension_mask,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-		.extra1		= SYSCTL_ZERO,
-		.extra2		= &icmpv6_errors_extension_mask_all,
-	},
-};
+#define IPV6_ICMP_DATA(type, name, field)				\
+static type *ipv6_icmp_##name##_data(const struct sysctl_context *ctx)	\
+{									\
+	return &ctx->ns.net_ns->ipv6.sysctl.field;			\
+}
 
-struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net)
-{
-	struct ctl_table *table;
-
-	table = kmemdup(ipv6_icmp_table_template,
-			sizeof(ipv6_icmp_table_template),
-			GFP_KERNEL);
-
-	if (table) {
-		table[0].data = &net->ipv6.sysctl.icmpv6_time;
-		table[1].data = &net->ipv6.sysctl.icmpv6_echo_ignore_all;
-		table[2].data = &net->ipv6.sysctl.icmpv6_echo_ignore_multicast;
-		table[3].data = &net->ipv6.sysctl.icmpv6_echo_ignore_anycast;
-		table[4].data = &net->ipv6.sysctl.icmpv6_ratemask_ptr;
-		table[5].data = &net->ipv6.sysctl.icmpv6_error_anycast_as_unicast;
-		table[6].data = &net->ipv6.sysctl.icmpv6_errors_extension_mask;
-	}
-	return table;
+#define IPV6_ICMP_CUSTOM_DATA(name, field)				\
+static void *ipv6_icmp_##name##_data(const struct sysctl_context *ctx)	\
+{									\
+	return &ctx->ns.net_ns->ipv6.sysctl.field;			\
 }
 
-size_t ipv6_icmp_sysctl_table_size(void)
+IPV6_ICMP_CUSTOM_DATA(ratelimit, icmpv6_time)
+IPV6_ICMP_DATA(u8, echo_ignore_all, icmpv6_echo_ignore_all)
+IPV6_ICMP_DATA(u8, echo_ignore_multicast, icmpv6_echo_ignore_multicast)
+IPV6_ICMP_DATA(u8, echo_ignore_anycast, icmpv6_echo_ignore_anycast)
+IPV6_ICMP_CUSTOM_DATA(ratemask, icmpv6_ratemask_ptr)
+IPV6_ICMP_DATA(u8, error_anycast_as_unicast,
+	       icmpv6_error_anycast_as_unicast)
+IPV6_ICMP_DATA(u8, errors_extension_mask,
+	       icmpv6_errors_extension_mask)
+
+static const struct sysctl_field ipv6_icmp_table[] = {
+	SYSCTL_FIELD_CUSTOM("ratelimit", 0644, sizeof(int),
+			 ipv6_icmp_ratelimit_data, proc_dointvec_ms_jiffies),
+	SYSCTL_FIELD_U8("echo_ignore_all", 0644,
+		     ipv6_icmp_echo_ignore_all_data),
+	SYSCTL_FIELD_U8("echo_ignore_multicast", 0644,
+		     ipv6_icmp_echo_ignore_multicast_data),
+	SYSCTL_FIELD_U8("echo_ignore_anycast", 0644,
+		     ipv6_icmp_echo_ignore_anycast_data),
+	SYSCTL_FIELD_CUSTOM("ratemask", 0644, ICMPV6_MSG_MAX + 1,
+			 ipv6_icmp_ratemask_data, proc_do_large_bitmap),
+	SYSCTL_FIELD_STATIC_U8_MINMAX("error_anycast_as_unicast", 0644,
+				   ipv6_icmp_error_anycast_as_unicast_data,
+				   SYSCTL_UINT_ZERO, SYSCTL_UINT_ONE),
+	SYSCTL_FIELD_STATIC_U8_MINMAX("errors_extension_mask", 0644,
+				   ipv6_icmp_errors_extension_mask_data,
+				   SYSCTL_UINT_ZERO,
+				   &icmpv6_errors_extension_mask_all),
+};
+
+int ipv6_icmp_sysctl_register(struct sysctl_context *ctx)
 {
-	return ARRAY_SIZE(ipv6_icmp_table_template);
+	struct ctl_table_header *hdr;
+
+	hdr = register_sysctl_fields(&ctx->ns.net_ns->sysctls, "net/ipv6/icmp",
+				     ipv6_icmp_table, ctx);
+	if (!hdr)
+		return -ENOMEM;
+
+	ctx->ns.net_ns->ipv6.sysctl.icmp_hdr = hdr;
+
+	return 0;
 }
 #endif
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b106e5fef9cb..4861972d6bd3 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -6539,127 +6539,82 @@ static int ipv6_sysctl_rtcache_flush(const struct ctl_table *ctl, int write,
 	if (ret)
 		return ret;
 
-	net = (struct net *)ctl->extra1;
+	net = container_of(ctl->data, struct net, ipv6.sysctl.flush_delay);
 	delay = READ_ONCE(net->ipv6.sysctl.flush_delay);
 	fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
 	return 0;
 }
 
-static struct ctl_table ipv6_route_table_template[] = {
-	{
-		.procname	=	"max_size",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_max_size,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec,
-	},
-	{
-		.procname	=	"gc_thresh",
-		.data		=	&ip6_dst_ops_template.gc_thresh,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec,
-	},
-	{
-		.procname	=	"flush",
-		.data		=	&init_net.ipv6.sysctl.flush_delay,
-		.maxlen		=	sizeof(int),
-		.mode		=	0200,
-		.proc_handler	=	ipv6_sysctl_rtcache_flush
-	},
-	{
-		.procname	=	"gc_min_interval",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec_jiffies,
-	},
-	{
-		.procname	=	"gc_timeout",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_timeout,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec_jiffies,
-	},
-	{
-		.procname	=	"gc_interval",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_interval,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec_jiffies,
-	},
-	{
-		.procname	=	"gc_elasticity",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec,
-	},
-	{
-		.procname	=	"mtu_expires",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_mtu_expires,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec_jiffies,
-	},
-	{
-		.procname	=	"min_adv_mss",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_min_advmss,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec,
-	},
-	{
-		.procname	=	"gc_min_interval_ms",
-		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_min_interval,
-		.maxlen		=	sizeof(int),
-		.mode		=	0644,
-		.proc_handler	=	proc_dointvec_ms_jiffies,
-	},
-	{
-		.procname	=	"skip_notify_on_dev_down",
-		.data		=	&init_net.ipv6.sysctl.skip_notify_on_dev_down,
-		.maxlen		=	sizeof(u8),
-		.mode		=	0644,
-		.proc_handler	=	proc_dou8vec_minmax,
-		.extra1		=	SYSCTL_ZERO,
-		.extra2		=	SYSCTL_ONE,
-	},
+#define IPV6_ROUTE_DATA(type, name, field)				\
+static type *ipv6_route_##name##_data(const struct sysctl_context *ctx)	\
+{									\
+	return &ctx->ns.net_ns->ipv6.sysctl.field;			\
+}
+
+#define IPV6_ROUTE_CUSTOM_DATA(name, field)				\
+static void *ipv6_route_##name##_data(const struct sysctl_context *ctx)	\
+{									\
+	return &ctx->ns.net_ns->ipv6.sysctl.field;			\
+}
+
+IPV6_ROUTE_DATA(int, max_size, ip6_rt_max_size)
+IPV6_ROUTE_DATA(int, gc_elasticity, ip6_rt_gc_elasticity)
+IPV6_ROUTE_DATA(int, min_adv_mss, ip6_rt_min_advmss)
+IPV6_ROUTE_DATA(u8, skip_notify_on_dev_down, skip_notify_on_dev_down)
+IPV6_ROUTE_CUSTOM_DATA(flush, flush_delay)
+IPV6_ROUTE_CUSTOM_DATA(gc_min_interval, ip6_rt_gc_min_interval)
+IPV6_ROUTE_CUSTOM_DATA(gc_timeout, ip6_rt_gc_timeout)
+IPV6_ROUTE_CUSTOM_DATA(gc_interval, ip6_rt_gc_interval)
+IPV6_ROUTE_CUSTOM_DATA(mtu_expires, ip6_rt_mtu_expires)
+
+static int *ipv6_route_gc_thresh_data(const struct sysctl_context *ctx)
+{
+	return &ctx->ns.net_ns->ipv6.ip6_dst_ops.gc_thresh;
+}
+
+static const struct sysctl_field ipv6_route_table[] = {
+	SYSCTL_FIELD_INT("max_size", 0644, ipv6_route_max_size_data),
+	SYSCTL_FIELD_INT("gc_thresh", 0644, ipv6_route_gc_thresh_data),
+	SYSCTL_FIELD_CUSTOM("flush", 0200, sizeof(int), ipv6_route_flush_data,
+			 ipv6_sysctl_rtcache_flush),
+	SYSCTL_FIELD_CUSTOM("gc_min_interval", 0644, sizeof(int),
+			 ipv6_route_gc_min_interval_data,
+			 proc_dointvec_jiffies),
+	SYSCTL_FIELD_CUSTOM("gc_timeout", 0644, sizeof(int),
+			 ipv6_route_gc_timeout_data, proc_dointvec_jiffies),
+	SYSCTL_FIELD_CUSTOM("gc_interval", 0644, sizeof(int),
+			 ipv6_route_gc_interval_data, proc_dointvec_jiffies),
+	SYSCTL_FIELD_INT("gc_elasticity", 0644,
+		      ipv6_route_gc_elasticity_data),
+	SYSCTL_FIELD_CUSTOM("mtu_expires", 0644, sizeof(int),
+			 ipv6_route_mtu_expires_data, proc_dointvec_jiffies),
+	SYSCTL_FIELD_INT("min_adv_mss", 0644, ipv6_route_min_adv_mss_data),
+	SYSCTL_FIELD_CUSTOM("gc_min_interval_ms", 0644, sizeof(int),
+			 ipv6_route_gc_min_interval_data,
+			 proc_dointvec_ms_jiffies),
+	SYSCTL_FIELD_STATIC_U8_MINMAX("skip_notify_on_dev_down", 0644,
+				   ipv6_route_skip_notify_on_dev_down_data,
+				   SYSCTL_UINT_ZERO, SYSCTL_UINT_ONE),
 };
 
-struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net)
+int ipv6_route_sysctl_register(struct sysctl_context *ctx)
 {
-	struct ctl_table *table;
-
-	table = kmemdup(ipv6_route_table_template,
-			sizeof(ipv6_route_table_template),
-			GFP_KERNEL);
+	struct ctl_table_header *hdr;
+	size_t table_size = ARRAY_SIZE(ipv6_route_table);
 
-	if (table) {
-		table[0].data = &net->ipv6.sysctl.ip6_rt_max_size;
-		table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh;
-		table[2].data = &net->ipv6.sysctl.flush_delay;
-		table[2].extra1 = net;
-		table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
-		table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
-		table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
-		table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
-		table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
-		table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
-		table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
-		table[10].data = &net->ipv6.sysctl.skip_notify_on_dev_down;
-	}
+	/* Don't export sysctls to unprivileged users */
+	if (ctx->ns.net_ns->user_ns != &init_user_ns)
+		table_size = 1;
 
-	return table;
-}
+	hdr = __register_sysctl_fields(&ctx->ns.net_ns->sysctls, "net/ipv6/route",
+				       ipv6_route_table, table_size,
+				       ctx, sizeof(*ctx));
+	if (!hdr)
+		return -ENOMEM;
 
-size_t ipv6_route_sysctl_table_size(struct net *net)
-{
-	/* Don't export sysctls to unprivileged users */
-	if (net->user_ns != &init_user_ns)
-		return 1;
+	ctx->ns.net_ns->ipv6.sysctl.route_hdr = hdr;
 
-	return ARRAY_SIZE(ipv6_route_table_template);
+	return 0;
 }
 #endif
 
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index d2cd33e2698d..45485ead8048 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -10,7 +10,6 @@
 #include <linux/sysctl.h>
 #include <linux/in6.h>
 #include <linux/ipv6.h>
-#include <linux/slab.h>
 #include <linux/export.h>
 #include <net/ndisc.h>
 #include <net/ipv6.h>
@@ -24,21 +23,24 @@
 #include <linux/ioam6.h>
 
 static int flowlabel_reflect_max = 0x7;
-static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
-static u32 rt6_multipath_hash_fields_all_mask =
+static unsigned int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX;
+static unsigned int rt6_multipath_hash_fields_all_mask =
 	FIB_MULTIPATH_HASH_FIELD_ALL_MASK;
-static u32 ioam6_id_max = IOAM6_DEFAULT_ID;
+static unsigned int ioam6_id_max = IOAM6_DEFAULT_ID;
 static u64 ioam6_id_wide_max = IOAM6_DEFAULT_ID_WIDE;
 
 static int proc_rt6_multipath_hash_policy(const struct ctl_table *table, int write,
 					  void *buffer, size_t *lenp, loff_t *ppos)
 {
+	struct ctl_table tmp = *table;
 	struct net *net;
 	int ret;
 
 	net = container_of(table->data, struct net,
 			   ipv6.sysctl.multipath_hash_policy);
-	ret = proc_dou8vec_minmax(table, write, buffer, lenp, ppos);
+	tmp.extra1 = SYSCTL_UINT_ZERO;
+	tmp.extra2 = SYSCTL_UINT_THREE;
+	ret = proc_dou8vec_minmax(&tmp, write, buffer, lenp, ppos);
 	if (write && ret == 0)
 		call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net);
 
@@ -49,170 +51,103 @@ static int
 proc_rt6_multipath_hash_fields(const struct ctl_table *table, int write, void *buffer,
 			       size_t *lenp, loff_t *ppos)
 {
+	struct ctl_table tmp = *table;
 	struct net *net;
 	int ret;
 
 	net = container_of(table->data, struct net,
 			   ipv6.sysctl.multipath_hash_fields);
-	ret = proc_douintvec_minmax(table, write, buffer, lenp, ppos);
+	tmp.extra1 = SYSCTL_UINT_ONE;
+	tmp.extra2 = &rt6_multipath_hash_fields_all_mask;
+	ret = proc_douintvec_minmax(&tmp, write, buffer, lenp, ppos);
 	if (write && ret == 0)
 		call_netevent_notifiers(NETEVENT_IPV6_MPATH_HASH_UPDATE, net);
 
 	return ret;
 }
 
-static struct ctl_table ipv6_table_template[] = {
-	{
-		.procname	= "bindv6only",
-		.data		= &init_net.ipv6.sysctl.bindv6only,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "anycast_src_echo_reply",
-		.data		= &init_net.ipv6.sysctl.anycast_src_echo_reply,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "flowlabel_consistency",
-		.data		= &init_net.ipv6.sysctl.flowlabel_consistency,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "auto_flowlabels",
-		.data		= &init_net.ipv6.sysctl.auto_flowlabels,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-		.extra2		= &auto_flowlabels_max
-	},
-	{
-		.procname	= "fwmark_reflect",
-		.data		= &init_net.ipv6.sysctl.fwmark_reflect,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "idgen_retries",
-		.data		= &init_net.ipv6.sysctl.idgen_retries,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
-	},
-	{
-		.procname	= "idgen_delay",
-		.data		= &init_net.ipv6.sysctl.idgen_delay,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec_jiffies,
-	},
-	{
-		.procname	= "flowlabel_state_ranges",
-		.data		= &init_net.ipv6.sysctl.flowlabel_state_ranges,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "ip_nonlocal_bind",
-		.data		= &init_net.ipv6.sysctl.ip_nonlocal_bind,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-	},
-	{
-		.procname	= "flowlabel_reflect",
-		.data		= &init_net.ipv6.sysctl.flowlabel_reflect,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec_minmax,
-		.extra1		= SYSCTL_ZERO,
-		.extra2		= &flowlabel_reflect_max,
-	},
-	{
-		.procname	= "max_dst_opts_number",
-		.data		= &init_net.ipv6.sysctl.max_dst_opts_cnt,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{
-		.procname	= "max_hbh_opts_number",
-		.data		= &init_net.ipv6.sysctl.max_hbh_opts_cnt,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{
-		.procname	= "max_dst_opts_length",
-		.data		= &init_net.ipv6.sysctl.max_dst_opts_len,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{
-		.procname	= "max_hbh_length",
-		.data		= &init_net.ipv6.sysctl.max_hbh_opts_len,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{
-		.procname	= "fib_multipath_hash_policy",
-		.data		= &init_net.ipv6.sysctl.multipath_hash_policy,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler   = proc_rt6_multipath_hash_policy,
-		.extra1		= SYSCTL_ZERO,
-		.extra2		= SYSCTL_THREE,
-	},
-	{
-		.procname	= "fib_multipath_hash_fields",
-		.data		= &init_net.ipv6.sysctl.multipath_hash_fields,
-		.maxlen		= sizeof(u32),
-		.mode		= 0644,
-		.proc_handler	= proc_rt6_multipath_hash_fields,
-		.extra1		= SYSCTL_ONE,
-		.extra2		= &rt6_multipath_hash_fields_all_mask,
-	},
-	{
-		.procname	= "seg6_flowlabel",
-		.data		= &init_net.ipv6.sysctl.seg6_flowlabel,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= proc_dointvec
-	},
-	{
-		.procname	= "fib_notify_on_flag_change",
-		.data		= &init_net.ipv6.sysctl.fib_notify_on_flag_change,
-		.maxlen		= sizeof(u8),
-		.mode		= 0644,
-		.proc_handler	= proc_dou8vec_minmax,
-		.extra1         = SYSCTL_ZERO,
-		.extra2         = SYSCTL_TWO,
-	},
-	{
-		.procname	= "ioam6_id",
-		.data		= &init_net.ipv6.sysctl.ioam6_id,
-		.maxlen		= sizeof(u32),
-		.mode		= 0644,
-		.proc_handler	= proc_douintvec_minmax,
-		.extra2		= &ioam6_id_max,
-	},
-	{
-		.procname	= "ioam6_id_wide",
-		.data		= &init_net.ipv6.sysctl.ioam6_id_wide,
-		.maxlen		= sizeof(u64),
-		.mode		= 0644,
-		.proc_handler	= proc_doulongvec_minmax,
-		.extra2		= &ioam6_id_wide_max,
-	},
+#define IPV6_SYSCTL_DATA(type, name, field)				\
+static type *ipv6_##name##_data(const struct sysctl_context *ctx)		\
+{									\
+	return &ctx->ns.net_ns->ipv6.sysctl.field;			\
+}
+
+#define IPV6_SYSCTL_CUSTOM_DATA(name, field)				\
+static void *ipv6_##name##_data(const struct sysctl_context *ctx)		\
+{									\
+	return &ctx->ns.net_ns->ipv6.sysctl.field;			\
+}
+
+IPV6_SYSCTL_DATA(u8, bindv6only, bindv6only)
+IPV6_SYSCTL_DATA(u8, anycast_src_echo_reply, anycast_src_echo_reply)
+IPV6_SYSCTL_DATA(u8, flowlabel_consistency, flowlabel_consistency)
+IPV6_SYSCTL_DATA(u8, auto_flowlabels, auto_flowlabels)
+IPV6_SYSCTL_DATA(u8, fwmark_reflect, fwmark_reflect)
+IPV6_SYSCTL_DATA(int, idgen_retries, idgen_retries)
+IPV6_SYSCTL_CUSTOM_DATA(idgen_delay, idgen_delay)
+IPV6_SYSCTL_DATA(u8, flowlabel_state_ranges, flowlabel_state_ranges)
+IPV6_SYSCTL_DATA(u8, ip_nonlocal_bind, ip_nonlocal_bind)
+IPV6_SYSCTL_DATA(int, flowlabel_reflect, flowlabel_reflect)
+IPV6_SYSCTL_DATA(int, max_dst_opts_number, max_dst_opts_cnt)
+IPV6_SYSCTL_DATA(int, max_hbh_opts_number, max_hbh_opts_cnt)
+IPV6_SYSCTL_DATA(int, max_dst_opts_length, max_dst_opts_len)
+IPV6_SYSCTL_DATA(int, max_hbh_length, max_hbh_opts_len)
+IPV6_SYSCTL_CUSTOM_DATA(fib_multipath_hash_policy, multipath_hash_policy)
+IPV6_SYSCTL_CUSTOM_DATA(fib_multipath_hash_fields, multipath_hash_fields)
+IPV6_SYSCTL_DATA(int, seg6_flowlabel, seg6_flowlabel)
+IPV6_SYSCTL_DATA(u8, fib_notify_on_flag_change, fib_notify_on_flag_change)
+IPV6_SYSCTL_DATA(unsigned int, ioam6_id, ioam6_id)
+IPV6_SYSCTL_CUSTOM_DATA(ioam6_id_wide, ioam6_id_wide)
+
+static int proc_ioam6_id_wide(const struct ctl_table *table, int write,
+			      void *buffer, size_t *lenp, loff_t *ppos)
+{
+	struct ctl_table tmp = *table;
+
+	tmp.extra2 = &ioam6_id_wide_max;
+	return proc_doulongvec_minmax(&tmp, write, buffer, lenp, ppos);
+}
+
+static const struct sysctl_field ipv6_table[] = {
+	SYSCTL_FIELD_U8("bindv6only", 0644, ipv6_bindv6only_data),
+	SYSCTL_FIELD_U8("anycast_src_echo_reply", 0644,
+		     ipv6_anycast_src_echo_reply_data),
+	SYSCTL_FIELD_U8("flowlabel_consistency", 0644,
+		     ipv6_flowlabel_consistency_data),
+	SYSCTL_FIELD_STATIC_U8_MINMAX("auto_flowlabels", 0644,
+				   ipv6_auto_flowlabels_data, NULL,
+				   &auto_flowlabels_max),
+	SYSCTL_FIELD_U8("fwmark_reflect", 0644, ipv6_fwmark_reflect_data),
+	SYSCTL_FIELD_INT("idgen_retries", 0644, ipv6_idgen_retries_data),
+	SYSCTL_FIELD_CUSTOM("idgen_delay", 0644, sizeof(int),
+			 ipv6_idgen_delay_data, proc_dointvec_jiffies),
+	SYSCTL_FIELD_U8("flowlabel_state_ranges", 0644,
+		     ipv6_flowlabel_state_ranges_data),
+	SYSCTL_FIELD_U8("ip_nonlocal_bind", 0644, ipv6_ip_nonlocal_bind_data),
+	SYSCTL_FIELD_STATIC_INT_MINMAX("flowlabel_reflect", 0644,
+				    ipv6_flowlabel_reflect_data,
+				    SYSCTL_ZERO, &flowlabel_reflect_max),
+	SYSCTL_FIELD_INT("max_dst_opts_number", 0644,
+		      ipv6_max_dst_opts_number_data),
+	SYSCTL_FIELD_INT("max_hbh_opts_number", 0644,
+		      ipv6_max_hbh_opts_number_data),
+	SYSCTL_FIELD_INT("max_dst_opts_length", 0644,
+		      ipv6_max_dst_opts_length_data),
+	SYSCTL_FIELD_INT("max_hbh_length", 0644, ipv6_max_hbh_length_data),
+	SYSCTL_FIELD_CUSTOM("fib_multipath_hash_policy", 0644, sizeof(u8),
+			 ipv6_fib_multipath_hash_policy_data,
+			 proc_rt6_multipath_hash_policy),
+	SYSCTL_FIELD_CUSTOM("fib_multipath_hash_fields", 0644, sizeof(u32),
+			 ipv6_fib_multipath_hash_fields_data,
+			 proc_rt6_multipath_hash_fields),
+	SYSCTL_FIELD_INT("seg6_flowlabel", 0644, ipv6_seg6_flowlabel_data),
+	SYSCTL_FIELD_STATIC_U8_MINMAX("fib_notify_on_flag_change", 0644,
+				   ipv6_fib_notify_on_flag_change_data,
+				   SYSCTL_UINT_ZERO, SYSCTL_UINT_TWO),
+	SYSCTL_FIELD_STATIC_UINT_MINMAX("ioam6_id", 0644, ipv6_ioam6_id_data,
+				     NULL, &ioam6_id_max),
+	SYSCTL_FIELD_CUSTOM("ioam6_id_wide", 0644, sizeof(u64),
+			 ipv6_ioam6_id_wide_data, proc_ioam6_id_wide),
 };
 
 static struct ctl_table ipv6_rotable[] = {
@@ -251,81 +186,38 @@ static struct ctl_table ipv6_rotable[] = {
 
 static int __net_init ipv6_sysctl_net_init(struct net *net)
 {
-	size_t table_size = ARRAY_SIZE(ipv6_table_template);
-	struct ctl_table *ipv6_table;
-	struct ctl_table *ipv6_route_table;
-	struct ctl_table *ipv6_icmp_table;
-	int err, i;
-
-	err = -ENOMEM;
-	ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template),
-			     GFP_KERNEL);
-	if (!ipv6_table)
-		goto out;
-	/* Update the variables to point into the current struct net */
-	for (i = 0; i < table_size; i++)
-		ipv6_table[i].data += (void *)net - (void *)&init_net;
-
-	ipv6_route_table = ipv6_route_sysctl_init(net);
-	if (!ipv6_route_table)
-		goto out_ipv6_table;
-
-	ipv6_icmp_table = ipv6_icmp_sysctl_init(net);
-	if (!ipv6_icmp_table)
-		goto out_ipv6_route_table;
+	struct sysctl_context ctx = {
+		.ns.net_ns = net,
+	};
+	int err = -ENOMEM;
 
-	net->ipv6.sysctl.hdr = register_net_sysctl_sz(net, "net/ipv6",
-						      ipv6_table, table_size);
+	net->ipv6.sysctl.hdr = register_sysctl_fields(&net->sysctls, "net/ipv6",
+						      ipv6_table, &ctx);
 	if (!net->ipv6.sysctl.hdr)
-		goto out_ipv6_icmp_table;
+		goto out;
 
-	net->ipv6.sysctl.route_hdr = register_net_sysctl_sz(net,
-							    "net/ipv6/route",
-							    ipv6_route_table,
-							    ipv6_route_sysctl_table_size(net));
-	if (!net->ipv6.sysctl.route_hdr)
-		goto out_unregister_ipv6_table;
+	err = ipv6_route_sysctl_register(&ctx);
+	if (err)
+		goto out_err;
 
-	net->ipv6.sysctl.icmp_hdr = register_net_sysctl_sz(net,
-							   "net/ipv6/icmp",
-							   ipv6_icmp_table,
-							   ipv6_icmp_sysctl_table_size());
-	if (!net->ipv6.sysctl.icmp_hdr)
-		goto out_unregister_route_table;
+	err = ipv6_icmp_sysctl_register(&ctx);
+	if (err)
+		goto out_err;
 
 	err = 0;
 out:
 	return err;
-out_unregister_route_table:
+out_err:
 	unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
-out_unregister_ipv6_table:
 	unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
-out_ipv6_icmp_table:
-	kfree(ipv6_icmp_table);
-out_ipv6_route_table:
-	kfree(ipv6_route_table);
-out_ipv6_table:
-	kfree(ipv6_table);
 	goto out;
 }
 
 static void __net_exit ipv6_sysctl_net_exit(struct net *net)
 {
-	const struct ctl_table *ipv6_table;
-	const struct ctl_table *ipv6_route_table;
-	const struct ctl_table *ipv6_icmp_table;
-
-	ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg;
-	ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg;
-	ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg;
-
 	unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr);
 	unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr);
 	unregister_net_sysctl_table(net->ipv6.sysctl.hdr);
-
-	kfree(ipv6_table);
-	kfree(ipv6_route_table);
-	kfree(ipv6_icmp_table);
 }
 
 static struct pernet_operations ipv6_sysctl_net_ops = {
-- 
2.55.0


  parent reply	other threads:[~2026-08-26 19:43 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cover.1787771905.git.legion@kernel.org>
2026-08-26 19:42 ` [RFC PATCH v1 01/30] proc: sysctl: address table entries by index Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 02/30] sysctl: add unsigned int limit constants Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 03/30] sysctl: add typed field descriptors Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 04/30] sysctl: use sysctl_field in ucounts Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 05/30] sysctl: ipc: use sysctl_field in mq_sysctl Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 06/30] sysctl: ipc: use sysctl_field in ipc_sysctl Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 07/30] sysctl: use sysctl_field in pid sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 08/30] sysctl: net: use sysctl_field in unix sysctl Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 09/30] sysctl: net: use sysctl_field in xfrm sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 10/30] sysctl: net: use sysctl_field for simple IPv4 per-net sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 11/30] sysctl: net: use sysctl_field in IPv4 sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 12/30] sysctl: net: use sysctl_field in IPv6 xfrm sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 13/30] sysctl: net: use sysctl_field in IPv6 fragment sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 14/30] sysctl: net: use sysctl_field in 6lowpan " Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 15/30] sysctl: net: use sysctl_field in vsock sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 16/30] sysctl: net: use sysctl_field in MPTCP sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 17/30] sysctl: net: use sysctl_field in SCTP sysctls Alexey Gladkov
2026-08-26 20:29   ` Linus Torvalds
2026-08-29 16:14     ` Alexey Gladkov
2026-08-29 16:14       ` [RFC PATCH 1/4] sysctl: add typed field descriptors Alexey Gladkov
2026-08-29 16:14       ` [RFC PATCH 2/4] sysctl: ipc: use typed fields for IPC namespace sysctls Alexey Gladkov
2026-08-29 16:14       ` [RFC PATCH 3/4] sctp: use typed fields for per-net sysctls Alexey Gladkov
2026-08-29 16:14       ` [RFC PATCH 4/4] mpls: use typed fields for per-device sysctls Alexey Gladkov
2026-08-30 15:38       ` [RFC PATCH v1 17/30] sysctl: net: use sysctl_field in SCTP sysctls Linus Torvalds
2026-08-26 19:42 ` Alexey Gladkov [this message]
2026-08-26 19:42 ` [RFC PATCH v1 19/30] sysctl: net: use sysctl_field in net core per-net sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 20/30] sysctl: net: use sysctl_field in SMC sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 21/30] sysctl: net: use sysctl_field in VRF sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 22/30] sysctl: net: use sysctl_field in RDS sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 23/30] sysctl: netfilter: use sysctl_field for per-net sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 24/30] sysctl: ipvs: " Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 25/30] sysctl: bridge: use sysctl_field for br_netfilter sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 26/30] sysctl: net: use sysctl_field for MPLS sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 27/30] sysctl: net: use sysctl_field in IPv4 devconf sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 28/30] sysctl: net: use sysctl_field in IPv6 " Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 29/30] sysctl: net: use sysctl_field in neighbour sysctls Alexey Gladkov
2026-08-26 19:42 ` [RFC PATCH v1 30/30] sysctl: parport: use sysctl_field for dynamic sysctls Alexey Gladkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e10a1f7d819dde0bfa5931479f28ce6e4cc2b158.1787771905.git.legion@kernel.org \
    --to=legion@kernel.org \
    --cc=ebiederm@xmission.com \
    --cc=joel.granados@kernel.org \
    --cc=kees@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®