diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2008-11-25 20:58:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-11-25 20:58:07 -0500 |
commit | 3fa87a3210a24ae406c2ccd37a52585baeb21546 (patch) | |
tree | b4fee69b1314d107659c7e2f22c00fa5a845fe68 /net/key | |
parent | 7c2776ee21a60e0d370538bd08b9ed82979f6e3a (diff) |
netns PF_KEY: part 1
* netns boilerplate
* keep per-netns socket list
* keep per-netns number of sockets
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/key')
-rw-r--r-- | net/key/af_key.c | 88 |
1 files changed, 73 insertions, 15 deletions
diff --git a/net/key/af_key.c b/net/key/af_key.c index ea7755ab7e6a..e80b26488bb3 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <net/net_namespace.h> | 29 | #include <net/net_namespace.h> |
30 | #include <net/netns/generic.h> | ||
30 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
31 | 32 | ||
32 | #include <net/sock.h> | 33 | #include <net/sock.h> |
@@ -34,15 +35,16 @@ | |||
34 | #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x)) | 35 | #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x)) |
35 | #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x)) | 36 | #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x)) |
36 | 37 | ||
37 | 38 | static int pfkey_net_id; | |
38 | /* List of all pfkey sockets. */ | 39 | struct netns_pfkey { |
39 | static HLIST_HEAD(pfkey_table); | 40 | /* List of all pfkey sockets. */ |
41 | struct hlist_head table; | ||
42 | atomic_t socks_nr; | ||
43 | }; | ||
40 | static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait); | 44 | static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait); |
41 | static DEFINE_RWLOCK(pfkey_table_lock); | 45 | static DEFINE_RWLOCK(pfkey_table_lock); |
42 | static atomic_t pfkey_table_users = ATOMIC_INIT(0); | 46 | static atomic_t pfkey_table_users = ATOMIC_INIT(0); |
43 | 47 | ||
44 | static atomic_t pfkey_socks_nr = ATOMIC_INIT(0); | ||
45 | |||
46 | struct pfkey_sock { | 48 | struct pfkey_sock { |
47 | /* struct sock must be the first member of struct pfkey_sock */ | 49 | /* struct sock must be the first member of struct pfkey_sock */ |
48 | struct sock sk; | 50 | struct sock sk; |
@@ -89,6 +91,9 @@ static void pfkey_terminate_dump(struct pfkey_sock *pfk) | |||
89 | 91 | ||
90 | static void pfkey_sock_destruct(struct sock *sk) | 92 | static void pfkey_sock_destruct(struct sock *sk) |
91 | { | 93 | { |
94 | struct net *net = sock_net(sk); | ||
95 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
96 | |||
92 | pfkey_terminate_dump(pfkey_sk(sk)); | 97 | pfkey_terminate_dump(pfkey_sk(sk)); |
93 | skb_queue_purge(&sk->sk_receive_queue); | 98 | skb_queue_purge(&sk->sk_receive_queue); |
94 | 99 | ||
@@ -100,7 +105,7 @@ static void pfkey_sock_destruct(struct sock *sk) | |||
100 | WARN_ON(atomic_read(&sk->sk_rmem_alloc)); | 105 | WARN_ON(atomic_read(&sk->sk_rmem_alloc)); |
101 | WARN_ON(atomic_read(&sk->sk_wmem_alloc)); | 106 | WARN_ON(atomic_read(&sk->sk_wmem_alloc)); |
102 | 107 | ||
103 | atomic_dec(&pfkey_socks_nr); | 108 | atomic_dec(&net_pfkey->socks_nr); |
104 | } | 109 | } |
105 | 110 | ||
106 | static void pfkey_table_grab(void) | 111 | static void pfkey_table_grab(void) |
@@ -151,8 +156,11 @@ static const struct proto_ops pfkey_ops; | |||
151 | 156 | ||
152 | static void pfkey_insert(struct sock *sk) | 157 | static void pfkey_insert(struct sock *sk) |
153 | { | 158 | { |
159 | struct net *net = sock_net(sk); | ||
160 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
161 | |||
154 | pfkey_table_grab(); | 162 | pfkey_table_grab(); |
155 | sk_add_node(sk, &pfkey_table); | 163 | sk_add_node(sk, &net_pfkey->table); |
156 | pfkey_table_ungrab(); | 164 | pfkey_table_ungrab(); |
157 | } | 165 | } |
158 | 166 | ||
@@ -171,12 +179,10 @@ static struct proto key_proto = { | |||
171 | 179 | ||
172 | static int pfkey_create(struct net *net, struct socket *sock, int protocol) | 180 | static int pfkey_create(struct net *net, struct socket *sock, int protocol) |
173 | { | 181 | { |
182 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
174 | struct sock *sk; | 183 | struct sock *sk; |
175 | int err; | 184 | int err; |
176 | 185 | ||
177 | if (net != &init_net) | ||
178 | return -EAFNOSUPPORT; | ||
179 | |||
180 | if (!capable(CAP_NET_ADMIN)) | 186 | if (!capable(CAP_NET_ADMIN)) |
181 | return -EPERM; | 187 | return -EPERM; |
182 | if (sock->type != SOCK_RAW) | 188 | if (sock->type != SOCK_RAW) |
@@ -195,7 +201,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol) | |||
195 | sk->sk_family = PF_KEY; | 201 | sk->sk_family = PF_KEY; |
196 | sk->sk_destruct = pfkey_sock_destruct; | 202 | sk->sk_destruct = pfkey_sock_destruct; |
197 | 203 | ||
198 | atomic_inc(&pfkey_socks_nr); | 204 | atomic_inc(&net_pfkey->socks_nr); |
199 | 205 | ||
200 | pfkey_insert(sk); | 206 | pfkey_insert(sk); |
201 | 207 | ||
@@ -257,6 +263,8 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, | |||
257 | static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | 263 | static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, |
258 | int broadcast_flags, struct sock *one_sk) | 264 | int broadcast_flags, struct sock *one_sk) |
259 | { | 265 | { |
266 | struct net *net = &init_net; | ||
267 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
260 | struct sock *sk; | 268 | struct sock *sk; |
261 | struct hlist_node *node; | 269 | struct hlist_node *node; |
262 | struct sk_buff *skb2 = NULL; | 270 | struct sk_buff *skb2 = NULL; |
@@ -269,7 +277,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, | |||
269 | return -ENOMEM; | 277 | return -ENOMEM; |
270 | 278 | ||
271 | pfkey_lock_table(); | 279 | pfkey_lock_table(); |
272 | sk_for_each(sk, node, &pfkey_table) { | 280 | sk_for_each(sk, node, &net_pfkey->table) { |
273 | struct pfkey_sock *pfk = pfkey_sk(sk); | 281 | struct pfkey_sock *pfk = pfkey_sk(sk); |
274 | int err2; | 282 | int err2; |
275 | 283 | ||
@@ -2943,7 +2951,10 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) | |||
2943 | 2951 | ||
2944 | static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) | 2952 | static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) |
2945 | { | 2953 | { |
2946 | if (atomic_read(&pfkey_socks_nr) == 0) | 2954 | struct net *net = &init_net; |
2955 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
2956 | |||
2957 | if (atomic_read(&net_pfkey->socks_nr) == 0) | ||
2947 | return 0; | 2958 | return 0; |
2948 | 2959 | ||
2949 | switch (c->event) { | 2960 | switch (c->event) { |
@@ -3647,6 +3658,8 @@ static int pfkey_seq_show(struct seq_file *f, void *v) | |||
3647 | 3658 | ||
3648 | static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) | 3659 | static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) |
3649 | { | 3660 | { |
3661 | struct net *net = &init_net; | ||
3662 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
3650 | struct sock *s; | 3663 | struct sock *s; |
3651 | struct hlist_node *node; | 3664 | struct hlist_node *node; |
3652 | loff_t pos = *ppos; | 3665 | loff_t pos = *ppos; |
@@ -3655,7 +3668,7 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) | |||
3655 | if (pos == 0) | 3668 | if (pos == 0) |
3656 | return SEQ_START_TOKEN; | 3669 | return SEQ_START_TOKEN; |
3657 | 3670 | ||
3658 | sk_for_each(s, node, &pfkey_table) | 3671 | sk_for_each(s, node, &net_pfkey->table) |
3659 | if (pos-- == 1) | 3672 | if (pos-- == 1) |
3660 | return s; | 3673 | return s; |
3661 | 3674 | ||
@@ -3664,9 +3677,12 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) | |||
3664 | 3677 | ||
3665 | static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) | 3678 | static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) |
3666 | { | 3679 | { |
3680 | struct net *net = &init_net; | ||
3681 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
3682 | |||
3667 | ++*ppos; | 3683 | ++*ppos; |
3668 | return (v == SEQ_START_TOKEN) ? | 3684 | return (v == SEQ_START_TOKEN) ? |
3669 | sk_head(&pfkey_table) : | 3685 | sk_head(&net_pfkey->table) : |
3670 | sk_next((struct sock *)v); | 3686 | sk_next((struct sock *)v); |
3671 | } | 3687 | } |
3672 | 3688 | ||
@@ -3731,8 +3747,45 @@ static struct xfrm_mgr pfkeyv2_mgr = | |||
3731 | .migrate = pfkey_send_migrate, | 3747 | .migrate = pfkey_send_migrate, |
3732 | }; | 3748 | }; |
3733 | 3749 | ||
3750 | static int __net_init pfkey_net_init(struct net *net) | ||
3751 | { | ||
3752 | struct netns_pfkey *net_pfkey; | ||
3753 | int rv; | ||
3754 | |||
3755 | net_pfkey = kmalloc(sizeof(struct netns_pfkey), GFP_KERNEL); | ||
3756 | if (!net_pfkey) { | ||
3757 | rv = -ENOMEM; | ||
3758 | goto out_kmalloc; | ||
3759 | } | ||
3760 | INIT_HLIST_HEAD(&net_pfkey->table); | ||
3761 | atomic_set(&net_pfkey->socks_nr, 0); | ||
3762 | rv = net_assign_generic(net, pfkey_net_id, net_pfkey); | ||
3763 | if (rv < 0) | ||
3764 | goto out_assign; | ||
3765 | return 0; | ||
3766 | |||
3767 | out_assign: | ||
3768 | kfree(net_pfkey); | ||
3769 | out_kmalloc: | ||
3770 | return rv; | ||
3771 | } | ||
3772 | |||
3773 | static void __net_exit pfkey_net_exit(struct net *net) | ||
3774 | { | ||
3775 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | ||
3776 | |||
3777 | BUG_ON(!hlist_empty(&net_pfkey->table)); | ||
3778 | kfree(net_pfkey); | ||
3779 | } | ||
3780 | |||
3781 | static struct pernet_operations pfkey_net_ops = { | ||
3782 | .init = pfkey_net_init, | ||
3783 | .exit = pfkey_net_exit, | ||
3784 | }; | ||
3785 | |||
3734 | static void __exit ipsec_pfkey_exit(void) | 3786 | static void __exit ipsec_pfkey_exit(void) |
3735 | { | 3787 | { |
3788 | unregister_pernet_gen_subsys(pfkey_net_id, &pfkey_net_ops); | ||
3736 | xfrm_unregister_km(&pfkeyv2_mgr); | 3789 | xfrm_unregister_km(&pfkeyv2_mgr); |
3737 | pfkey_exit_proc(); | 3790 | pfkey_exit_proc(); |
3738 | sock_unregister(PF_KEY); | 3791 | sock_unregister(PF_KEY); |
@@ -3755,8 +3808,13 @@ static int __init ipsec_pfkey_init(void) | |||
3755 | err = xfrm_register_km(&pfkeyv2_mgr); | 3808 | err = xfrm_register_km(&pfkeyv2_mgr); |
3756 | if (err != 0) | 3809 | if (err != 0) |
3757 | goto out_remove_proc_entry; | 3810 | goto out_remove_proc_entry; |
3811 | err = register_pernet_gen_subsys(&pfkey_net_id, &pfkey_net_ops); | ||
3812 | if (err != 0) | ||
3813 | goto out_xfrm_unregister_km; | ||
3758 | out: | 3814 | out: |
3759 | return err; | 3815 | return err; |
3816 | out_xfrm_unregister_km: | ||
3817 | xfrm_unregister_km(&pfkeyv2_mgr); | ||
3760 | out_remove_proc_entry: | 3818 | out_remove_proc_entry: |
3761 | pfkey_exit_proc(); | 3819 | pfkey_exit_proc(); |
3762 | out_sock_unregister: | 3820 | out_sock_unregister: |