xfrm: make gc_thresh configurable in all namespaces
authorMichal Kubecek <mkubecek@suse.cz>
Wed, 6 Feb 2013 09:46:33 +0000 (10:46 +0100)
committerSteffen Klassert <steffen.klassert@secunet.com>
Wed, 6 Feb 2013 10:36:29 +0000 (11:36 +0100)
The xfrm gc threshold can be configured via xfrm{4,6}_gc_thresh
sysctl but currently only in init_net, other namespaces always
use the default value. This can substantially limit the number
of IPsec tunnels that can be effectively used.

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
include/net/netns/ipv4.h
include/net/netns/ipv6.h
net/ipv4/xfrm4_policy.c
net/ipv6/xfrm6_policy.c

index 9b78862014a4c27609236b4ce9f73e69d682e7c7..2ba9de89e8ec778990e8b2ff5183fd3e97eee1aa 100644 (file)
@@ -22,6 +22,7 @@ struct netns_ipv4 {
        struct ctl_table_header *frags_hdr;
        struct ctl_table_header *ipv4_hdr;
        struct ctl_table_header *route_hdr;
+       struct ctl_table_header *xfrm4_hdr;
 #endif
        struct ipv4_devconf     *devconf_all;
        struct ipv4_devconf     *devconf_dflt;
index 214cb0a53359e03b476670e49eb73298545e1859..1242f371718b7aa0db39f62269b806b1babe4883 100644 (file)
@@ -16,6 +16,7 @@ struct netns_sysctl_ipv6 {
        struct ctl_table_header *route_hdr;
        struct ctl_table_header *icmp_hdr;
        struct ctl_table_header *frags_hdr;
+       struct ctl_table_header *xfrm6_hdr;
 #endif
        int bindv6only;
        int flush_delay;
index 0e28383c096f69fc0ef207ac495b64adf9bf3233..9a459be24af762b42e2d667618f7149c055e5ef6 100644 (file)
@@ -262,7 +262,51 @@ static struct ctl_table xfrm4_policy_table[] = {
        { }
 };
 
-static struct ctl_table_header *sysctl_hdr;
+static int __net_init xfrm4_net_init(struct net *net)
+{
+       struct ctl_table *table;
+       struct ctl_table_header *hdr;
+
+       table = xfrm4_policy_table;
+       if (!net_eq(net, &init_net)) {
+               table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
+               if (!table)
+                       goto err_alloc;
+
+               table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
+       }
+
+       hdr = register_net_sysctl(net, "net/ipv4", table);
+       if (!hdr)
+               goto err_reg;
+
+       net->ipv4.xfrm4_hdr = hdr;
+       return 0;
+
+err_reg:
+       if (!net_eq(net, &init_net))
+               kfree(table);
+err_alloc:
+       return -ENOMEM;
+}
+
+static void __net_exit xfrm4_net_exit(struct net *net)
+{
+       struct ctl_table *table;
+
+       if (net->ipv4.xfrm4_hdr == NULL)
+               return;
+
+       table = net->ipv4.xfrm4_hdr->ctl_table_arg;
+       unregister_net_sysctl_table(net->ipv4.xfrm4_hdr);
+       if (!net_eq(net, &init_net))
+               kfree(table);
+}
+
+static struct pernet_operations __net_initdata xfrm4_net_ops = {
+       .init   = xfrm4_net_init,
+       .exit   = xfrm4_net_exit,
+};
 #endif
 
 static void __init xfrm4_policy_init(void)
@@ -277,8 +321,7 @@ void __init xfrm4_init(void)
        xfrm4_state_init();
        xfrm4_policy_init();
 #ifdef CONFIG_SYSCTL
-       sysctl_hdr = register_net_sysctl(&init_net, "net/ipv4",
-                                        xfrm4_policy_table);
+       register_pernet_subsys(&xfrm4_net_ops);
 #endif
 }
 
index 128273744332bef4f8d661bc559c8c8e5f0fb407..4ef7bdb65440ca965561d4ca6fdd10b4d97f97d6 100644 (file)
@@ -320,7 +320,51 @@ static struct ctl_table xfrm6_policy_table[] = {
        { }
 };
 
-static struct ctl_table_header *sysctl_hdr;
+static int __net_init xfrm6_net_init(struct net *net)
+{
+       struct ctl_table *table;
+       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(net, "net/ipv6", table);
+       if (!hdr)
+               goto err_reg;
+
+       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_exit(struct net *net)
+{
+       struct ctl_table *table;
+
+       if (net->ipv6.sysctl.xfrm6_hdr == NULL)
+               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);
+}
+
+static struct pernet_operations xfrm6_net_ops = {
+       .init   = xfrm6_net_init,
+       .exit   = xfrm6_net_exit,
+};
 #endif
 
 int __init xfrm6_init(void)
@@ -339,8 +383,7 @@ int __init xfrm6_init(void)
                goto out_policy;
 
 #ifdef CONFIG_SYSCTL
-       sysctl_hdr = register_net_sysctl(&init_net, "net/ipv6",
-                                        xfrm6_policy_table);
+       register_pernet_subsys(&xfrm6_net_ops);
 #endif
 out:
        return ret;
@@ -352,8 +395,7 @@ out_policy:
 void xfrm6_fini(void)
 {
 #ifdef CONFIG_SYSCTL
-       if (sysctl_hdr)
-               unregister_net_sysctl_table(sysctl_hdr);
+       unregister_pernet_subsys(&xfrm6_net_ops);
 #endif
        xfrm6_policy_fini();
        xfrm6_state_fini();