diff options
author | Pavel Emelyanov <xemul@openvz.org> | 2008-01-11 04:42:55 +0300 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-29 02:01:40 +0300 |
commit | e0da5a480cafc7ca228d6b5a05dbd77344a6bd29 (patch) | |
tree | 5ef0bca857db98dbe773e8c50bb4826deefd0d4c /net/ipv6 | |
parent | bff16c2f991386883dc81ec969ba15eb270a0c7f (diff) | |
download | linux-e0da5a480cafc7ca228d6b5a05dbd77344a6bd29.tar.xz |
[NETNS]: Create ipv6 devconf-s for namespaces
This is the core. Declare and register the pernet subsys for
addrconf. The init callback the will create the devconf-s.
The init_net will reuse the existing statically declared confs,
so that accessing them from inside the ipv6 code will still
work.
The register_pernet_subsys() is moved above the ipv6_add_dev()
call for loopback, because this function will need the
net->devconf_dflt pointer to be already set.
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 82 |
1 files changed, 70 insertions, 12 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index bde50c686722..3ad081e9366b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4135,6 +4135,70 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev) #endif +static int addrconf_init_net(struct net *net) +{ + int err; + struct ipv6_devconf *all, *dflt; + + err = -ENOMEM; + all = &ipv6_devconf; + dflt = &ipv6_devconf_dflt; + + if (net != &init_net) { + all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL); + if (all == NULL) + goto err_alloc_all; + + dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); + if (dflt == NULL) + goto err_alloc_dflt; + } + + net->ipv6.devconf_all = all; + net->ipv6.devconf_dflt = dflt; + +#ifdef CONFIG_SYSCTL + err = __addrconf_sysctl_register(net, "all", NET_PROTO_CONF_ALL, + NULL, all); + if (err < 0) + goto err_reg_all; + + err = __addrconf_sysctl_register(net, "default", NET_PROTO_CONF_DEFAULT, + NULL, dflt); + if (err < 0) + goto err_reg_dflt; +#endif + return 0; + +#ifdef CONFIG_SYSCTL +err_reg_dflt: + __addrconf_sysctl_unregister(all); +err_reg_all: + kfree(dflt); +#endif +err_alloc_dflt: + kfree(all); +err_alloc_all: + return err; +} + +static void addrconf_exit_net(struct net *net) +{ +#ifdef CONFIG_SYSCTL + __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); + __addrconf_sysctl_unregister(net->ipv6.devconf_all); +#endif + if (net != &init_net) { + kfree(net->ipv6.devconf_dflt); + kfree(net->ipv6.devconf_all); + } +} + +static struct pernet_operations addrconf_ops = { + .init = addrconf_init_net, + .exit = addrconf_exit_net, +}; + /* * Device notifier */ @@ -4167,6 +4231,8 @@ int __init addrconf_init(void) return err; } + register_pernet_subsys(&addrconf_ops); + /* The addrconf netdev notifier requires that loopback_dev * has it's ipv6 private information allocated and setup * before it can bring up and give link-local addresses @@ -4190,7 +4256,7 @@ int __init addrconf_init(void) err = -ENOMEM; rtnl_unlock(); if (err) - return err; + goto errlo; ip6_null_entry.u.dst.dev = init_net.loopback_dev; ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); @@ -4218,16 +4284,11 @@ int __init addrconf_init(void) ipv6_addr_label_rtnl_register(); -#ifdef CONFIG_SYSCTL - __addrconf_sysctl_register(&init_net, "all", NET_PROTO_CONF_ALL, - NULL, &ipv6_devconf); - __addrconf_sysctl_register(&init_net, "default", NET_PROTO_CONF_DEFAULT, - NULL, &ipv6_devconf_dflt); -#endif - return 0; errout: unregister_netdevice_notifier(&ipv6_dev_notf); +errlo: + unregister_pernet_subsys(&addrconf_ops); return err; } @@ -4240,10 +4301,7 @@ void addrconf_cleanup(void) unregister_netdevice_notifier(&ipv6_dev_notf); -#ifdef CONFIG_SYSCTL - __addrconf_sysctl_unregister(&ipv6_devconf_dflt); - __addrconf_sysctl_unregister(&ipv6_devconf); -#endif + unregister_pernet_subsys(&addrconf_ops); rtnl_lock(); |