diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/Kconfig | 8 | ||||
-rw-r--r-- | net/core/net_namespace.c | 43 |
2 files changed, 49 insertions, 2 deletions
diff --git a/net/Kconfig b/net/Kconfig index cdba08ca2efe..ab4e6da5012f 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -27,6 +27,14 @@ if NET menu "Networking options" +config NET_NS + bool "Network namespace support" + default n + depends on EXPERIMENTAL && !SYSFS + help + Allow user space to create what appear to be multiple instances + of the network stack. + source "net/packet/Kconfig" source "net/unix/Kconfig" source "net/xfrm/Kconfig" diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 0e6cb02d7b77..e478e353ea6b 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -4,6 +4,7 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/delay.h> +#include <linux/sched.h> #include <net/net_namespace.h> /* @@ -32,12 +33,10 @@ void net_unlock(void) mutex_unlock(&net_list_mutex); } -#if 0 static struct net *net_alloc(void) { return kmem_cache_alloc(net_cachep, GFP_KERNEL); } -#endif static void net_free(struct net *net) { @@ -128,6 +127,46 @@ out_undo: goto out; } +struct net *copy_net_ns(unsigned long flags, struct net *old_net) +{ + struct net *new_net = NULL; + int err; + + get_net(old_net); + + if (!(flags & CLONE_NEWNET)) + return old_net; + +#ifndef CONFIG_NET_NS + return ERR_PTR(-EINVAL); +#endif + + err = -ENOMEM; + new_net = net_alloc(); + if (!new_net) + goto out; + + mutex_lock(&net_mutex); + err = setup_net(new_net); + if (err) + goto out_unlock; + + net_lock(); + list_add_tail(&new_net->list, &net_namespace_list); + net_unlock(); + + +out_unlock: + mutex_unlock(&net_mutex); +out: + put_net(old_net); + if (err) { + net_free(new_net); + new_net = ERR_PTR(err); + } + return new_net; +} + static int __init net_ns_init(void) { int err; |