linux/net/ipv6/sysctl_net_ipv6.c
Daniel Lezcano 760f2d0186 [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>
2008-01-28 15:01:17 -08:00

171 lines
3.8 KiB
C

/*
* sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem.
*
* Changes:
* YOSHIFUJI Hideaki @USAGI: added icmp sysctl table.
*/
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/in6.h>
#include <linux/ipv6.h>
#include <net/ndisc.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
#include <net/inet_frag.h>
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_template
},
{
.ctl_name = NET_IPV6_ICMP,
.procname = "icmp",
.maxlen = 0,
.mode = 0555,
.child = ipv6_icmp_table_template
},
{
.ctl_name = NET_IPV6_BINDV6ONLY,
.procname = "bindv6only",
.data = &sysctl_ipv6_bindv6only,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
},
{
.ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH,
.procname = "ip6frag_high_thresh",
.data = &ip6_frags_ctl.high_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
},
{
.ctl_name = NET_IPV6_IP6FRAG_LOW_THRESH,
.procname = "ip6frag_low_thresh",
.data = &ip6_frags_ctl.low_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
},
{
.ctl_name = NET_IPV6_IP6FRAG_TIME,
.procname = "ip6frag_time",
.data = &ip6_frags_ctl.timeout,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
},
{
.ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL,
.procname = "ip6frag_secret_interval",
.data = &ip6_frags_ctl.secret_interval,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies
},
{
.ctl_name = NET_IPV6_MLD_MAX_MSF,
.procname = "mld_max_msf",
.data = &sysctl_mld_max_msf,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
},
{ .ctl_name = 0 }
};
struct ctl_path net_ipv6_ctl_path[] = {
{ .procname = "net", .ctl_name = CTL_NET, },
{ .procname = "ipv6", .ctl_name = NET_IPV6, },
{ },
};
EXPORT_SYMBOL_GPL(net_ipv6_ctl_path);
static int ipv6_sysctl_net_init(struct net *net)
{
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;
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)
{
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 = {
.init = ipv6_sysctl_net_init,
.exit = ipv6_sysctl_net_exit,
};
int ipv6_sysctl_register(void)
{
return register_pernet_subsys(&ipv6_sysctl_net_ops);
}
void ipv6_sysctl_unregister(void)
{
unregister_pernet_subsys(&ipv6_sysctl_net_ops);
}