[RFC PATCH v1 12/30] sysctl: net: use sysctl_field in IPv6 xfrm sysctls
From: Alexey Gladkov
Date: Wed Aug 26 2026 - 15:46:28 EST
The IPv6 xfrm sysctl table is cloned for every non-init network
namespace only to rebind the xfrm6_gc_thresh data pointer. The
descriptor itself is static and does not need per-net storage.
Use a sysctl_field descriptor so the data pointer is derived from the
network namespace registration context. This keeps the table const
and removes the per-net allocation and free path.
Signed-off-by: Alexey Gladkov <legion@xxxxxxxxxx>
---
net/ipv6/xfrm6_policy.c | 48 +++++++++++------------------------------
1 file changed, 13 insertions(+), 35 deletions(-)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 125ea9a5b8a0..3df9872100c8 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -186,56 +186,34 @@ static void xfrm6_policy_fini(void)
}
#ifdef CONFIG_SYSCTL
-static struct ctl_table xfrm6_policy_table[] = {
- {
- .procname = "xfrm6_gc_thresh",
- .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
+static int *xfrm6_gc_thresh_data(const struct sysctl_context *ctx)
+{
+ return &ctx->ns.net_ns->xfrm.xfrm6_dst_ops.gc_thresh;
+}
+
+static const struct sysctl_field xfrm6_policy_table[] = {
+ SYSCTL_FIELD_INT("xfrm6_gc_thresh", 0644, xfrm6_gc_thresh_data),
};
static int __net_init xfrm6_net_sysctl_init(struct net *net)
{
- struct ctl_table *table;
+ struct sysctl_context ctx = {
+ .ns.net_ns = net,
+ };
struct ctl_table_header *hdr;
- table = xfrm6_policy_table;
- if (!net_eq(net, &init_net)) {
- table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL);
- if (!table)
- goto err_alloc;
-
- table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
- }
-
- hdr = register_net_sysctl_sz(net, "net/ipv6", table,
- ARRAY_SIZE(xfrm6_policy_table));
+ hdr = register_sysctl_fields(&net->sysctls, "net/ipv6",
+ xfrm6_policy_table, &ctx);
if (!hdr)
- goto err_reg;
+ return -ENOMEM;
net->ipv6.sysctl.xfrm6_hdr = hdr;
return 0;
-
-err_reg:
- if (!net_eq(net, &init_net))
- kfree(table);
-err_alloc:
- return -ENOMEM;
}
static void __net_exit xfrm6_net_sysctl_exit(struct net *net)
{
- const struct ctl_table *table;
-
- if (!net->ipv6.sysctl.xfrm6_hdr)
- return;
-
- table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg;
unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr);
- if (!net_eq(net, &init_net))
- kfree(table);
}
#else /* CONFIG_SYSCTL */
static inline int xfrm6_net_sysctl_init(struct net *net)
--
2.55.0