-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 66379 b: refs/heads/master c: 5f256be h: refs/heads/master i: 66377: df7b402 66375: 0217f8e v: v3
- Loading branch information
Eric W. Biederman
authored and
David S. Miller
committed
Oct 10, 2007
1 parent
18daea9
commit 021fb1a
Showing
4 changed files
with
362 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 32da477a5bfe96b6dfc8960e0d22d89ca09fd10a | ||
refs/heads/master: 5f256becd868bf63b70da8f2769033d6734670e9 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* | ||
* Operations on the network namespace | ||
*/ | ||
#ifndef __NET_NET_NAMESPACE_H | ||
#define __NET_NET_NAMESPACE_H | ||
|
||
#include <asm/atomic.h> | ||
#include <linux/workqueue.h> | ||
#include <linux/list.h> | ||
|
||
struct net { | ||
atomic_t count; /* To decided when the network | ||
* namespace should be freed. | ||
*/ | ||
atomic_t use_count; /* To track references we | ||
* destroy on demand | ||
*/ | ||
struct list_head list; /* list of network namespaces */ | ||
struct work_struct work; /* work struct for freeing */ | ||
}; | ||
|
||
extern struct net init_net; | ||
extern struct list_head net_namespace_list; | ||
|
||
extern void __put_net(struct net *net); | ||
|
||
static inline struct net *get_net(struct net *net) | ||
{ | ||
atomic_inc(&net->count); | ||
return net; | ||
} | ||
|
||
static inline void put_net(struct net *net) | ||
{ | ||
if (atomic_dec_and_test(&net->count)) | ||
__put_net(net); | ||
} | ||
|
||
static inline struct net *hold_net(struct net *net) | ||
{ | ||
atomic_inc(&net->use_count); | ||
return net; | ||
} | ||
|
||
static inline void release_net(struct net *net) | ||
{ | ||
atomic_dec(&net->use_count); | ||
} | ||
|
||
extern void net_lock(void); | ||
extern void net_unlock(void); | ||
|
||
#define for_each_net(VAR) \ | ||
list_for_each_entry(VAR, &net_namespace_list, list) | ||
|
||
|
||
struct pernet_operations { | ||
struct list_head list; | ||
int (*init)(struct net *net); | ||
void (*exit)(struct net *net); | ||
}; | ||
|
||
extern int register_pernet_subsys(struct pernet_operations *); | ||
extern void unregister_pernet_subsys(struct pernet_operations *); | ||
extern int register_pernet_device(struct pernet_operations *); | ||
extern void unregister_pernet_device(struct pernet_operations *); | ||
|
||
#endif /* __NET_NET_NAMESPACE_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,292 @@ | ||
#include <linux/workqueue.h> | ||
#include <linux/rtnetlink.h> | ||
#include <linux/cache.h> | ||
#include <linux/slab.h> | ||
#include <linux/list.h> | ||
#include <linux/delay.h> | ||
#include <net/net_namespace.h> | ||
|
||
/* | ||
* Our network namespace constructor/destructor lists | ||
*/ | ||
|
||
static LIST_HEAD(pernet_list); | ||
static struct list_head *first_device = &pernet_list; | ||
static DEFINE_MUTEX(net_mutex); | ||
|
||
static DEFINE_MUTEX(net_list_mutex); | ||
LIST_HEAD(net_namespace_list); | ||
|
||
static struct kmem_cache *net_cachep; | ||
|
||
struct net init_net; | ||
EXPORT_SYMBOL_GPL(init_net); | ||
|
||
void net_lock(void) | ||
{ | ||
mutex_lock(&net_list_mutex); | ||
} | ||
|
||
void net_unlock(void) | ||
{ | ||
mutex_unlock(&net_list_mutex); | ||
} | ||
|
||
static struct net *net_alloc(void) | ||
{ | ||
return kmem_cache_alloc(net_cachep, GFP_KERNEL); | ||
} | ||
|
||
static void net_free(struct net *net) | ||
{ | ||
if (!net) | ||
return; | ||
|
||
if (unlikely(atomic_read(&net->use_count) != 0)) { | ||
printk(KERN_EMERG "network namespace not free! Usage: %d\n", | ||
atomic_read(&net->use_count)); | ||
return; | ||
} | ||
|
||
kmem_cache_free(net_cachep, net); | ||
} | ||
|
||
static void cleanup_net(struct work_struct *work) | ||
{ | ||
struct pernet_operations *ops; | ||
struct list_head *ptr; | ||
struct net *net; | ||
|
||
net = container_of(work, struct net, work); | ||
|
||
mutex_lock(&net_mutex); | ||
|
||
/* Don't let anyone else find us. */ | ||
net_lock(); | ||
list_del(&net->list); | ||
net_unlock(); | ||
|
||
/* Run all of the network namespace exit methods */ | ||
list_for_each_prev(ptr, &pernet_list) { | ||
ops = list_entry(ptr, struct pernet_operations, list); | ||
if (ops->exit) | ||
ops->exit(net); | ||
} | ||
|
||
mutex_unlock(&net_mutex); | ||
|
||
/* Ensure there are no outstanding rcu callbacks using this | ||
* network namespace. | ||
*/ | ||
rcu_barrier(); | ||
|
||
/* Finally it is safe to free my network namespace structure */ | ||
net_free(net); | ||
} | ||
|
||
|
||
void __put_net(struct net *net) | ||
{ | ||
/* Cleanup the network namespace in process context */ | ||
INIT_WORK(&net->work, cleanup_net); | ||
schedule_work(&net->work); | ||
} | ||
EXPORT_SYMBOL_GPL(__put_net); | ||
|
||
/* | ||
* setup_net runs the initializers for the network namespace object. | ||
*/ | ||
static int setup_net(struct net *net) | ||
{ | ||
/* Must be called with net_mutex held */ | ||
struct pernet_operations *ops; | ||
struct list_head *ptr; | ||
int error; | ||
|
||
memset(net, 0, sizeof(struct net)); | ||
atomic_set(&net->count, 1); | ||
atomic_set(&net->use_count, 0); | ||
|
||
error = 0; | ||
list_for_each(ptr, &pernet_list) { | ||
ops = list_entry(ptr, struct pernet_operations, list); | ||
if (ops->init) { | ||
error = ops->init(net); | ||
if (error < 0) | ||
goto out_undo; | ||
} | ||
} | ||
out: | ||
return error; | ||
out_undo: | ||
/* Walk through the list backwards calling the exit functions | ||
* for the pernet modules whose init functions did not fail. | ||
*/ | ||
for (ptr = ptr->prev; ptr != &pernet_list; ptr = ptr->prev) { | ||
ops = list_entry(ptr, struct pernet_operations, list); | ||
if (ops->exit) | ||
ops->exit(net); | ||
} | ||
goto out; | ||
} | ||
|
||
static int __init net_ns_init(void) | ||
{ | ||
int err; | ||
|
||
printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net)); | ||
net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), | ||
SMP_CACHE_BYTES, | ||
SLAB_PANIC, NULL); | ||
mutex_lock(&net_mutex); | ||
err = setup_net(&init_net); | ||
|
||
net_lock(); | ||
list_add_tail(&init_net.list, &net_namespace_list); | ||
net_unlock(); | ||
|
||
mutex_unlock(&net_mutex); | ||
if (err) | ||
panic("Could not setup the initial network namespace"); | ||
|
||
return 0; | ||
} | ||
|
||
pure_initcall(net_ns_init); | ||
|
||
static int register_pernet_operations(struct list_head *list, | ||
struct pernet_operations *ops) | ||
{ | ||
struct net *net, *undo_net; | ||
int error; | ||
|
||
error = 0; | ||
list_add_tail(&ops->list, list); | ||
for_each_net(net) { | ||
if (ops->init) { | ||
error = ops->init(net); | ||
if (error) | ||
goto out_undo; | ||
} | ||
} | ||
out: | ||
return error; | ||
|
||
out_undo: | ||
/* If I have an error cleanup all namespaces I initialized */ | ||
list_del(&ops->list); | ||
for_each_net(undo_net) { | ||
if (undo_net == net) | ||
goto undone; | ||
if (ops->exit) | ||
ops->exit(undo_net); | ||
} | ||
undone: | ||
goto out; | ||
} | ||
|
||
static void unregister_pernet_operations(struct pernet_operations *ops) | ||
{ | ||
struct net *net; | ||
|
||
list_del(&ops->list); | ||
for_each_net(net) | ||
if (ops->exit) | ||
ops->exit(net); | ||
} | ||
|
||
/** | ||
* register_pernet_subsys - register a network namespace subsystem | ||
* @ops: pernet operations structure for the subsystem | ||
* | ||
* Register a subsystem which has init and exit functions | ||
* that are called when network namespaces are created and | ||
* destroyed respectively. | ||
* | ||
* When registered all network namespace init functions are | ||
* called for every existing network namespace. Allowing kernel | ||
* modules to have a race free view of the set of network namespaces. | ||
* | ||
* When a new network namespace is created all of the init | ||
* methods are called in the order in which they were registered. | ||
* | ||
* When a network namespace is destroyed all of the exit methods | ||
* are called in the reverse of the order with which they were | ||
* registered. | ||
*/ | ||
int register_pernet_subsys(struct pernet_operations *ops) | ||
{ | ||
int error; | ||
mutex_lock(&net_mutex); | ||
error = register_pernet_operations(first_device, ops); | ||
mutex_unlock(&net_mutex); | ||
return error; | ||
} | ||
EXPORT_SYMBOL_GPL(register_pernet_subsys); | ||
|
||
/** | ||
* unregister_pernet_subsys - unregister a network namespace subsystem | ||
* @ops: pernet operations structure to manipulate | ||
* | ||
* Remove the pernet operations structure from the list to be | ||
* used when network namespaces are created or destoryed. In | ||
* addition run the exit method for all existing network | ||
* namespaces. | ||
*/ | ||
void unregister_pernet_subsys(struct pernet_operations *module) | ||
{ | ||
mutex_lock(&net_mutex); | ||
unregister_pernet_operations(module); | ||
mutex_unlock(&net_mutex); | ||
} | ||
EXPORT_SYMBOL_GPL(unregister_pernet_subsys); | ||
|
||
/** | ||
* register_pernet_device - register a network namespace device | ||
* @ops: pernet operations structure for the subsystem | ||
* | ||
* Register a device which has init and exit functions | ||
* that are called when network namespaces are created and | ||
* destroyed respectively. | ||
* | ||
* When registered all network namespace init functions are | ||
* called for every existing network namespace. Allowing kernel | ||
* modules to have a race free view of the set of network namespaces. | ||
* | ||
* When a new network namespace is created all of the init | ||
* methods are called in the order in which they were registered. | ||
* | ||
* When a network namespace is destroyed all of the exit methods | ||
* are called in the reverse of the order with which they were | ||
* registered. | ||
*/ | ||
int register_pernet_device(struct pernet_operations *ops) | ||
{ | ||
int error; | ||
mutex_lock(&net_mutex); | ||
error = register_pernet_operations(&pernet_list, ops); | ||
if (!error && (first_device == &pernet_list)) | ||
first_device = &ops->list; | ||
mutex_unlock(&net_mutex); | ||
return error; | ||
} | ||
EXPORT_SYMBOL_GPL(register_pernet_device); | ||
|
||
/** | ||
* unregister_pernet_device - unregister a network namespace netdevice | ||
* @ops: pernet operations structure to manipulate | ||
* | ||
* Remove the pernet operations structure from the list to be | ||
* used when network namespaces are created or destoryed. In | ||
* addition run the exit method for all existing network | ||
* namespaces. | ||
*/ | ||
void unregister_pernet_device(struct pernet_operations *ops) | ||
{ | ||
mutex_lock(&net_mutex); | ||
if (&ops->list == first_device) | ||
first_device = first_device->next; | ||
unregister_pernet_operations(ops); | ||
mutex_unlock(&net_mutex); | ||
} | ||
EXPORT_SYMBOL_GPL(unregister_pernet_device); |