aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-09-12 05:50:50 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:49:03 -0400
commit5f256becd868bf63b70da8f2769033d6734670e9 (patch)
tree0a3550303488e7740f349e7b5f7b296dfeb276ef
parent32da477a5bfe96b6dfc8960e0d22d89ca09fd10a (diff)
[NET]: Basic network namespace infrastructure.
This is the basic infrastructure needed to support network namespaces. This infrastructure is: - Registration functions to support initializing per network namespace data when a network namespaces is created or destroyed. - struct net. The network namespace data structure. This structure will grow as variables are made per network namespace but this is the minimal starting point. - Functions to grab a reference to the network namespace. I provide both get/put functions that keep a network namespace from being freed. And hold/release functions serve as weak references and will warn if their count is not zero when the data structure is freed. Useful for dealing with more complicated data structures like the ipv4 route cache. - A list of all of the network namespaces so we can iterate over them. - A slab for the network namespace data structure allowing leaks to be spotted. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/net_namespace.h68
-rw-r--r--net/core/Makefile2
-rw-r--r--net/core/net_namespace.c292
3 files changed, 361 insertions, 1 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
new file mode 100644
index 000000000000..6344b77f81a2
--- /dev/null
+++ b/include/net/net_namespace.h
@@ -0,0 +1,68 @@
1/*
2 * Operations on the network namespace
3 */
4#ifndef __NET_NET_NAMESPACE_H
5#define __NET_NET_NAMESPACE_H
6
7#include <asm/atomic.h>
8#include <linux/workqueue.h>
9#include <linux/list.h>
10
11struct net {
12 atomic_t count; /* To decided when the network
13 * namespace should be freed.
14 */
15 atomic_t use_count; /* To track references we
16 * destroy on demand
17 */
18 struct list_head list; /* list of network namespaces */
19 struct work_struct work; /* work struct for freeing */
20};
21
22extern struct net init_net;
23extern struct list_head net_namespace_list;
24
25extern void __put_net(struct net *net);
26
27static inline struct net *get_net(struct net *net)
28{
29 atomic_inc(&net->count);
30 return net;
31}
32
33static inline void put_net(struct net *net)
34{
35 if (atomic_dec_and_test(&net->count))
36 __put_net(net);
37}
38
39static inline struct net *hold_net(struct net *net)
40{
41 atomic_inc(&net->use_count);
42 return net;
43}
44
45static inline void release_net(struct net *net)
46{
47 atomic_dec(&net->use_count);
48}
49
50extern void net_lock(void);
51extern void net_unlock(void);
52
53#define for_each_net(VAR) \
54 list_for_each_entry(VAR, &net_namespace_list, list)
55
56
57struct pernet_operations {
58 struct list_head list;
59 int (*init)(struct net *net);
60 void (*exit)(struct net *net);
61};
62
63extern int register_pernet_subsys(struct pernet_operations *);
64extern void unregister_pernet_subsys(struct pernet_operations *);
65extern int register_pernet_device(struct pernet_operations *);
66extern void unregister_pernet_device(struct pernet_operations *);
67
68#endif /* __NET_NET_NAMESPACE_H */
diff --git a/net/core/Makefile b/net/core/Makefile
index 4751613e1b59..ea9b3f32d1c0 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -3,7 +3,7 @@
3# 3#
4 4
5obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \ 5obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
6 gen_stats.o gen_estimator.o 6 gen_stats.o gen_estimator.o net_namespace.o
7 7
8obj-$(CONFIG_SYSCTL) += sysctl_net_core.o 8obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
9 9
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
new file mode 100644
index 000000000000..f259a9b6fdc1
--- /dev/null
+++ b/net/core/net_namespace.c
@@ -0,0 +1,292 @@
1#include <linux/workqueue.h>
2#include <linux/rtnetlink.h>
3#include <linux/cache.h>
4#include <linux/slab.h>
5#include <linux/list.h>
6#include <linux/delay.h>
7#include <net/net_namespace.h>
8
9/*
10 * Our network namespace constructor/destructor lists
11 */
12
13static LIST_HEAD(pernet_list);
14static struct list_head *first_device = &pernet_list;
15static DEFINE_MUTEX(net_mutex);
16
17static DEFINE_MUTEX(net_list_mutex);
18LIST_HEAD(net_namespace_list);
19
20static struct kmem_cache *net_cachep;
21
22struct net init_net;
23EXPORT_SYMBOL_GPL(init_net);
24
25void net_lock(void)
26{
27 mutex_lock(&net_list_mutex);
28}
29
30void net_unlock(void)
31{
32 mutex_unlock(&net_list_mutex);
33}
34
35static struct net *net_alloc(void)
36{
37 return kmem_cache_alloc(net_cachep, GFP_KERNEL);
38}
39
40static void net_free(struct net *net)
41{
42 if (!net)
43 return;
44
45 if (unlikely(atomic_read(&net->use_count) != 0)) {
46 printk(KERN_EMERG "network namespace not free! Usage: %d\n",
47 atomic_read(&net->use_count));
48 return;
49 }
50
51 kmem_cache_free(net_cachep, net);
52}
53
54static void cleanup_net(struct work_struct *work)
55{
56 struct pernet_operations *ops;
57 struct list_head *ptr;
58 struct net *net;
59
60 net = container_of(work, struct net, work);
61
62 mutex_lock(&net_mutex);
63
64 /* Don't let anyone else find us. */
65 net_lock();
66 list_del(&net->list);
67 net_unlock();
68
69 /* Run all of the network namespace exit methods */
70 list_for_each_prev(ptr, &pernet_list) {
71 ops = list_entry(ptr, struct pernet_operations, list);
72 if (ops->exit)
73 ops->exit(net);
74 }
75
76 mutex_unlock(&net_mutex);
77
78 /* Ensure there are no outstanding rcu callbacks using this
79 * network namespace.
80 */
81 rcu_barrier();
82
83 /* Finally it is safe to free my network namespace structure */
84 net_free(net);
85}
86
87
88void __put_net(struct net *net)
89{
90 /* Cleanup the network namespace in process context */
91 INIT_WORK(&net->work, cleanup_net);
92 schedule_work(&net->work);
93}
94EXPORT_SYMBOL_GPL(__put_net);
95
96/*
97 * setup_net runs the initializers for the network namespace object.
98 */
99static int setup_net(struct net *net)
100{
101 /* Must be called with net_mutex held */
102 struct pernet_operations *ops;
103 struct list_head *ptr;
104 int error;
105
106 memset(net, 0, sizeof(struct net));
107 atomic_set(&net->count, 1);
108 atomic_set(&net->use_count, 0);
109
110 error = 0;
111 list_for_each(ptr, &pernet_list) {
112 ops = list_entry(ptr, struct pernet_operations, list);
113 if (ops->init) {
114 error = ops->init(net);
115 if (error < 0)
116 goto out_undo;
117 }
118 }
119out:
120 return error;
121out_undo:
122 /* Walk through the list backwards calling the exit functions
123 * for the pernet modules whose init functions did not fail.
124 */
125 for (ptr = ptr->prev; ptr != &pernet_list; ptr = ptr->prev) {
126 ops = list_entry(ptr, struct pernet_operations, list);
127 if (ops->exit)
128 ops->exit(net);
129 }
130 goto out;
131}
132
133static int __init net_ns_init(void)
134{
135 int err;
136
137 printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net));
138 net_cachep = kmem_cache_create("net_namespace", sizeof(struct net),
139 SMP_CACHE_BYTES,
140 SLAB_PANIC, NULL);
141 mutex_lock(&net_mutex);
142 err = setup_net(&init_net);
143
144 net_lock();
145 list_add_tail(&init_net.list, &net_namespace_list);
146 net_unlock();
147
148 mutex_unlock(&net_mutex);
149 if (err)
150 panic("Could not setup the initial network namespace");
151
152 return 0;
153}
154
155pure_initcall(net_ns_init);
156
157static int register_pernet_operations(struct list_head *list,
158 struct pernet_operations *ops)
159{
160 struct net *net, *undo_net;
161 int error;
162
163 error = 0;
164 list_add_tail(&ops->list, list);
165 for_each_net(net) {
166 if (ops->init) {
167 error = ops->init(net);
168 if (error)
169 goto out_undo;
170 }
171 }
172out:
173 return error;
174
175out_undo:
176 /* If I have an error cleanup all namespaces I initialized */
177 list_del(&ops->list);
178 for_each_net(undo_net) {
179 if (undo_net == net)
180 goto undone;
181 if (ops->exit)
182 ops->exit(undo_net);
183 }
184undone:
185 goto out;
186}
187
188static void unregister_pernet_operations(struct pernet_operations *ops)
189{
190 struct net *net;
191
192 list_del(&ops->list);
193 for_each_net(net)
194 if (ops->exit)
195 ops->exit(net);
196}
197
198/**
199 * register_pernet_subsys - register a network namespace subsystem
200 * @ops: pernet operations structure for the subsystem
201 *
202 * Register a subsystem which has init and exit functions
203 * that are called when network namespaces are created and
204 * destroyed respectively.
205 *
206 * When registered all network namespace init functions are
207 * called for every existing network namespace. Allowing kernel
208 * modules to have a race free view of the set of network namespaces.
209 *
210 * When a new network namespace is created all of the init
211 * methods are called in the order in which they were registered.
212 *
213 * When a network namespace is destroyed all of the exit methods
214 * are called in the reverse of the order with which they were
215 * registered.
216 */
217int register_pernet_subsys(struct pernet_operations *ops)
218{
219 int error;
220 mutex_lock(&net_mutex);
221 error = register_pernet_operations(first_device, ops);
222 mutex_unlock(&net_mutex);
223 return error;
224}
225EXPORT_SYMBOL_GPL(register_pernet_subsys);
226
227/**
228 * unregister_pernet_subsys - unregister a network namespace subsystem
229 * @ops: pernet operations structure to manipulate
230 *
231 * Remove the pernet operations structure from the list to be
232 * used when network namespaces are created or destoryed. In
233 * addition run the exit method for all existing network
234 * namespaces.
235 */
236void unregister_pernet_subsys(struct pernet_operations *module)
237{
238 mutex_lock(&net_mutex);
239 unregister_pernet_operations(module);
240 mutex_unlock(&net_mutex);
241}
242EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
243
244/**
245 * register_pernet_device - register a network namespace device
246 * @ops: pernet operations structure for the subsystem
247 *
248 * Register a device which has init and exit functions
249 * that are called when network namespaces are created and
250 * destroyed respectively.
251 *
252 * When registered all network namespace init functions are
253 * called for every existing network namespace. Allowing kernel
254 * modules to have a race free view of the set of network namespaces.
255 *
256 * When a new network namespace is created all of the init
257 * methods are called in the order in which they were registered.
258 *
259 * When a network namespace is destroyed all of the exit methods
260 * are called in the reverse of the order with which they were
261 * registered.
262 */
263int register_pernet_device(struct pernet_operations *ops)
264{
265 int error;
266 mutex_lock(&net_mutex);
267 error = register_pernet_operations(&pernet_list, ops);
268 if (!error && (first_device == &pernet_list))
269 first_device = &ops->list;
270 mutex_unlock(&net_mutex);
271 return error;
272}
273EXPORT_SYMBOL_GPL(register_pernet_device);
274
275/**
276 * unregister_pernet_device - unregister a network namespace netdevice
277 * @ops: pernet operations structure to manipulate
278 *
279 * Remove the pernet operations structure from the list to be
280 * used when network namespaces are created or destoryed. In
281 * addition run the exit method for all existing network
282 * namespaces.
283 */
284void unregister_pernet_device(struct pernet_operations *ops)
285{
286 mutex_lock(&net_mutex);
287 if (&ops->list == first_device)
288 first_device = first_device->next;
289 unregister_pernet_operations(ops);
290 mutex_unlock(&net_mutex);
291}
292EXPORT_SYMBOL_GPL(unregister_pernet_device);