Blame view

net/core/net_namespace.c 14.4 KB
5f256becd   Eric W. Biederman   [NET]: Basic netw...
1
2
3
4
5
6
  #include <linux/workqueue.h>
  #include <linux/rtnetlink.h>
  #include <linux/cache.h>
  #include <linux/slab.h>
  #include <linux/list.h>
  #include <linux/delay.h>
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
7
  #include <linux/sched.h>
c93cf61fd   Pavel Emelyanov   [NETNS]: The net-...
8
  #include <linux/idr.h>
11a28d373   Johannes Berg   net: make namespa...
9
  #include <linux/rculist.h>
30ffee848   Johannes Berg   net: move and exp...
10
  #include <linux/nsproxy.h>
f06305294   Eric W. Biederman   net: Allow settin...
11
12
  #include <linux/proc_fs.h>
  #include <linux/file.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
13
  #include <linux/export.h>
5f256becd   Eric W. Biederman   [NET]: Basic netw...
14
  #include <net/net_namespace.h>
dec827d17   Pavel Emelyanov   [NETNS]: The gene...
15
  #include <net/netns/generic.h>
5f256becd   Eric W. Biederman   [NET]: Basic netw...
16
17
18
19
20
21
22
23
  
  /*
   *	Our network namespace constructor/destructor lists
   */
  
  static LIST_HEAD(pernet_list);
  static struct list_head *first_device = &pernet_list;
  static DEFINE_MUTEX(net_mutex);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
24
  LIST_HEAD(net_namespace_list);
b76a461f1   Alexey Dobriyan   netns: export net...
25
  EXPORT_SYMBOL_GPL(net_namespace_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
26

5f256becd   Eric W. Biederman   [NET]: Basic netw...
27
  struct net init_net;
ff4b95027   Denis V. Lunev   [NETNS]: Re-expor...
28
  EXPORT_SYMBOL(init_net);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
29

dec827d17   Pavel Emelyanov   [NETNS]: The gene...
30
  #define INITIAL_NET_GEN_PTRS	13 /* +1 for len +2 for rcu_head */
05fceb4ad   Jiri Pirko   net: disallow to ...
31
32
33
34
35
36
  static int net_assign_generic(struct net *net, int id, void *data)
  {
  	struct net_generic *ng, *old_ng;
  
  	BUG_ON(!mutex_is_locked(&net_mutex));
  	BUG_ON(id == 0);
1c87733d0   Eric Dumazet   net_ns: add __rcu...
37
38
39
  	old_ng = rcu_dereference_protected(net->gen,
  					   lockdep_is_held(&net_mutex));
  	ng = old_ng;
05fceb4ad   Jiri Pirko   net: disallow to ...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  	if (old_ng->len >= id)
  		goto assign;
  
  	ng = kzalloc(sizeof(struct net_generic) +
  			id * sizeof(void *), GFP_KERNEL);
  	if (ng == NULL)
  		return -ENOMEM;
  
  	/*
  	 * Some synchronisation notes:
  	 *
  	 * The net_generic explores the net->gen array inside rcu
  	 * read section. Besides once set the net->gen->ptr[x]
  	 * pointer never changes (see rules in netns/generic.h).
  	 *
  	 * That said, we simply duplicate this array and schedule
  	 * the old copy for kfree after a grace period.
  	 */
  
  	ng->len = id;
  	memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
  
  	rcu_assign_pointer(net->gen, ng);
04d4dfed8   Lai Jiangshan   net,rcu: convert ...
63
  	kfree_rcu(old_ng, rcu);
05fceb4ad   Jiri Pirko   net: disallow to ...
64
65
66
67
  assign:
  	ng->ptr[id - 1] = data;
  	return 0;
  }
f875bae06   Eric W. Biederman   net: Automaticall...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  static int ops_init(const struct pernet_operations *ops, struct net *net)
  {
  	int err;
  	if (ops->id && ops->size) {
  		void *data = kzalloc(ops->size, GFP_KERNEL);
  		if (!data)
  			return -ENOMEM;
  
  		err = net_assign_generic(net, *ops->id, data);
  		if (err) {
  			kfree(data);
  			return err;
  		}
  	}
  	if (ops->init)
  		return ops->init(net);
  	return 0;
  }
  
  static void ops_free(const struct pernet_operations *ops, struct net *net)
  {
  	if (ops->id && ops->size) {
  		int id = *ops->id;
  		kfree(net_generic(net, id));
  	}
  }
72ad937ab   Eric W. Biederman   net: Add support ...
94
95
96
97
98
99
100
101
  static void ops_exit_list(const struct pernet_operations *ops,
  			  struct list_head *net_exit_list)
  {
  	struct net *net;
  	if (ops->exit) {
  		list_for_each_entry(net, net_exit_list, exit_list)
  			ops->exit(net);
  	}
72ad937ab   Eric W. Biederman   net: Add support ...
102
103
104
105
106
107
108
109
110
111
112
113
114
  	if (ops->exit_batch)
  		ops->exit_batch(net_exit_list);
  }
  
  static void ops_free_list(const struct pernet_operations *ops,
  			  struct list_head *net_exit_list)
  {
  	struct net *net;
  	if (ops->size && ops->id) {
  		list_for_each_entry(net, net_exit_list, exit_list)
  			ops_free(ops, net);
  	}
  }
5f256becd   Eric W. Biederman   [NET]: Basic netw...
115
116
117
  /*
   * setup_net runs the initializers for the network namespace object.
   */
1a2ee93d2   Pavel Emelyanov   [NET]: Mark the s...
118
  static __net_init int setup_net(struct net *net)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
119
120
  {
  	/* Must be called with net_mutex held */
f875bae06   Eric W. Biederman   net: Automaticall...
121
  	const struct pernet_operations *ops, *saved_ops;
486a87f1e   Daniel Lezcano   netns: fix double...
122
  	int error = 0;
72ad937ab   Eric W. Biederman   net: Add support ...
123
  	LIST_HEAD(net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
124

5f256becd   Eric W. Biederman   [NET]: Basic netw...
125
  	atomic_set(&net->count, 1);
a685e0898   Al Viro   Delay struct net ...
126
  	atomic_set(&net->passive, 1);
4e985adaa   Thomas Graf   rtnl: provide lin...
127
  	net->dev_base_seq = 1;
486a87f1e   Daniel Lezcano   netns: fix double...
128

5d1e4468a   Denis V. Lunev   [NETNS]: Make net...
129
  #ifdef NETNS_REFCNT_DEBUG
5f256becd   Eric W. Biederman   [NET]: Basic netw...
130
  	atomic_set(&net->use_count, 0);
5d1e4468a   Denis V. Lunev   [NETNS]: Make net...
131
  #endif
5f256becd   Eric W. Biederman   [NET]: Basic netw...
132

768f3591e   Pavel Emelyanov   [NETNS]: Cleanup ...
133
  	list_for_each_entry(ops, &pernet_list, list) {
f875bae06   Eric W. Biederman   net: Automaticall...
134
135
136
  		error = ops_init(ops, net);
  		if (error < 0)
  			goto out_undo;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
137
138
139
  	}
  out:
  	return error;
768f3591e   Pavel Emelyanov   [NETNS]: Cleanup ...
140

5f256becd   Eric W. Biederman   [NET]: Basic netw...
141
142
143
144
  out_undo:
  	/* Walk through the list backwards calling the exit functions
  	 * for the pernet modules whose init functions did not fail.
  	 */
72ad937ab   Eric W. Biederman   net: Add support ...
145
  	list_add(&net->exit_list, &net_exit_list);
f875bae06   Eric W. Biederman   net: Automaticall...
146
  	saved_ops = ops;
72ad937ab   Eric W. Biederman   net: Add support ...
147
148
  	list_for_each_entry_continue_reverse(ops, &pernet_list, list)
  		ops_exit_list(ops, &net_exit_list);
f875bae06   Eric W. Biederman   net: Automaticall...
149
150
  	ops = saved_ops;
  	list_for_each_entry_continue_reverse(ops, &pernet_list, list)
72ad937ab   Eric W. Biederman   net: Add support ...
151
  		ops_free_list(ops, &net_exit_list);
310928d96   Daniel Lezcano   [NETNS]: fix net ...
152
153
  
  	rcu_barrier();
5f256becd   Eric W. Biederman   [NET]: Basic netw...
154
155
  	goto out;
  }
486a87f1e   Daniel Lezcano   netns: fix double...
156
  static struct net_generic *net_alloc_generic(void)
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
157
  {
486a87f1e   Daniel Lezcano   netns: fix double...
158
159
160
161
162
163
164
165
166
  	struct net_generic *ng;
  	size_t generic_size = sizeof(struct net_generic) +
  		INITIAL_NET_GEN_PTRS * sizeof(void *);
  
  	ng = kzalloc(generic_size, GFP_KERNEL);
  	if (ng)
  		ng->len = INITIAL_NET_GEN_PTRS;
  
  	return ng;
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
167
  }
ebe47d47b   Clemens Noss   netns: build fix ...
168
169
170
  #ifdef CONFIG_NET_NS
  static struct kmem_cache *net_cachep;
  static struct workqueue_struct *netns_wq;
486a87f1e   Daniel Lezcano   netns: fix double...
171
  static struct net *net_alloc(void)
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
172
  {
486a87f1e   Daniel Lezcano   netns: fix double...
173
174
175
176
177
178
179
180
  	struct net *net = NULL;
  	struct net_generic *ng;
  
  	ng = net_alloc_generic();
  	if (!ng)
  		goto out;
  
  	net = kmem_cache_zalloc(net_cachep, GFP_KERNEL);
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
181
  	if (!net)
486a87f1e   Daniel Lezcano   netns: fix double...
182
  		goto out_free;
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
183

486a87f1e   Daniel Lezcano   netns: fix double...
184
185
186
187
188
189
190
191
192
193
194
  	rcu_assign_pointer(net->gen, ng);
  out:
  	return net;
  
  out_free:
  	kfree(ng);
  	goto out;
  }
  
  static void net_free(struct net *net)
  {
5d1e4468a   Denis V. Lunev   [NETNS]: Make net...
195
  #ifdef NETNS_REFCNT_DEBUG
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
196
197
198
199
200
201
  	if (unlikely(atomic_read(&net->use_count) != 0)) {
  		printk(KERN_EMERG "network namespace not free! Usage: %d
  ",
  			atomic_read(&net->use_count));
  		return;
  	}
5d1e4468a   Denis V. Lunev   [NETNS]: Make net...
202
  #endif
4ef079ccc   Alexey Dobriyan   netns: fix net_ge...
203
  	kfree(net->gen);
45a19b0a7   Johann Felix Soden   [NETNS]: Fix comp...
204
205
  	kmem_cache_free(net_cachep, net);
  }
a685e0898   Al Viro   Delay struct net ...
206
207
208
209
210
211
  void net_drop_ns(void *p)
  {
  	struct net *ns = p;
  	if (ns && atomic_dec_and_test(&ns->passive))
  		net_free(ns);
  }
911cb193f   Rob Landley   net: minor cleanu...
212
  struct net *copy_net_ns(unsigned long flags, struct net *old_net)
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
213
  {
088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
214
215
  	struct net *net;
  	int rv;
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
216

911cb193f   Rob Landley   net: minor cleanu...
217
218
  	if (!(flags & CLONE_NEWNET))
  		return get_net(old_net);
088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
219
220
221
  	net = net_alloc();
  	if (!net)
  		return ERR_PTR(-ENOMEM);
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
222
  	mutex_lock(&net_mutex);
088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
223
224
  	rv = setup_net(net);
  	if (rv == 0) {
486a87f1e   Daniel Lezcano   netns: fix double...
225
  		rtnl_lock();
11a28d373   Johannes Berg   net: make namespa...
226
  		list_add_tail_rcu(&net->list, &net_namespace_list);
486a87f1e   Daniel Lezcano   netns: fix double...
227
228
  		rtnl_unlock();
  	}
9dd776b6d   Eric W. Biederman   [NET]: Add networ...
229
  	mutex_unlock(&net_mutex);
088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
230
  	if (rv < 0) {
a685e0898   Al Viro   Delay struct net ...
231
  		net_drop_ns(net);
088eb2d90   Alexey Dobriyan   netns 2/2: extrac...
232
233
234
235
  		return ERR_PTR(rv);
  	}
  	return net;
  }
486a87f1e   Daniel Lezcano   netns: fix double...
236

2b035b399   Eric W. Biederman   net: Batch networ...
237
238
  static DEFINE_SPINLOCK(cleanup_list_lock);
  static LIST_HEAD(cleanup_list);  /* Must hold cleanup_list_lock to touch */
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
239
240
  static void cleanup_net(struct work_struct *work)
  {
f875bae06   Eric W. Biederman   net: Automaticall...
241
  	const struct pernet_operations *ops;
2b035b399   Eric W. Biederman   net: Batch networ...
242
243
  	struct net *net, *tmp;
  	LIST_HEAD(net_kill_list);
72ad937ab   Eric W. Biederman   net: Add support ...
244
  	LIST_HEAD(net_exit_list);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
245

2b035b399   Eric W. Biederman   net: Batch networ...
246
247
248
249
  	/* Atomically snapshot the list of namespaces to cleanup */
  	spin_lock_irq(&cleanup_list_lock);
  	list_replace_init(&cleanup_list, &net_kill_list);
  	spin_unlock_irq(&cleanup_list_lock);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
250
251
252
253
254
  
  	mutex_lock(&net_mutex);
  
  	/* Don't let anyone else find us. */
  	rtnl_lock();
72ad937ab   Eric W. Biederman   net: Add support ...
255
  	list_for_each_entry(net, &net_kill_list, cleanup_list) {
2b035b399   Eric W. Biederman   net: Batch networ...
256
  		list_del_rcu(&net->list);
72ad937ab   Eric W. Biederman   net: Add support ...
257
258
  		list_add_tail(&net->exit_list, &net_exit_list);
  	}
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
259
  	rtnl_unlock();
11a28d373   Johannes Berg   net: make namespa...
260
261
262
263
264
265
  	/*
  	 * Another CPU might be rcu-iterating the list, wait for it.
  	 * This needs to be before calling the exit() notifiers, so
  	 * the rcu_barrier() below isn't sufficient alone.
  	 */
  	synchronize_rcu();
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
266
  	/* Run all of the network namespace exit methods */
72ad937ab   Eric W. Biederman   net: Add support ...
267
268
  	list_for_each_entry_reverse(ops, &pernet_list, list)
  		ops_exit_list(ops, &net_exit_list);
f875bae06   Eric W. Biederman   net: Automaticall...
269
  	/* Free the net generic variables */
72ad937ab   Eric W. Biederman   net: Add support ...
270
271
  	list_for_each_entry_reverse(ops, &pernet_list, list)
  		ops_free_list(ops, &net_exit_list);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
272
273
274
275
276
277
278
279
280
  
  	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 */
72ad937ab   Eric W. Biederman   net: Add support ...
281
282
  	list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) {
  		list_del_init(&net->exit_list);
a685e0898   Al Viro   Delay struct net ...
283
  		net_drop_ns(net);
2b035b399   Eric W. Biederman   net: Batch networ...
284
  	}
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
285
  }
2b035b399   Eric W. Biederman   net: Batch networ...
286
  static DECLARE_WORK(net_cleanup_work, cleanup_net);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
287
288
289
290
  
  void __put_net(struct net *net)
  {
  	/* Cleanup the network namespace in process context */
2b035b399   Eric W. Biederman   net: Batch networ...
291
292
293
294
295
296
297
  	unsigned long flags;
  
  	spin_lock_irqsave(&cleanup_list_lock, flags);
  	list_add(&net->cleanup_list, &cleanup_list);
  	spin_unlock_irqrestore(&cleanup_list_lock, flags);
  
  	queue_work(netns_wq, &net_cleanup_work);
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
298
299
  }
  EXPORT_SYMBOL_GPL(__put_net);
956c92078   Stephen Rothwell   net: fix get_net_...
300
301
302
303
304
  struct net *get_net_ns_by_fd(int fd)
  {
  	struct proc_inode *ei;
  	struct file *file;
  	struct net *net;
956c92078   Stephen Rothwell   net: fix get_net_...
305
  	file = proc_ns_fget(fd);
c316e6a30   Al Viro   get_net_ns_by_fd(...
306
307
  	if (IS_ERR(file))
  		return ERR_CAST(file);
956c92078   Stephen Rothwell   net: fix get_net_...
308
309
  
  	ei = PROC_I(file->f_dentry->d_inode);
c316e6a30   Al Viro   get_net_ns_by_fd(...
310
311
312
313
  	if (ei->ns_ops == &netns_operations)
  		net = get_net(ei->ns);
  	else
  		net = ERR_PTR(-EINVAL);
956c92078   Stephen Rothwell   net: fix get_net_...
314

c316e6a30   Al Viro   get_net_ns_by_fd(...
315
  	fput(file);
956c92078   Stephen Rothwell   net: fix get_net_...
316
317
  	return net;
  }
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
318
319
320
321
322
323
324
  #else
  struct net *copy_net_ns(unsigned long flags, struct net *old_net)
  {
  	if (flags & CLONE_NEWNET)
  		return ERR_PTR(-EINVAL);
  	return old_net;
  }
956c92078   Stephen Rothwell   net: fix get_net_...
325
326
327
328
329
  
  struct net *get_net_ns_by_fd(int fd)
  {
  	return ERR_PTR(-EINVAL);
  }
6a1a3b9f6   Pavel Emelyanov   [NET]: Hide the d...
330
  #endif
30ffee848   Johannes Berg   net: move and exp...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  struct net *get_net_ns_by_pid(pid_t pid)
  {
  	struct task_struct *tsk;
  	struct net *net;
  
  	/* Lookup the network namespace */
  	net = ERR_PTR(-ESRCH);
  	rcu_read_lock();
  	tsk = find_task_by_vpid(pid);
  	if (tsk) {
  		struct nsproxy *nsproxy;
  		nsproxy = task_nsproxy(tsk);
  		if (nsproxy)
  			net = get_net(nsproxy->net_ns);
  	}
  	rcu_read_unlock();
  	return net;
  }
  EXPORT_SYMBOL_GPL(get_net_ns_by_pid);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
350
351
  static int __init net_ns_init(void)
  {
486a87f1e   Daniel Lezcano   netns: fix double...
352
  	struct net_generic *ng;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
353

d57a9212e   Pavel Emelyanov   [NET]: Hide the n...
354
  #ifdef CONFIG_NET_NS
5f256becd   Eric W. Biederman   [NET]: Basic netw...
355
356
357
  	net_cachep = kmem_cache_create("net_namespace", sizeof(struct net),
  					SMP_CACHE_BYTES,
  					SLAB_PANIC, NULL);
3ef1355dc   Benjamin Thery   [NET]: Make netns...
358
359
360
361
362
  
  	/* Create workqueue for cleanup */
  	netns_wq = create_singlethread_workqueue("netns");
  	if (!netns_wq)
  		panic("Could not create netns workq");
d57a9212e   Pavel Emelyanov   [NET]: Hide the n...
363
  #endif
3ef1355dc   Benjamin Thery   [NET]: Make netns...
364

486a87f1e   Daniel Lezcano   netns: fix double...
365
366
367
368
369
  	ng = net_alloc_generic();
  	if (!ng)
  		panic("Could not allocate generic netns");
  
  	rcu_assign_pointer(init_net.gen, ng);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
370
  	mutex_lock(&net_mutex);
ca0f31125   Stephen Hemminger   netns: simplify n...
371
372
  	if (setup_net(&init_net))
  		panic("Could not setup the initial network namespace");
5f256becd   Eric W. Biederman   [NET]: Basic netw...
373

f4618d39a   Eric W. Biederman   [NETNS]: Simplify...
374
  	rtnl_lock();
11a28d373   Johannes Berg   net: make namespa...
375
  	list_add_tail_rcu(&init_net.list, &net_namespace_list);
f4618d39a   Eric W. Biederman   [NETNS]: Simplify...
376
  	rtnl_unlock();
5f256becd   Eric W. Biederman   [NET]: Basic netw...
377
378
  
  	mutex_unlock(&net_mutex);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
379
380
381
382
383
  
  	return 0;
  }
  
  pure_initcall(net_ns_init);
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
384
  #ifdef CONFIG_NET_NS
f875bae06   Eric W. Biederman   net: Automaticall...
385
386
  static int __register_pernet_operations(struct list_head *list,
  					struct pernet_operations *ops)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
387
  {
72ad937ab   Eric W. Biederman   net: Add support ...
388
  	struct net *net;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
389
  	int error;
72ad937ab   Eric W. Biederman   net: Add support ...
390
  	LIST_HEAD(net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
391

5f256becd   Eric W. Biederman   [NET]: Basic netw...
392
  	list_add_tail(&ops->list, list);
f875bae06   Eric W. Biederman   net: Automaticall...
393
  	if (ops->init || (ops->id && ops->size)) {
1dba323b3   Pavel Emelyanov   [NETNS]: Make the...
394
  		for_each_net(net) {
f875bae06   Eric W. Biederman   net: Automaticall...
395
  			error = ops_init(ops, net);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
396
397
  			if (error)
  				goto out_undo;
72ad937ab   Eric W. Biederman   net: Add support ...
398
  			list_add_tail(&net->exit_list, &net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
399
400
  		}
  	}
1dba323b3   Pavel Emelyanov   [NETNS]: Make the...
401
  	return 0;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
402
403
404
405
  
  out_undo:
  	/* If I have an error cleanup all namespaces I initialized */
  	list_del(&ops->list);
72ad937ab   Eric W. Biederman   net: Add support ...
406
407
  	ops_exit_list(ops, &net_exit_list);
  	ops_free_list(ops, &net_exit_list);
1dba323b3   Pavel Emelyanov   [NETNS]: Make the...
408
  	return error;
5f256becd   Eric W. Biederman   [NET]: Basic netw...
409
  }
f875bae06   Eric W. Biederman   net: Automaticall...
410
  static void __unregister_pernet_operations(struct pernet_operations *ops)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
411
412
  {
  	struct net *net;
72ad937ab   Eric W. Biederman   net: Add support ...
413
  	LIST_HEAD(net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
414
415
  
  	list_del(&ops->list);
72ad937ab   Eric W. Biederman   net: Add support ...
416
417
418
419
  	for_each_net(net)
  		list_add_tail(&net->exit_list, &net_exit_list);
  	ops_exit_list(ops, &net_exit_list);
  	ops_free_list(ops, &net_exit_list);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
420
  }
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
421
  #else
f875bae06   Eric W. Biederman   net: Automaticall...
422
423
  static int __register_pernet_operations(struct list_head *list,
  					struct pernet_operations *ops)
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
424
  {
f875bae06   Eric W. Biederman   net: Automaticall...
425
426
427
428
429
430
  	int err = 0;
  	err = ops_init(ops, &init_net);
  	if (err)
  		ops_free(ops, &init_net);
  	return err;
  	
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
431
  }
f875bae06   Eric W. Biederman   net: Automaticall...
432
  static void __unregister_pernet_operations(struct pernet_operations *ops)
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
433
  {
72ad937ab   Eric W. Biederman   net: Add support ...
434
435
436
437
  	LIST_HEAD(net_exit_list);
  	list_add(&init_net.exit_list, &net_exit_list);
  	ops_exit_list(ops, &net_exit_list);
  	ops_free_list(ops, &net_exit_list);
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
438
  }
f875bae06   Eric W. Biederman   net: Automaticall...
439
440
  
  #endif /* CONFIG_NET_NS */
ed160e839   Denis V. Lunev   [NET]: Cleanup pe...
441

c93cf61fd   Pavel Emelyanov   [NETNS]: The net-...
442
  static DEFINE_IDA(net_generic_ids);
f875bae06   Eric W. Biederman   net: Automaticall...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  static int register_pernet_operations(struct list_head *list,
  				      struct pernet_operations *ops)
  {
  	int error;
  
  	if (ops->id) {
  again:
  		error = ida_get_new_above(&net_generic_ids, 1, ops->id);
  		if (error < 0) {
  			if (error == -EAGAIN) {
  				ida_pre_get(&net_generic_ids, GFP_KERNEL);
  				goto again;
  			}
  			return error;
  		}
  	}
  	error = __register_pernet_operations(list, ops);
3a765edad   Eric W. Biederman   netns: Add an exp...
460
461
462
463
464
  	if (error) {
  		rcu_barrier();
  		if (ops->id)
  			ida_remove(&net_generic_ids, *ops->id);
  	}
f875bae06   Eric W. Biederman   net: Automaticall...
465
466
467
468
469
470
471
472
  
  	return error;
  }
  
  static void unregister_pernet_operations(struct pernet_operations *ops)
  {
  	
  	__unregister_pernet_operations(ops);
3a765edad   Eric W. Biederman   netns: Add an exp...
473
  	rcu_barrier();
f875bae06   Eric W. Biederman   net: Automaticall...
474
475
476
  	if (ops->id)
  		ida_remove(&net_generic_ids, *ops->id);
  }
5f256becd   Eric W. Biederman   [NET]: Basic netw...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  /**
   *      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
53379e57a   Oliver Pinter   typo fixes in net...
511
   *	used when network namespaces are created or destroyed.  In
5f256becd   Eric W. Biederman   [NET]: Basic netw...
512
513
514
   *	addition run the exit method for all existing network
   *	namespaces.
   */
b3c981d2b   Jiri Pirko   netns: rename unr...
515
  void unregister_pernet_subsys(struct pernet_operations *ops)
5f256becd   Eric W. Biederman   [NET]: Basic netw...
516
517
  {
  	mutex_lock(&net_mutex);
b3c981d2b   Jiri Pirko   netns: rename unr...
518
  	unregister_pernet_operations(ops);
5f256becd   Eric W. Biederman   [NET]: Basic netw...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
  	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
53379e57a   Oliver Pinter   typo fixes in net...
559
   *	used when network namespaces are created or destroyed.  In
5f256becd   Eric W. Biederman   [NET]: Basic netw...
560
561
562
563
564
565
566
567
568
569
570
571
   *	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);
13b6f5762   Eric W. Biederman   ns proc: Add supp...
572
573
574
575
  
  #ifdef CONFIG_NET_NS
  static void *netns_get(struct task_struct *task)
  {
f06305294   Eric W. Biederman   net: Allow settin...
576
577
  	struct net *net = NULL;
  	struct nsproxy *nsproxy;
13b6f5762   Eric W. Biederman   ns proc: Add supp...
578
  	rcu_read_lock();
f06305294   Eric W. Biederman   net: Allow settin...
579
580
581
  	nsproxy = task_nsproxy(task);
  	if (nsproxy)
  		net = get_net(nsproxy->net_ns);
13b6f5762   Eric W. Biederman   ns proc: Add supp...
582
  	rcu_read_unlock();
f06305294   Eric W. Biederman   net: Allow settin...
583

13b6f5762   Eric W. Biederman   ns proc: Add supp...
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
  	return net;
  }
  
  static void netns_put(void *ns)
  {
  	put_net(ns);
  }
  
  static int netns_install(struct nsproxy *nsproxy, void *ns)
  {
  	put_net(nsproxy->net_ns);
  	nsproxy->net_ns = get_net(ns);
  	return 0;
  }
  
  const struct proc_ns_operations netns_operations = {
  	.name		= "net",
  	.type		= CLONE_NEWNET,
  	.get		= netns_get,
  	.put		= netns_put,
  	.install	= netns_install,
  };
  #endif