diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/netfilter/ebt_ulog.c | 125 |
1 files changed, 88 insertions, 37 deletions
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index 442b0321acb9..0ddd612787e3 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/netfilter_bridge/ebtables.h> | 41 | #include <linux/netfilter_bridge/ebtables.h> |
42 | #include <linux/netfilter_bridge/ebt_ulog.h> | 42 | #include <linux/netfilter_bridge/ebt_ulog.h> |
43 | #include <net/netfilter/nf_log.h> | 43 | #include <net/netfilter/nf_log.h> |
44 | #include <net/netns/generic.h> | ||
44 | #include <net/sock.h> | 45 | #include <net/sock.h> |
45 | #include "../br_private.h" | 46 | #include "../br_private.h" |
46 | 47 | ||
@@ -62,13 +63,22 @@ typedef struct { | |||
62 | spinlock_t lock; /* the per-queue lock */ | 63 | spinlock_t lock; /* the per-queue lock */ |
63 | } ebt_ulog_buff_t; | 64 | } ebt_ulog_buff_t; |
64 | 65 | ||
65 | static ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS]; | 66 | static int ebt_ulog_net_id __read_mostly; |
66 | static struct sock *ebtulognl; | 67 | struct ebt_ulog_net { |
68 | unsigned int nlgroup[EBT_ULOG_MAXNLGROUPS]; | ||
69 | ebt_ulog_buff_t ulog_buffers[EBT_ULOG_MAXNLGROUPS]; | ||
70 | struct sock *ebtulognl; | ||
71 | }; | ||
72 | |||
73 | static struct ebt_ulog_net *ebt_ulog_pernet(struct net *net) | ||
74 | { | ||
75 | return net_generic(net, ebt_ulog_net_id); | ||
76 | } | ||
67 | 77 | ||
68 | /* send one ulog_buff_t to userspace */ | 78 | /* send one ulog_buff_t to userspace */ |
69 | static void ulog_send(unsigned int nlgroup) | 79 | static void ulog_send(struct ebt_ulog_net *ebt, unsigned int nlgroup) |
70 | { | 80 | { |
71 | ebt_ulog_buff_t *ub = &ulog_buffers[nlgroup]; | 81 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[nlgroup]; |
72 | 82 | ||
73 | del_timer(&ub->timer); | 83 | del_timer(&ub->timer); |
74 | 84 | ||
@@ -80,7 +90,7 @@ static void ulog_send(unsigned int nlgroup) | |||
80 | ub->lastnlh->nlmsg_type = NLMSG_DONE; | 90 | ub->lastnlh->nlmsg_type = NLMSG_DONE; |
81 | 91 | ||
82 | NETLINK_CB(ub->skb).dst_group = nlgroup + 1; | 92 | NETLINK_CB(ub->skb).dst_group = nlgroup + 1; |
83 | netlink_broadcast(ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC); | 93 | netlink_broadcast(ebt->ebtulognl, ub->skb, 0, nlgroup + 1, GFP_ATOMIC); |
84 | 94 | ||
85 | ub->qlen = 0; | 95 | ub->qlen = 0; |
86 | ub->skb = NULL; | 96 | ub->skb = NULL; |
@@ -89,10 +99,15 @@ static void ulog_send(unsigned int nlgroup) | |||
89 | /* timer function to flush queue in flushtimeout time */ | 99 | /* timer function to flush queue in flushtimeout time */ |
90 | static void ulog_timer(unsigned long data) | 100 | static void ulog_timer(unsigned long data) |
91 | { | 101 | { |
92 | spin_lock_bh(&ulog_buffers[data].lock); | 102 | struct ebt_ulog_net *ebt = container_of((void *)data, |
93 | if (ulog_buffers[data].skb) | 103 | struct ebt_ulog_net, |
94 | ulog_send(data); | 104 | nlgroup[*(unsigned int *)data]); |
95 | spin_unlock_bh(&ulog_buffers[data].lock); | 105 | |
106 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[*(unsigned int *)data]; | ||
107 | spin_lock_bh(&ub->lock); | ||
108 | if (ub->skb) | ||
109 | ulog_send(ebt, *(unsigned int *)data); | ||
110 | spin_unlock_bh(&ub->lock); | ||
96 | } | 111 | } |
97 | 112 | ||
98 | static struct sk_buff *ulog_alloc_skb(unsigned int size) | 113 | static struct sk_buff *ulog_alloc_skb(unsigned int size) |
@@ -123,8 +138,10 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
123 | ebt_ulog_packet_msg_t *pm; | 138 | ebt_ulog_packet_msg_t *pm; |
124 | size_t size, copy_len; | 139 | size_t size, copy_len; |
125 | struct nlmsghdr *nlh; | 140 | struct nlmsghdr *nlh; |
141 | struct net *net = dev_net(in ? in : out); | ||
142 | struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); | ||
126 | unsigned int group = uloginfo->nlgroup; | 143 | unsigned int group = uloginfo->nlgroup; |
127 | ebt_ulog_buff_t *ub = &ulog_buffers[group]; | 144 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[group]; |
128 | spinlock_t *lock = &ub->lock; | 145 | spinlock_t *lock = &ub->lock; |
129 | ktime_t kt; | 146 | ktime_t kt; |
130 | 147 | ||
@@ -146,7 +163,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
146 | if (!(ub->skb = ulog_alloc_skb(size))) | 163 | if (!(ub->skb = ulog_alloc_skb(size))) |
147 | goto unlock; | 164 | goto unlock; |
148 | } else if (size > skb_tailroom(ub->skb)) { | 165 | } else if (size > skb_tailroom(ub->skb)) { |
149 | ulog_send(group); | 166 | ulog_send(ebt, group); |
150 | 167 | ||
151 | if (!(ub->skb = ulog_alloc_skb(size))) | 168 | if (!(ub->skb = ulog_alloc_skb(size))) |
152 | goto unlock; | 169 | goto unlock; |
@@ -205,7 +222,7 @@ static void ebt_ulog_packet(unsigned int hooknr, const struct sk_buff *skb, | |||
205 | ub->lastnlh = nlh; | 222 | ub->lastnlh = nlh; |
206 | 223 | ||
207 | if (ub->qlen >= uloginfo->qthreshold) | 224 | if (ub->qlen >= uloginfo->qthreshold) |
208 | ulog_send(group); | 225 | ulog_send(ebt, group); |
209 | else if (!timer_pending(&ub->timer)) { | 226 | else if (!timer_pending(&ub->timer)) { |
210 | ub->timer.expires = jiffies + flushtimeout * HZ / 100; | 227 | ub->timer.expires = jiffies + flushtimeout * HZ / 100; |
211 | add_timer(&ub->timer); | 228 | add_timer(&ub->timer); |
@@ -277,47 +294,39 @@ static struct nf_logger ebt_ulog_logger __read_mostly = { | |||
277 | .me = THIS_MODULE, | 294 | .me = THIS_MODULE, |
278 | }; | 295 | }; |
279 | 296 | ||
280 | static int __init ebt_ulog_init(void) | 297 | static int __net_init ebt_ulog_net_init(struct net *net) |
281 | { | 298 | { |
282 | int ret; | ||
283 | int i; | 299 | int i; |
300 | struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); | ||
301 | |||
284 | struct netlink_kernel_cfg cfg = { | 302 | struct netlink_kernel_cfg cfg = { |
285 | .groups = EBT_ULOG_MAXNLGROUPS, | 303 | .groups = EBT_ULOG_MAXNLGROUPS, |
286 | }; | 304 | }; |
287 | 305 | ||
288 | if (nlbufsiz >= 128*1024) { | ||
289 | pr_warning("Netlink buffer has to be <= 128kB," | ||
290 | " please try a smaller nlbufsiz parameter.\n"); | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | |||
294 | /* initialize ulog_buffers */ | 306 | /* initialize ulog_buffers */ |
295 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { | 307 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { |
296 | setup_timer(&ulog_buffers[i].timer, ulog_timer, i); | 308 | ebt->nlgroup[i] = i; |
297 | spin_lock_init(&ulog_buffers[i].lock); | 309 | setup_timer(&ebt->ulog_buffers[i].timer, ulog_timer, |
310 | (unsigned long)&ebt->nlgroup[i]); | ||
311 | spin_lock_init(&ebt->ulog_buffers[i].lock); | ||
298 | } | 312 | } |
299 | 313 | ||
300 | ebtulognl = netlink_kernel_create(&init_net, NETLINK_NFLOG, &cfg); | 314 | ebt->ebtulognl = netlink_kernel_create(net, NETLINK_NFLOG, &cfg); |
301 | if (!ebtulognl) | 315 | if (!ebt->ebtulognl) |
302 | ret = -ENOMEM; | 316 | return -ENOMEM; |
303 | else if ((ret = xt_register_target(&ebt_ulog_tg_reg)) != 0) | ||
304 | netlink_kernel_release(ebtulognl); | ||
305 | 317 | ||
306 | if (ret == 0) | 318 | nf_log_set(net, NFPROTO_BRIDGE, &ebt_ulog_logger); |
307 | nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger); | 319 | return 0; |
308 | |||
309 | return ret; | ||
310 | } | 320 | } |
311 | 321 | ||
312 | static void __exit ebt_ulog_fini(void) | 322 | static void __net_exit ebt_ulog_net_fini(struct net *net) |
313 | { | 323 | { |
314 | ebt_ulog_buff_t *ub; | ||
315 | int i; | 324 | int i; |
325 | struct ebt_ulog_net *ebt = ebt_ulog_pernet(net); | ||
316 | 326 | ||
317 | nf_log_unregister(&ebt_ulog_logger); | 327 | nf_log_unset(net, &ebt_ulog_logger); |
318 | xt_unregister_target(&ebt_ulog_tg_reg); | ||
319 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { | 328 | for (i = 0; i < EBT_ULOG_MAXNLGROUPS; i++) { |
320 | ub = &ulog_buffers[i]; | 329 | ebt_ulog_buff_t *ub = &ebt->ulog_buffers[i]; |
321 | del_timer(&ub->timer); | 330 | del_timer(&ub->timer); |
322 | 331 | ||
323 | if (ub->skb) { | 332 | if (ub->skb) { |
@@ -325,7 +334,49 @@ static void __exit ebt_ulog_fini(void) | |||
325 | ub->skb = NULL; | 334 | ub->skb = NULL; |
326 | } | 335 | } |
327 | } | 336 | } |
328 | netlink_kernel_release(ebtulognl); | 337 | netlink_kernel_release(ebt->ebtulognl); |
338 | } | ||
339 | |||
340 | static struct pernet_operations ebt_ulog_net_ops = { | ||
341 | .init = ebt_ulog_net_init, | ||
342 | .exit = ebt_ulog_net_fini, | ||
343 | .id = &ebt_ulog_net_id, | ||
344 | .size = sizeof(struct ebt_ulog_net), | ||
345 | }; | ||
346 | |||
347 | static int __init ebt_ulog_init(void) | ||
348 | { | ||
349 | int ret; | ||
350 | |||
351 | if (nlbufsiz >= 128*1024) { | ||
352 | pr_warn("Netlink buffer has to be <= 128kB," | ||
353 | "please try a smaller nlbufsiz parameter.\n"); | ||
354 | return -EINVAL; | ||
355 | } | ||
356 | |||
357 | ret = register_pernet_subsys(&ebt_ulog_net_ops); | ||
358 | if (ret) | ||
359 | goto out_pernet; | ||
360 | |||
361 | ret = xt_register_target(&ebt_ulog_tg_reg); | ||
362 | if (ret) | ||
363 | goto out_target; | ||
364 | |||
365 | nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger); | ||
366 | |||
367 | return 0; | ||
368 | |||
369 | out_target: | ||
370 | unregister_pernet_subsys(&ebt_ulog_net_ops); | ||
371 | out_pernet: | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static void __exit ebt_ulog_fini(void) | ||
376 | { | ||
377 | nf_log_unregister(&ebt_ulog_logger); | ||
378 | xt_unregister_target(&ebt_ulog_tg_reg); | ||
379 | unregister_pernet_subsys(&ebt_ulog_net_ops); | ||
329 | } | 380 | } |
330 | 381 | ||
331 | module_init(ebt_ulog_init); | 382 | module_init(ebt_ulog_init); |