diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2010-01-13 10:02:14 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-01-13 10:02:14 -0500 |
commit | cd8c20b650f49354722b8cc1f03320b004815a0a (patch) | |
tree | 56c21f6211f0acea000452d5f6063453276ca215 | |
parent | 7f635d0d1bf84ad7a0032cbce9d902b9384c48b7 (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.h | 8 | ||||
-rw-r--r-- | include/net/net_namespace.h | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 13 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 65 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 3 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_queue.c | 2 |
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 { | |||
73 | extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); | 73 | extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); |
74 | extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); | 74 | extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); |
75 | 75 | ||
76 | extern int nfnetlink_has_listeners(unsigned int group); | 76 | extern int nfnetlink_has_listeners(struct net *net, unsigned int group); |
77 | extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, | 77 | extern 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); |
79 | extern void nfnetlink_set_err(u32 pid, u32 group, int error); | 79 | extern void nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error); |
80 | extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); | 80 | extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags); |
81 | 81 | ||
82 | extern void nfnl_lock(void); | 82 | extern void nfnl_lock(void); |
83 | extern void nfnl_unlock(void); | 83 | extern 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: | |||
571 | nlmsg_failure: | 572 | nlmsg_failure: |
572 | kfree_skb(skb); | 573 | kfree_skb(skb); |
573 | errout: | 574 | errout: |
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: | |||
1572 | nlmsg_failure: | 1573 | nlmsg_failure: |
1573 | kfree_skb(skb); | 1574 | kfree_skb(skb); |
1574 | errout: | 1575 | errout: |
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 | ||
41 | static char __initdata nfversion[] = "0.30"; | 41 | static char __initdata nfversion[] = "0.30"; |
42 | 42 | ||
43 | static struct sock *nfnl = NULL; | ||
44 | static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; | 43 | static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; |
45 | static DEFINE_MUTEX(nfnl_mutex); | 44 | static 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 | ||
104 | int nfnetlink_has_listeners(unsigned int group) | 103 | int 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 | } |
108 | EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); | 107 | EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); |
109 | 108 | ||
110 | int nfnetlink_send(struct sk_buff *skb, u32 pid, | 109 | int 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 | } |
115 | EXPORT_SYMBOL_GPL(nfnetlink_send); | 114 | EXPORT_SYMBOL_GPL(nfnetlink_send); |
116 | 115 | ||
117 | void nfnetlink_set_err(u32 pid, u32 group, int error) | 116 | void 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 | } |
121 | EXPORT_SYMBOL_GPL(nfnetlink_set_err); | 120 | EXPORT_SYMBOL_GPL(nfnetlink_set_err); |
122 | 121 | ||
123 | int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) | 122 | int 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 | } |
127 | EXPORT_SYMBOL_GPL(nfnetlink_unicast); | 126 | EXPORT_SYMBOL_GPL(nfnetlink_unicast); |
128 | 127 | ||
129 | /* Process one complete nfnetlink message. */ | 128 | /* Process one complete nfnetlink message. */ |
130 | static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | 129 | static 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 | ||
187 | static void __exit nfnetlink_exit(void) | 187 | static 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 | ||
194 | static int __init nfnetlink_init(void) | 200 | static 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; | 211 | static struct pernet_operations nfnetlink_net_ops = { |
212 | .init = nfnetlink_net_init, | ||
213 | .exit_batch = nfnetlink_net_exit_batch, | ||
214 | }; | ||
215 | |||
216 | static 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 | ||
222 | static void __exit nfnetlink_exit(void) | ||
223 | { | ||
224 | printk("Removing netfilter NETLINK layer.\n"); | ||
225 | unregister_pernet_subsys(&nfnetlink_net_ops); | ||
226 | } | ||
208 | module_init(nfnetlink_init); | 227 | module_init(nfnetlink_init); |
209 | module_exit(nfnetlink_exit); | 228 | module_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; |