aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2010-01-13 10:02:14 -0500
committerPatrick McHardy <kaber@trash.net>2010-01-13 10:02:14 -0500
commitcd8c20b650f49354722b8cc1f03320b004815a0a (patch)
tree56c21f6211f0acea000452d5f6063453276ca215
parent7f635d0d1bf84ad7a0032cbce9d902b9384c48b7 (diff)
netfilter: nfnetlink: netns support
Make nfnl socket per-petns. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/linux/netfilter/nfnetlink.h8
-rw-r--r--include/net/net_namespace.h2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c13
-rw-r--r--net/netfilter/nfnetlink.c65
-rw-r--r--net/netfilter/nfnetlink_log.c3
-rw-r--r--net/netfilter/nfnetlink_queue.c2
6 files changed, 58 insertions, 35 deletions
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 49d321f3ccd2..53923868c9bd 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -73,11 +73,11 @@ struct nfnetlink_subsystem {
73extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); 73extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n);
74extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); 74extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n);
75 75
76extern int nfnetlink_has_listeners(unsigned int group); 76extern int nfnetlink_has_listeners(struct net *net, unsigned int group);
77extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, 77extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group,
78 int echo, gfp_t flags); 78 int echo, gfp_t flags);
79extern void nfnetlink_set_err(u32 pid, u32 group, int error); 79extern void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error);
80extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); 80extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags);
81 81
82extern void nfnl_lock(void); 82extern void nfnl_lock(void);
83extern void nfnl_unlock(void); 83extern void nfnl_unlock(void);
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index f307e133d14c..82b7be4db89a 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -81,6 +81,8 @@ struct net {
81#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) 81#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
82 struct netns_ct ct; 82 struct netns_ct ct;
83#endif 83#endif
84 struct sock *nfnl;
85 struct sock *nfnl_stash;
84#endif 86#endif
85#ifdef CONFIG_XFRM 87#ifdef CONFIG_XFRM
86 struct netns_xfrm xfrm; 88 struct netns_xfrm xfrm;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 59d8064eb522..d4c5d06677f9 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -482,7 +482,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
482 } else 482 } else
483 return 0; 483 return 0;
484 484
485 if (!item->report && !nfnetlink_has_listeners(group)) 485 if (!item->report && !nfnetlink_has_listeners(&init_net, group))
486 return 0; 486 return 0;
487 487
488 skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC); 488 skb = nlmsg_new(ctnetlink_nlmsg_size(ct), GFP_ATOMIC);
@@ -559,7 +559,8 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
559 rcu_read_unlock(); 559 rcu_read_unlock();
560 560
561 nlmsg_end(skb, nlh); 561 nlmsg_end(skb, nlh);
562 err = nfnetlink_send(skb, item->pid, group, item->report, GFP_ATOMIC); 562 err = nfnetlink_send(skb, &init_net, item->pid, group, item->report,
563 GFP_ATOMIC);
563 if (err == -ENOBUFS || err == -EAGAIN) 564 if (err == -ENOBUFS || err == -EAGAIN)
564 return -ENOBUFS; 565 return -ENOBUFS;
565 566
@@ -571,7 +572,7 @@ nla_put_failure:
571nlmsg_failure: 572nlmsg_failure:
572 kfree_skb(skb); 573 kfree_skb(skb);
573errout: 574errout:
574 nfnetlink_set_err(0, group, -ENOBUFS); 575 nfnetlink_set_err(&init_net, 0, group, -ENOBUFS);
575 return 0; 576 return 0;
576} 577}
577#endif /* CONFIG_NF_CONNTRACK_EVENTS */ 578#endif /* CONFIG_NF_CONNTRACK_EVENTS */
@@ -1539,7 +1540,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
1539 return 0; 1540 return 0;
1540 1541
1541 if (!item->report && 1542 if (!item->report &&
1542 !nfnetlink_has_listeners(NFNLGRP_CONNTRACK_EXP_NEW)) 1543 !nfnetlink_has_listeners(&init_net, NFNLGRP_CONNTRACK_EXP_NEW))
1543 return 0; 1544 return 0;
1544 1545
1545 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1546 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
@@ -1562,7 +1563,7 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
1562 rcu_read_unlock(); 1563 rcu_read_unlock();
1563 1564
1564 nlmsg_end(skb, nlh); 1565 nlmsg_end(skb, nlh);
1565 nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, 1566 nfnetlink_send(skb, &init_net, item->pid, NFNLGRP_CONNTRACK_EXP_NEW,
1566 item->report, GFP_ATOMIC); 1567 item->report, GFP_ATOMIC);
1567 return 0; 1568 return 0;
1568 1569
@@ -1572,7 +1573,7 @@ nla_put_failure:
1572nlmsg_failure: 1573nlmsg_failure:
1573 kfree_skb(skb); 1574 kfree_skb(skb);
1574errout: 1575errout:
1575 nfnetlink_set_err(0, 0, -ENOBUFS); 1576 nfnetlink_set_err(&init_net, 0, 0, -ENOBUFS);
1576 return 0; 1577 return 0;
1577} 1578}
1578#endif 1579#endif
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index eedc0c1ac7a4..8eb0cc23ada3 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -40,7 +40,6 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
40 40
41static char __initdata nfversion[] = "0.30"; 41static char __initdata nfversion[] = "0.30";
42 42
43static struct sock *nfnl = NULL;
44static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; 43static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT];
45static DEFINE_MUTEX(nfnl_mutex); 44static DEFINE_MUTEX(nfnl_mutex);
46 45
@@ -101,34 +100,35 @@ nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss)
101 return &ss->cb[cb_id]; 100 return &ss->cb[cb_id];
102} 101}
103 102
104int nfnetlink_has_listeners(unsigned int group) 103int nfnetlink_has_listeners(struct net *net, unsigned int group)
105{ 104{
106 return netlink_has_listeners(nfnl, group); 105 return netlink_has_listeners(net->nfnl, group);
107} 106}
108EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); 107EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
109 108
110int nfnetlink_send(struct sk_buff *skb, u32 pid, 109int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid,
111 unsigned group, int echo, gfp_t flags) 110 unsigned group, int echo, gfp_t flags)
112{ 111{
113 return nlmsg_notify(nfnl, skb, pid, group, echo, flags); 112 return nlmsg_notify(net->nfnl, skb, pid, group, echo, flags);
114} 113}
115EXPORT_SYMBOL_GPL(nfnetlink_send); 114EXPORT_SYMBOL_GPL(nfnetlink_send);
116 115
117void nfnetlink_set_err(u32 pid, u32 group, int error) 116void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error)
118{ 117{
119 netlink_set_err(nfnl, pid, group, error); 118 netlink_set_err(net->nfnl, pid, group, error);
120} 119}
121EXPORT_SYMBOL_GPL(nfnetlink_set_err); 120EXPORT_SYMBOL_GPL(nfnetlink_set_err);
122 121
123int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) 122int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags)
124{ 123{
125 return netlink_unicast(nfnl, skb, pid, flags); 124 return netlink_unicast(net->nfnl, skb, pid, flags);
126} 125}
127EXPORT_SYMBOL_GPL(nfnetlink_unicast); 126EXPORT_SYMBOL_GPL(nfnetlink_unicast);
128 127
129/* Process one complete nfnetlink message. */ 128/* Process one complete nfnetlink message. */
130static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 129static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
131{ 130{
131 struct net *net = sock_net(skb->sk);
132 const struct nfnl_callback *nc; 132 const struct nfnl_callback *nc;
133 const struct nfnetlink_subsystem *ss; 133 const struct nfnetlink_subsystem *ss;
134 int type, err; 134 int type, err;
@@ -170,7 +170,7 @@ replay:
170 if (err < 0) 170 if (err < 0)
171 return err; 171 return err;
172 172
173 err = nc->call(nfnl, skb, nlh, (const struct nlattr **)cda); 173 err = nc->call(net->nfnl, skb, nlh, (const struct nlattr **)cda);
174 if (err == -EAGAIN) 174 if (err == -EAGAIN)
175 goto replay; 175 goto replay;
176 return err; 176 return err;
@@ -184,26 +184,45 @@ static void nfnetlink_rcv(struct sk_buff *skb)
184 nfnl_unlock(); 184 nfnl_unlock();
185} 185}
186 186
187static void __exit nfnetlink_exit(void) 187static int __net_init nfnetlink_net_init(struct net *net)
188{ 188{
189 printk("Removing netfilter NETLINK layer.\n"); 189 struct sock *nfnl;
190 netlink_kernel_release(nfnl); 190
191 return; 191 nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, NFNLGRP_MAX,
192 nfnetlink_rcv, NULL, THIS_MODULE);
193 if (!nfnl)
194 return -ENOMEM;
195 net->nfnl_stash = nfnl;
196 rcu_assign_pointer(net->nfnl, nfnl);
197 return 0;
192} 198}
193 199
194static int __init nfnetlink_init(void) 200static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list)
195{ 201{
196 printk("Netfilter messages via NETLINK v%s.\n", nfversion); 202 struct net *net;
197 203
198 nfnl = netlink_kernel_create(&init_net, NETLINK_NETFILTER, NFNLGRP_MAX, 204 list_for_each_entry(net, net_exit_list, exit_list)
199 nfnetlink_rcv, NULL, THIS_MODULE); 205 rcu_assign_pointer(net->nfnl, NULL);
200 if (!nfnl) { 206 synchronize_net();
201 printk(KERN_ERR "cannot initialize nfnetlink!\n"); 207 list_for_each_entry(net, net_exit_list, exit_list)
202 return -ENOMEM; 208 netlink_kernel_release(net->nfnl_stash);
203 } 209}
204 210
205 return 0; 211static struct pernet_operations nfnetlink_net_ops = {
212 .init = nfnetlink_net_init,
213 .exit_batch = nfnetlink_net_exit_batch,
214};
215
216static int __init nfnetlink_init(void)
217{
218 printk("Netfilter messages via NETLINK v%s.\n", nfversion);
219 return register_pernet_subsys(&nfnetlink_net_ops);
206} 220}
207 221
222static void __exit nfnetlink_exit(void)
223{
224 printk("Removing netfilter NETLINK layer.\n");
225 unregister_pernet_subsys(&nfnetlink_net_ops);
226}
208module_init(nfnetlink_init); 227module_init(nfnetlink_init);
209module_exit(nfnetlink_exit); 228module_exit(nfnetlink_exit);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 9de0470d557e..285e9029a9ff 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -323,7 +323,8 @@ __nfulnl_send(struct nfulnl_instance *inst)
323 NLMSG_DONE, 323 NLMSG_DONE,
324 sizeof(struct nfgenmsg)); 324 sizeof(struct nfgenmsg));
325 325
326 status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT); 326 status = nfnetlink_unicast(inst->skb, &init_net, inst->peer_pid,
327 MSG_DONTWAIT);
327 328
328 inst->qlen = 0; 329 inst->qlen = 0;
329 inst->skb = NULL; 330 inst->skb = NULL;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 7e3fa410641e..5c589b27d6eb 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -420,7 +420,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
420 } 420 }
421 421
422 /* nfnetlink_unicast will either free the nskb or add it to a socket */ 422 /* nfnetlink_unicast will either free the nskb or add it to a socket */
423 err = nfnetlink_unicast(nskb, queue->peer_pid, MSG_DONTWAIT); 423 err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
424 if (err < 0) { 424 if (err < 0) {
425 queue->queue_user_dropped++; 425 queue->queue_user_dropped++;
426 goto err_out_unlock; 426 goto err_out_unlock;