Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3fa87a32 authored by Alexey Dobriyan's avatar Alexey Dobriyan Committed by David S. Miller
Browse files

netns PF_KEY: part 1



* netns boilerplate
* keep per-netns socket list
* keep per-netns number of sockets

Signed-off-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7c2776ee
Loading
Loading
Loading
Loading
+73 −15
Original line number Diff line number Diff line
@@ -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))


static int pfkey_net_id;
struct netns_pfkey {
	/* List of all pfkey sockets. */
static HLIST_HEAD(pfkey_table);
	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: