diff options
author | Daniel Lezcano <dlezcano@fr.ibm.com> | 2008-01-10 02:53:43 -0800 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 15:01:17 -0800 |
commit | 760f2d0186225f06d46e07232d65219c5055cad3 (patch) | |
tree | 56096a88e003753434c135d22ffab8f4f9904bc6 /net/ipv6/sysctl_net_ipv6.c | |
parent | 89918fc270bb77cb1a0703f0ea566a692b32e324 (diff) |
[NETNS][IPV6]: Make multiple instance of sysctl tables.
Each network namespace wants its own set of sysctl value, eg. we
should not be able from a namespace to set a sysctl value for another
namespace , especially for the initial network namespace.
This patch duplicates the sysctl table when we register a new network
namespace for ipv6. The duplicated table are postfixed with the
"template" word to notify the developper the table is cloned.
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/sysctl_net_ipv6.c')
-rw-r--r-- | net/ipv6/sysctl_net_ipv6.c | 67 |
1 files changed, 57 insertions, 10 deletions
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 7329decf1f9d..7970f3366f87 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -14,20 +14,23 @@ #include <net/addrconf.h> #include <net/inet_frag.h> -static ctl_table ipv6_table[] = { +extern struct ctl_table *ipv6_route_sysctl_init(struct net *net); +extern struct ctl_table *ipv6_icmp_sysctl_init(struct net *net); + +static ctl_table ipv6_table_template[] = { { .ctl_name = NET_IPV6_ROUTE, .procname = "route", .maxlen = 0, .mode = 0555, - .child = ipv6_route_table + .child = ipv6_route_table_template }, { .ctl_name = NET_IPV6_ICMP, .procname = "icmp", .maxlen = 0, .mode = 0555, - .child = ipv6_icmp_table + .child = ipv6_icmp_table_template }, { .ctl_name = NET_IPV6_BINDV6ONLY, @@ -89,22 +92,66 @@ struct ctl_path net_ipv6_ctl_path[] = { }; EXPORT_SYMBOL_GPL(net_ipv6_ctl_path); -static struct ctl_table_header *ipv6_sysctl_header; - static int ipv6_sysctl_net_init(struct net *net) { - ipv6_sysctl_header = register_net_sysctl_table(net, net_ipv6_ctl_path, - ipv6_table); - if (!ipv6_sysctl_header) + struct ctl_table *ipv6_table; + struct ctl_table *ipv6_route_table; + struct ctl_table *ipv6_icmp_table; + int err; + + err = -ENOMEM; + ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template), + GFP_KERNEL); + if (!ipv6_table) + goto out; + + 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; + + ipv6_table[0].child = ipv6_route_table; + ipv6_table[1].child = ipv6_icmp_table; + + net->ipv6.sysctl.table = register_net_sysctl_table(net, net_ipv6_ctl_path, + ipv6_table); + if (!net->ipv6.sysctl.table) return -ENOMEM; - return 0; + if (!net->ipv6.sysctl.table) + goto out_ipv6_icmp_table; + + err = 0; +out: + return err; +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 ipv6_sysctl_net_exit(struct net *net) { - unregister_net_sysctl_table(ipv6_sysctl_header); + struct ctl_table *ipv6_table; + struct ctl_table *ipv6_route_table; + struct ctl_table *ipv6_icmp_table; + + ipv6_table = net->ipv6.sysctl.table->ctl_table_arg; + ipv6_route_table = ipv6_table[0].child; + ipv6_icmp_table = ipv6_table[1].child; + + unregister_net_sysctl_table(net->ipv6.sysctl.table); + + kfree(ipv6_table); + kfree(ipv6_route_table); + kfree(ipv6_icmp_table); } static struct pernet_operations ipv6_sysctl_net_ops = { |