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>
This commit is contained in:
parent
7c2776ee21
commit
3fa87a3210
|
@ -27,6 +27,7 @@
|
|||
#include <linux/proc_fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
#include <net/xfrm.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
|
@ -34,15 +35,16 @@
|
|||
#define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
|
||||
#define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x))
|
||||
|
||||
|
||||
/* List of all pfkey sockets. */
|
||||
static HLIST_HEAD(pfkey_table);
|
||||
static int pfkey_net_id;
|
||||
struct netns_pfkey {
|
||||
/* List of all pfkey sockets. */
|
||||
struct hlist_head table;
|
||||
atomic_t socks_nr;
|
||||
};
|
||||
static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait);
|
||||
static DEFINE_RWLOCK(pfkey_table_lock);
|
||||
static atomic_t pfkey_table_users = ATOMIC_INIT(0);
|
||||
|
||||
static atomic_t pfkey_socks_nr = ATOMIC_INIT(0);
|
||||
|
||||
struct pfkey_sock {
|
||||
/* struct sock must be the first member of struct pfkey_sock */
|
||||
struct sock sk;
|
||||
|
@ -89,6 +91,9 @@ static void pfkey_terminate_dump(struct pfkey_sock *pfk)
|
|||
|
||||
static void pfkey_sock_destruct(struct sock *sk)
|
||||
{
|
||||
struct net *net = sock_net(sk);
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
|
||||
pfkey_terminate_dump(pfkey_sk(sk));
|
||||
skb_queue_purge(&sk->sk_receive_queue);
|
||||
|
||||
|
@ -100,7 +105,7 @@ static void pfkey_sock_destruct(struct sock *sk)
|
|||
WARN_ON(atomic_read(&sk->sk_rmem_alloc));
|
||||
WARN_ON(atomic_read(&sk->sk_wmem_alloc));
|
||||
|
||||
atomic_dec(&pfkey_socks_nr);
|
||||
atomic_dec(&net_pfkey->socks_nr);
|
||||
}
|
||||
|
||||
static void pfkey_table_grab(void)
|
||||
|
@ -151,8 +156,11 @@ static const struct proto_ops pfkey_ops;
|
|||
|
||||
static void pfkey_insert(struct sock *sk)
|
||||
{
|
||||
struct net *net = sock_net(sk);
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
|
||||
pfkey_table_grab();
|
||||
sk_add_node(sk, &pfkey_table);
|
||||
sk_add_node(sk, &net_pfkey->table);
|
||||
pfkey_table_ungrab();
|
||||
}
|
||||
|
||||
|
@ -171,12 +179,10 @@ static struct proto key_proto = {
|
|||
|
||||
static int pfkey_create(struct net *net, struct socket *sock, int protocol)
|
||||
{
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
struct sock *sk;
|
||||
int err;
|
||||
|
||||
if (net != &init_net)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
if (sock->type != SOCK_RAW)
|
||||
|
@ -195,7 +201,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol)
|
|||
sk->sk_family = PF_KEY;
|
||||
sk->sk_destruct = pfkey_sock_destruct;
|
||||
|
||||
atomic_inc(&pfkey_socks_nr);
|
||||
atomic_inc(&net_pfkey->socks_nr);
|
||||
|
||||
pfkey_insert(sk);
|
||||
|
||||
|
@ -257,6 +263,8 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
|
|||
static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
|
||||
int broadcast_flags, struct sock *one_sk)
|
||||
{
|
||||
struct net *net = &init_net;
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
struct sk_buff *skb2 = NULL;
|
||||
|
@ -269,7 +277,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
|
|||
return -ENOMEM;
|
||||
|
||||
pfkey_lock_table();
|
||||
sk_for_each(sk, node, &pfkey_table) {
|
||||
sk_for_each(sk, node, &net_pfkey->table) {
|
||||
struct pfkey_sock *pfk = pfkey_sk(sk);
|
||||
int err2;
|
||||
|
||||
|
@ -2943,7 +2951,10 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c)
|
|||
|
||||
static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c)
|
||||
{
|
||||
if (atomic_read(&pfkey_socks_nr) == 0)
|
||||
struct net *net = &init_net;
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
|
||||
if (atomic_read(&net_pfkey->socks_nr) == 0)
|
||||
return 0;
|
||||
|
||||
switch (c->event) {
|
||||
|
@ -3647,6 +3658,8 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
|
|||
|
||||
static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos)
|
||||
{
|
||||
struct net *net = &init_net;
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
struct sock *s;
|
||||
struct hlist_node *node;
|
||||
loff_t pos = *ppos;
|
||||
|
@ -3655,7 +3668,7 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos)
|
|||
if (pos == 0)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
sk_for_each(s, node, &pfkey_table)
|
||||
sk_for_each(s, node, &net_pfkey->table)
|
||||
if (pos-- == 1)
|
||||
return s;
|
||||
|
||||
|
@ -3664,9 +3677,12 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos)
|
|||
|
||||
static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos)
|
||||
{
|
||||
struct net *net = &init_net;
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
|
||||
++*ppos;
|
||||
return (v == SEQ_START_TOKEN) ?
|
||||
sk_head(&pfkey_table) :
|
||||
sk_head(&net_pfkey->table) :
|
||||
sk_next((struct sock *)v);
|
||||
}
|
||||
|
||||
|
@ -3731,8 +3747,45 @@ static struct xfrm_mgr pfkeyv2_mgr =
|
|||
.migrate = pfkey_send_migrate,
|
||||
};
|
||||
|
||||
static int __net_init pfkey_net_init(struct net *net)
|
||||
{
|
||||
struct netns_pfkey *net_pfkey;
|
||||
int rv;
|
||||
|
||||
net_pfkey = kmalloc(sizeof(struct netns_pfkey), GFP_KERNEL);
|
||||
if (!net_pfkey) {
|
||||
rv = -ENOMEM;
|
||||
goto out_kmalloc;
|
||||
}
|
||||
INIT_HLIST_HEAD(&net_pfkey->table);
|
||||
atomic_set(&net_pfkey->socks_nr, 0);
|
||||
rv = net_assign_generic(net, pfkey_net_id, net_pfkey);
|
||||
if (rv < 0)
|
||||
goto out_assign;
|
||||
return 0;
|
||||
|
||||
out_assign:
|
||||
kfree(net_pfkey);
|
||||
out_kmalloc:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void __net_exit pfkey_net_exit(struct net *net)
|
||||
{
|
||||
struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id);
|
||||
|
||||
BUG_ON(!hlist_empty(&net_pfkey->table));
|
||||
kfree(net_pfkey);
|
||||
}
|
||||
|
||||
static struct pernet_operations pfkey_net_ops = {
|
||||
.init = pfkey_net_init,
|
||||
.exit = pfkey_net_exit,
|
||||
};
|
||||
|
||||
static void __exit ipsec_pfkey_exit(void)
|
||||
{
|
||||
unregister_pernet_gen_subsys(pfkey_net_id, &pfkey_net_ops);
|
||||
xfrm_unregister_km(&pfkeyv2_mgr);
|
||||
pfkey_exit_proc();
|
||||
sock_unregister(PF_KEY);
|
||||
|
@ -3755,8 +3808,13 @@ static int __init ipsec_pfkey_init(void)
|
|||
err = xfrm_register_km(&pfkeyv2_mgr);
|
||||
if (err != 0)
|
||||
goto out_remove_proc_entry;
|
||||
err = register_pernet_gen_subsys(&pfkey_net_id, &pfkey_net_ops);
|
||||
if (err != 0)
|
||||
goto out_xfrm_unregister_km;
|
||||
out:
|
||||
return err;
|
||||
out_xfrm_unregister_km:
|
||||
xfrm_unregister_km(&pfkeyv2_mgr);
|
||||
out_remove_proc_entry:
|
||||
pfkey_exit_proc();
|
||||
out_sock_unregister:
|
||||
|
|
Loading…
Reference in a new issue