netns PF_KEY: part 1
authorAlexey Dobriyan <adobriyan@gmail.com>
Wed, 26 Nov 2008 01:58:07 +0000 (17:58 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 26 Nov 2008 01:58:07 +0000 (17:58 -0800)
* 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>
net/key/af_key.c

index ea7755ab7e6a5656f68c88f15708705044fa7398..e80b26488bb31202143e4b717f8c4368ee80fc6b 100644 (file)
@@ -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>
 #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: