Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
2
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
1f7a2bb
Documentation
arch
block
crypto
drivers
firmware
fs
include
init
ipc
kernel
lib
mm
net
802
8021q
9p
appletalk
atm
ax25
bluetooth
bridge
can
core
Makefile
datagram.c
dev.c
dev_mcast.c
drop_monitor.c
dst.c
ethtool.c
fib_rules.c
filter.c
flow.c
gen_estimator.c
gen_stats.c
iovec.c
kmap_skb.h
link_watch.c
neighbour.c
net-sysfs.c
net-sysfs.h
net-traces.c
net_namespace.c
netevent.c
netpoll.c
pktgen.c
request_sock.c
rtnetlink.c
scm.c
skb_dma_map.c
skbuff.c
sock.c
stream.c
sysctl_net_core.c
user_dma.c
utils.c
dcb
dccp
decnet
dsa
econet
ethernet
ipv4
ipv6
ipx
irda
iucv
key
lapb
llc
mac80211
netfilter
netlabel
netlink
netrom
packet
phonet
rds
rfkill
rose
rxrpc
sched
sctp
sunrpc
tipc
unix
wanrouter
wimax
wireless
x25
xfrm
Kconfig
Makefile
TUNABLE
compat.c
nonet.c
socket.c
sysctl_net.c
samples
scripts
security
sound
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
net
/
core
/
net_namespace.c
Blame
Blame
Latest commit
History
History
501 lines (430 loc) · 11.3 KB
Breadcrumbs
linux
/
net
/
core
/
net_namespace.c
Top
File metadata and controls
Code
Blame
501 lines (430 loc) · 11.3 KB
Raw
#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 <linux/sched.h> #include <linux/idr.h> #include <net/net_namespace.h> #include <net/netns/generic.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); LIST_HEAD(net_namespace_list); EXPORT_SYMBOL_GPL(net_namespace_list); struct net init_net; EXPORT_SYMBOL(init_net); #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ /* * setup_net runs the initializers for the network namespace object. */ static __net_init int setup_net(struct net *net) { /* Must be called with net_mutex held */ struct pernet_operations *ops; int error = 0; atomic_set(&net->count, 1); #ifdef NETNS_REFCNT_DEBUG atomic_set(&net->use_count, 0); #endif list_for_each_entry(ops, &pernet_list, 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. */ list_for_each_entry_continue_reverse(ops, &pernet_list, list) { if (ops->exit) ops->exit(net); } rcu_barrier(); goto out; } static struct net_generic *net_alloc_generic(void) { 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; } #ifdef CONFIG_NET_NS static struct kmem_cache *net_cachep; static struct workqueue_struct *netns_wq; static struct net *net_alloc(void) { struct net *net = NULL; struct net_generic *ng; ng = net_alloc_generic(); if (!ng) goto out; net = kmem_cache_zalloc(net_cachep, GFP_KERNEL); if (!net) goto out_free; rcu_assign_pointer(net->gen, ng); out: return net; out_free: kfree(ng); goto out; } static void net_free(struct net *net) { #ifdef NETNS_REFCNT_DEBUG if (unlikely(atomic_read(&net->use_count) != 0)) { printk(KERN_EMERG "network namespace not free! Usage: %d\n", atomic_read(&net->use_count)); return; } #endif kfree(net->gen); kmem_cache_free(net_cachep, net); } static struct net *net_create(void) { struct net *net; int rv; net = net_alloc(); if (!net) return ERR_PTR(-ENOMEM); mutex_lock(&net_mutex); rv = setup_net(net); if (rv == 0) { rtnl_lock(); list_add_tail(&net->list, &net_namespace_list); rtnl_unlock(); } mutex_unlock(&net_mutex); if (rv < 0) { net_free(net); return ERR_PTR(rv); } return net; } struct net *copy_net_ns(unsigned long flags, struct net *old_net) { if (!(flags & CLONE_NEWNET)) return get_net(old_net); return net_create(); } static void cleanup_net(struct work_struct *work) { struct pernet_operations *ops; struct net *net; net = container_of(work, struct net, work); mutex_lock(&net_mutex); /* Don't let anyone else find us. */ rtnl_lock(); list_del(&net->list); rtnl_unlock(); /* Run all of the network namespace exit methods */ list_for_each_entry_reverse(ops, &pernet_list, 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); queue_work(netns_wq, &net->work); } EXPORT_SYMBOL_GPL(__put_net); #else struct net *copy_net_ns(unsigned long flags, struct net *old_net) { if (flags & CLONE_NEWNET) return ERR_PTR(-EINVAL); return old_net; } #endif static int __init net_ns_init(void) { struct net_generic *ng; int err; #ifdef CONFIG_NET_NS net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), SMP_CACHE_BYTES, SLAB_PANIC, NULL); /* Create workqueue for cleanup */ netns_wq = create_singlethread_workqueue("netns"); if (!netns_wq) panic("Could not create netns workq"); #endif ng = net_alloc_generic(); if (!ng) panic("Could not allocate generic netns"); rcu_assign_pointer(init_net.gen, ng); mutex_lock(&net_mutex); err = setup_net(&init_net); rtnl_lock(); list_add_tail(&init_net.list, &net_namespace_list); rtnl_unlock(); mutex_unlock(&net_mutex); if (err) panic("Could not setup the initial network namespace"); return 0; } pure_initcall(net_ns_init); #ifdef CONFIG_NET_NS static int register_pernet_operations(struct list_head *list, struct pernet_operations *ops) { struct net *net, *undo_net; int error; list_add_tail(&ops->list, list); if (ops->init) { for_each_net(net) { error = ops->init(net); if (error) goto out_undo; } } return 0; out_undo: /* If I have an error cleanup all namespaces I initialized */ list_del(&ops->list); if (ops->exit) { for_each_net(undo_net) { if (undo_net == net) goto undone; ops->exit(undo_net); } } undone: return error; } static void unregister_pernet_operations(struct pernet_operations *ops) { struct net *net; list_del(&ops->list); if (ops->exit) for_each_net(net) ops->exit(net); } #else static int register_pernet_operations(struct list_head *list, struct pernet_operations *ops) { if (ops->init == NULL) return 0; return ops->init(&init_net); } static void unregister_pernet_operations(struct pernet_operations *ops) { if (ops->exit) ops->exit(&init_net); } #endif static DEFINE_IDA(net_generic_ids); /** * 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 destroyed. 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); int register_pernet_gen_subsys(int *id, struct pernet_operations *ops) { int rv; mutex_lock(&net_mutex); again: rv = ida_get_new_above(&net_generic_ids, 1, id); if (rv < 0) { if (rv == -EAGAIN) { ida_pre_get(&net_generic_ids, GFP_KERNEL); goto again; } goto out; } rv = register_pernet_operations(first_device, ops); if (rv < 0) ida_remove(&net_generic_ids, *id); out: mutex_unlock(&net_mutex); return rv; } EXPORT_SYMBOL_GPL(register_pernet_gen_subsys); void unregister_pernet_gen_subsys(int id, struct pernet_operations *ops) { mutex_lock(&net_mutex); unregister_pernet_operations(ops); ida_remove(&net_generic_ids, id); mutex_unlock(&net_mutex); } EXPORT_SYMBOL_GPL(unregister_pernet_gen_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); int register_pernet_gen_device(int *id, struct pernet_operations *ops) { int error; mutex_lock(&net_mutex); again: error = ida_get_new_above(&net_generic_ids, 1, id); if (error) { if (error == -EAGAIN) { ida_pre_get(&net_generic_ids, GFP_KERNEL); goto again; } goto out; } error = register_pernet_operations(&pernet_list, ops); if (error) ida_remove(&net_generic_ids, *id); else if (first_device == &pernet_list) first_device = &ops->list; out: mutex_unlock(&net_mutex); return error; } EXPORT_SYMBOL_GPL(register_pernet_gen_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 destroyed. 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); void unregister_pernet_gen_device(int id, struct pernet_operations *ops) { mutex_lock(&net_mutex); if (&ops->list == first_device) first_device = first_device->next; unregister_pernet_operations(ops); ida_remove(&net_generic_ids, id); mutex_unlock(&net_mutex); } EXPORT_SYMBOL_GPL(unregister_pernet_gen_device); static void net_generic_release(struct rcu_head *rcu) { struct net_generic *ng; ng = container_of(rcu, struct net_generic, rcu); kfree(ng); } 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); ng = old_ng = net->gen; 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); rcu_assign_pointer(net->gen, ng); call_rcu(&old_ng->rcu, net_generic_release); assign: ng->ptr[id - 1] = data; return 0; } EXPORT_SYMBOL_GPL(net_assign_generic);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
94
95
96
97
98
99
100
101
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
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
You can’t perform that action at this time.